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