PageSourceSearch

http://docs.cython.org/en/latest/_static/sphinx_highlight.js?v=36527ec2

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

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.