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