155 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
/* Highlighting utilities for Sphinx HTML documentation. */
 | 
						|
"use strict";
 | 
						|
 | 
						|
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();
 | 
						|
});
 |