PageSourceSearch

https://box2d.org/documentation/navtree.js

js box2d.org collected 2026-09-24 15:28:34 UTC 15,876 bytes, 483 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.