diff --git a/scripts/content-search-filtering.js b/scripts/content-search-filtering.js index 95076c7..94cd063 100644 --- a/scripts/content-search-filtering.js +++ b/scripts/content-search-filtering.js @@ -143,10 +143,15 @@ function mountToTopOfSearchResults(element) { document.querySelector('#topstuff')?.prepend(element); } else if (document.querySelector('#main')) { var el = document.querySelector('#main'); - if (el.querySelector('#main > div[data-hveid]')) { - el.insertBefore(element, el.querySelector('div[data-hveid]')); - } else { - el.insertBefore(element, el.querySelector('div div[data-hveid]').parentElement); + if (el) { + if (el.querySelector('#main > div[data-hveid]')) { + el.insertBefore(element, el.querySelector('div[data-hveid]')); + } else { + const hveid = el.querySelector('div div[data-hveid]'); + if (hveid) { + el.insertBefore(element, hveid.parentElement); + } + } } } break; @@ -199,8 +204,15 @@ function mountToTopOfSearchResults(element) { document.querySelector('#main')?.prepend(element); break; default: - } - }; + } + + // Return whether element was successfully mounted + if (element.id && document.querySelector(element.id)) { + return true; + } else { + return false; + } +}; /** * Shows a banner at the top of the search results page for a given wiki type, if one is not already present. @@ -242,7 +254,7 @@ function mountSearchBanner(wikiInfo) { /** @param {MouseEvent & { target: HTMLDivElement, currentTarget: HTMLDivElement }} e */ showResultsButton.onclick = function (e) { - if (e.target.textContent.includes(extensionAPI.i18n.getMessage('searchFilteredResultsShow'))) { + if (e.target.textContent?.includes(extensionAPI.i18n.getMessage('searchFilteredResultsShow'))) { e.target.textContent = extensionAPI.i18n.getMessage('searchFilteredResultsHide'); hiddenWikisRevealed[elementId] = true; const selector = e.currentTarget.dataset.group; @@ -356,7 +368,7 @@ function getResultContainer(searchEngine, searchResult) { case 'qwant': if (searchResult.closest('div[data-testid=webResult]')) { const cssQuery = 'div[data-testid=webResult]'; - searchResultContainer = searchResult.closest(cssQuery).parentElement; + searchResultContainer = searchResult.closest(cssQuery)?.parentElement; } break; case 'startpage': @@ -653,10 +665,10 @@ function filterAnchors(newAnchors) { // Extract the URL between "RU=" and "/RK=" const embeddedUrlRegex = /RU=([^/]+)\/RK=/; const match = searchResult.href.match(embeddedUrlRegex); - const extractedURL = decodeURIComponent(match && match[1]); - - if (extractedURL) searchResult.setAttribute('data-iwb-href', extractedURL); - + if (match) { + const extractedURL = decodeURIComponent(match && match[1]); + if (extractedURL) searchResult.setAttribute('data-iwb-href', extractedURL); + } } catch (e) { console.error('Indie Wiki Buddy failed to parse Yahoo link with error: ', e); } @@ -676,13 +688,13 @@ function filterAnchors(newAnchors) { default: { if (storage.customSearchEngines) { function filterSearXNG() { - const searchResults = newAnchors.filter(e => e.matches('h3>a')); - filterSearchResults(searchResults); + const searchResults = newAnchors?.filter(e => e.matches('h3>a')); + if (searchResults) filterSearchResults(searchResults); } function filterWhoogle() { - const searchResults = newAnchors.filter(e => e.matches('div>a')); - filterSearchResults(searchResults); + const searchResults = newAnchors?.filter(e => e.matches('div>a')); + if (searchResults) filterSearchResults(searchResults); } /** @param {string} searchEngine */ @@ -716,7 +728,9 @@ function checkRevalidate() { pageChangeDetector.id = 'iwb-page-change-detector'; pageChangeDetector.style.display = 'none'; try { - mountToTopOfSearchResults(pageChangeDetector); + /** @type {boolean} */ + const containerMounted = mountToTopOfSearchResults(pageChangeDetector); + if (!containerMounted) return; // just in case, re-process search results console.debug('IWB: Reprocessing search results...'); filterAnchors(Array.from(document.body?.querySelectorAll('a'))); @@ -736,11 +750,17 @@ function filterMutations(mutations, observer) { if (document.body == undefined || mutations == undefined) return; checkRevalidate(); - const addedSubtrees = mutations.flatMap(mutation => Array.from(mutation.addedNodes)); const newAnchors = /** @type {HTMLAnchorElement[]} */ (addedSubtrees .filter(node => node instanceof HTMLElement) - .flatMap(node => (isAnchor(node) && node) || Array.from(node.querySelectorAll('a'))) + .flatMap(node => { + if (isAnchor(node)) { + return node; + } else if (node instanceof HTMLElement) { + return Array.from(node.querySelectorAll('a')); + } + return []; + }) ); filterAnchors(newAnchors);