Lock tracker anchor to post action bar to prevent drift

This commit is contained in:
2026-02-26 00:22:42 +01:00
parent f2a12f1fbf
commit 2fc5dbfacc

View File

@@ -242,61 +242,36 @@ function getTrackerInsertionAnchorInPost(postElement, buttonBar) {
return anchor && anchor.parentElement === postElement ? anchor : null; 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) { function getDirectActionAnchorInPost(postElement, buttonBar) {
if (!postElement) { if (!postElement) {
return null; return null;
} }
const seeds = []; const resolvedButtonBar = resolveActionButtonBar(postElement, buttonBar);
const seedSelectors = [ if (!resolvedButtonBar) {
'[data-ad-rendering-role="share_button"]', return null;
'[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);
} }
for (const seed of seeds) { return getTopLevelAnchorWithinPost(postElement, resolvedButtonBar)
let current = seed.closest('[role="button"], button') || seed; || getTrackerInsertionAnchorInPost(postElement, resolvedButtonBar)
while (current && current !== postElement) { || resolvedButtonBar;
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);
} }
function getTopLevelAnchorWithinPost(postElement, element) { function getTopLevelAnchorWithinPost(postElement, element) {
@@ -3932,8 +3907,8 @@ async function createTrackerUI(postElement, buttonBar, postNum = '?', options =
inserted = tryInsertBeforeReelsCommentComposer(); inserted = tryInsertBeforeReelsCommentComposer();
} }
const directActionAnchor = getDirectActionAnchorInPost(postElement, buttonBar); const resolvedButtonBar = resolveActionButtonBar(postElement, buttonBar);
const inPostActionAnchor = getTopLevelAnchorWithinPost(postElement, directActionAnchor) || directActionAnchor; const inPostActionAnchor = getDirectActionAnchorInPost(postElement, resolvedButtonBar);
const commentSortAnchor = findAdjacentCommentSortAnchor(postElement, inPostActionAnchor); const commentSortAnchor = findAdjacentCommentSortAnchor(postElement, inPostActionAnchor);
const preferredAnchor = commentSortAnchor || inPostActionAnchor; const preferredAnchor = commentSortAnchor || inPostActionAnchor;
@@ -3948,8 +3923,8 @@ async function createTrackerUI(postElement, buttonBar, postNum = '?', options =
inserted = true; inserted = true;
} }
// Strategy 2: Insert directly after the detected button bar if still inside the post container // Strategy 2: Insert directly after the detected button bar if still inside the post container
if (!inserted && buttonBar && buttonBar.parentElement && postElement.contains(buttonBar.parentElement)) { if (!inserted && resolvedButtonBar && resolvedButtonBar.parentElement && postElement.contains(resolvedButtonBar.parentElement)) {
buttonBar.parentElement.insertBefore(container, buttonBar.nextSibling); resolvedButtonBar.parentElement.insertBefore(container, resolvedButtonBar.nextSibling);
console.log('[FB Tracker] Post #' + postNum + ' - UI inserted after button bar (in-post fallback). ID: #' + container.id); console.log('[FB Tracker] Post #' + postNum + ' - UI inserted after button bar (in-post fallback). ID: #' + container.id);
inserted = true; inserted = true;
} }
@@ -3991,14 +3966,14 @@ async function createTrackerUI(postElement, buttonBar, postNum = '?', options =
console.log('[FB Tracker] Post #' + postNum + ' - UI was removed, re-inserting...'); console.log('[FB Tracker] Post #' + postNum + ' - UI was removed, re-inserting...');
observer.disconnect(); observer.disconnect();
// Try to re-insert // Try to re-insert
const currentDirectActionAnchor = getDirectActionAnchorInPost(postElement, buttonBar); const currentResolvedButtonBar = resolveActionButtonBar(postElement, buttonBar);
const currentInPostActionAnchor = getTopLevelAnchorWithinPost(postElement, currentDirectActionAnchor) || currentDirectActionAnchor; const currentInPostActionAnchor = getDirectActionAnchorInPost(postElement, currentResolvedButtonBar);
const currentCommentSortAnchor = findAdjacentCommentSortAnchor(postElement, currentInPostActionAnchor); const currentCommentSortAnchor = findAdjacentCommentSortAnchor(postElement, currentInPostActionAnchor);
const currentPreferredAnchor = currentCommentSortAnchor || currentInPostActionAnchor; const currentPreferredAnchor = currentCommentSortAnchor || currentInPostActionAnchor;
if (currentPreferredAnchor && currentPreferredAnchor.parentElement) { if (currentPreferredAnchor && currentPreferredAnchor.parentElement) {
currentPreferredAnchor.parentElement.insertBefore(container, currentPreferredAnchor.nextSibling); currentPreferredAnchor.parentElement.insertBefore(container, currentPreferredAnchor.nextSibling);
} else if (buttonBar && buttonBar.parentElement && postElement.contains(buttonBar.parentElement)) { } else if (currentResolvedButtonBar && currentResolvedButtonBar.parentElement && postElement.contains(currentResolvedButtonBar.parentElement)) {
buttonBar.parentElement.insertBefore(container, buttonBar.nextSibling); currentResolvedButtonBar.parentElement.insertBefore(container, currentResolvedButtonBar.nextSibling);
} else if (buttonBar && buttonBar.parentElement && buttonBar.parentElement.parentElement && !postElement.contains(buttonBar.parentElement.parentElement)) { } else if (buttonBar && buttonBar.parentElement && buttonBar.parentElement.parentElement && !postElement.contains(buttonBar.parentElement.parentElement)) {
buttonBar.parentElement.parentElement.insertBefore(container, buttonBar.parentElement.nextSibling); buttonBar.parentElement.parentElement.insertBefore(container, buttonBar.parentElement.nextSibling);
} else if (postElement) { } else if (postElement) {