adamstark@114: /* adamstark@114: @licstart The following is the entire license notice for the JavaScript code in this file. adamstark@60: adamstark@114: The MIT License (MIT) adamstark@60: adamstark@114: Copyright (C) 1997-2020 by Dimitri van Heesch adamstark@60: adamstark@114: Permission is hereby granted, free of charge, to any person obtaining a copy of this software adamstark@114: and associated documentation files (the "Software"), to deal in the Software without restriction, adamstark@114: including without limitation the rights to use, copy, modify, merge, publish, distribute, adamstark@114: sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is adamstark@114: furnished to do so, subject to the following conditions: adamstark@60: adamstark@114: The above copyright notice and this permission notice shall be included in all copies or adamstark@114: substantial portions of the Software. adamstark@114: adamstark@114: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING adamstark@114: BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND adamstark@114: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, adamstark@114: DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, adamstark@114: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. adamstark@114: adamstark@114: @licend The above is the entire license notice for the JavaScript code in this file adamstark@114: */ adamstark@60: function convertToId(search) adamstark@60: { adamstark@60: var result = ''; adamstark@60: for (i=0;i do a search adamstark@60: { adamstark@60: this.Search(); adamstark@60: } adamstark@60: } adamstark@60: adamstark@60: this.OnSearchSelectKey = function(evt) adamstark@60: { adamstark@60: var e = (evt) ? evt : window.event; // for IE adamstark@60: if (e.keyCode==40 && this.searchIndex0) // Up adamstark@60: { adamstark@60: this.searchIndex--; adamstark@60: this.OnSelectItem(this.searchIndex); adamstark@60: } adamstark@60: else if (e.keyCode==13 || e.keyCode==27) adamstark@60: { adamstark@60: this.OnSelectItem(this.searchIndex); adamstark@60: this.CloseSelectionWindow(); adamstark@60: this.DOMSearchField().focus(); adamstark@60: } adamstark@60: return false; adamstark@60: } adamstark@60: adamstark@60: // --------- Actions adamstark@60: adamstark@60: // Closes the results window. adamstark@60: this.CloseResultsWindow = function() adamstark@60: { adamstark@60: this.DOMPopupSearchResultsWindow().style.display = 'none'; adamstark@60: this.DOMSearchClose().style.display = 'none'; adamstark@60: this.Activate(false); adamstark@60: } adamstark@60: adamstark@60: this.CloseSelectionWindow = function() adamstark@60: { adamstark@60: this.DOMSearchSelectWindow().style.display = 'none'; adamstark@60: } adamstark@60: adamstark@60: // Performs a search. adamstark@60: this.Search = function() adamstark@60: { adamstark@60: this.keyTimeout = 0; adamstark@60: adamstark@60: // strip leading whitespace adamstark@60: var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); adamstark@60: adamstark@60: var code = searchValue.toLowerCase().charCodeAt(0); adamstark@114: var idxChar = searchValue.substr(0, 1).toLowerCase(); adamstark@114: if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair adamstark@60: { adamstark@114: idxChar = searchValue.substr(0, 2); adamstark@60: } adamstark@60: adamstark@114: var jsFile; adamstark@60: adamstark@114: var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); adamstark@114: if (idx!=-1) adamstark@60: { adamstark@114: var hexCode=idx.toString(16); adamstark@114: jsFile = this.resultsPath + indexSectionNames[this.searchIndex] + '_' + hexCode + '.js'; adamstark@60: } adamstark@60: adamstark@114: var loadJS = function(url, impl, loc){ adamstark@114: var scriptTag = document.createElement('script'); adamstark@114: scriptTag.src = url; adamstark@114: scriptTag.onload = impl; adamstark@114: scriptTag.onreadystatechange = impl; adamstark@114: loc.appendChild(scriptTag); adamstark@114: } adamstark@114: adamstark@60: var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); adamstark@114: var domSearchBox = this.DOMSearchBox(); adamstark@114: var domPopupSearchResults = this.DOMPopupSearchResults(); adamstark@114: var domSearchClose = this.DOMSearchClose(); adamstark@114: var resultsPath = this.resultsPath; adamstark@60: adamstark@114: var handleResults = function() { adamstark@114: document.getElementById("Loading").style.display="none"; adamstark@114: if (typeof searchData !== 'undefined') { adamstark@114: createResults(resultsPath); adamstark@114: document.getElementById("NoMatches").style.display="none"; adamstark@114: } adamstark@114: adamstark@114: if (idx!=-1) { adamstark@114: searchResults.Search(searchValue); adamstark@114: } else { // no file with search results => force empty search results adamstark@114: searchResults.Search('===='); adamstark@114: } adamstark@114: adamstark@114: if (domPopupSearchResultsWindow.style.display!='block') adamstark@114: { adamstark@114: domSearchClose.style.display = 'inline-block'; adamstark@114: var left = getXPos(domSearchBox) + 150; adamstark@114: var top = getYPos(domSearchBox) + 20; adamstark@114: domPopupSearchResultsWindow.style.display = 'block'; adamstark@114: left -= domPopupSearchResults.offsetWidth; adamstark@114: var maxWidth = document.body.clientWidth; adamstark@114: var maxHeight = document.body.clientHeight; adamstark@114: var width = 300; adamstark@114: if (left<10) left=10; adamstark@114: if (width+left+8>maxWidth) width=maxWidth-left-8; adamstark@114: var height = 400; adamstark@114: if (height+top+8>maxHeight) height=maxHeight-top-8; adamstark@114: domPopupSearchResultsWindow.style.top = top + 'px'; adamstark@114: domPopupSearchResultsWindow.style.left = left + 'px'; adamstark@114: domPopupSearchResultsWindow.style.width = width + 'px'; adamstark@114: domPopupSearchResultsWindow.style.height = height + 'px'; adamstark@114: } adamstark@114: } adamstark@114: adamstark@114: if (jsFile) { adamstark@114: loadJS(jsFile, handleResults, this.DOMPopupSearchResultsWindow()); adamstark@114: } else { adamstark@114: handleResults(); adamstark@60: } adamstark@60: adamstark@60: this.lastSearchValue = searchValue; adamstark@60: } adamstark@60: adamstark@60: // -------- Activation Functions adamstark@60: adamstark@114: // Activates or deactivates the search panel, resetting things to adamstark@114: // their default values if necessary. adamstark@60: this.Activate = function(isActive) adamstark@60: { adamstark@60: if (isActive || // open it adamstark@114: this.DOMPopupSearchResultsWindow().style.display == 'block' adamstark@60: ) adamstark@60: { adamstark@60: this.DOMSearchBox().className = 'MSearchBoxActive'; adamstark@114: this.searchActive = true; adamstark@60: } adamstark@60: else if (!isActive) // directly remove the panel adamstark@60: { adamstark@60: this.DOMSearchBox().className = 'MSearchBoxInactive'; adamstark@60: this.searchActive = false; adamstark@60: this.lastSearchValue = '' adamstark@60: this.lastResultsPage = ''; adamstark@114: this.DOMSearchField().value = ''; adamstark@60: } adamstark@60: } adamstark@60: } adamstark@60: adamstark@60: // ----------------------------------------------------------------------- adamstark@60: adamstark@60: // The class that handles everything on the search results page. adamstark@60: function SearchResults(name) adamstark@60: { adamstark@60: // The number of matches from the last run of . adamstark@60: this.lastMatchCount = 0; adamstark@60: this.lastKey = 0; adamstark@60: this.repeatOn = false; adamstark@60: adamstark@60: // Toggles the visibility of the passed element ID. adamstark@60: this.FindChildElement = function(id) adamstark@60: { adamstark@60: var parentElement = document.getElementById(id); adamstark@60: var element = parentElement.firstChild; adamstark@60: adamstark@60: while (element && element!=parentElement) adamstark@60: { adamstark@114: if (element.nodeName.toLowerCase() == 'div' && element.className == 'SRChildren') adamstark@60: { adamstark@60: return element; adamstark@60: } adamstark@60: adamstark@114: if (element.nodeName.toLowerCase() == 'div' && element.hasChildNodes()) adamstark@114: { adamstark@114: element = element.firstChild; adamstark@60: } adamstark@60: else if (element.nextSibling) adamstark@114: { adamstark@114: element = element.nextSibling; adamstark@60: } adamstark@60: else adamstark@60: { adamstark@60: do adamstark@60: { adamstark@60: element = element.parentNode; adamstark@60: } adamstark@60: while (element && element!=parentElement && !element.nextSibling); adamstark@60: adamstark@60: if (element && element!=parentElement) adamstark@114: { adamstark@114: element = element.nextSibling; adamstark@60: } adamstark@60: } adamstark@60: } adamstark@60: } adamstark@60: adamstark@60: this.Toggle = function(id) adamstark@60: { adamstark@60: var element = this.FindChildElement(id); adamstark@60: if (element) adamstark@60: { adamstark@60: if (element.style.display == 'block') adamstark@60: { adamstark@60: element.style.display = 'none'; adamstark@60: } adamstark@60: else adamstark@60: { adamstark@60: element.style.display = 'block'; adamstark@60: } adamstark@60: } adamstark@60: } adamstark@60: adamstark@60: // Searches for the passed string. If there is no parameter, adamstark@60: // it takes it from the URL query. adamstark@60: // adamstark@60: // Always returns true, since other documents may try to call it adamstark@60: // and that may or may not be possible. adamstark@60: this.Search = function(search) adamstark@60: { adamstark@60: if (!search) // get search word from URL adamstark@60: { adamstark@60: search = window.location.search; adamstark@60: search = search.substring(1); // Remove the leading '?' adamstark@60: search = unescape(search); adamstark@60: } adamstark@60: adamstark@60: search = search.replace(/^ +/, ""); // strip leading spaces adamstark@60: search = search.replace(/ +$/, ""); // strip trailing spaces adamstark@60: search = search.toLowerCase(); adamstark@60: search = convertToId(search); adamstark@60: adamstark@60: var resultRows = document.getElementsByTagName("div"); adamstark@60: var matches = 0; adamstark@60: adamstark@60: var i = 0; adamstark@60: while (i < resultRows.length) adamstark@60: { adamstark@60: var row = resultRows.item(i); adamstark@60: if (row.className == "SRResult") adamstark@60: { adamstark@60: var rowMatchName = row.id.toLowerCase(); adamstark@60: rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' adamstark@60: adamstark@114: if (search.length<=rowMatchName.length && adamstark@60: rowMatchName.substr(0, search.length)==search) adamstark@60: { adamstark@60: row.style.display = 'block'; adamstark@60: matches++; adamstark@60: } adamstark@60: else adamstark@60: { adamstark@60: row.style.display = 'none'; adamstark@60: } adamstark@60: } adamstark@60: i++; adamstark@60: } adamstark@60: document.getElementById("Searching").style.display='none'; adamstark@60: if (matches == 0) // no results adamstark@60: { adamstark@60: document.getElementById("NoMatches").style.display='block'; adamstark@60: } adamstark@60: else // at least one result adamstark@60: { adamstark@60: document.getElementById("NoMatches").style.display='none'; adamstark@60: } adamstark@60: this.lastMatchCount = matches; adamstark@60: return true; adamstark@60: } adamstark@60: adamstark@60: // return the first item with index index or higher that is visible adamstark@60: this.NavNext = function(index) adamstark@60: { adamstark@60: var focusItem; adamstark@60: while (1) adamstark@60: { adamstark@60: var focusName = 'Item'+index; adamstark@60: focusItem = document.getElementById(focusName); adamstark@60: if (focusItem && focusItem.parentNode.parentNode.style.display=='block') adamstark@60: { adamstark@60: break; adamstark@60: } adamstark@60: else if (!focusItem) // last element adamstark@60: { adamstark@60: break; adamstark@60: } adamstark@60: focusItem=null; adamstark@60: index++; adamstark@60: } adamstark@60: return focusItem; adamstark@60: } adamstark@60: adamstark@60: this.NavPrev = function(index) adamstark@60: { adamstark@60: var focusItem; adamstark@60: while (1) adamstark@60: { adamstark@60: var focusName = 'Item'+index; adamstark@60: focusItem = document.getElementById(focusName); adamstark@60: if (focusItem && focusItem.parentNode.parentNode.style.display=='block') adamstark@60: { adamstark@60: break; adamstark@60: } adamstark@60: else if (!focusItem) // last element adamstark@60: { adamstark@60: break; adamstark@60: } adamstark@60: focusItem=null; adamstark@60: index--; adamstark@60: } adamstark@60: return focusItem; adamstark@60: } adamstark@60: adamstark@60: this.ProcessKeys = function(e) adamstark@60: { adamstark@114: if (e.type == "keydown") adamstark@60: { adamstark@60: this.repeatOn = false; adamstark@60: this.lastKey = e.keyCode; adamstark@60: } adamstark@60: else if (e.type == "keypress") adamstark@60: { adamstark@60: if (!this.repeatOn) adamstark@60: { adamstark@60: if (this.lastKey) this.repeatOn = true; adamstark@60: return false; // ignore first keypress after keydown adamstark@60: } adamstark@60: } adamstark@60: else if (e.type == "keyup") adamstark@60: { adamstark@60: this.lastKey = 0; adamstark@60: this.repeatOn = false; adamstark@60: } adamstark@60: return this.lastKey!=0; adamstark@60: } adamstark@60: adamstark@114: this.Nav = function(evt,itemIndex) adamstark@60: { adamstark@60: var e = (evt) ? evt : window.event; // for IE adamstark@60: if (e.keyCode==13) return true; adamstark@60: if (!this.ProcessKeys(e)) return false; adamstark@60: adamstark@60: if (this.lastKey==38) // Up adamstark@60: { adamstark@60: var newIndex = itemIndex-1; adamstark@60: var focusItem = this.NavPrev(newIndex); adamstark@60: if (focusItem) adamstark@60: { adamstark@60: var child = this.FindChildElement(focusItem.parentNode.parentNode.id); adamstark@60: if (child && child.style.display == 'block') // children visible adamstark@114: { adamstark@60: var n=0; adamstark@60: var tmpElem; adamstark@60: while (1) // search for last child adamstark@60: { adamstark@60: tmpElem = document.getElementById('Item'+newIndex+'_c'+n); adamstark@60: if (tmpElem) adamstark@60: { adamstark@60: focusItem = tmpElem; adamstark@60: } adamstark@60: else // found it! adamstark@60: { adamstark@60: break; adamstark@60: } adamstark@60: n++; adamstark@60: } adamstark@60: } adamstark@60: } adamstark@60: if (focusItem) adamstark@60: { adamstark@60: focusItem.focus(); adamstark@60: } adamstark@60: else // return focus to search field adamstark@60: { adamstark@114: document.getElementById("MSearchField").focus(); adamstark@60: } adamstark@60: } adamstark@60: else if (this.lastKey==40) // Down adamstark@60: { adamstark@60: var newIndex = itemIndex+1; adamstark@60: var focusItem; adamstark@60: var item = document.getElementById('Item'+itemIndex); adamstark@60: var elem = this.FindChildElement(item.parentNode.parentNode.id); adamstark@60: if (elem && elem.style.display == 'block') // children visible adamstark@60: { adamstark@60: focusItem = document.getElementById('Item'+itemIndex+'_c0'); adamstark@60: } adamstark@60: if (!focusItem) focusItem = this.NavNext(newIndex); adamstark@60: if (focusItem) focusItem.focus(); adamstark@60: } adamstark@60: else if (this.lastKey==39) // Right adamstark@60: { adamstark@60: var item = document.getElementById('Item'+itemIndex); adamstark@60: var elem = this.FindChildElement(item.parentNode.parentNode.id); adamstark@60: if (elem) elem.style.display = 'block'; adamstark@60: } adamstark@60: else if (this.lastKey==37) // Left adamstark@60: { adamstark@60: var item = document.getElementById('Item'+itemIndex); adamstark@60: var elem = this.FindChildElement(item.parentNode.parentNode.id); adamstark@60: if (elem) elem.style.display = 'none'; adamstark@60: } adamstark@60: else if (this.lastKey==27) // Escape adamstark@60: { adamstark@114: searchBox.CloseResultsWindow(); adamstark@114: document.getElementById("MSearchField").focus(); adamstark@60: } adamstark@60: else if (this.lastKey==13) // Enter adamstark@60: { adamstark@60: return true; adamstark@60: } adamstark@60: return false; adamstark@60: } adamstark@60: adamstark@60: this.NavChild = function(evt,itemIndex,childIndex) adamstark@60: { adamstark@60: var e = (evt) ? evt : window.event; // for IE adamstark@60: if (e.keyCode==13) return true; adamstark@60: if (!this.ProcessKeys(e)) return false; adamstark@60: adamstark@60: if (this.lastKey==38) // Up adamstark@60: { adamstark@60: if (childIndex>0) adamstark@60: { adamstark@60: var newIndex = childIndex-1; adamstark@60: document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); adamstark@60: } adamstark@60: else // already at first child, jump to parent adamstark@60: { adamstark@60: document.getElementById('Item'+itemIndex).focus(); adamstark@60: } adamstark@60: } adamstark@60: else if (this.lastKey==40) // Down adamstark@60: { adamstark@60: var newIndex = childIndex+1; adamstark@60: var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); adamstark@60: if (!elem) // last child, jump to parent next parent adamstark@60: { adamstark@60: elem = this.NavNext(itemIndex+1); adamstark@60: } adamstark@60: if (elem) adamstark@60: { adamstark@60: elem.focus(); adamstark@114: } adamstark@60: } adamstark@60: else if (this.lastKey==27) // Escape adamstark@60: { adamstark@114: searchBox.CloseResultsWindow(); adamstark@114: document.getElementById("MSearchField").focus(); adamstark@60: } adamstark@60: else if (this.lastKey==13) // Enter adamstark@60: { adamstark@60: return true; adamstark@60: } adamstark@60: return false; adamstark@60: } adamstark@60: } adamstark@60: adamstark@60: function setKeyActions(elem,action) adamstark@60: { adamstark@60: elem.setAttribute('onkeydown',action); adamstark@60: elem.setAttribute('onkeypress',action); adamstark@60: elem.setAttribute('onkeyup',action); adamstark@60: } adamstark@60: adamstark@60: function setClassAttr(elem,attr) adamstark@60: { adamstark@60: elem.setAttribute('class',attr); adamstark@60: elem.setAttribute('className',attr); adamstark@60: } adamstark@60: adamstark@114: function createResults(resultsPath) adamstark@60: { adamstark@60: var results = document.getElementById("SRResults"); adamstark@114: results.innerHTML = ''; adamstark@60: for (var e=0; e