comparison doc/html/search/search.js @ 23:92ee4ace9d46 develop

Did more commenting. Added documentation.
author Adam <adamstark.uk@gmail.com>
date Sat, 25 Jan 2014 18:17:51 +0000
parents
children deb49a2590f3
comparison
equal deleted inserted replaced
22:a8e3e95d14e4 23:92ee4ace9d46
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: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011101101000001100100010000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
11 1: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
12 2: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
13 3: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011101101000001100100000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
14 4: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
15 };
16
17 var indexSectionNames =
18 {
19 0: "all",
20 1: "classes",
21 2: "files",
22 3: "functions",
23 4: "enums"
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='&#8226;';
269 }
270 else
271 {
272 node.innerHTML='&#160;';
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 = 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) + 150; // domSearchBox.offsetWidth;
385 var top = getYPos(domSearchBox) + 20; // 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 }
735
736 function setKeyActions(elem,action)
737 {
738 elem.setAttribute('onkeydown',action);
739 elem.setAttribute('onkeypress',action);
740 elem.setAttribute('onkeyup',action);
741 }
742
743 function setClassAttr(elem,attr)
744 {
745 elem.setAttribute('class',attr);
746 elem.setAttribute('className',attr);
747 }
748
749 function createResults()
750 {
751 var results = document.getElementById("SRResults");
752 for (var e=0; e<searchData.length; e++)
753 {
754 var id = searchData[e][0];
755 var srResult = document.createElement('div');
756 srResult.setAttribute('id','SR_'+id);
757 setClassAttr(srResult,'SRResult');
758 var srEntry = document.createElement('div');
759 setClassAttr(srEntry,'SREntry');
760 var srLink = document.createElement('a');
761 srLink.setAttribute('id','Item'+e);
762 setKeyActions(srLink,'return searchResults.Nav(event,'+e+')');
763 setClassAttr(srLink,'SRSymbol');
764 srLink.innerHTML = searchData[e][1][0];
765 srEntry.appendChild(srLink);
766 if (searchData[e][1].length==2) // single result
767 {
768 srLink.setAttribute('href',searchData[e][1][1][0]);
769 if (searchData[e][1][1][1])
770 {
771 srLink.setAttribute('target','_parent');
772 }
773 var srScope = document.createElement('span');
774 setClassAttr(srScope,'SRScope');
775 srScope.innerHTML = searchData[e][1][1][2];
776 srEntry.appendChild(srScope);
777 }
778 else // multiple results
779 {
780 srLink.setAttribute('href','javascript:searchResults.Toggle("SR_'+id+'")');
781 var srChildren = document.createElement('div');
782 setClassAttr(srChildren,'SRChildren');
783 for (var c=0; c<searchData[e][1].length-1; c++)
784 {
785 var srChild = document.createElement('a');
786 srChild.setAttribute('id','Item'+e+'_c'+c);
787 setKeyActions(srChild,'return searchResults.NavChild(event,'+e+','+c+')');
788 setClassAttr(srChild,'SRScope');
789 srChild.setAttribute('href',searchData[e][1][c+1][0]);
790 if (searchData[e][1][c+1][1])
791 {
792 srChild.setAttribute('target','_parent');
793 }
794 srChild.innerHTML = searchData[e][1][c+1][2];
795 srChildren.appendChild(srChild);
796 }
797 srEntry.appendChild(srChildren);
798 }
799 srResult.appendChild(srEntry);
800 results.appendChild(srResult);
801 }
802 }
803