Chameleon

Chameleon Svn Source Tree

Root/branches/xZenu/src/util/doxygen/src/search.js

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

Archive Download this file

Revision: 1322