Spaces:
Running
Running
| /* Highlighting utilities for Sphinx HTML documentation. */ | |
| ; | |
| const SPHINX_HIGHLIGHT_ENABLED = true | |
| /** | |
| * highlight a given string on a node by wrapping it in | |
| * span elements with the given class name. | |
| */ | |
| const _highlight = (node, addItems, text, className) => { | |
| if (node.nodeType === Node.TEXT_NODE) { | |
| const val = node.nodeValue; | |
| const parent = node.parentNode; | |
| const pos = val.toLowerCase().indexOf(text); | |
| if ( | |
| pos >= 0 && | |
| !parent.classList.contains(className) && | |
| !parent.classList.contains("nohighlight") | |
| ) { | |
| let span; | |
| const closestNode = parent.closest("body, svg, foreignObject"); | |
| const isInSVG = closestNode && closestNode.matches("svg"); | |
| if (isInSVG) { | |
| span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); | |
| } else { | |
| span = document.createElement("span"); | |
| span.classList.add(className); | |
| } | |
| span.appendChild(document.createTextNode(val.substr(pos, text.length))); | |
| const rest = document.createTextNode(val.substr(pos + text.length)); | |
| parent.insertBefore( | |
| span, | |
| 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( | |
| "http://www.w3.org/2000/svg", | |
| "rect" | |
| ); | |
| const bbox = parent.getBBox(); | |
| rect.x.baseVal.value = bbox.x; | |
| rect.y.baseVal.value = bbox.y; | |
| rect.width.baseVal.value = bbox.width; | |
| rect.height.baseVal.value = bbox.height; | |
| rect.setAttribute("class", className); | |
| addItems.push({ parent: parent, target: rect }); | |
| } | |
| } | |
| } else if (node.matches && !node.matches("button, select, textarea")) { | |
| node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); | |
| } | |
| }; | |
| const _highlightText = (thisNode, text, className) => { | |
| let addItems = []; | |
| _highlight(thisNode, addItems, text, className); | |
| addItems.forEach((obj) => | |
| obj.parent.insertAdjacentElement("beforebegin", obj.target) | |
| ); | |
| }; | |
| /** | |
| * Small JavaScript module for the documentation. | |
| */ | |
| const SphinxHighlight = { | |
| /** | |
| * highlight the search words provided in localstorage in the text | |
| */ | |
| highlightSearchWords: () => { | |
| if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight | |
| // get and clear terms from localstorage | |
| const url = new URL(window.location); | |
| const highlight = | |
| localStorage.getItem("sphinx_highlight_terms") | |
| || url.searchParams.get("highlight") | |
| || ""; | |
| localStorage.removeItem("sphinx_highlight_terms") | |
| url.searchParams.delete("highlight"); | |
| window.history.replaceState({}, "", url); | |
| // get individual terms from highlight string | |
| const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); | |
| if (terms.length === 0) return; // nothing to do | |
| // There should never be more than one element matching "div.body" | |
| const divBody = document.querySelectorAll("div.body"); | |
| const body = divBody.length ? divBody[0] : document.querySelector("body"); | |
| window.setTimeout(() => { | |
| terms.forEach((term) => _highlightText(body, term, "highlighted")); | |
| }, 10); | |
| const searchBox = document.getElementById("searchbox"); | |
| if (searchBox === null) return; | |
| searchBox.appendChild( | |
| document | |
| .createRange() | |
| .createContextualFragment( | |
| '<p class="highlight-link">' + | |
| '<a href="javascript:SphinxHighlight.hideSearchWords()">' + | |
| _("Hide Search Matches") + | |
| "</a></p>" | |
| ) | |
| ); | |
| }, | |
| /** | |
| * helper function to hide the search marks again | |
| */ | |
| hideSearchWords: () => { | |
| document | |
| .querySelectorAll("#searchbox .highlight-link") | |
| .forEach((el) => el.remove()); | |
| document | |
| .querySelectorAll("span.highlighted") | |
| .forEach((el) => el.classList.remove("highlighted")); | |
| localStorage.removeItem("sphinx_highlight_terms") | |
| }, | |
| initEscapeListener: () => { | |
| // only install a listener if it is really needed | |
| if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; | |
| document.addEventListener("keydown", (event) => { | |
| // bail for input elements | |
| if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; | |
| // bail with special keys | |
| if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; | |
| if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { | |
| SphinxHighlight.hideSearchWords(); | |
| event.preventDefault(); | |
| } | |
| }); | |
| }, | |
| }; | |
| _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(); | |
| }); | |