/ docs / manual / _static / doctools.js
doctools.js
  1  /*
  2   * doctools.js
  3   * ~~~~~~~~~~~
  4   *
  5   * Base JavaScript utilities for all Sphinx HTML documentation.
  6   *
  7   * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
  8   * :license: BSD, see LICENSE for details.
  9   *
 10   */
 11  "use strict";
 12  
 13  const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([
 14    "TEXTAREA",
 15    "INPUT",
 16    "SELECT",
 17    "BUTTON",
 18  ]);
 19  
 20  const _ready = (callback) => {
 21    if (document.readyState !== "loading") {
 22      callback();
 23    } else {
 24      document.addEventListener("DOMContentLoaded", callback);
 25    }
 26  };
 27  
 28  /**
 29   * Small JavaScript module for the documentation.
 30   */
 31  const Documentation = {
 32    init: () => {
 33      Documentation.initDomainIndexTable();
 34      Documentation.initOnKeyListeners();
 35    },
 36  
 37    /**
 38     * i18n support
 39     */
 40    TRANSLATIONS: {},
 41    PLURAL_EXPR: (n) => (n === 1 ? 0 : 1),
 42    LOCALE: "unknown",
 43  
 44    // gettext and ngettext don't access this so that the functions
 45    // can safely bound to a different name (_ = Documentation.gettext)
 46    gettext: (string) => {
 47      const translated = Documentation.TRANSLATIONS[string];
 48      switch (typeof translated) {
 49        case "undefined":
 50          return string; // no translation
 51        case "string":
 52          return translated; // translation exists
 53        default:
 54          return translated[0]; // (singular, plural) translation tuple exists
 55      }
 56    },
 57  
 58    ngettext: (singular, plural, n) => {
 59      const translated = Documentation.TRANSLATIONS[singular];
 60      if (typeof translated !== "undefined")
 61        return translated[Documentation.PLURAL_EXPR(n)];
 62      return n === 1 ? singular : plural;
 63    },
 64  
 65    addTranslations: (catalog) => {
 66      Object.assign(Documentation.TRANSLATIONS, catalog.messages);
 67      Documentation.PLURAL_EXPR = new Function(
 68        "n",
 69        `return (${catalog.plural_expr})`
 70      );
 71      Documentation.LOCALE = catalog.locale;
 72    },
 73  
 74    /**
 75     * helper function to focus on search bar
 76     */
 77    focusSearchBar: () => {
 78      document.querySelectorAll("input[name=q]")[0]?.focus();
 79    },
 80  
 81    /**
 82     * Initialise the domain index toggle buttons
 83     */
 84    initDomainIndexTable: () => {
 85      const toggler = (el) => {
 86        const idNumber = el.id.substr(7);
 87        const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`);
 88        if (el.src.substr(-9) === "minus.png") {
 89          el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`;
 90          toggledRows.forEach((el) => (el.style.display = "none"));
 91        } else {
 92          el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`;
 93          toggledRows.forEach((el) => (el.style.display = ""));
 94        }
 95      };
 96  
 97      const togglerElements = document.querySelectorAll("img.toggler");
 98      togglerElements.forEach((el) =>
 99        el.addEventListener("click", (event) => toggler(event.currentTarget))
100      );
101      togglerElements.forEach((el) => (el.style.display = ""));
102      if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler);
103    },
104  
105    initOnKeyListeners: () => {
106      // only install a listener if it is really needed
107      if (
108        !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS &&
109        !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS
110      )
111        return;
112  
113      document.addEventListener("keydown", (event) => {
114        // bail for input elements
115        if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;
116        // bail with special keys
117        if (event.altKey || event.ctrlKey || event.metaKey) return;
118  
119        if (!event.shiftKey) {
120          switch (event.key) {
121            case "ArrowLeft":
122              if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
123  
124              const prevLink = document.querySelector('link[rel="prev"]');
125              if (prevLink && prevLink.href) {
126                window.location.href = prevLink.href;
127                event.preventDefault();
128              }
129              break;
130            case "ArrowRight":
131              if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
132  
133              const nextLink = document.querySelector('link[rel="next"]');
134              if (nextLink && nextLink.href) {
135                window.location.href = nextLink.href;
136                event.preventDefault();
137              }
138              break;
139          }
140        }
141  
142        // some keyboard layouts may need Shift to get /
143        switch (event.key) {
144          case "/":
145            if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break;
146            Documentation.focusSearchBar();
147            event.preventDefault();
148        }
149      });
150    },
151  };
152  
153  // quick alias for translations
154  const _ = Documentation.gettext;
155  
156  _ready(Documentation.init);