From 211042401e2a7f70689cbba04df0a0c2f387409f Mon Sep 17 00:00:00 2001 From: Huey Date: Thu, 24 Nov 2022 20:59:09 +0800 Subject: [PATCH 1/8] fix: should now inject properly on post detail page --- src/content_script/mastodonInject.js | 32 +++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/content_script/mastodonInject.js b/src/content_script/mastodonInject.js index ee1c5d7..9b53534 100644 --- a/src/content_script/mastodonInject.js +++ b/src/content_script/mastodonInject.js @@ -129,20 +129,26 @@ async function injectInteractionButtons() { async function init() { injectFollowButton(); - const observer = new MutationObserver(() => { - Promise.allSettled([ - injectInteractionButtons(), - ]); - }); + const ogType = document.querySelector("meta[property='og:type']"); - const feedElement = await waitForElement( - "#mastodon .item-list[role='feed']", - false, - TIMEOUT_DURATION - ); - observer.observe(feedElement, { - childList: true, subtree: true, - }); + if (ogType && ogType.getAttribute("content") === "article"){ + injectInteractionButtons(); + } else { + const observer = new MutationObserver(() => { + Promise.allSettled([ + injectInteractionButtons(), + ]); + }); + + const feedElement = await waitForElement( + "#mastodon .item-list[role='feed']", + false, + TIMEOUT_DURATION + ); + observer.observe(feedElement, { + childList: true, subtree: true, + }); + } } init(); \ No newline at end of file From 46468116f6584534f64ea736642cd98c00fa9c7f Mon Sep 17 00:00:00 2001 From: Huey Date: Sat, 26 Nov 2022 09:49:18 +0800 Subject: [PATCH 2/8] Update src/content_script/mastodonInject.js Co-authored-by: rugk --- src/content_script/mastodonInject.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/content_script/mastodonInject.js b/src/content_script/mastodonInject.js index 9b53534..1864a3c 100644 --- a/src/content_script/mastodonInject.js +++ b/src/content_script/mastodonInject.js @@ -131,6 +131,7 @@ async function init() { const ogType = document.querySelector("meta[property='og:type']"); + // inject only once on detail toots view pages if (ogType && ogType.getAttribute("content") === "article"){ injectInteractionButtons(); } else { From 9c5ae05385a090e8567ce49b510418b10acf658f Mon Sep 17 00:00:00 2001 From: Huey Date: Sat, 26 Nov 2022 09:49:42 +0800 Subject: [PATCH 3/8] Update src/content_script/mastodonInject.js Co-authored-by: rugk --- src/content_script/mastodonInject.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/content_script/mastodonInject.js b/src/content_script/mastodonInject.js index 1864a3c..f6b3d21 100644 --- a/src/content_script/mastodonInject.js +++ b/src/content_script/mastodonInject.js @@ -134,7 +134,8 @@ async function init() { // inject only once on detail toots view pages if (ogType && ogType.getAttribute("content") === "article"){ injectInteractionButtons(); - } else { + // otherwise listen to the feed for new posts + } else { const observer = new MutationObserver(() => { Promise.allSettled([ injectInteractionButtons(), From a1e07a0564b4b91dd3944e69e99774f5df9194d4 Mon Sep 17 00:00:00 2001 From: Huey Date: Sat, 26 Nov 2022 09:52:04 +0800 Subject: [PATCH 4/8] fix: catch error when feedElement not found --- src/content_script/mastodonInject.js | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/content_script/mastodonInject.js b/src/content_script/mastodonInject.js index f6b3d21..8f4d20f 100644 --- a/src/content_script/mastodonInject.js +++ b/src/content_script/mastodonInject.js @@ -135,21 +135,25 @@ async function init() { if (ogType && ogType.getAttribute("content") === "article"){ injectInteractionButtons(); // otherwise listen to the feed for new posts - } else { + } else { const observer = new MutationObserver(() => { - Promise.allSettled([ - injectInteractionButtons(), - ]); + injectInteractionButtons(); }); - const feedElement = await waitForElement( - "#mastodon .item-list[role='feed']", - false, - TIMEOUT_DURATION - ); - observer.observe(feedElement, { - childList: true, subtree: true, - }); + try { + const feedElement = await waitForElement( + "#mastodon .item-list[role='feed']", + false, + TIMEOUT_DURATION + ); + + observer.observe(feedElement, { + childList: true, subtree: true, + }); + } catch (error){ + // feedElement not found + } + } } From 8490dbe1a7ad8d40448f08d894496be9f917d00c Mon Sep 17 00:00:00 2001 From: Huey Date: Sat, 26 Nov 2022 15:36:08 +0800 Subject: [PATCH 5/8] fix: issue preventing re-execution of content_script on PWA history navigation --- src/background/modules/AutoRemoteFollow.js | 2 +- src/content_script/mastodonInject.js | 56 ++++++++++++---------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/background/modules/AutoRemoteFollow.js b/src/background/modules/AutoRemoteFollow.js index efba3bf..a074540 100644 --- a/src/background/modules/AutoRemoteFollow.js +++ b/src/background/modules/AutoRemoteFollow.js @@ -156,7 +156,7 @@ async function onTabUpdate(tabId, changeInfo) { const currentURL = new URL(changeInfo.url); if (ownMastodon.server !== currentURL.hostname){ browser.tabs.executeScript({ - file: "/content_script/mastodonInject.js" + file: "/content_script/mastodonInject.js", }); } } diff --git a/src/content_script/mastodonInject.js b/src/content_script/mastodonInject.js index 8f4d20f..dc95bcf 100644 --- a/src/content_script/mastodonInject.js +++ b/src/content_script/mastodonInject.js @@ -1,7 +1,5 @@ "use strict"; -const TIMEOUT_DURATION = 20000; - /** * Replacement onClick handler for Follow button. * @@ -40,12 +38,12 @@ function onClickInteract(event) { * * @param {string} selector * @param {boolean} [multiple=false] - * @param {number} timeoutDuration + * @param {number} [timeoutDuration=200000] * @see {@link https://github.com/storybookjs/test-runner/blob/6d41927154e8dd1e4c9e7493122e24e2739a7a0f/src/setup-page.ts#L134} * from which this was adapted * @returns {Promise} */ -function waitForElement(selector, multiple = false, timeoutDuration) { +function waitForElement(selector, multiple = false, timeoutDuration = 200000) { return new Promise((resolve, reject) => { const getElement = () => ( multiple @@ -89,7 +87,7 @@ function waitForElement(selector, multiple = false, timeoutDuration) { */ async function injectFollowButton() { try { - const followButton = await waitForElement("#mastodon .account__header__tabs__buttons button:first-of-type", false, TIMEOUT_DURATION); + const followButton = await waitForElement("#mastodon .account__header__tabs__buttons button:first-of-type", false); followButton.addEventListener("click", onClickFollow); } catch (error) { // Follow button failed to appear @@ -107,7 +105,6 @@ async function injectInteractionButtons() { "#mastodon .item-list[role='feed'] article[data-id] .status__action-bar button," + "#mastodon .detailed-status__wrapper .detailed-status__action-bar button", true, - TIMEOUT_DURATION, ); replyButtons.forEach((button) => { try { @@ -121,12 +118,36 @@ async function injectInteractionButtons() { }); } +/** + * Initialise injection for feedElement. + * + * @returns {void} + */ +async function injectFeed() { + const observer = new MutationObserver(() => { + injectInteractionButtons(); + }); + + try { + const feedElement = await waitForElement( + "#mastodon .item-list[role='feed']", + false, + ); + + observer.observe(feedElement, { + childList: true, subtree: true, + }); + } catch (error){ + // feedElement not found + } +} + /** * Initialise injection for all remote Mastodon buttons. * * @returns {void} */ -async function init() { +function init() { injectFollowButton(); const ogType = document.querySelector("meta[property='og:type']"); @@ -134,26 +155,9 @@ async function init() { // inject only once on detail toots view pages if (ogType && ogType.getAttribute("content") === "article"){ injectInteractionButtons(); - // otherwise listen to the feed for new posts } else { - const observer = new MutationObserver(() => { - injectInteractionButtons(); - }); - - try { - const feedElement = await waitForElement( - "#mastodon .item-list[role='feed']", - false, - TIMEOUT_DURATION - ); - - observer.observe(feedElement, { - childList: true, subtree: true, - }); - } catch (error){ - // feedElement not found - } - + // otherwise listen to the feed for new posts + injectFeed(); } } From ff52b95ee40a09cebe0007c14c506be0dcc4f3e2 Mon Sep 17 00:00:00 2001 From: Huey Date: Thu, 1 Dec 2022 10:43:13 +0800 Subject: [PATCH 6/8] use overall MutationObserver and avoid re-running content script functions --- src/content_script/mastodonInject.js | 101 ++++++++++++++------------- 1 file changed, 53 insertions(+), 48 deletions(-) diff --git a/src/content_script/mastodonInject.js b/src/content_script/mastodonInject.js index dc95bcf..cd24859 100644 --- a/src/content_script/mastodonInject.js +++ b/src/content_script/mastodonInject.js @@ -101,45 +101,28 @@ async function injectFollowButton() { */ async function injectInteractionButtons() { const INJECTED_REPLY_CLASS = "mastodon-simplified-federation-injected-interaction"; - const replyButtons = await waitForElement( - "#mastodon .item-list[role='feed'] article[data-id] .status__action-bar button," + - "#mastodon .detailed-status__wrapper .detailed-status__action-bar button", - true, - ); - replyButtons.forEach((button) => { - try { - if (!button.classList.contains(INJECTED_REPLY_CLASS)){ - button.addEventListener("click", onClickInteract); - button.classList.add(INJECTED_REPLY_CLASS); - } - } catch (error) { - // Interaction buttons failed to appear - } - }); -} - -/** - * Initialise injection for feedElement. - * - * @returns {void} - */ -async function injectFeed() { - const observer = new MutationObserver(() => { - injectInteractionButtons(); - }); - try { - const feedElement = await waitForElement( - "#mastodon .item-list[role='feed']", - false, + const replyButtons = await waitForElement( + "#mastodon .item-list[role='feed'] article[data-id] .status__action-bar button," + // timeline / user profile + "#mastodon .detailed-status__wrapper .detailed-status__action-bar button," + // status with no replies + "#mastodon .status__wrapper .status__action-bar button", // status with replies + true, ); - - observer.observe(feedElement, { - childList: true, subtree: true, + replyButtons.forEach((button) => { + try { + if (!button.classList.contains(INJECTED_REPLY_CLASS)){ + button.addEventListener("click", onClickInteract); + button.classList.add(INJECTED_REPLY_CLASS); + } + } catch (error) { + // Failed to inject interaction buttons + } }); - } catch (error){ - // feedElement not found + } catch (error) { + // Interaction buttons failed to appear } + + } /** @@ -147,18 +130,40 @@ async function injectFeed() { * * @returns {void} */ -function init() { - injectFollowButton(); - - const ogType = document.querySelector("meta[property='og:type']"); - - // inject only once on detail toots view pages - if (ogType && ogType.getAttribute("content") === "article"){ - injectInteractionButtons(); - } else { - // otherwise listen to the feed for new posts - injectFeed(); - } +function initInjections() { + injectFollowButton().catch(console.error); + injectInteractionButtons().catch(console.error); } -init(); \ No newline at end of file +/** + * Initialise script and re-run if there are changes. + * + * @returns {void} + */ +async function init() { + const MASTODON_INJECTED_CLASS = "mastodon-simplified-federation-injected"; + + if (document.body.classList.contains(MASTODON_INJECTED_CLASS)){ + // init has already run + return; + } + + document.body.classList.add(MASTODON_INJECTED_CLASS); + initInjections(); + + const observer = new MutationObserver(() => { + initInjections(); + }); + + // monitor only the main column in the Mastodon UI + const mainColumn = await waitForElement( + "#mastodon .ui", + false, + ); + observer.observe(mainColumn, { + childList: true, + subtree: true, + }); +} + +init().catch(console.error); \ No newline at end of file From 6105b79e169ef72583d338448d1b1d236b7836fe Mon Sep 17 00:00:00 2001 From: rugk Date: Sat, 3 Dec 2022 12:44:29 +0100 Subject: [PATCH 7/8] fix: adjust options for new tab opening instead of popup opening behaviour Further to be improved in https://github.com/rugk/mastodon-simplified-federation/issues/86 --- src/_locales/de/messages.json | 4 ++-- src/_locales/en/messages.json | 4 ++-- src/options/options.html | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/_locales/de/messages.json b/src/_locales/de/messages.json index e21b327..b912edd 100644 --- a/src/_locales/de/messages.json +++ b/src/_locales/de/messages.json @@ -156,11 +156,11 @@ }, "optionRedirectInMainWindow": { - "message": "Verhindere die Nutzung eines Popups.", + "message": "In aktuellem Tab umleiten.", "description": "This is an option shown in the add-on settings." }, "optionRedirectInMainWindowDescr": { - "message": "Verhindert die Benutzung eines extra Fensters und leitet stattdessen die Hauptseite um.", + "message": "Verhindert die Benutzung eines extra Tabs und leitet stattdessen die Hauptseite um.", "description": "This is an option shown in the add-on settings." }, diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 64a8bb3..cb2c872 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -156,11 +156,11 @@ }, "optionRedirectInMainWindow": { - "message": "Prevent popup usage.", + "message": "Redirect in main window.", "description": "This is an option shown in the add-on settings." }, "optionRedirectInMainWindowDescr": { - "message": "Prevents the use of an extra window and instead redirects the action on the main page.", + "message": "Prevents the use of an extra tab and instead redirects the action on the main page.", "description": "This is an option shown in the add-on settings." }, "translatorCredit": { diff --git a/src/options/options.html b/src/options/options.html index ed7f738..cffa210 100644 --- a/src/options/options.html +++ b/src/options/options.html @@ -71,10 +71,10 @@
  • - +
    - Prevents the use of an extra window and instead redirects the action on the main page. + Prevents the use of an extra tab and instead redirects the action on the main page.