Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: should now inject interaction buttons properly on post detail page #87

Merged
merged 7 commits into from
Dec 13, 2022
2 changes: 1 addition & 1 deletion src/background/modules/AutoRemoteFollow.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
});
}
}
Expand Down
81 changes: 51 additions & 30 deletions src/content_script/mastodonInject.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"use strict";

const TIMEOUT_DURATION = 20000;

/**
* Replacement onClick handler for Follow button.
*
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -103,46 +101,69 @@ 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,
TIMEOUT_DURATION,
);
replyButtons.forEach((button) => {
try {
if (!button.classList.contains(INJECTED_REPLY_CLASS)){
button.addEventListener("click", onClickInteract);
button.classList.add(INJECTED_REPLY_CLASS);
try {
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
hueyy marked this conversation as resolved.
Show resolved Hide resolved
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) {
// Interaction buttons failed to appear
}
});
});
} catch (error) {
// Interaction buttons failed to appear
}


}

/**
* Initialise injection for all remote Mastodon buttons.
*
* @returns {void}
*/
function initInjections() {
injectFollowButton().catch(console.error);
injectInteractionButtons().catch(console.error);
}

/**
* Initialise script and re-run if there are changes.
*
* @returns {void}
*/
async function init() {
injectFollowButton();
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(() => {
Promise.allSettled([
injectInteractionButtons(),
]);
initInjections();
});

const feedElement = await waitForElement(
"#mastodon .item-list[role='feed']",
hueyy marked this conversation as resolved.
Show resolved Hide resolved
// monitor only the main column in the Mastodon UI
const mainColumn = await waitForElement(
"#mastodon .ui",
false,
TIMEOUT_DURATION
);
observer.observe(feedElement, {
childList: true, subtree: true,
observer.observe(mainColumn, {
childList: true,
subtree: true,
});
}

init();
init().catch(console.error);