From 339f03e38e81300faba0b3310fd9c76f64fba1d0 Mon Sep 17 00:00:00 2001 From: MDeeApp <6595194+MDeeApp@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:36:58 +0100 Subject: [PATCH] fix: clean up stray timestamp artifacts on search results --- extension/content.js | 131 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/extension/content.js b/extension/content.js index 1c6a76b..3cdb29e 100644 --- a/extension/content.js +++ b/extension/content.js @@ -18,6 +18,15 @@ const FEED_HOME_PATHS = ['/', '/home.php']; const sessionSearchRecordedUrls = new Set(); const sessionSearchInfoCache = new Map(); +function isOnSearchResultsPage() { + try { + const pathname = window.location && window.location.pathname; + return typeof pathname === 'string' && pathname.startsWith(SEARCH_RESULTS_PATH_PREFIX); + } catch (error) { + return false; + } +} + const trackerElementsByPost = new WeakMap(); const postAdditionalNotes = new WeakMap(); @@ -1002,6 +1011,28 @@ function hidePostElement(postElement) { } let removalRoot = elementToRemove; + let parentForTimestampCheck = removalRoot.parentElement; + while (parentForTimestampCheck && parentForTimestampCheck !== document.body && parentForTimestampCheck !== document.documentElement) { + const siblings = Array.from(parentForTimestampCheck.children); + const nonRootSiblings = siblings.filter((sibling) => sibling !== removalRoot); + if (!nonRootSiblings.length) { + break; + } + const hasOnlyTimestampSiblings = nonRootSiblings.every((sibling) => isTimestampArtifactNode(sibling)); + if (hasOnlyTimestampSiblings) { + removalRoot = parentForTimestampCheck; + parentForTimestampCheck = removalRoot.parentElement; + continue; + } + const hasTimestampSibling = nonRootSiblings.some((sibling) => isTimestampArtifactNode(sibling)); + if (hasTimestampSibling && siblings.length <= 3) { + removalRoot = parentForTimestampCheck; + parentForTimestampCheck = removalRoot.parentElement; + continue; + } + break; + } + let parent = removalRoot.parentElement; while (parent && parent !== document.body && parent !== document.documentElement) { @@ -1046,6 +1077,12 @@ function hidePostElement(postElement) { } else { removalRoot.style.display = 'none'; } + + if (removalParent) { + cleanupDanglingSearchArtifacts(removalParent); + } else { + cleanupDanglingSearchArtifacts(document); + } } function collectButtonMeta(button) { @@ -3463,6 +3500,100 @@ function findAndClickCommentButton(postElement) { return false; } +function containsPostContent(element) { + if (!element || element.nodeType !== Node.ELEMENT_NODE) { + return false; + } + if (element.matches && element.matches('article, [role="article"]')) { + return true; + } + if (element.querySelector && element.querySelector('article, [role="article"]')) { + return true; + } + if (element.matches && element.matches('[data-fb-tracker-processed="1"]')) { + return true; + } + return false; +} + +function isTimestampArtifactNode(node) { + if (!node || node.nodeType !== Node.ELEMENT_NODE) { + return false; + } + if (!node.classList) { + return false; + } + if (!node.classList.contains('__fb-light-mode') && !node.classList.contains('__fb-dark-mode')) { + return false; + } + if (node.querySelector && node.querySelector('article, [role="article"]')) { + return false; + } + const text = node.textContent ? node.textContent.trim() : ''; + if (!text) { + return true; + } + if (text.length > 80) { + return false; + } + const lowered = text.toLowerCase(); + const hasDate = /\b\d{1,2}\.\s*(?:jan|feb|mär|mae|apr|mai|jun|jul|aug|sep|okt|nov|dez)/i.test(lowered); + const hasTime = /\b\d{1,2}[:.]\d{2}\b/.test(lowered); + const hasMonthWord = /\b(?:januar|februar|märz|maerz|april|mai|juni|juli|august|september|oktober|november|dezember)\b/.test(lowered); + if (hasDate || hasTime || hasMonthWord) { + return true; + } + return false; +} + +function removeNodeAndEmptyAncestors(node) { + if (!node || node.nodeType !== Node.ELEMENT_NODE) { + return; + } + const parents = []; + let currentParent = node.parentElement; + node.remove(); + + while (currentParent && currentParent !== document.body && currentParent !== document.documentElement) { + parents.push(currentParent); + currentParent = currentParent.parentElement; + } + + parents.forEach((parentNode) => { + if (parentNode.childElementCount === 0) { + parentNode.remove(); + } + }); +} + +function cleanupDanglingSearchArtifacts(context) { + if (!isOnSearchResultsPage()) { + return; + } + const scope = (context && context.nodeType === Node.ELEMENT_NODE) + ? context + : document; + const candidates = scope.querySelectorAll('div.__fb-light-mode, div.__fb-dark-mode'); + candidates.forEach((node) => { + if (!isTimestampArtifactNode(node)) { + return; + } + const parent = node.parentElement; + if (parent) { + const hasContentSibling = Array.from(parent.children).some((child) => { + if (child === node) { + return false; + } + return containsPostContent(child); + }); + if (hasContentSibling) { + return; + } + } + removeNodeAndEmptyAncestors(node); + }); +} + /** * Find comment input field on current page */