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