Insert tracker directly below action row
This commit is contained in:
@@ -242,88 +242,61 @@ function getTrackerInsertionAnchorInPost(postElement, buttonBar) {
|
|||||||
return anchor && anchor.parentElement === postElement ? anchor : null;
|
return anchor && anchor.parentElement === postElement ? anchor : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isNodeAfter(node, referenceNode) {
|
function getDirectActionAnchorInPost(postElement, buttonBar) {
|
||||||
if (!node || !referenceNode || node === referenceNode) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return Boolean(referenceNode.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_FOLLOWING);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTopLevelAnchorWithinPost(postElement, element) {
|
|
||||||
if (!postElement || !element || !postElement.contains(element)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let anchor = element;
|
|
||||||
while (anchor.parentElement && anchor.parentElement !== postElement) {
|
|
||||||
anchor = anchor.parentElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
return anchor && anchor.parentElement === postElement ? anchor : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findCommentSectionAnchorInPost(postElement, actionAnchor = null) {
|
|
||||||
if (!postElement) {
|
if (!postElement) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectors = [
|
const seeds = [];
|
||||||
'[aria-label*="relevantes zuerst" i]',
|
const seedSelectors = [
|
||||||
'[aria-label*="most relevant" i]',
|
'[data-ad-rendering-role="share_button"]',
|
||||||
'[aria-label*="neueste" i]',
|
'[data-ad-rendering-role="comment_button"]',
|
||||||
'[aria-label*="newest" i]',
|
'[data-ad-rendering-role*="gefällt"]',
|
||||||
'[aria-roledescription*="kommentar" i]',
|
'[data-ad-rendering-role*="like_button"]',
|
||||||
'[aria-roledescription*="comment" i]',
|
'[data-ad-rendering-role*="reaction-like"]'
|
||||||
'[data-testid*="comment" i]',
|
|
||||||
'[data-scope="comment"]',
|
|
||||||
'div[role="textbox"][contenteditable="true"]',
|
|
||||||
'div[contenteditable="true"][data-lexical-editor="true"]',
|
|
||||||
'[aria-placeholder*="komment" i]',
|
|
||||||
'[aria-placeholder*="comment" i]'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const anchors = new Set();
|
seedSelectors.forEach((selector) => {
|
||||||
|
const candidate = postElement.querySelector(selector);
|
||||||
postElement.querySelectorAll(selectors.join(', ')).forEach((candidate) => {
|
if (candidate) {
|
||||||
if (!candidate || candidate.closest('.fb-tracker-ui') || !isElementVisible(candidate)) {
|
seeds.push(candidate);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let anchorSeed = candidate;
|
|
||||||
const isTextBox = candidate.matches('div[role="textbox"][contenteditable="true"], div[contenteditable="true"][data-lexical-editor="true"]');
|
|
||||||
if (isTextBox) {
|
|
||||||
anchorSeed = candidate.closest('form[role="presentation"]')
|
|
||||||
|| candidate.closest('form')
|
|
||||||
|| candidate;
|
|
||||||
}
|
|
||||||
|
|
||||||
let anchor = getTopLevelAnchorWithinPost(postElement, anchorSeed);
|
|
||||||
if (anchor === actionAnchor) {
|
|
||||||
anchor = anchorSeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!anchor || anchor === actionAnchor || !anchor.parentElement) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const anchorIsInsideAction = Boolean(actionAnchor && actionAnchor.contains(anchor));
|
|
||||||
if (actionAnchor && !anchorIsInsideAction && !isNodeAfter(anchor, actionAnchor)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.add(anchor);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!anchors.size) {
|
if (buttonBar && postElement.contains(buttonBar)) {
|
||||||
return null;
|
seeds.push(buttonBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Array.from(anchors).sort((a, b) => {
|
for (const seed of seeds) {
|
||||||
if (a === b) {
|
let current = seed.closest('[role="button"], button') || seed;
|
||||||
return 0;
|
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;
|
||||||
}
|
}
|
||||||
return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
|
}
|
||||||
})[0];
|
|
||||||
|
if (buttonBar && buttonBar.parentElement && postElement.contains(buttonBar.parentElement)) {
|
||||||
|
return buttonBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getTrackerInsertionAnchorInPost(postElement, buttonBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
const AI_CREDENTIAL_CACHE_TTL = 60 * 1000; // 1 minute cache
|
const AI_CREDENTIAL_CACHE_TTL = 60 * 1000; // 1 minute cache
|
||||||
@@ -3874,35 +3847,28 @@ async function createTrackerUI(postElement, buttonBar, postNum = '?', options =
|
|||||||
inserted = tryInsertBeforeReelsCommentComposer();
|
inserted = tryInsertBeforeReelsCommentComposer();
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionAnchor = getTrackerInsertionAnchorInPost(postElement, buttonBar);
|
const directActionAnchor = getDirectActionAnchorInPost(postElement, buttonBar);
|
||||||
const commentAnchor = findCommentSectionAnchorInPost(postElement, actionAnchor);
|
|
||||||
|
|
||||||
// Strategy 1: Insert before comment section so the bar stays above lazy-loaded comments
|
// Strategy 1: Insert directly below the actions row
|
||||||
if (!inserted && commentAnchor && commentAnchor.parentElement) {
|
if (!inserted && directActionAnchor && directActionAnchor.parentElement) {
|
||||||
commentAnchor.parentElement.insertBefore(container, commentAnchor);
|
directActionAnchor.parentElement.insertBefore(container, directActionAnchor.nextSibling);
|
||||||
console.log('[FB Tracker] Post #' + postNum + ' - UI inserted before comment section. ID: #' + container.id);
|
console.log('[FB Tracker] Post #' + postNum + ' - UI inserted directly below actions. ID: #' + container.id);
|
||||||
inserted = true;
|
inserted = true;
|
||||||
}
|
}
|
||||||
// Strategy 2: Insert right after the action block inside the current post container
|
// Strategy 2: Insert directly after the detected button bar if still inside the post container
|
||||||
if (!inserted && actionAnchor && actionAnchor.parentElement) {
|
|
||||||
actionAnchor.parentElement.insertBefore(container, actionAnchor.nextSibling);
|
|
||||||
console.log('[FB Tracker] Post #' + postNum + ' - UI inserted after in-post action block. ID: #' + container.id);
|
|
||||||
inserted = true;
|
|
||||||
}
|
|
||||||
// Strategy 3: Insert directly after the button bar if still inside the post container
|
|
||||||
if (!inserted && buttonBar && buttonBar.parentElement && postElement.contains(buttonBar.parentElement)) {
|
if (!inserted && buttonBar && buttonBar.parentElement && postElement.contains(buttonBar.parentElement)) {
|
||||||
buttonBar.parentElement.insertBefore(container, buttonBar.nextSibling);
|
buttonBar.parentElement.insertBefore(container, buttonBar.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;
|
||||||
}
|
}
|
||||||
// Strategy 4: Legacy fallback for old variants where the interaction bar is outside the post container
|
// Strategy 3: Legacy fallback for old variants where the interaction bar is outside the post container
|
||||||
if (!inserted && buttonBar && buttonBar.parentElement && buttonBar.parentElement.parentElement && !postElement.contains(buttonBar.parentElement.parentElement)) {
|
if (!inserted && buttonBar && buttonBar.parentElement && buttonBar.parentElement.parentElement && !postElement.contains(buttonBar.parentElement.parentElement)) {
|
||||||
const grandParent = buttonBar.parentElement.parentElement;
|
const grandParent = buttonBar.parentElement.parentElement;
|
||||||
grandParent.insertBefore(container, buttonBar.parentElement.nextSibling);
|
grandParent.insertBefore(container, buttonBar.parentElement.nextSibling);
|
||||||
console.log('[FB Tracker] Post #' + postNum + ' - UI inserted after external button bar parent (legacy). ID: #' + container.id);
|
console.log('[FB Tracker] Post #' + postNum + ' - UI inserted after external button bar parent (legacy). ID: #' + container.id);
|
||||||
inserted = true;
|
inserted = true;
|
||||||
}
|
}
|
||||||
// Strategy 5: Append to post element
|
// Strategy 4: Append to post element
|
||||||
if (!inserted) {
|
if (!inserted) {
|
||||||
postElement.appendChild(container);
|
postElement.appendChild(container);
|
||||||
console.log('[FB Tracker] Post #' + postNum + ' - UI inserted into article (fallback). ID: #' + container.id);
|
console.log('[FB Tracker] Post #' + postNum + ' - UI inserted into article (fallback). ID: #' + container.id);
|
||||||
@@ -3933,12 +3899,9 @@ 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 currentActionAnchor = getTrackerInsertionAnchorInPost(postElement, buttonBar);
|
const currentDirectActionAnchor = getDirectActionAnchorInPost(postElement, buttonBar);
|
||||||
const currentCommentAnchor = findCommentSectionAnchorInPost(postElement, currentActionAnchor);
|
if (currentDirectActionAnchor && currentDirectActionAnchor.parentElement) {
|
||||||
if (currentCommentAnchor && currentCommentAnchor.parentElement) {
|
currentDirectActionAnchor.parentElement.insertBefore(container, currentDirectActionAnchor.nextSibling);
|
||||||
currentCommentAnchor.parentElement.insertBefore(container, currentCommentAnchor);
|
|
||||||
} else if (currentActionAnchor && currentActionAnchor.parentElement) {
|
|
||||||
currentActionAnchor.parentElement.insertBefore(container, currentActionAnchor.nextSibling);
|
|
||||||
} else if (buttonBar && buttonBar.parentElement && postElement.contains(buttonBar.parentElement)) {
|
} else if (buttonBar && buttonBar.parentElement && postElement.contains(buttonBar.parentElement)) {
|
||||||
buttonBar.parentElement.insertBefore(container, buttonBar.nextSibling);
|
buttonBar.parentElement.insertBefore(container, buttonBar.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)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user