From b175603b549e0595a78890233a52d247957974fd Mon Sep 17 00:00:00 2001 From: Meik Date: Thu, 26 Feb 2026 00:45:04 +0100 Subject: [PATCH] Harden tracker anchor detection for new comment layout --- extension/content.js | 112 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 2 deletions(-) diff --git a/extension/content.js b/extension/content.js index 152bb3a..297bd12 100644 --- a/extension/content.js +++ b/extension/content.js @@ -309,17 +309,94 @@ function getTrackerInsertionAnchorInPost(postElement, buttonBar) { return anchor && anchor.parentElement === postElement ? anchor : null; } +function hasCommentComposerSignal(node) { + if (!node || !node.querySelector) { + return false; + } + + return Boolean( + node.querySelector( + 'div[role="textbox"][contenteditable="true"], [role="textbox"][aria-label*="komment" i], [role="textbox"][aria-label*="comment" i], [role="textbox"][aria-placeholder*="komment" i], [role="textbox"][aria-placeholder*="comment" i]' + ) + ); +} + +function countActionRoleSignals(node) { + if (!node || !node.querySelector) { + return 0; + } + + const hasLike = Boolean(node.querySelector('[data-ad-rendering-role="like_button"], [data-ad-rendering-role*="gefällt" i]')); + const hasComment = Boolean(node.querySelector('[data-ad-rendering-role="comment_button"]')); + const hasShare = Boolean(node.querySelector('[data-ad-rendering-role="share_button"]')); + + return [hasLike, hasComment, hasShare].filter(Boolean).length; +} + +function isReliableActionBarCandidate(postElement, candidate) { + if (!postElement || !candidate || !candidate.isConnected || !postElement.contains(candidate)) { + return false; + } + + if (candidate.closest('.fb-tracker-ui')) { + return false; + } + + if (hasCommentComposerSignal(candidate)) { + return false; + } + + const buttonCount = candidate.querySelectorAll('[role="button"], button').length; + if (buttonCount > 80) { + return false; + } + + const actionRoleSignals = countActionRoleSignals(candidate); + if (actionRoleSignals >= 2) { + return true; + } + + return hasInteractionButtons(candidate); +} + +function findActionBarByDataRoles(postElement) { + if (!postElement) { + return null; + } + + const markers = Array.from(postElement.querySelectorAll( + '[data-ad-rendering-role="like_button"], [data-ad-rendering-role*="gefällt" i], [data-ad-rendering-role="comment_button"], [data-ad-rendering-role="share_button"]' + )); + + for (const marker of markers) { + let current = marker; + for (let depth = 0; depth < 8 && current && current !== postElement; depth++) { + if (isReliableActionBarCandidate(postElement, current)) { + return current; + } + current = current.parentElement; + } + } + + return null; +} + function resolveActionButtonBar(postElement, buttonBar) { if (!postElement) { return null; } - if (buttonBar && buttonBar.isConnected && postElement.contains(buttonBar)) { + const dataRoleResolved = findActionBarByDataRoles(postElement); + if (dataRoleResolved) { + return dataRoleResolved; + } + + if (buttonBar && isReliableActionBarCandidate(postElement, buttonBar)) { return buttonBar; } const resolved = findButtonBar(postElement); - if (resolved && resolved.isConnected && postElement.contains(resolved)) { + if (resolved && isReliableActionBarCandidate(postElement, resolved)) { return resolved; } @@ -428,6 +505,29 @@ function findAdjacentCommentSortAnchor(postElement, actionAnchor = null) { return null; } +function findCommentSortAnchorInPost(postElement) { + if (!postElement) { + return null; + } + + const sortCandidates = Array.from( + postElement.querySelectorAll('[aria-label*="relevantes zuerst" i], [aria-label*="most relevant" i], [aria-label*="neueste" i], [aria-label*="newest" i], [role="button"], button') + ); + + for (const candidate of sortCandidates) { + if (!isLikelyCommentSortNode(candidate)) { + continue; + } + + const topLevel = getTopLevelAnchorWithinPost(postElement, candidate) || candidate; + if (topLevel && topLevel.parentElement && postElement.contains(topLevel)) { + return topLevel; + } + } + + return null; +} + function createTrackerInsertionMarker() { const marker = document.createElement('div'); marker.className = 'fb-tracker-insertion-anchor'; @@ -472,6 +572,14 @@ function positionTrackerInsertionMarker(postElement, marker, buttonBar, postNum return true; } + const fallbackSortAnchor = findCommentSortAnchorInPost(postElement); + if (fallbackSortAnchor && fallbackSortAnchor.parentElement) { + fallbackSortAnchor.parentElement.insertBefore(marker, fallbackSortAnchor); + setTrackerInsertionMarkerLocked(marker, true); + console.log('[FB Tracker] Post #' + postNum + ' - Marker fallback inserted before comment sort'); + return true; + } + postElement.appendChild(marker); setTrackerInsertionMarkerLocked(marker, false); console.log('[FB Tracker] Post #' + postNum + ' - Marker fallback appended to post');