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