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