source: flair-dev/trunk/doc/Flair/search/search.js@ 15

Last change on this file since 15 was 14, checked in by Sanahuja Guillaume, 9 years ago

doc

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