1{#
2  Override the default searchbox from RTD theme to provide the ability to select a search method
3  (ex. built-in search, Google Custom Search, ...)
4#}
5{%- if ('singlehtml' not in builder) %}
6<div class="search-container" role="search">
7  <form id="rtd-search-form" class="wy-form" action="{{ pathto('search') }}" method="get">
8    <input type="search" name="q" placeholder="{{ _('Search docs') }}"
9           aria-label="{{ _('Search docs') }}" />
10    {%- if google_searchengine_id is defined %}
11    <span id="search-se-settings-icon" class="fa fa-gear" role="button" tabindex="0"
12          title="Search settings" aria-label="Search settings"
13          aria-haspopup="true" aria-controls="search-se-menu" aria-expanded="false"
14          onclick="toggleSearchEngineSettingsMenu()">
15    </span>
16    <div id="search-se-menu" role="menu" aria-labelledby="search-se-settings-icon">
17      <ul>
18        <li id="search-se-menuitem-sphinx" role="menuitemradio" tabindex="-1"
19            aria-label="Built-in search" onclick="switchSearchEngine('sphinx')">
20          Built-in search <span class="fa fa-check">
21        </li>
22        <li id="search-se-menuitem-google" role="menuitemradio" tabindex="-1"
23            aria-label="Google search" onclick="switchSearchEngine('google')">
24          Google search <span class="fa fa-check">
25        </li>
26    </div>
27    {%- endif %}
28    <input type="hidden" name="check_keywords" value="yes" />
29    <input type="hidden" name="area" value="default" />
30  </form>
31</div>
32{%- if google_searchengine_id is defined %}
33<script>
34(function () {
35  var form = document.getElementById("rtd-search-form");
36  var searchMenu = document.getElementById("search-se-menu");
37  var isBrowsingLatest = window.location.pathname.startsWith("/latest");
38  var preferenceKey = "search-se-" + (isBrowsingLatest ? "latest" : "default");
39  var query = new URLSearchParams(window.location.search).get("q");
40
41  if (query !== null) {
42    form.q.value = query;
43    form.q.focus();
44  }
45
46  // Load the saved search preference. Defaults to Google when browsing "/latest" documentation,
47  // built-in Sphinx search otherwise.
48  var engine = localStorage.getItem(preferenceKey);
49  if (engine === null) {
50    engine = isBrowsingLatest ? "google" : "sphinx";
51  }
52  setActiveSearchEngine(engine);
53
54  setSearchEngineSettingsMenuVisibility = function (visible) {
55    searchMenu.style.display = visible ? "block" : "none";
56    document
57      .getElementById("search-se-settings-icon")
58      .setAttribute("aria-expanded", visible ? "true" : "false");
59  };
60  setSearchEngineSettingsMenuVisibility(false);
61
62  window.toggleSearchEngineSettingsMenu = function () {
63    isVisible = searchMenu.style.display === "block";
64    setSearchEngineSettingsMenuVisibility(!isVisible);
65  };
66
67  function setActiveSearchEngine(engine) {
68    if(engine === "sphinx") {
69      form.action = "{{ pathto('search') }}";
70      form.q.placeholder = "Search docs (built-in search)";
71    } else {
72      form.action = "{{ pathto('gsearch') }}";
73      form.q.placeholder = "Search docs (powered by Google)";
74    }
75
76    var selectedElement = document.getElementById("search-se-menuitem-" + engine);
77    var otherElement = document.getElementById(
78      "search-se-menuitem-" + (engine === "sphinx" ? "google" : "sphinx")
79    );
80
81    selectedElement.classList.add("selected");
82    selectedElement.setAttribute("aria-checked", "true");
83    otherElement.classList.remove("selected");
84    otherElement.setAttribute("aria-checked", "false");
85  }
86
87  window.switchSearchEngine = function (engine) {
88    setActiveSearchEngine(engine);
89    localStorage.setItem(preferenceKey, engine);
90    setSearchEngineSettingsMenuVisibility(false);
91    form.q.focus();
92    if (form.q.value !== "") {
93      form.submit();
94    }
95  };
96
97  // Close the dropdown if the user clicks outside of it
98  window.onclick = function (event) {
99    if (!event.target.matches("#search-se-settings-icon")) {
100      if (searchMenu.style.display === "block") {
101        setSearchEngineSettingsMenuVisibility(false);
102      }
103    }
104  };
105
106  document.addEventListener("keydown", function (event) {
107    if(searchMenu.style.display === "none") return;
108
109    let menuItems = document.querySelectorAll('[role="menuitemradio"]');
110    let currentIndex = Array.from(menuItems).findIndex((item) => item === document.activeElement);
111
112    if (event.key === "ArrowDown" || event.key === "ArrowUp") {
113      let nextIndex = event.key === "ArrowDown" ? currentIndex + 1 : currentIndex - 1;
114
115      if (nextIndex >= menuItems.length) nextIndex = 0;
116      if (nextIndex < 0) nextIndex = menuItems.length - 1;
117
118      menuItems[nextIndex].focus();
119      event.preventDefault();
120    } else if (event.key === "Enter") {
121      let activeItem = document.activeElement;
122      if (activeItem && activeItem.getAttribute("role") === "menuitemradio") {
123        activeItem.click();
124        event.preventDefault();
125      }
126    }
127  });
128})();
129</script>
130{%- endif %}
131{%- endif %}