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