From: Dmitry Shachnev Date: Sun, 23 Oct 2022 22:38:55 +0300 Subject: Highlight all search terms on search results page SphinxHighlight.highlightSearchWords() is called on DOMContentLoaded event, and it will not highlight page fragments loaded asynchronously. So we should highlight all such fragments manually. Forwarded: https://github.com/sphinx-doc/sphinx/pull/10930 --- sphinx/themes/basic/static/searchtools.js | 20 ++++++++++++++------ sphinx/themes/basic/static/sphinx_highlight.js | 20 ++++++++++++++------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/sphinx/themes/basic/static/searchtools.js b/sphinx/themes/basic/static/searchtools.js index 8279279..0b5537f 100644 --- a/sphinx/themes/basic/static/searchtools.js +++ b/sphinx/themes/basic/static/searchtools.js @@ -57,7 +57,7 @@ const _removeChildren = (element) => { const _escapeRegExp = (string) => string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string -const _displayItem = (item, searchTerms) => { +const _displayItem = (item, searchTerms, highlightTerms) => { const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT; const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; @@ -86,9 +86,15 @@ const _displayItem = (item, searchTerms) => { linkEl.href = linkUrl + anchor; linkEl.dataset.score = score; linkEl.innerHTML = title; - if (descr) + const rehighlightListItem = () => window.setTimeout(() => { + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }, 10); + if (descr) { listItem.appendChild(document.createElement("span")).innerHTML = " (" + descr + ")"; + rehighlightListItem(); + } else if (showSearchSummary) fetch(requestUrl) .then((responseData) => responseData.text()) @@ -97,6 +103,7 @@ const _displayItem = (item, searchTerms) => { listItem.appendChild( Search.makeSearchSummary(data, searchTerms) ); + rehighlightListItem(); }); Search.output.appendChild(listItem); }; @@ -115,14 +122,15 @@ const _finishSearch = (resultCount) => { const _displayNextItem = ( results, resultCount, - searchTerms + searchTerms, + highlightTerms, ) => { // results left, load the summary and display it // this is intended to be dynamic (don't sub resultsCount) if (results.length) { - _displayItem(results.pop(), searchTerms); + _displayItem(results.pop(), searchTerms, highlightTerms); setTimeout( - () => _displayNextItem(results, resultCount, searchTerms), + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), 5 ); } @@ -360,7 +368,7 @@ const Search = { // console.info("search results:", Search.lastresults); // print the results - _displayNextItem(results, results.length, searchTerms); + _displayNextItem(results, results.length, searchTerms, highlightTerms); }, /** diff --git a/sphinx/themes/basic/static/sphinx_highlight.js b/sphinx/themes/basic/static/sphinx_highlight.js index aae669d..5fbd3ce 100644 --- a/sphinx/themes/basic/static/sphinx_highlight.js +++ b/sphinx/themes/basic/static/sphinx_highlight.js @@ -29,14 +29,16 @@ const _highlight = (node, addItems, text, className) => { } span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); parent.insertBefore( span, - parent.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling - ) + parent.insertBefore(rest, node.nextSibling) ); node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); if (isInSVG) { const rect = document.createElementNS( @@ -140,5 +142,11 @@ const SphinxHighlight = { }, }; -_ready(SphinxHighlight.highlightSearchWords); -_ready(SphinxHighlight.initEscapeListener); +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the _previous_ search query. + */ + if (typeof Search === "undefined") + SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +});