search.js 23 KB

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