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