• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 @licstart  The following is the entire license notice for the
3 JavaScript code in this file.
4
5 Copyright (C) 1997-2017 by Dimitri van Heesch
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 @licend  The above is the entire license notice
22 for the JavaScript code in this file
23 */
24function convertToId(search)
25{
26  var result = '';
27  for (i=0;i<search.length;i++)
28  {
29    var c = search.charAt(i);
30    var cn = c.charCodeAt(0);
31    if (c.match(/[a-z0-9\u0080-\uFFFF]/))
32    {
33      result+=c;
34    }
35    else if (cn<16)
36    {
37      result+="_0"+cn.toString(16);
38    }
39    else
40    {
41      result+="_"+cn.toString(16);
42    }
43  }
44  return result;
45}
46
47function getXPos(item)
48{
49  var x = 0;
50  if (item.offsetWidth)
51  {
52    while (item && item!=document.body)
53    {
54      x   += item.offsetLeft;
55      item = item.offsetParent;
56    }
57  }
58  return x;
59}
60
61function getYPos(item)
62{
63  var y = 0;
64  if (item.offsetWidth)
65  {
66     while (item && item!=document.body)
67     {
68       y   += item.offsetTop;
69       item = item.offsetParent;
70     }
71  }
72  return y;
73}
74
75/* A class handling everything associated with the search panel.
76
77   Parameters:
78   name - The name of the global variable that will be
79          storing this instance.  Is needed to be able to set timeouts.
80   resultPath - path to use for external files
81*/
82function SearchBox(name, resultsPath, inFrame, label)
83{
84  if (!name || !resultsPath) {  alert("Missing parameters to SearchBox."); }
85
86  // ---------- Instance variables
87  this.name                  = name;
88  this.resultsPath           = resultsPath;
89  this.keyTimeout            = 0;
90  this.keyTimeoutLength      = 500;
91  this.closeSelectionTimeout = 300;
92  this.lastSearchValue       = "";
93  this.lastResultsPage       = "";
94  this.hideTimeout           = 0;
95  this.searchIndex           = 0;
96  this.searchActive          = false;
97  this.insideFrame           = inFrame;
98  this.searchLabel           = label;
99
100  // ----------- DOM Elements
101
102  this.DOMSearchField = function()
103  {  return document.getElementById("MSearchField");  }
104
105  this.DOMSearchSelect = function()
106  {  return document.getElementById("MSearchSelect");  }
107
108  this.DOMSearchSelectWindow = function()
109  {  return document.getElementById("MSearchSelectWindow");  }
110
111  this.DOMPopupSearchResults = function()
112  {  return document.getElementById("MSearchResults");  }
113
114  this.DOMPopupSearchResultsWindow = function()
115  {  return document.getElementById("MSearchResultsWindow");  }
116
117  this.DOMSearchClose = function()
118  {  return document.getElementById("MSearchClose"); }
119
120  this.DOMSearchBox = function()
121  {  return document.getElementById("MSearchBox");  }
122
123  // ------------ Event Handlers
124
125  // Called when focus is added or removed from the search field.
126  this.OnSearchFieldFocus = function(isActive)
127  {
128    this.Activate(isActive);
129  }
130
131  this.OnSearchSelectShow = function()
132  {
133    var searchSelectWindow = this.DOMSearchSelectWindow();
134    var searchField        = this.DOMSearchSelect();
135
136    if (this.insideFrame)
137    {
138      var left = getXPos(searchField);
139      var top  = getYPos(searchField);
140      left += searchField.offsetWidth + 6;
141      top += searchField.offsetHeight;
142
143      // show search selection popup
144      searchSelectWindow.style.display='block';
145      left -= searchSelectWindow.offsetWidth;
146      searchSelectWindow.style.left =  left + 'px';
147      searchSelectWindow.style.top  =  top  + 'px';
148    }
149    else
150    {
151      var left = getXPos(searchField);
152      var top  = getYPos(searchField);
153      top += searchField.offsetHeight;
154
155      // show search selection popup
156      searchSelectWindow.style.display='block';
157      searchSelectWindow.style.left =  left + 'px';
158      searchSelectWindow.style.top  =  top  + 'px';
159    }
160
161    // stop selection hide timer
162    if (this.hideTimeout)
163    {
164      clearTimeout(this.hideTimeout);
165      this.hideTimeout=0;
166    }
167    return false; // to avoid "image drag" default event
168  }
169
170  this.OnSearchSelectHide = function()
171  {
172    this.hideTimeout = setTimeout(this.name +".CloseSelectionWindow()",
173                                  this.closeSelectionTimeout);
174  }
175
176  // Called when the content of the search field is changed.
177  this.OnSearchFieldChange = function(evt)
178  {
179    if (this.keyTimeout) // kill running timer
180    {
181      clearTimeout(this.keyTimeout);
182      this.keyTimeout = 0;
183    }
184
185    var e  = (evt) ? evt : window.event; // for IE
186    if (e.keyCode==40 || e.keyCode==13)
187    {
188      if (e.shiftKey==1)
189      {
190        this.OnSearchSelectShow();
191        var win=this.DOMSearchSelectWindow();
192        for (i=0;i<win.childNodes.length;i++)
193        {
194          var child = win.childNodes[i]; // get span within a
195          if (child.className=='SelectItem')
196          {
197            child.focus();
198            return;
199          }
200        }
201        return;
202      }
203      else if (window.frames.MSearchResults.searchResults)
204      {
205        var elem = window.frames.MSearchResults.searchResults.NavNext(0);
206        if (elem) elem.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';
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