Fix for UBSan build
[platform/upstream/doxygen.git] / src / navtree.js
1 var navTreeSubIndices = new Array();
2
3 function getData(varName)
4 {
5   var i = varName.lastIndexOf('/');
6   var n = i>=0 ? varName.substring(i+1) : varName;
7   return eval(n.replace(/\-/g,'_'));
8 }
9
10 function stripPath(uri)
11 {
12   return uri.substring(uri.lastIndexOf('/')+1);
13 }
14
15 function stripPath2(uri)
16 {
17   var i = uri.lastIndexOf('/');
18   var s = uri.substring(i+1);
19   var m = uri.substring(0,i+1).match(/\/d\w\/d\w\w\/$/);
20   return m ? uri.substring(i-6) : s;
21 }
22
23 function localStorageSupported()
24 {
25   try {
26     return 'localStorage' in window && window['localStorage'] !== null && window.localStorage.getItem;
27   }
28   catch(e) {
29     return false;
30   }
31 }
32
33
34 function storeLink(link)
35 {
36   if (!$("#nav-sync").hasClass('sync') && localStorageSupported()) {
37       window.localStorage.setItem('navpath',link);
38   }
39 }
40
41 function deleteLink()
42 {
43   if (localStorageSupported()) {
44     window.localStorage.setItem('navpath','');
45   } 
46 }
47
48 function cachedLink()
49 {
50   if (localStorageSupported()) {
51     return window.localStorage.getItem('navpath');
52   } else {
53     return '';
54   }
55 }
56
57 function getScript(scriptName,func,show)
58 {
59   var head = document.getElementsByTagName("head")[0]; 
60   var script = document.createElement('script');
61   script.id = scriptName;
62   script.type = 'text/javascript';
63   script.onload = func; 
64   script.src = scriptName+'.js'; 
65   if ($.browser.msie && $.browser.version<=8) { 
66     // script.onload does work with older versions of IE
67     script.onreadystatechange = function() {
68       if (script.readyState=='complete' || script.readyState=='loaded') { 
69         func(); if (show) showRoot(); 
70       }
71     }
72   }
73   head.appendChild(script); 
74 }
75
76 function createIndent(o,domNode,node,level)
77 {
78   if (node.parentNode && node.parentNode.parentNode) {
79     createIndent(o,domNode,node.parentNode,level+1);
80   }
81   var imgNode = document.createElement("img");
82   imgNode.width = 16;
83   imgNode.height = 22;
84   if (level==0 && node.childrenData) {
85     node.plus_img = imgNode;
86     node.expandToggle = document.createElement("a");
87     node.expandToggle.href = "javascript:void(0)";
88     node.expandToggle.onclick = function() {
89       if (node.expanded) {
90         $(node.getChildrenUL()).slideUp("fast");
91         if (node.isLast) {
92           node.plus_img.src = node.relpath+"ftv2plastnode.png";
93         } else {
94           node.plus_img.src = node.relpath+"ftv2pnode.png";
95         }
96         node.expanded = false;
97       } else {
98         expandNode(o, node, false, false);
99       }
100     }
101     node.expandToggle.appendChild(imgNode);
102     domNode.appendChild(node.expandToggle);
103   } else {
104     domNode.appendChild(imgNode);
105   }
106   if (level==0) {
107     if (node.isLast) {
108       if (node.childrenData) {
109         imgNode.src = node.relpath+"ftv2plastnode.png";
110       } else {
111         imgNode.src = node.relpath+"ftv2lastnode.png";
112         domNode.appendChild(imgNode);
113       }
114     } else {
115       if (node.childrenData) {
116         imgNode.src = node.relpath+"ftv2pnode.png";
117       } else {
118         imgNode.src = node.relpath+"ftv2node.png";
119         domNode.appendChild(imgNode);
120       }
121     }
122   } else {
123     if (node.isLast) {
124       imgNode.src = node.relpath+"ftv2blank.png";
125     } else {
126       imgNode.src = node.relpath+"ftv2vertline.png";
127     }
128   }
129   imgNode.border = "0";
130 }
131
132 function newNode(o, po, text, link, childrenData, lastNode)
133 {
134   var node = new Object();
135   node.children = Array();
136   node.childrenData = childrenData;
137   node.depth = po.depth + 1;
138   node.relpath = po.relpath;
139   node.isLast = lastNode;
140
141   node.li = document.createElement("li");
142   po.getChildrenUL().appendChild(node.li);
143   node.parentNode = po;
144
145   node.itemDiv = document.createElement("div");
146   node.itemDiv.className = "item";
147
148   node.labelSpan = document.createElement("span");
149   node.labelSpan.className = "label";
150
151   createIndent(o,node.itemDiv,node,0);
152   node.itemDiv.appendChild(node.labelSpan);
153   node.li.appendChild(node.itemDiv);
154
155   var a = document.createElement("a");
156   node.labelSpan.appendChild(a);
157   node.label = document.createTextNode(text);
158   node.expanded = false;
159   a.appendChild(node.label);
160   if (link) {
161     var url;
162     if (link.substring(0,1)=='^') {
163       url = link.substring(1);
164       link = url;
165     } else {
166       url = node.relpath+link;
167     }
168     a.className = stripPath(link.replace('#',':'));
169     if (link.indexOf('#')!=-1) {
170       var aname = '#'+link.split('#')[1];
171       var srcPage = stripPath($(location).attr('pathname'));
172       var targetPage = stripPath(link.split('#')[0]);
173       a.href = srcPage!=targetPage ? url : '#';
174       a.onclick = function(){
175         storeLink(link);
176         if (!$(a).parent().parent().hasClass('selected'))
177         {
178           $('.item').removeClass('selected');
179           $('.item').removeAttr('id');
180           $(a).parent().parent().addClass('selected');
181           $(a).parent().parent().attr('id','selected');
182         }
183         var pos, anchor = $(aname), docContent = $('#doc-content');
184         if (anchor.parent().attr('class')=='memItemLeft') {
185           pos = anchor.parent().position().top;
186         } else if (anchor.position()) {
187           pos = anchor.position().top;
188         }
189         if (pos) {
190           var dist = Math.abs(Math.min(
191                      pos-docContent.offset().top,
192                      docContent[0].scrollHeight-
193                      docContent.height()-docContent.scrollTop()));
194           docContent.animate({
195             scrollTop: pos + docContent.scrollTop() - docContent.offset().top
196           },Math.max(50,Math.min(500,dist)),function(){
197             window.location.replace(aname);
198           });
199         }
200       };
201     } else {
202       a.href = url;
203       a.onclick = function() { storeLink(link); }
204     }
205   } else {
206     if (childrenData != null) 
207     {
208       a.className = "nolink";
209       a.href = "javascript:void(0)";
210       a.onclick = node.expandToggle.onclick;
211     }
212   }
213
214   node.childrenUL = null;
215   node.getChildrenUL = function() {
216     if (!node.childrenUL) {
217       node.childrenUL = document.createElement("ul");
218       node.childrenUL.className = "children_ul";
219       node.childrenUL.style.display = "none";
220       node.li.appendChild(node.childrenUL);
221     }
222     return node.childrenUL;
223   };
224
225   return node;
226 }
227
228 function showRoot()
229 {
230   var headerHeight = $("#top").height();
231   var footerHeight = $("#nav-path").height();
232   var windowHeight = $(window).height() - headerHeight - footerHeight;
233   (function (){ // retry until we can scroll to the selected item
234     try {
235       var navtree=$('#nav-tree');
236       navtree.scrollTo('#selected',0,{offset:-windowHeight/2});
237     } catch (err) {
238       setTimeout(arguments.callee, 0);
239     }
240   })();
241 }
242
243 function expandNode(o, node, imm, showRoot)
244 {
245   if (node.childrenData && !node.expanded) {
246     if (typeof(node.childrenData)==='string') {
247       var varName    = node.childrenData;
248       getScript(node.relpath+varName,function(){
249         node.childrenData = getData(varName);
250         expandNode(o, node, imm, showRoot);
251       }, showRoot);
252     } else {
253       if (!node.childrenVisited) {
254         getNode(o, node);
255       } if (imm || ($.browser.msie && $.browser.version>8)) { 
256         // somehow slideDown jumps to the start of tree for IE9 :-(
257         $(node.getChildrenUL()).show();
258       } else {
259         $(node.getChildrenUL()).slideDown("fast");
260       }
261       if (node.isLast) {
262         node.plus_img.src = node.relpath+"ftv2mlastnode.png";
263       } else {
264         node.plus_img.src = node.relpath+"ftv2mnode.png";
265       }
266       node.expanded = true;
267     }
268   }
269 }
270
271 function glowEffect(n,duration)
272 {
273   n.addClass('glow').delay(duration).queue(function(next){
274     $(this).removeClass('glow');next();
275   });
276 }
277
278 function highlightAnchor()
279 {
280   var anchor = $($(location).attr('hash'));
281   if (anchor.parent().attr('class')=='memItemLeft'){
282     var rows = $('.memberdecls tr[class$="'+
283                window.location.hash.substring(1)+'"]');
284     glowEffect(rows.children(),300); // member without details
285   } else if (anchor.parents().slice(2).prop('tagName')=='TR') {
286     glowEffect(anchor.parents('div.memitem'),1000); // enum value
287   } else if (anchor.parent().attr('class')=='fieldtype'){
288     glowEffect(anchor.parent().parent(),1000); // struct field
289   } else if (anchor.parent().is(":header")) {
290     glowEffect(anchor.parent(),1000); // section header
291   } else {
292     glowEffect(anchor.next(),1000); // normal member
293   }
294 }
295
296 function selectAndHighlight(hash,n)
297 {
298   var a;
299   if (hash) {
300     var link=stripPath($(location).attr('pathname'))+':'+hash.substring(1);
301     a=$('.item a[class$="'+link+'"]');
302   }
303   if (a && a.length) {
304     a.parent().parent().addClass('selected');
305     a.parent().parent().attr('id','selected');
306     highlightAnchor();
307   } else if (n) {
308     $(n.itemDiv).addClass('selected');
309     $(n.itemDiv).attr('id','selected');
310   }
311   showRoot();
312 }
313
314 function showNode(o, node, index, hash)
315 {
316   if (node && node.childrenData) {
317     if (typeof(node.childrenData)==='string') {
318       var varName    = node.childrenData;
319       getScript(node.relpath+varName,function(){
320         node.childrenData = getData(varName);
321         showNode(o,node,index,hash);
322       },true);
323     } else {
324       if (!node.childrenVisited) {
325         getNode(o, node);
326       }
327       $(node.getChildrenUL()).show();
328       if (node.isLast) {
329         node.plus_img.src = node.relpath+"ftv2mlastnode.png";
330       } else {
331         node.plus_img.src = node.relpath+"ftv2mnode.png";
332       }
333       node.expanded = true;
334       var n = node.children[o.breadcrumbs[index]];
335       if (index+1<o.breadcrumbs.length) {
336         showNode(o,n,index+1,hash);
337       } else {
338         if (typeof(n.childrenData)==='string') {
339           var varName = n.childrenData;
340           getScript(n.relpath+varName,function(){
341             n.childrenData = getData(varName);
342             node.expanded=false;
343             showNode(o,node,index,hash); // retry with child node expanded
344           },true);
345         } else {
346           var rootBase = stripPath(o.toroot.replace(/\..+$/, ''));
347           if (rootBase=="index" || rootBase=="pages") {
348             expandNode(o, n, true, true);
349           }
350           selectAndHighlight(hash,n);
351         }
352       }
353     }
354   } else {
355     selectAndHighlight(hash);
356   }
357 }
358
359 function getNode(o, po)
360 {
361   po.childrenVisited = true;
362   var l = po.childrenData.length-1;
363   for (var i in po.childrenData) {
364     var nodeData = po.childrenData[i];
365     po.children[i] = newNode(o, po, nodeData[0], nodeData[1], nodeData[2],
366       i==l);
367   }
368 }
369
370 function gotoNode(o,subIndex,root,hash,relpath)
371 {
372   var nti = navTreeSubIndices[subIndex][root+hash];
373   o.breadcrumbs = $.extend(true, [], nti ? nti : navTreeSubIndices[subIndex][root]);
374   if (!o.breadcrumbs && root!=NAVTREE[0][1]) { // fallback: show index
375     navTo(o,NAVTREE[0][1],"",relpath);
376     $('.item').removeClass('selected');
377     $('.item').removeAttr('id');
378   }
379   if (o.breadcrumbs) {
380     o.breadcrumbs.unshift(0); // add 0 for root node
381     showNode(o, o.node, 0, hash);
382   }
383 }
384
385 function navTo(o,root,hash,relpath)
386 {
387   var link = cachedLink();
388   if (link) {
389     var parts = link.split('#');
390     root = parts[0];
391     if (parts.length>1) hash = '#'+parts[1];
392     else hash='';
393   }
394   if (root==NAVTREE[0][1]) {
395     $('#nav-sync').css('top','30px');
396   } else {
397     $('#nav-sync').css('top','5px');
398   }
399   if (hash.match(/^#l\d+$/)) {
400     var anchor=$('a[name='+hash.substring(1)+']');
401     glowEffect(anchor.parent(),1000); // line number
402     hash=''; // strip line number anchors
403     //root=root.replace(/_source\./,'.'); // source link to doc link
404   }
405   var url=root+hash;
406   var i=-1;
407   while (NAVTREEINDEX[i+1]<=url) i++;
408   if (navTreeSubIndices[i]) {
409     gotoNode(o,i,root,hash,relpath)
410   } else {
411     getScript(relpath+'navtreeindex'+i,function(){
412       navTreeSubIndices[i] = eval('NAVTREEINDEX'+i);
413       if (navTreeSubIndices[i]) {
414         gotoNode(o,i,root,hash,relpath);
415       }
416     },true);
417   }
418 }
419
420 function showSyncOff(n,relpath)
421 {
422     n.html('<img src="'+relpath+'sync_off.png" title="'+SYNCOFFMSG+'"/>');
423 }
424
425 function showSyncOn(n,relpath)
426 {
427     n.html('<img src="'+relpath+'sync_on.png"/ title="'+SYNCONMSG+'">');
428 }
429
430 function toggleSyncButton(relpath)
431 {
432   var navSync = $('#nav-sync');
433   if (navSync.hasClass('sync')) {
434     navSync.removeClass('sync');
435     showSyncOff(navSync,relpath);
436     storeLink(stripPath2($(location).attr('pathname'))+$(location).attr('hash'));
437   } else {
438     navSync.addClass('sync');
439     showSyncOn(navSync,relpath);
440     deleteLink();
441   }
442 }
443
444 function initNavTree(toroot,relpath)
445 {
446   var o = new Object();
447   o.toroot = toroot;
448   o.node = new Object();
449   o.node.li = document.getElementById("nav-tree-contents");
450   o.node.childrenData = NAVTREE;
451   o.node.children = new Array();
452   o.node.childrenUL = document.createElement("ul");
453   o.node.getChildrenUL = function() { return o.node.childrenUL; };
454   o.node.li.appendChild(o.node.childrenUL);
455   o.node.depth = 0;
456   o.node.relpath = relpath;
457   o.node.expanded = false;
458   o.node.isLast = true;
459   o.node.plus_img = document.createElement("img");
460   o.node.plus_img.src = relpath+"ftv2pnode.png";
461   o.node.plus_img.width = 16;
462   o.node.plus_img.height = 22;
463
464   if (localStorageSupported()) {
465     var navSync = $('#nav-sync');
466     if (cachedLink()) {
467       showSyncOff(navSync,relpath);
468       navSync.removeClass('sync');
469     } else {
470       showSyncOn(navSync,relpath);
471     }
472     navSync.click(function(){ toggleSyncButton(relpath); });
473   }
474
475   navTo(o,toroot,window.location.hash,relpath);
476
477   $(window).bind('hashchange', function(){
478      if (window.location.hash && window.location.hash.length>1){
479        var a;
480        if ($(location).attr('hash')){
481          var clslink=stripPath($(location).attr('pathname'))+':'+
482                                $(location).attr('hash').substring(1);
483          a=$('.item a[class$="'+clslink+'"]');
484        }
485        if (a==null || !$(a).parent().parent().hasClass('selected')){
486          $('.item').removeClass('selected');
487          $('.item').removeAttr('id');
488        }
489        var link=stripPath2($(location).attr('pathname'));
490        navTo(o,link,$(location).attr('hash'),relpath);
491      }
492   })
493
494   $(window).load(showRoot);
495 }
496