• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2024 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15document.addEventListener('DOMContentLoaded', () => {
16  'use strict';
17
18  const searchModule = function () {
19    let index = [];
20    const highlight = document.querySelector('#ls-highlight').value === 'true';
21    // First we add all page titles
22    const SidebarSearchIndex = window.SidebarSearchIndex;
23    SidebarSearchIndex.titles.forEach((title, docIndex) => {
24      let doc = SidebarSearchIndex.docnames[docIndex];
25      if (doc.endsWith('/doc')) doc = doc.slice(0, -3);
26      index.push({
27        title: title,
28        doc: doc,
29        hash: '',
30      });
31    });
32
33    const searchField = document.querySelector('#ls_search-field');
34    const searchResults = document.querySelector('#ls_search-results');
35
36    searchField.addEventListener('keyup', onKeyUp);
37    searchField.addEventListener('keypress', onKeyPress);
38    searchField.addEventListener('focusout', () => {
39      setTimeout(() => {
40        searchResults.style.display = 'none';
41      }, 100);
42    });
43    searchField.addEventListener('focusin', () => {
44      if (searchResults.querySelectorAll('li').length > 0) {
45        searchResults.style.display = 'block';
46      }
47    });
48
49    function onKeyUp(event) {
50      const keycode = event.keyCode || event.which;
51      const query = searchField.value;
52      let results = null;
53
54      if (keycode === 13) {
55        return;
56      }
57      if (keycode === 40 || keycode === 38) {
58        handleKeyboardNavigation(keycode);
59        return;
60      }
61      if (query === '') {
62        searchResults.innerHTML = '';
63        searchResults.style.display = 'none';
64        return;
65      }
66
67      results = window.fuzzysort.go(query, index, { key: 'title' });
68      searchResults.innerHTML = '';
69      searchResults.style.display = 'block';
70
71      if (results.length === 0) {
72        searchResults.innerHTML = '<li><a href="#">No results found</a></li>';
73      } else {
74        results.slice(0, 15).forEach((result) => {
75          searchResults.appendChild(createResultListElement(result));
76        });
77      }
78
79      // Set the width of the dropdown
80      searchResults.style.width =
81        Math.max(
82          searchField.offsetWidth,
83          Array.from(searchResults.children).reduce(
84            (max, child) => Math.max(max, child.offsetWidth),
85            0,
86          ) + 20,
87        ) + 'px';
88    }
89
90    function onKeyPress(event) {
91      if (event.keyCode === 13) {
92        event.preventDefault();
93        const active = searchResults.querySelector('li a.hover');
94        if (active) {
95          active.click();
96        } else {
97          window.location.href = `${window.DOCUMENTATION_OPTIONS.URL_ROOT}search.html?q=${searchField.value}&check_keywords=yes&area=default`;
98        }
99      }
100    }
101
102    function handleKeyboardNavigation(keycode) {
103      const items = Array.from(searchResults.querySelectorAll('li a'));
104      const activeIndex = items.findIndex((item) =>
105        item.classList.contains('hover'),
106      );
107
108      if (keycode === 40 && activeIndex < items.length - 1) {
109        // next
110        if (activeIndex > -1) items[activeIndex].classList.remove('hover');
111        items[activeIndex + 1].classList.add('hover');
112      } else if (keycode === 38 && activeIndex > 0) {
113        // prev
114        items[activeIndex].classList.remove('hover');
115        items[activeIndex - 1].classList.add('hover');
116      }
117    }
118
119    function buildHref(s) {
120      const highlightString = highlight
121        ? `?highlight=${encodeURIComponent(s.title || s.heading)}`
122        : '';
123      return `${window.DOCUMENTATION_OPTIONS.URL_ROOT}${s.doc}${window.DOCUMENTATION_OPTIONS.FILE_SUFFIX}${highlightString}#${s.hash}`;
124    }
125
126    function createResultListElement(s) {
127      const li = document.createElement('li');
128      const a = document.createElement('a');
129      a.href = buildHref(s.obj);
130      // create content
131      const span = document.createElement('span');
132      span.innerHTML = window.fuzzysort.highlight(s);
133      const small = document.createElement('small');
134      small.textContent = `${s.obj.doc}${window.DOCUMENTATION_OPTIONS.FILE_SUFFIX}`;
135      a.appendChild(span);
136      a.appendChild(small);
137
138      a.addEventListener('mouseenter', () => {
139        Array.from(searchResults.querySelectorAll('li a')).forEach((el) =>
140          el.classList.remove('hover'),
141        );
142        a.classList.add('hover');
143      });
144      a.addEventListener('mouseleave', () => {
145        a.classList.remove('hover');
146      });
147      li.appendChild(a);
148      return li;
149    }
150  };
151
152  searchModule();
153});
154