PageSourceSearch

https://python-future.org/_static/sphinx_highlight.js?v=dc90522c

js python-future.org collected 2026-09-24 08:52:15 UTC 5,123 bytes, 154 lines download raw bytes

1/* Highlighting utilities for Sphinx HTML documentation. */
2"use strict";
3
4const SPHINX_HIGHLIGHT_ENABLED = true
5
6/**
7 * highlight a given string on a node by wrapping it in
8 * span elements with the given class name.
9 */
10const _highlight = (node, addItems, text, className) => {
11  if (node.nodeType === Node.TEXT_NODE) {
12    const val = node.nodeValue;
13    const parent = node.parentNode;
14    const pos = val.toLowerCase().indexOf(text);
15    if (
16      pos >= 0 &&
17      !parent.classList.contains(className) &&
18      !parent.classList.contains("nohighlight")
19    ) {
20      let span;
21
22      const closestNode = parent.closest("body, svg, foreignObject");
23      const isInSVG = closestNode && closestNode.matches("svg");
24      if (isInSVG) {
25        span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
26      } else {
27        span = document.createElement("span");
28        span.classList.add(className);
29      }
30
31      span.appendChild(document.createTextNode(val.substr(pos, text.length)));
32      const rest = document.createTextNode(val.substr(pos + text.length));
33      parent.insertBefore(
34        span,
35        parent.insertBefore(
36          rest,
37          node.nextSibling
38        )
39      );
40      node.nodeValue = val.substr(0, pos);
41      /* There may be more occurrences of search term in this node. So call this
42       * function recursively on the remaining fragment.
43       */
44      _highlight(rest, addItems, text, className);
45
46      if (isInSVG) {
47        const rect = document.createElementNS(
48          "http://www.w3.org/2000/svg",
49          "rect"
50        );
51        const bbox = parent.getBBox();
52        rect.x.baseVal.value = bbox.x;
53        rect.y.baseVal.value = bbox.y;
54        rect.width.baseVal.value = bbox.width;
55        rect.height.baseVal.value = bbox.height;
56        rect.setAttribute("class", className);
57        addItems.push({ parent: parent, target: rect });
58      }
59    }
60  } else if (node.matches && !node.matches("button, select, textarea")) {
61    node.childNodes.forEach((el) => _highlight(el, addItems, text, className));
62  }
63};
64const _highlightText = (thisNode, text, className) => {
65  let addItems = [];
66  _highlight(thisNode, addItems, text, className);
67  addItems.forEach((obj) =>
68    obj.parent.insertAdjacentElement("beforebegin", obj.target)
69  );
70};
71
72/**
73 * Small JavaScript module for the documentation.
74 */
75const SphinxHighlight = {
76
77  /**
78   * highlight the search words provided in localstorage in the text
79   */
80  highlightSearchWords: () => {
81    if (!SPHINX_HIGHLIGHT_ENABLED) return;  // bail if no highlight
82
83    // get and clear terms from localstorage
84    const url = new URL(window.location);
85    const highlight =
86        localStorage.getItem("sphinx_highlight_terms")
87        || url.searchParams.get("highlight")
88        || "";
89    localStorage.removeItem("sphinx_highlight_terms")
90    url.searchParams.delete("highlight");
91    window.history.replaceState({}, "", url);
92
93    // get individual terms from highlight string
94    const terms = highlight.toLowerCase().split(/\s+/).filter(x => x);
95    if (terms.length === 0) return; // nothing to do
96
97    // There should never be more than one element matching "div.body"
98    const divBody = document.querySelectorAll("div.body");
99    const body = divBody.length ? divBody[0] : document.querySelector("body");
100    window.setTimeout(() => {
101      terms.forEach((term) => _highlightText(body, term, "highlighted"));
102    }, 10);
103
104    const searchBox = document.getElementById("searchbox");
105    if (searchBox === null) return;
106    searchBox.appendChild(
107      document
108        .createRange()
109        .createContextualFragment(
110          '<p class="highlight-link">' +
111            '<a href="javascript:SphinxHighlight.hideSearchWords()">' +
112            _("Hide Search Matches") +
113            "</a></p>"
114        )
115    );
116  },
117
118  /**
119   * helper function to hide the search marks again
120   */
121  hideSearchWords: () => {
122    document
123      .querySelectorAll("#searchbox .highlight-link")
124      .forEach((el) => el.remove());
125    document
126      .querySelectorAll("span.highlighted")
127      .forEach((el) => el.classList.remove("highlighted"));
128    localStorage.removeItem("sphinx_highlight_terms")
129  },
130
131  initEscapeListener: () => {
132    // only install a listener if it is really needed
133    if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return;
134
135    document.addEventListener("keydown", (event) => {
136      // bail for input elements
137      if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;
138      // bail with special keys
139      if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return;
140      if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) {
141        SphinxHighlight.hideSearchWords();
142        event.preventDefault();
143      }
144    });
145  },
146};
147
148_ready(() => {
149  /* Do not call highlightSearchWords() when we are on the search page.
150   * It will highlight words from the *previous* search query.
151   */
152  if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords();
153  SphinxHighlight.initEscapeListener();
154});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.