1*7485b225SElliott Hughes/* 2*7485b225SElliott Hughes @licstart The following is the entire license notice for the JavaScript code in this file. 3*7485b225SElliott Hughes 4*7485b225SElliott Hughes The MIT License (MIT) 5*7485b225SElliott Hughes 6*7485b225SElliott Hughes Copyright (C) 1997-2020 by Dimitri van Heesch 7*7485b225SElliott Hughes 8*7485b225SElliott Hughes Permission is hereby granted, free of charge, to any person obtaining a copy of this software 9*7485b225SElliott Hughes and associated documentation files (the "Software"), to deal in the Software without restriction, 10*7485b225SElliott Hughes including without limitation the rights to use, copy, modify, merge, publish, distribute, 11*7485b225SElliott Hughes sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 12*7485b225SElliott Hughes furnished to do so, subject to the following conditions: 13*7485b225SElliott Hughes 14*7485b225SElliott Hughes The above copyright notice and this permission notice shall be included in all copies or 15*7485b225SElliott Hughes substantial portions of the Software. 16*7485b225SElliott Hughes 17*7485b225SElliott Hughes THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 18*7485b225SElliott Hughes BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19*7485b225SElliott Hughes NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 20*7485b225SElliott Hughes DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21*7485b225SElliott Hughes OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22*7485b225SElliott Hughes 23*7485b225SElliott Hughes @licend The above is the entire license notice for the JavaScript code in this file 24*7485b225SElliott Hughes */ 25*7485b225SElliott Hughesconst SEARCH_COOKIE_NAME = ''+'search_grp'; 26*7485b225SElliott Hughes 27*7485b225SElliott Hughesconst searchResults = new SearchResults(); 28*7485b225SElliott Hughes 29*7485b225SElliott Hughes/* A class handling everything associated with the search panel. 30*7485b225SElliott Hughes 31*7485b225SElliott Hughes Parameters: 32*7485b225SElliott Hughes name - The name of the global variable that will be 33*7485b225SElliott Hughes storing this instance. Is needed to be able to set timeouts. 34*7485b225SElliott Hughes resultPath - path to use for external files 35*7485b225SElliott Hughes*/ 36*7485b225SElliott Hughesfunction SearchBox(name, resultsPath, extension) { 37*7485b225SElliott Hughes if (!name || !resultsPath) { alert("Missing parameters to SearchBox."); } 38*7485b225SElliott Hughes if (!extension || extension == "") { extension = ".html"; } 39*7485b225SElliott Hughes 40*7485b225SElliott Hughes function getXPos(item) { 41*7485b225SElliott Hughes let x = 0; 42*7485b225SElliott Hughes if (item.offsetWidth) { 43*7485b225SElliott Hughes while (item && item!=document.body) { 44*7485b225SElliott Hughes x += item.offsetLeft; 45*7485b225SElliott Hughes item = item.offsetParent; 46*7485b225SElliott Hughes } 47*7485b225SElliott Hughes } 48*7485b225SElliott Hughes return x; 49*7485b225SElliott Hughes } 50*7485b225SElliott Hughes 51*7485b225SElliott Hughes function getYPos(item) { 52*7485b225SElliott Hughes let y = 0; 53*7485b225SElliott Hughes if (item.offsetWidth) { 54*7485b225SElliott Hughes while (item && item!=document.body) { 55*7485b225SElliott Hughes y += item.offsetTop; 56*7485b225SElliott Hughes item = item.offsetParent; 57*7485b225SElliott Hughes } 58*7485b225SElliott Hughes } 59*7485b225SElliott Hughes return y; 60*7485b225SElliott Hughes } 61*7485b225SElliott Hughes 62*7485b225SElliott Hughes // ---------- Instance variables 63*7485b225SElliott Hughes this.name = name; 64*7485b225SElliott Hughes this.resultsPath = resultsPath; 65*7485b225SElliott Hughes this.keyTimeout = 0; 66*7485b225SElliott Hughes this.keyTimeoutLength = 500; 67*7485b225SElliott Hughes this.closeSelectionTimeout = 300; 68*7485b225SElliott Hughes this.lastSearchValue = ""; 69*7485b225SElliott Hughes this.lastResultsPage = ""; 70*7485b225SElliott Hughes this.hideTimeout = 0; 71*7485b225SElliott Hughes this.searchIndex = 0; 72*7485b225SElliott Hughes this.searchActive = false; 73*7485b225SElliott Hughes this.extension = extension; 74*7485b225SElliott Hughes 75*7485b225SElliott Hughes // ----------- DOM Elements 76*7485b225SElliott Hughes 77*7485b225SElliott Hughes this.DOMSearchField = () => document.getElementById("MSearchField"); 78*7485b225SElliott Hughes this.DOMSearchSelect = () => document.getElementById("MSearchSelect"); 79*7485b225SElliott Hughes this.DOMSearchSelectWindow = () => document.getElementById("MSearchSelectWindow"); 80*7485b225SElliott Hughes this.DOMPopupSearchResults = () => document.getElementById("MSearchResults"); 81*7485b225SElliott Hughes this.DOMPopupSearchResultsWindow = () => document.getElementById("MSearchResultsWindow"); 82*7485b225SElliott Hughes this.DOMSearchClose = () => document.getElementById("MSearchClose"); 83*7485b225SElliott Hughes this.DOMSearchBox = () => document.getElementById("MSearchBox"); 84*7485b225SElliott Hughes 85*7485b225SElliott Hughes // ------------ Event Handlers 86*7485b225SElliott Hughes 87*7485b225SElliott Hughes // Called when focus is added or removed from the search field. 88*7485b225SElliott Hughes this.OnSearchFieldFocus = function(isActive) { 89*7485b225SElliott Hughes this.Activate(isActive); 90*7485b225SElliott Hughes } 91*7485b225SElliott Hughes 92*7485b225SElliott Hughes this.OnSearchSelectShow = function() { 93*7485b225SElliott Hughes const searchSelectWindow = this.DOMSearchSelectWindow(); 94*7485b225SElliott Hughes const searchField = this.DOMSearchSelect(); 95*7485b225SElliott Hughes 96*7485b225SElliott Hughes const left = getXPos(searchField); 97*7485b225SElliott Hughes const top = getYPos(searchField) + searchField.offsetHeight; 98*7485b225SElliott Hughes 99*7485b225SElliott Hughes // show search selection popup 100*7485b225SElliott Hughes searchSelectWindow.style.display='block'; 101*7485b225SElliott Hughes searchSelectWindow.style.left = left + 'px'; 102*7485b225SElliott Hughes searchSelectWindow.style.top = top + 'px'; 103*7485b225SElliott Hughes 104*7485b225SElliott Hughes // stop selection hide timer 105*7485b225SElliott Hughes if (this.hideTimeout) { 106*7485b225SElliott Hughes clearTimeout(this.hideTimeout); 107*7485b225SElliott Hughes this.hideTimeout=0; 108*7485b225SElliott Hughes } 109*7485b225SElliott Hughes return false; // to avoid "image drag" default event 110*7485b225SElliott Hughes } 111*7485b225SElliott Hughes 112*7485b225SElliott Hughes this.OnSearchSelectHide = function() { 113*7485b225SElliott Hughes this.hideTimeout = setTimeout(this.CloseSelectionWindow.bind(this), 114*7485b225SElliott Hughes this.closeSelectionTimeout); 115*7485b225SElliott Hughes } 116*7485b225SElliott Hughes 117*7485b225SElliott Hughes // Called when the content of the search field is changed. 118*7485b225SElliott Hughes this.OnSearchFieldChange = function(evt) { 119*7485b225SElliott Hughes if (this.keyTimeout) { // kill running timer 120*7485b225SElliott Hughes clearTimeout(this.keyTimeout); 121*7485b225SElliott Hughes this.keyTimeout = 0; 122*7485b225SElliott Hughes } 123*7485b225SElliott Hughes 124*7485b225SElliott Hughes const e = evt ? evt : window.event; // for IE 125*7485b225SElliott Hughes if (e.keyCode==40 || e.keyCode==13) { 126*7485b225SElliott Hughes if (e.shiftKey==1) { 127*7485b225SElliott Hughes this.OnSearchSelectShow(); 128*7485b225SElliott Hughes const win=this.DOMSearchSelectWindow(); 129*7485b225SElliott Hughes for (let i=0;i<win.childNodes.length;i++) { 130*7485b225SElliott Hughes const child = win.childNodes[i]; // get span within a 131*7485b225SElliott Hughes if (child.className=='SelectItem') { 132*7485b225SElliott Hughes child.focus(); 133*7485b225SElliott Hughes return; 134*7485b225SElliott Hughes } 135*7485b225SElliott Hughes } 136*7485b225SElliott Hughes return; 137*7485b225SElliott Hughes } else { 138*7485b225SElliott Hughes const elem = searchResults.NavNext(0); 139*7485b225SElliott Hughes if (elem) elem.focus(); 140*7485b225SElliott Hughes } 141*7485b225SElliott Hughes } else if (e.keyCode==27) { // Escape out of the search field 142*7485b225SElliott Hughes e.stopPropagation(); 143*7485b225SElliott Hughes this.DOMSearchField().blur(); 144*7485b225SElliott Hughes this.DOMPopupSearchResultsWindow().style.display = 'none'; 145*7485b225SElliott Hughes this.DOMSearchClose().style.display = 'none'; 146*7485b225SElliott Hughes this.lastSearchValue = ''; 147*7485b225SElliott Hughes this.Activate(false); 148*7485b225SElliott Hughes return; 149*7485b225SElliott Hughes } 150*7485b225SElliott Hughes 151*7485b225SElliott Hughes // strip whitespaces 152*7485b225SElliott Hughes const searchValue = this.DOMSearchField().value.replace(/ +/g, ""); 153*7485b225SElliott Hughes 154*7485b225SElliott Hughes if (searchValue != this.lastSearchValue) { // search value has changed 155*7485b225SElliott Hughes if (searchValue != "") { // non-empty search 156*7485b225SElliott Hughes // set timer for search update 157*7485b225SElliott Hughes this.keyTimeout = setTimeout(this.Search.bind(this), this.keyTimeoutLength); 158*7485b225SElliott Hughes } else { // empty search field 159*7485b225SElliott Hughes this.DOMPopupSearchResultsWindow().style.display = 'none'; 160*7485b225SElliott Hughes this.DOMSearchClose().style.display = 'none'; 161*7485b225SElliott Hughes this.lastSearchValue = ''; 162*7485b225SElliott Hughes } 163*7485b225SElliott Hughes } 164*7485b225SElliott Hughes } 165*7485b225SElliott Hughes 166*7485b225SElliott Hughes this.SelectItemCount = function() { 167*7485b225SElliott Hughes let count=0; 168*7485b225SElliott Hughes const win=this.DOMSearchSelectWindow(); 169*7485b225SElliott Hughes for (let i=0;i<win.childNodes.length;i++) { 170*7485b225SElliott Hughes const child = win.childNodes[i]; // get span within a 171*7485b225SElliott Hughes if (child.className=='SelectItem') { 172*7485b225SElliott Hughes count++; 173*7485b225SElliott Hughes } 174*7485b225SElliott Hughes } 175*7485b225SElliott Hughes return count; 176*7485b225SElliott Hughes } 177*7485b225SElliott Hughes 178*7485b225SElliott Hughes this.GetSelectionIdByName = function(name) { 179*7485b225SElliott Hughes let j=0; 180*7485b225SElliott Hughes const win=this.DOMSearchSelectWindow(); 181*7485b225SElliott Hughes for (let i=0;i<win.childNodes.length;i++) { 182*7485b225SElliott Hughes const child = win.childNodes[i]; 183*7485b225SElliott Hughes if (child.className=='SelectItem') { 184*7485b225SElliott Hughes if (child.childNodes[1].nodeValue==name) { 185*7485b225SElliott Hughes return j; 186*7485b225SElliott Hughes } 187*7485b225SElliott Hughes j++; 188*7485b225SElliott Hughes } 189*7485b225SElliott Hughes } 190*7485b225SElliott Hughes return 0; 191*7485b225SElliott Hughes } 192*7485b225SElliott Hughes 193*7485b225SElliott Hughes this.SelectItemSet = function(id) { 194*7485b225SElliott Hughes let j=0; 195*7485b225SElliott Hughes const win=this.DOMSearchSelectWindow(); 196*7485b225SElliott Hughes for (let i=0;i<win.childNodes.length;i++) { 197*7485b225SElliott Hughes const child = win.childNodes[i]; // get span within a 198*7485b225SElliott Hughes if (child.className=='SelectItem') { 199*7485b225SElliott Hughes const node = child.firstChild; 200*7485b225SElliott Hughes if (j==id) { 201*7485b225SElliott Hughes node.innerHTML='•'; 202*7485b225SElliott Hughes Cookie.writeSetting(SEARCH_COOKIE_NAME, child.childNodes[1].nodeValue, 0) 203*7485b225SElliott Hughes } else { 204*7485b225SElliott Hughes node.innerHTML=' '; 205*7485b225SElliott Hughes } 206*7485b225SElliott Hughes j++; 207*7485b225SElliott Hughes } 208*7485b225SElliott Hughes } 209*7485b225SElliott Hughes } 210*7485b225SElliott Hughes 211*7485b225SElliott Hughes // Called when an search filter selection is made. 212*7485b225SElliott Hughes // set item with index id as the active item 213*7485b225SElliott Hughes this.OnSelectItem = function(id) { 214*7485b225SElliott Hughes this.searchIndex = id; 215*7485b225SElliott Hughes this.SelectItemSet(id); 216*7485b225SElliott Hughes const searchValue = this.DOMSearchField().value.replace(/ +/g, ""); 217*7485b225SElliott Hughes if (searchValue!="" && this.searchActive) { // something was found -> do a search 218*7485b225SElliott Hughes this.Search(); 219*7485b225SElliott Hughes } 220*7485b225SElliott Hughes } 221*7485b225SElliott Hughes 222*7485b225SElliott Hughes this.OnSearchSelectKey = function(evt) { 223*7485b225SElliott Hughes const e = (evt) ? evt : window.event; // for IE 224*7485b225SElliott Hughes if (e.keyCode==40 && this.searchIndex<this.SelectItemCount()) { // Down 225*7485b225SElliott Hughes this.searchIndex++; 226*7485b225SElliott Hughes this.OnSelectItem(this.searchIndex); 227*7485b225SElliott Hughes } else if (e.keyCode==38 && this.searchIndex>0) { // Up 228*7485b225SElliott Hughes this.searchIndex--; 229*7485b225SElliott Hughes this.OnSelectItem(this.searchIndex); 230*7485b225SElliott Hughes } else if (e.keyCode==13 || e.keyCode==27) { 231*7485b225SElliott Hughes e.stopPropagation(); 232*7485b225SElliott Hughes this.OnSelectItem(this.searchIndex); 233*7485b225SElliott Hughes this.CloseSelectionWindow(); 234*7485b225SElliott Hughes this.DOMSearchField().focus(); 235*7485b225SElliott Hughes } 236*7485b225SElliott Hughes return false; 237*7485b225SElliott Hughes } 238*7485b225SElliott Hughes 239*7485b225SElliott Hughes // --------- Actions 240*7485b225SElliott Hughes 241*7485b225SElliott Hughes // Closes the results window. 242*7485b225SElliott Hughes this.CloseResultsWindow = function() { 243*7485b225SElliott Hughes this.DOMPopupSearchResultsWindow().style.display = 'none'; 244*7485b225SElliott Hughes this.DOMSearchClose().style.display = 'none'; 245*7485b225SElliott Hughes this.Activate(false); 246*7485b225SElliott Hughes } 247*7485b225SElliott Hughes 248*7485b225SElliott Hughes this.CloseSelectionWindow = function() { 249*7485b225SElliott Hughes this.DOMSearchSelectWindow().style.display = 'none'; 250*7485b225SElliott Hughes } 251*7485b225SElliott Hughes 252*7485b225SElliott Hughes // Performs a search. 253*7485b225SElliott Hughes this.Search = function() { 254*7485b225SElliott Hughes this.keyTimeout = 0; 255*7485b225SElliott Hughes 256*7485b225SElliott Hughes // strip leading whitespace 257*7485b225SElliott Hughes const searchValue = this.DOMSearchField().value.replace(/^ +/, ""); 258*7485b225SElliott Hughes 259*7485b225SElliott Hughes const code = searchValue.toLowerCase().charCodeAt(0); 260*7485b225SElliott Hughes let idxChar = searchValue.substr(0, 1).toLowerCase(); 261*7485b225SElliott Hughes if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) { // surrogate pair 262*7485b225SElliott Hughes idxChar = searchValue.substr(0, 2); 263*7485b225SElliott Hughes } 264*7485b225SElliott Hughes 265*7485b225SElliott Hughes let jsFile; 266*7485b225SElliott Hughes let idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); 267*7485b225SElliott Hughes if (idx!=-1) { 268*7485b225SElliott Hughes const hexCode=idx.toString(16); 269*7485b225SElliott Hughes jsFile = this.resultsPath + indexSectionNames[this.searchIndex] + '_' + hexCode + '.js'; 270*7485b225SElliott Hughes } 271*7485b225SElliott Hughes 272*7485b225SElliott Hughes const loadJS = function(url, impl, loc) { 273*7485b225SElliott Hughes const scriptTag = document.createElement('script'); 274*7485b225SElliott Hughes scriptTag.src = url; 275*7485b225SElliott Hughes scriptTag.onload = impl; 276*7485b225SElliott Hughes scriptTag.onreadystatechange = impl; 277*7485b225SElliott Hughes loc.appendChild(scriptTag); 278*7485b225SElliott Hughes } 279*7485b225SElliott Hughes 280*7485b225SElliott Hughes const domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); 281*7485b225SElliott Hughes const domSearchBox = this.DOMSearchBox(); 282*7485b225SElliott Hughes const domPopupSearchResults = this.DOMPopupSearchResults(); 283*7485b225SElliott Hughes const domSearchClose = this.DOMSearchClose(); 284*7485b225SElliott Hughes const resultsPath = this.resultsPath; 285*7485b225SElliott Hughes 286*7485b225SElliott Hughes const handleResults = function() { 287*7485b225SElliott Hughes document.getElementById("Loading").style.display="none"; 288*7485b225SElliott Hughes if (typeof searchData !== 'undefined') { 289*7485b225SElliott Hughes createResults(resultsPath); 290*7485b225SElliott Hughes document.getElementById("NoMatches").style.display="none"; 291*7485b225SElliott Hughes } 292*7485b225SElliott Hughes 293*7485b225SElliott Hughes if (idx!=-1) { 294*7485b225SElliott Hughes searchResults.Search(searchValue); 295*7485b225SElliott Hughes } else { // no file with search results => force empty search results 296*7485b225SElliott Hughes searchResults.Search('===='); 297*7485b225SElliott Hughes } 298*7485b225SElliott Hughes 299*7485b225SElliott Hughes if (domPopupSearchResultsWindow.style.display!='block') { 300*7485b225SElliott Hughes domSearchClose.style.display = 'inline-block'; 301*7485b225SElliott Hughes let left = getXPos(domSearchBox) + 150; 302*7485b225SElliott Hughes let top = getYPos(domSearchBox) + 20; 303*7485b225SElliott Hughes domPopupSearchResultsWindow.style.display = 'block'; 304*7485b225SElliott Hughes left -= domPopupSearchResults.offsetWidth; 305*7485b225SElliott Hughes const maxWidth = document.body.clientWidth; 306*7485b225SElliott Hughes const maxHeight = document.body.clientHeight; 307*7485b225SElliott Hughes let width = 300; 308*7485b225SElliott Hughes if (left<10) left=10; 309*7485b225SElliott Hughes if (width+left+8>maxWidth) width=maxWidth-left-8; 310*7485b225SElliott Hughes let height = 400; 311*7485b225SElliott Hughes if (height+top+8>maxHeight) height=maxHeight-top-8; 312*7485b225SElliott Hughes domPopupSearchResultsWindow.style.top = top + 'px'; 313*7485b225SElliott Hughes domPopupSearchResultsWindow.style.left = left + 'px'; 314*7485b225SElliott Hughes domPopupSearchResultsWindow.style.width = width + 'px'; 315*7485b225SElliott Hughes domPopupSearchResultsWindow.style.height = height + 'px'; 316*7485b225SElliott Hughes } 317*7485b225SElliott Hughes } 318*7485b225SElliott Hughes 319*7485b225SElliott Hughes if (jsFile) { 320*7485b225SElliott Hughes loadJS(jsFile, handleResults, this.DOMPopupSearchResultsWindow()); 321*7485b225SElliott Hughes } else { 322*7485b225SElliott Hughes handleResults(); 323*7485b225SElliott Hughes } 324*7485b225SElliott Hughes 325*7485b225SElliott Hughes this.lastSearchValue = searchValue; 326*7485b225SElliott Hughes } 327*7485b225SElliott Hughes 328*7485b225SElliott Hughes // -------- Activation Functions 329*7485b225SElliott Hughes 330*7485b225SElliott Hughes // Activates or deactivates the search panel, resetting things to 331*7485b225SElliott Hughes // their default values if necessary. 332*7485b225SElliott Hughes this.Activate = function(isActive) { 333*7485b225SElliott Hughes if (isActive || // open it 334*7485b225SElliott Hughes this.DOMPopupSearchResultsWindow().style.display == 'block' 335*7485b225SElliott Hughes ) { 336*7485b225SElliott Hughes this.DOMSearchBox().className = 'MSearchBoxActive'; 337*7485b225SElliott Hughes this.searchActive = true; 338*7485b225SElliott Hughes } else if (!isActive) { // directly remove the panel 339*7485b225SElliott Hughes this.DOMSearchBox().className = 'MSearchBoxInactive'; 340*7485b225SElliott Hughes this.searchActive = false; 341*7485b225SElliott Hughes this.lastSearchValue = '' 342*7485b225SElliott Hughes this.lastResultsPage = ''; 343*7485b225SElliott Hughes this.DOMSearchField().value = ''; 344*7485b225SElliott Hughes } 345*7485b225SElliott Hughes } 346*7485b225SElliott Hughes} 347*7485b225SElliott Hughes 348*7485b225SElliott Hughes// ----------------------------------------------------------------------- 349*7485b225SElliott Hughes 350*7485b225SElliott Hughes// The class that handles everything on the search results page. 351*7485b225SElliott Hughesfunction SearchResults() { 352*7485b225SElliott Hughes 353*7485b225SElliott Hughes function convertToId(search) { 354*7485b225SElliott Hughes let result = ''; 355*7485b225SElliott Hughes for (let i=0;i<search.length;i++) { 356*7485b225SElliott Hughes const c = search.charAt(i); 357*7485b225SElliott Hughes const cn = c.charCodeAt(0); 358*7485b225SElliott Hughes if (c.match(/[a-z0-9\u0080-\uFFFF]/)) { 359*7485b225SElliott Hughes result+=c; 360*7485b225SElliott Hughes } else if (cn<16) { 361*7485b225SElliott Hughes result+="_0"+cn.toString(16); 362*7485b225SElliott Hughes } else { 363*7485b225SElliott Hughes result+="_"+cn.toString(16); 364*7485b225SElliott Hughes } 365*7485b225SElliott Hughes } 366*7485b225SElliott Hughes return result; 367*7485b225SElliott Hughes } 368*7485b225SElliott Hughes 369*7485b225SElliott Hughes // The number of matches from the last run of <Search()>. 370*7485b225SElliott Hughes this.lastMatchCount = 0; 371*7485b225SElliott Hughes this.lastKey = 0; 372*7485b225SElliott Hughes this.repeatOn = false; 373*7485b225SElliott Hughes 374*7485b225SElliott Hughes // Toggles the visibility of the passed element ID. 375*7485b225SElliott Hughes this.FindChildElement = function(id) { 376*7485b225SElliott Hughes const parentElement = document.getElementById(id); 377*7485b225SElliott Hughes let element = parentElement.firstChild; 378*7485b225SElliott Hughes 379*7485b225SElliott Hughes while (element && element!=parentElement) { 380*7485b225SElliott Hughes if (element.nodeName.toLowerCase() == 'div' && element.className == 'SRChildren') { 381*7485b225SElliott Hughes return element; 382*7485b225SElliott Hughes } 383*7485b225SElliott Hughes 384*7485b225SElliott Hughes if (element.nodeName.toLowerCase() == 'div' && element.hasChildNodes()) { 385*7485b225SElliott Hughes element = element.firstChild; 386*7485b225SElliott Hughes } else if (element.nextSibling) { 387*7485b225SElliott Hughes element = element.nextSibling; 388*7485b225SElliott Hughes } else { 389*7485b225SElliott Hughes do { 390*7485b225SElliott Hughes element = element.parentNode; 391*7485b225SElliott Hughes } 392*7485b225SElliott Hughes while (element && element!=parentElement && !element.nextSibling); 393*7485b225SElliott Hughes 394*7485b225SElliott Hughes if (element && element!=parentElement) { 395*7485b225SElliott Hughes element = element.nextSibling; 396*7485b225SElliott Hughes } 397*7485b225SElliott Hughes } 398*7485b225SElliott Hughes } 399*7485b225SElliott Hughes } 400*7485b225SElliott Hughes 401*7485b225SElliott Hughes this.Toggle = function(id) { 402*7485b225SElliott Hughes const element = this.FindChildElement(id); 403*7485b225SElliott Hughes if (element) { 404*7485b225SElliott Hughes if (element.style.display == 'block') { 405*7485b225SElliott Hughes element.style.display = 'none'; 406*7485b225SElliott Hughes } else { 407*7485b225SElliott Hughes element.style.display = 'block'; 408*7485b225SElliott Hughes } 409*7485b225SElliott Hughes } 410*7485b225SElliott Hughes } 411*7485b225SElliott Hughes 412*7485b225SElliott Hughes // Searches for the passed string. If there is no parameter, 413*7485b225SElliott Hughes // it takes it from the URL query. 414*7485b225SElliott Hughes // 415*7485b225SElliott Hughes // Always returns true, since other documents may try to call it 416*7485b225SElliott Hughes // and that may or may not be possible. 417*7485b225SElliott Hughes this.Search = function(search) { 418*7485b225SElliott Hughes if (!search) { // get search word from URL 419*7485b225SElliott Hughes search = window.location.search; 420*7485b225SElliott Hughes search = search.substring(1); // Remove the leading '?' 421*7485b225SElliott Hughes search = unescape(search); 422*7485b225SElliott Hughes } 423*7485b225SElliott Hughes 424*7485b225SElliott Hughes search = search.replace(/^ +/, ""); // strip leading spaces 425*7485b225SElliott Hughes search = search.replace(/ +$/, ""); // strip trailing spaces 426*7485b225SElliott Hughes search = search.toLowerCase(); 427*7485b225SElliott Hughes search = convertToId(search); 428*7485b225SElliott Hughes 429*7485b225SElliott Hughes const resultRows = document.getElementsByTagName("div"); 430*7485b225SElliott Hughes let matches = 0; 431*7485b225SElliott Hughes 432*7485b225SElliott Hughes let i = 0; 433*7485b225SElliott Hughes while (i < resultRows.length) { 434*7485b225SElliott Hughes const row = resultRows.item(i); 435*7485b225SElliott Hughes if (row.className == "SRResult") { 436*7485b225SElliott Hughes let rowMatchName = row.id.toLowerCase(); 437*7485b225SElliott Hughes rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' 438*7485b225SElliott Hughes 439*7485b225SElliott Hughes if (search.length<=rowMatchName.length && 440*7485b225SElliott Hughes rowMatchName.substr(0, search.length)==search) { 441*7485b225SElliott Hughes row.style.display = 'block'; 442*7485b225SElliott Hughes matches++; 443*7485b225SElliott Hughes } else { 444*7485b225SElliott Hughes row.style.display = 'none'; 445*7485b225SElliott Hughes } 446*7485b225SElliott Hughes } 447*7485b225SElliott Hughes i++; 448*7485b225SElliott Hughes } 449*7485b225SElliott Hughes document.getElementById("Searching").style.display='none'; 450*7485b225SElliott Hughes if (matches == 0) { // no results 451*7485b225SElliott Hughes document.getElementById("NoMatches").style.display='block'; 452*7485b225SElliott Hughes } else { // at least one result 453*7485b225SElliott Hughes document.getElementById("NoMatches").style.display='none'; 454*7485b225SElliott Hughes } 455*7485b225SElliott Hughes this.lastMatchCount = matches; 456*7485b225SElliott Hughes return true; 457*7485b225SElliott Hughes } 458*7485b225SElliott Hughes 459*7485b225SElliott Hughes // return the first item with index index or higher that is visible 460*7485b225SElliott Hughes this.NavNext = function(index) { 461*7485b225SElliott Hughes let focusItem; 462*7485b225SElliott Hughes for (;;) { 463*7485b225SElliott Hughes const focusName = 'Item'+index; 464*7485b225SElliott Hughes focusItem = document.getElementById(focusName); 465*7485b225SElliott Hughes if (focusItem && focusItem.parentNode.parentNode.style.display=='block') { 466*7485b225SElliott Hughes break; 467*7485b225SElliott Hughes } else if (!focusItem) { // last element 468*7485b225SElliott Hughes break; 469*7485b225SElliott Hughes } 470*7485b225SElliott Hughes focusItem=null; 471*7485b225SElliott Hughes index++; 472*7485b225SElliott Hughes } 473*7485b225SElliott Hughes return focusItem; 474*7485b225SElliott Hughes } 475*7485b225SElliott Hughes 476*7485b225SElliott Hughes this.NavPrev = function(index) { 477*7485b225SElliott Hughes let focusItem; 478*7485b225SElliott Hughes for (;;) { 479*7485b225SElliott Hughes const focusName = 'Item'+index; 480*7485b225SElliott Hughes focusItem = document.getElementById(focusName); 481*7485b225SElliott Hughes if (focusItem && focusItem.parentNode.parentNode.style.display=='block') { 482*7485b225SElliott Hughes break; 483*7485b225SElliott Hughes } else if (!focusItem) { // last element 484*7485b225SElliott Hughes break; 485*7485b225SElliott Hughes } 486*7485b225SElliott Hughes focusItem=null; 487*7485b225SElliott Hughes index--; 488*7485b225SElliott Hughes } 489*7485b225SElliott Hughes return focusItem; 490*7485b225SElliott Hughes } 491*7485b225SElliott Hughes 492*7485b225SElliott Hughes this.ProcessKeys = function(e) { 493*7485b225SElliott Hughes if (e.type == "keydown") { 494*7485b225SElliott Hughes this.repeatOn = false; 495*7485b225SElliott Hughes this.lastKey = e.keyCode; 496*7485b225SElliott Hughes } else if (e.type == "keypress") { 497*7485b225SElliott Hughes if (!this.repeatOn) { 498*7485b225SElliott Hughes if (this.lastKey) this.repeatOn = true; 499*7485b225SElliott Hughes return false; // ignore first keypress after keydown 500*7485b225SElliott Hughes } 501*7485b225SElliott Hughes } else if (e.type == "keyup") { 502*7485b225SElliott Hughes this.lastKey = 0; 503*7485b225SElliott Hughes this.repeatOn = false; 504*7485b225SElliott Hughes } 505*7485b225SElliott Hughes return this.lastKey!=0; 506*7485b225SElliott Hughes } 507*7485b225SElliott Hughes 508*7485b225SElliott Hughes this.Nav = function(evt,itemIndex) { 509*7485b225SElliott Hughes const e = (evt) ? evt : window.event; // for IE 510*7485b225SElliott Hughes if (e.keyCode==13) return true; 511*7485b225SElliott Hughes if (!this.ProcessKeys(e)) return false; 512*7485b225SElliott Hughes 513*7485b225SElliott Hughes if (this.lastKey==38) { // Up 514*7485b225SElliott Hughes const newIndex = itemIndex-1; 515*7485b225SElliott Hughes let focusItem = this.NavPrev(newIndex); 516*7485b225SElliott Hughes if (focusItem) { 517*7485b225SElliott Hughes let child = this.FindChildElement(focusItem.parentNode.parentNode.id); 518*7485b225SElliott Hughes if (child && child.style.display == 'block') { // children visible 519*7485b225SElliott Hughes let n=0; 520*7485b225SElliott Hughes let tmpElem; 521*7485b225SElliott Hughes for (;;) { // search for last child 522*7485b225SElliott Hughes tmpElem = document.getElementById('Item'+newIndex+'_c'+n); 523*7485b225SElliott Hughes if (tmpElem) { 524*7485b225SElliott Hughes focusItem = tmpElem; 525*7485b225SElliott Hughes } else { // found it! 526*7485b225SElliott Hughes break; 527*7485b225SElliott Hughes } 528*7485b225SElliott Hughes n++; 529*7485b225SElliott Hughes } 530*7485b225SElliott Hughes } 531*7485b225SElliott Hughes } 532*7485b225SElliott Hughes if (focusItem) { 533*7485b225SElliott Hughes focusItem.focus(); 534*7485b225SElliott Hughes } else { // return focus to search field 535*7485b225SElliott Hughes document.getElementById("MSearchField").focus(); 536*7485b225SElliott Hughes } 537*7485b225SElliott Hughes } else if (this.lastKey==40) { // Down 538*7485b225SElliott Hughes const newIndex = itemIndex+1; 539*7485b225SElliott Hughes let focusItem; 540*7485b225SElliott Hughes const item = document.getElementById('Item'+itemIndex); 541*7485b225SElliott Hughes const elem = this.FindChildElement(item.parentNode.parentNode.id); 542*7485b225SElliott Hughes if (elem && elem.style.display == 'block') { // children visible 543*7485b225SElliott Hughes focusItem = document.getElementById('Item'+itemIndex+'_c0'); 544*7485b225SElliott Hughes } 545*7485b225SElliott Hughes if (!focusItem) focusItem = this.NavNext(newIndex); 546*7485b225SElliott Hughes if (focusItem) focusItem.focus(); 547*7485b225SElliott Hughes } else if (this.lastKey==39) { // Right 548*7485b225SElliott Hughes const item = document.getElementById('Item'+itemIndex); 549*7485b225SElliott Hughes const elem = this.FindChildElement(item.parentNode.parentNode.id); 550*7485b225SElliott Hughes if (elem) elem.style.display = 'block'; 551*7485b225SElliott Hughes } else if (this.lastKey==37) { // Left 552*7485b225SElliott Hughes const item = document.getElementById('Item'+itemIndex); 553*7485b225SElliott Hughes const elem = this.FindChildElement(item.parentNode.parentNode.id); 554*7485b225SElliott Hughes if (elem) elem.style.display = 'none'; 555*7485b225SElliott Hughes } else if (this.lastKey==27) { // Escape 556*7485b225SElliott Hughes e.stopPropagation(); 557*7485b225SElliott Hughes searchBox.CloseResultsWindow(); 558*7485b225SElliott Hughes document.getElementById("MSearchField").focus(); 559*7485b225SElliott Hughes } else if (this.lastKey==13) { // Enter 560*7485b225SElliott Hughes return true; 561*7485b225SElliott Hughes } 562*7485b225SElliott Hughes return false; 563*7485b225SElliott Hughes } 564*7485b225SElliott Hughes 565*7485b225SElliott Hughes this.NavChild = function(evt,itemIndex,childIndex) { 566*7485b225SElliott Hughes const e = (evt) ? evt : window.event; // for IE 567*7485b225SElliott Hughes if (e.keyCode==13) return true; 568*7485b225SElliott Hughes if (!this.ProcessKeys(e)) return false; 569*7485b225SElliott Hughes 570*7485b225SElliott Hughes if (this.lastKey==38) { // Up 571*7485b225SElliott Hughes if (childIndex>0) { 572*7485b225SElliott Hughes const newIndex = childIndex-1; 573*7485b225SElliott Hughes document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); 574*7485b225SElliott Hughes } else { // already at first child, jump to parent 575*7485b225SElliott Hughes document.getElementById('Item'+itemIndex).focus(); 576*7485b225SElliott Hughes } 577*7485b225SElliott Hughes } else if (this.lastKey==40) { // Down 578*7485b225SElliott Hughes const newIndex = childIndex+1; 579*7485b225SElliott Hughes let elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); 580*7485b225SElliott Hughes if (!elem) { // last child, jump to parent next parent 581*7485b225SElliott Hughes elem = this.NavNext(itemIndex+1); 582*7485b225SElliott Hughes } 583*7485b225SElliott Hughes if (elem) { 584*7485b225SElliott Hughes elem.focus(); 585*7485b225SElliott Hughes } 586*7485b225SElliott Hughes } else if (this.lastKey==27) { // Escape 587*7485b225SElliott Hughes e.stopPropagation(); 588*7485b225SElliott Hughes searchBox.CloseResultsWindow(); 589*7485b225SElliott Hughes document.getElementById("MSearchField").focus(); 590*7485b225SElliott Hughes } else if (this.lastKey==13) { // Enter 591*7485b225SElliott Hughes return true; 592*7485b225SElliott Hughes } 593*7485b225SElliott Hughes return false; 594*7485b225SElliott Hughes } 595*7485b225SElliott Hughes} 596*7485b225SElliott Hughes 597*7485b225SElliott Hughesfunction createResults(resultsPath) { 598*7485b225SElliott Hughes 599*7485b225SElliott Hughes function setKeyActions(elem,action) { 600*7485b225SElliott Hughes elem.setAttribute('onkeydown',action); 601*7485b225SElliott Hughes elem.setAttribute('onkeypress',action); 602*7485b225SElliott Hughes elem.setAttribute('onkeyup',action); 603*7485b225SElliott Hughes } 604*7485b225SElliott Hughes 605*7485b225SElliott Hughes function setClassAttr(elem,attr) { 606*7485b225SElliott Hughes elem.setAttribute('class',attr); 607*7485b225SElliott Hughes elem.setAttribute('className',attr); 608*7485b225SElliott Hughes } 609*7485b225SElliott Hughes 610*7485b225SElliott Hughes const results = document.getElementById("SRResults"); 611*7485b225SElliott Hughes results.innerHTML = ''; 612*7485b225SElliott Hughes searchData.forEach((elem,index) => { 613*7485b225SElliott Hughes const id = elem[0]; 614*7485b225SElliott Hughes const srResult = document.createElement('div'); 615*7485b225SElliott Hughes srResult.setAttribute('id','SR_'+id); 616*7485b225SElliott Hughes setClassAttr(srResult,'SRResult'); 617*7485b225SElliott Hughes const srEntry = document.createElement('div'); 618*7485b225SElliott Hughes setClassAttr(srEntry,'SREntry'); 619*7485b225SElliott Hughes const srLink = document.createElement('a'); 620*7485b225SElliott Hughes srLink.setAttribute('id','Item'+index); 621*7485b225SElliott Hughes setKeyActions(srLink,'return searchResults.Nav(event,'+index+')'); 622*7485b225SElliott Hughes setClassAttr(srLink,'SRSymbol'); 623*7485b225SElliott Hughes srLink.innerHTML = elem[1][0]; 624*7485b225SElliott Hughes srEntry.appendChild(srLink); 625*7485b225SElliott Hughes if (elem[1].length==2) { // single result 626*7485b225SElliott Hughes srLink.setAttribute('href',resultsPath+elem[1][1][0]); 627*7485b225SElliott Hughes srLink.setAttribute('onclick','searchBox.CloseResultsWindow()'); 628*7485b225SElliott Hughes if (elem[1][1][1]) { 629*7485b225SElliott Hughes srLink.setAttribute('target','_parent'); 630*7485b225SElliott Hughes } else { 631*7485b225SElliott Hughes srLink.setAttribute('target','_blank'); 632*7485b225SElliott Hughes } 633*7485b225SElliott Hughes const srScope = document.createElement('span'); 634*7485b225SElliott Hughes setClassAttr(srScope,'SRScope'); 635*7485b225SElliott Hughes srScope.innerHTML = elem[1][1][2]; 636*7485b225SElliott Hughes srEntry.appendChild(srScope); 637*7485b225SElliott Hughes } else { // multiple results 638*7485b225SElliott Hughes srLink.setAttribute('href','javascript:searchResults.Toggle("SR_'+id+'")'); 639*7485b225SElliott Hughes const srChildren = document.createElement('div'); 640*7485b225SElliott Hughes setClassAttr(srChildren,'SRChildren'); 641*7485b225SElliott Hughes for (let c=0; c<elem[1].length-1; c++) { 642*7485b225SElliott Hughes const srChild = document.createElement('a'); 643*7485b225SElliott Hughes srChild.setAttribute('id','Item'+index+'_c'+c); 644*7485b225SElliott Hughes setKeyActions(srChild,'return searchResults.NavChild(event,'+index+','+c+')'); 645*7485b225SElliott Hughes setClassAttr(srChild,'SRScope'); 646*7485b225SElliott Hughes srChild.setAttribute('href',resultsPath+elem[1][c+1][0]); 647*7485b225SElliott Hughes srChild.setAttribute('onclick','searchBox.CloseResultsWindow()'); 648*7485b225SElliott Hughes if (elem[1][c+1][1]) { 649*7485b225SElliott Hughes srChild.setAttribute('target','_parent'); 650*7485b225SElliott Hughes } else { 651*7485b225SElliott Hughes srChild.setAttribute('target','_blank'); 652*7485b225SElliott Hughes } 653*7485b225SElliott Hughes srChild.innerHTML = elem[1][c+1][2]; 654*7485b225SElliott Hughes srChildren.appendChild(srChild); 655*7485b225SElliott Hughes } 656*7485b225SElliott Hughes srEntry.appendChild(srChildren); 657*7485b225SElliott Hughes } 658*7485b225SElliott Hughes srResult.appendChild(srEntry); 659*7485b225SElliott Hughes results.appendChild(srResult); 660*7485b225SElliott Hughes }); 661*7485b225SElliott Hughes} 662*7485b225SElliott Hughes 663*7485b225SElliott Hughesfunction init_search() { 664*7485b225SElliott Hughes const results = document.getElementById("MSearchSelectWindow"); 665*7485b225SElliott Hughes 666*7485b225SElliott Hughes results.tabIndex=0; 667*7485b225SElliott Hughes for (let key in indexSectionLabels) { 668*7485b225SElliott Hughes const link = document.createElement('a'); 669*7485b225SElliott Hughes link.setAttribute('class','SelectItem'); 670*7485b225SElliott Hughes link.setAttribute('onclick','searchBox.OnSelectItem('+key+')'); 671*7485b225SElliott Hughes link.href='javascript:void(0)'; 672*7485b225SElliott Hughes link.innerHTML='<span class="SelectionMark"> </span>'+indexSectionLabels[key]; 673*7485b225SElliott Hughes results.appendChild(link); 674*7485b225SElliott Hughes } 675*7485b225SElliott Hughes 676*7485b225SElliott Hughes const input = document.getElementById("MSearchSelect"); 677*7485b225SElliott Hughes const searchSelectWindow = document.getElementById("MSearchSelectWindow"); 678*7485b225SElliott Hughes input.tabIndex=0; 679*7485b225SElliott Hughes input.addEventListener("keydown", function(event) { 680*7485b225SElliott Hughes if (event.keyCode==13 || event.keyCode==40) { 681*7485b225SElliott Hughes event.preventDefault(); 682*7485b225SElliott Hughes if (searchSelectWindow.style.display == 'block') { 683*7485b225SElliott Hughes searchBox.CloseSelectionWindow(); 684*7485b225SElliott Hughes } else { 685*7485b225SElliott Hughes searchBox.OnSearchSelectShow(); 686*7485b225SElliott Hughes searchBox.DOMSearchSelectWindow().focus(); 687*7485b225SElliott Hughes } 688*7485b225SElliott Hughes } 689*7485b225SElliott Hughes }); 690*7485b225SElliott Hughes const name = Cookie.readSetting(SEARCH_COOKIE_NAME,0); 691*7485b225SElliott Hughes const id = searchBox.GetSelectionIdByName(name); 692*7485b225SElliott Hughes searchBox.OnSelectItem(id); 693*7485b225SElliott Hughes} 694*7485b225SElliott Hughes/* @license-end */ 695