From 2fc5dbfacc6cb0aa8bb894030cbd95bdc3277b1f Mon Sep 17 00:00:00 2001 From: Meik Date: Thu, 26 Feb 2026 00:22:42 +0100 Subject: [PATCH] Lock tracker anchor to post action bar to prevent drift --- extension/content.js | 87 ++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 56 deletions(-) diff --git a/extension/content.js b/extension/content.js index 1b73344..da4f6d2 100644 --- a/extension/content.js +++ b/extension/content.js @@ -242,61 +242,36 @@ function getTrackerInsertionAnchorInPost(postElement, buttonBar) { return anchor && anchor.parentElement === postElement ? anchor : null; } +function resolveActionButtonBar(postElement, buttonBar) { + if (!postElement) { + return null; + } + + if (buttonBar && buttonBar.isConnected && postElement.contains(buttonBar)) { + return buttonBar; + } + + const resolved = findButtonBar(postElement); + if (resolved && resolved.isConnected && postElement.contains(resolved)) { + return resolved; + } + + return null; +} + function getDirectActionAnchorInPost(postElement, buttonBar) { if (!postElement) { return null; } - const seeds = []; - const seedSelectors = [ - '[data-ad-rendering-role="share_button"]', - '[data-ad-rendering-role="comment_button"]', - '[data-ad-rendering-role*="gefällt"]', - '[data-ad-rendering-role*="like_button"]', - '[data-ad-rendering-role*="reaction-like"]' - ]; - - seedSelectors.forEach((selector) => { - const candidate = postElement.querySelector(selector); - if (candidate) { - seeds.push(candidate); - } - }); - - if (buttonBar && postElement.contains(buttonBar)) { - seeds.push(buttonBar); + const resolvedButtonBar = resolveActionButtonBar(postElement, buttonBar); + if (!resolvedButtonBar) { + return null; } - for (const seed of seeds) { - let current = seed.closest('[role="button"], button') || seed; - while (current && current !== postElement) { - if (!postElement.contains(current)) { - break; - } - - const hasShare = Boolean(current.querySelector('[data-ad-rendering-role="share_button"]')); - const hasComment = Boolean(current.querySelector('[data-ad-rendering-role="comment_button"]')); - const hasLike = Boolean( - current.querySelector('[data-ad-rendering-role*="gefällt"], [data-ad-rendering-role*="like_button"], [data-ad-rendering-role*="reaction-like"]') - ); - const interactionCount = [hasShare, hasComment, hasLike].filter(Boolean).length; - const hasComposer = Boolean( - current.querySelector('div[role="textbox"][contenteditable="true"], div[contenteditable="true"][data-lexical-editor="true"]') - ); - - if (interactionCount >= 2 && !hasComposer) { - return current; - } - - current = current.parentElement; - } - } - - if (buttonBar && buttonBar.parentElement && postElement.contains(buttonBar.parentElement)) { - return buttonBar; - } - - return getTrackerInsertionAnchorInPost(postElement, buttonBar); + return getTopLevelAnchorWithinPost(postElement, resolvedButtonBar) + || getTrackerInsertionAnchorInPost(postElement, resolvedButtonBar) + || resolvedButtonBar; } function getTopLevelAnchorWithinPost(postElement, element) { @@ -3932,8 +3907,8 @@ async function createTrackerUI(postElement, buttonBar, postNum = '?', options = inserted = tryInsertBeforeReelsCommentComposer(); } - const directActionAnchor = getDirectActionAnchorInPost(postElement, buttonBar); - const inPostActionAnchor = getTopLevelAnchorWithinPost(postElement, directActionAnchor) || directActionAnchor; + const resolvedButtonBar = resolveActionButtonBar(postElement, buttonBar); + const inPostActionAnchor = getDirectActionAnchorInPost(postElement, resolvedButtonBar); const commentSortAnchor = findAdjacentCommentSortAnchor(postElement, inPostActionAnchor); const preferredAnchor = commentSortAnchor || inPostActionAnchor; @@ -3948,8 +3923,8 @@ async function createTrackerUI(postElement, buttonBar, postNum = '?', options = inserted = true; } // Strategy 2: Insert directly after the detected button bar if still inside the post container - if (!inserted && buttonBar && buttonBar.parentElement && postElement.contains(buttonBar.parentElement)) { - buttonBar.parentElement.insertBefore(container, buttonBar.nextSibling); + if (!inserted && resolvedButtonBar && resolvedButtonBar.parentElement && postElement.contains(resolvedButtonBar.parentElement)) { + resolvedButtonBar.parentElement.insertBefore(container, resolvedButtonBar.nextSibling); console.log('[FB Tracker] Post #' + postNum + ' - UI inserted after button bar (in-post fallback). ID: #' + container.id); inserted = true; } @@ -3991,14 +3966,14 @@ async function createTrackerUI(postElement, buttonBar, postNum = '?', options = console.log('[FB Tracker] Post #' + postNum + ' - UI was removed, re-inserting...'); observer.disconnect(); // Try to re-insert - const currentDirectActionAnchor = getDirectActionAnchorInPost(postElement, buttonBar); - const currentInPostActionAnchor = getTopLevelAnchorWithinPost(postElement, currentDirectActionAnchor) || currentDirectActionAnchor; + const currentResolvedButtonBar = resolveActionButtonBar(postElement, buttonBar); + const currentInPostActionAnchor = getDirectActionAnchorInPost(postElement, currentResolvedButtonBar); const currentCommentSortAnchor = findAdjacentCommentSortAnchor(postElement, currentInPostActionAnchor); const currentPreferredAnchor = currentCommentSortAnchor || currentInPostActionAnchor; if (currentPreferredAnchor && currentPreferredAnchor.parentElement) { currentPreferredAnchor.parentElement.insertBefore(container, currentPreferredAnchor.nextSibling); - } else if (buttonBar && buttonBar.parentElement && postElement.contains(buttonBar.parentElement)) { - buttonBar.parentElement.insertBefore(container, buttonBar.nextSibling); + } else if (currentResolvedButtonBar && currentResolvedButtonBar.parentElement && postElement.contains(currentResolvedButtonBar.parentElement)) { + currentResolvedButtonBar.parentElement.insertBefore(container, currentResolvedButtonBar.nextSibling); } else if (buttonBar && buttonBar.parentElement && buttonBar.parentElement.parentElement && !postElement.contains(buttonBar.parentElement.parentElement)) { buttonBar.parentElement.parentElement.insertBefore(container, buttonBar.parentElement.nextSibling); } else if (postElement) {