Only place below sort row when adjacent to actions

This commit is contained in:
2026-02-26 00:20:01 +01:00
parent c863716537
commit f2a12f1fbf

View File

@@ -299,13 +299,6 @@ function getDirectActionAnchorInPost(postElement, buttonBar) {
return getTrackerInsertionAnchorInPost(postElement, buttonBar); return getTrackerInsertionAnchorInPost(postElement, buttonBar);
} }
function isNodeAfter(node, referenceNode) {
if (!node || !referenceNode || node === referenceNode) {
return false;
}
return Boolean(referenceNode.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_FOLLOWING);
}
function getTopLevelAnchorWithinPost(postElement, element) { function getTopLevelAnchorWithinPost(postElement, element) {
if (!postElement || !element || !postElement.contains(element)) { if (!postElement || !element || !postElement.contains(element)) {
return null; return null;
@@ -319,58 +312,78 @@ function getTopLevelAnchorWithinPost(postElement, element) {
return anchor && anchor.parentElement === postElement ? anchor : null; return anchor && anchor.parentElement === postElement ? anchor : null;
} }
function findCommentSortAnchorInPost(postElement, actionAnchor = null) { function isLikelyCommentSortNode(node) {
if (!postElement) { if (!node || !isElementVisible(node) || node.closest('.fb-tracker-ui')) {
return null; return false;
} }
const keywords = ['relevantes zuerst', 'most relevant', 'neueste', 'newest']; const keywords = ['relevantes zuerst', 'most relevant', 'neueste', 'newest'];
const selectorCandidates = postElement.querySelectorAll([
'[aria-label*="relevantes zuerst" i]',
'[aria-label*="most relevant" i]',
'[aria-label*="neueste" i]',
'[aria-label*="newest" i]'
].join(', '));
const candidates = new Set(selectorCandidates);
postElement.querySelectorAll('[role="button"], button').forEach((node) => {
const text = (node.textContent || '').trim().toLowerCase(); const text = (node.textContent || '').trim().toLowerCase();
if (text && text.length <= 80 && keywords.some((keyword) => text.includes(keyword))) { const ariaLabel = (node.getAttribute('aria-label') || '').trim().toLowerCase();
candidates.add(node);
}
});
const anchors = []; if (ariaLabel && keywords.some((keyword) => ariaLabel.includes(keyword))) {
candidates.forEach((candidate) => { return true;
if (!candidate || !isElementVisible(candidate) || candidate.closest('.fb-tracker-ui')) {
return;
} }
let anchor = getTopLevelAnchorWithinPost(postElement, candidate) || candidate; if (text && text.length <= 120 && keywords.some((keyword) => text.includes(keyword))) {
if (anchor === actionAnchor) { return true;
anchor = candidate;
}
if (!anchor || !anchor.parentElement) {
return;
}
if (actionAnchor && anchor !== actionAnchor && !isNodeAfter(anchor, actionAnchor)) {
return;
} }
anchors.push(anchor); return false;
}); }
if (!anchors.length) { function hasCommentContentSignal(node) {
if (!node) {
return false;
}
if (node.matches && node.matches('[data-testid*="comment" i], [data-scope="comment"]')) {
return true;
}
return Boolean(
node.querySelector(
'[data-testid*="comment" i], [data-scope="comment"], [aria-roledescription*="comment" i], [aria-roledescription*="kommentar" i], div[role="textbox"][contenteditable="true"]'
)
);
}
function findAdjacentCommentSortAnchor(postElement, actionAnchor = null) {
if (!postElement || !actionAnchor || !postElement.contains(actionAnchor)) {
return null; return null;
} }
anchors.sort((a, b) => { let sibling = actionAnchor.nextElementSibling;
if (a === b) { for (let i = 0; i < 4 && sibling; i++) {
return 0; if (sibling.classList && sibling.classList.contains('fb-tracker-ui')) {
sibling = sibling.nextElementSibling;
continue;
} }
return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
}); if (isLikelyCommentSortNode(sibling)) {
return anchors[0]; return sibling;
}
const innerSortNode = sibling.querySelector && sibling.querySelector([
'[aria-label*="relevantes zuerst" i]',
'[aria-label*="most relevant" i]',
'[aria-label*="neueste" i]',
'[aria-label*="newest" i]',
'[role="button"]',
'button'
].join(', '));
if (innerSortNode && isLikelyCommentSortNode(innerSortNode)) {
return sibling;
}
if (hasCommentContentSignal(sibling)) {
break;
}
sibling = sibling.nextElementSibling;
}
return null;
} }
const AI_CREDENTIAL_CACHE_TTL = 60 * 1000; // 1 minute cache const AI_CREDENTIAL_CACHE_TTL = 60 * 1000; // 1 minute cache
@@ -3921,7 +3934,7 @@ async function createTrackerUI(postElement, buttonBar, postNum = '?', options =
const directActionAnchor = getDirectActionAnchorInPost(postElement, buttonBar); const directActionAnchor = getDirectActionAnchorInPost(postElement, buttonBar);
const inPostActionAnchor = getTopLevelAnchorWithinPost(postElement, directActionAnchor) || directActionAnchor; const inPostActionAnchor = getTopLevelAnchorWithinPost(postElement, directActionAnchor) || directActionAnchor;
const commentSortAnchor = findCommentSortAnchorInPost(postElement, inPostActionAnchor); const commentSortAnchor = findAdjacentCommentSortAnchor(postElement, inPostActionAnchor);
const preferredAnchor = commentSortAnchor || inPostActionAnchor; const preferredAnchor = commentSortAnchor || inPostActionAnchor;
// Strategy 1: Insert below actions; if present, place below the sort row // Strategy 1: Insert below actions; if present, place below the sort row
@@ -3980,7 +3993,7 @@ async function createTrackerUI(postElement, buttonBar, postNum = '?', options =
// Try to re-insert // Try to re-insert
const currentDirectActionAnchor = getDirectActionAnchorInPost(postElement, buttonBar); const currentDirectActionAnchor = getDirectActionAnchorInPost(postElement, buttonBar);
const currentInPostActionAnchor = getTopLevelAnchorWithinPost(postElement, currentDirectActionAnchor) || currentDirectActionAnchor; const currentInPostActionAnchor = getTopLevelAnchorWithinPost(postElement, currentDirectActionAnchor) || currentDirectActionAnchor;
const currentCommentSortAnchor = findCommentSortAnchorInPost(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);