|
|
1.1 root 1: /** toc.js
2:
3: This is a simplified version of the scipt "generated_toc.js" written by:
4: Stuart Langridge, July 2007
5:
6: The script is licensed under the terms of the MIT license.
7: See the following page for details:
8: http://www.kryogenix.org/code/browser/generated-toc/
9:
10: Generate a table of contents, based on headings in the page.
11:
12: To place the TOC on the page, add
13:
14: <div id="generated-toc"></div>
15:
16: to the page where you want the TOC to appear. If this element
17: is not present, the TOC will not appear.
18:
19: */
20:
21: generated_toc = {
22: generate: function() {
23: // Identify our TOC element, and what it applies to
24: generate_from = '2';
25: tocparent = document.getElementById('generated-toc');
26: if (!tocparent) {
27: // They didn't specify a TOC element; exit
28: return;
29: }
30:
31: // set top_node to be the element in the document under which
32: // we'll be analysing headings
33: top_node = document.getElementsByTagName('body')[0];
34:
35: // If there isn't a specified header level to generate from, work
36: // out what the first header level inside top_node is
37: // and make that the specified header level
38: if (generate_from == 0) {
39: first_header_found = generated_toc.findFirstHeader(top_node);
40: if (!first_header_found) {
41: // there were no headers at all inside top_node!
42: return;
43: } else {
44: generate_from = first_header_found.toLowerCase().substr(1);
45: }
46: }
47:
48: // add all levels of heading we're paying attention to to the
49: // headings_to_treat dictionary, ready to be filled in later
50: headings_to_treat = {"h6":''};
51: for (var i=5; i>= parseInt(generate_from); i--) {
52: headings_to_treat["h" + i] = '';
53: }
54:
55: // get headings. We can't say
56: // getElementsByTagName("h1" or "h2" or "h3"), etc, so get all
57: // elements and filter them ourselves
58: // need to use .all here because IE doesn't support gEBTN('*')
59: nodes = top_node.all ? top_node.all : top_node.getElementsByTagName('*');
60:
61: // put all the headings we care about in headings
62: headings = [];
63: for (var i=0; i<nodes.length;i++) {
64: if (nodes[i].nodeName.toLowerCase() in headings_to_treat) {
65: // if heading has class no-TOC, skip it
66: if ((' ' + nodes[i].className + ' ').indexOf('no-TOC') != -1) {
67: continue;
68: }
69: headings.push(nodes[i]);
70: }
71: }
72:
73: // make the basic elements of the TOC itself, ready to fill into
74: cur_head_lvl = "h" + generate_from;
75: cur_list_el = document.createElement('ul');
76: tocparent.appendChild(cur_list_el);
77:
78: // now walk through our saved heading nodes
79: for (var i=0; i<headings.length; i++) {
80: this_head_el = headings[i];
81: this_head_lvl = headings[i].nodeName.toLowerCase();
82: if (!this_head_el.id) {
83: // if heading doesn't have an ID, give it one
84: //this_head_el.id = 'heading_toc_' + i;
85: var id = generated_toc.innerText(this_head_el).replace(/[ \/]/g, "_");
86: id = id.replace(/[^a-zA-Z0-9-_]/g, '');
87: this_head_el.id = id;
88: }
89:
90: while(this_head_lvl > cur_head_lvl) {
91: // this heading is at a lower level than the last one;
92: // create additional nested lists to put it at the right level
93:
94: // get the *last* LI in the current list, and add our new UL to it
95: var last_listitem_el = null;
96: for (var j=0; j<cur_list_el.childNodes.length; j++) {
97: if (cur_list_el.childNodes[j].nodeName.toLowerCase() == 'li') {
98: last_listitem_el = cur_list_el.childNodes[j];
99: }
100: }
101: if (!last_listitem_el) {
102: // there aren't any LIs, so create a new one to add the UL to
103: last_listitem_el = document.createElement('li');
104: }
105: new_list_el = document.createElement('ul');
106: last_listitem_el.appendChild(new_list_el);
107: cur_list_el.appendChild(last_listitem_el);
108: cur_list_el = new_list_el;
109: cur_head_lvl = 'h' + (parseInt(cur_head_lvl.substr(1,1)) + 1);
110: }
111:
112: while (this_head_lvl < cur_head_lvl) {
113: // this heading is at a higher level than the last one;
114: // go back up the TOC to put it at the right level
115: cur_list_el = cur_list_el.parentNode.parentNode;
116: cur_head_lvl = 'h' + (parseInt(cur_head_lvl.substr(1,1)) - 1);
117: }
118:
119: // create a link to this heading, and add it to the TOC
120: li = document.createElement('li');
121: a = document.createElement('a');
122: a.href = '#' + this_head_el.id;
123: a.appendChild(document.createTextNode(generated_toc.innerText(this_head_el)));
124: li.appendChild(a);
125: cur_list_el.appendChild(li);
126: }
127: },
128:
129: innerText: function(el) {
130: return (typeof(el.innerText) != 'undefined') ? el.innerText :
131: (typeof(el.textContent) != 'undefined') ? el.textContent :
132: el.innerHTML.replace(/<[^>]+>/g, '');
133: },
134:
135: findFirstHeader: function(node) {
136: // a recursive function which returns the first header it finds inside
137: // node, or null if there are no functions inside node.
138: var nn = node.nodeName.toLowerCase();
139: if (nn.match(/^h[1-6]$/)) {
140: // this node is itself a header; return our name
141: return nn;
142: } else {
143: for (var i=0; i<node.childNodes.length; i++) {
144: var subvalue = generated_toc.findFirstHeader(node.childNodes[i]);
145: // if one of the subnodes finds a header, abort the loop and return it
146: if (subvalue) return subvalue;
147: }
148: // no headers in this node at all
149: return null;
150: }
151: },
152:
153: getYPos: function(el) {
154: var y = 0;
155: while (el && !isNaN(el.offsetTop)) {
156: y += el.offsetTop;
157: el = el.parentNode;
158: }
159: return y;
160: },
161:
162: init: function() {
163: // quit if this function has already been called
164: if (arguments.callee.done) return;
165:
166: // flag this function so we don't do the same thing twice
167: arguments.callee.done = true;
168:
169: generated_toc.generate();
170:
171: if (location.hash.length != 0) {
172: // Make sure that the browser scrolled to the right location!
173: var anchor = location.hash.substring(1);
174: var y = generated_toc.getYPos(document.getElementById(anchor));
175: if ('scrollTo' in window) {
176: window.scrollTo(0, y);
177: }
178: else if ('scroll' in window) {
179: window.scroll(0, y);
180: }
181: }
182: }
183: };
184:
185: /* Run generated_toc.init as soon as possible */
186: (function(i) {
187: var u =navigator.userAgent;
188: var e=/*@cc_on!@*/false;
189: var st = setTimeout;
190: if(/webkit/i.test(u)) {
191: st(function() {
192: var dr=document.readyState;
193: if(dr=="loaded" || dr=="complete") {
194: i()
195: }
196: else {
197: st(arguments.callee,10);
198: }
199: },10
200: );
201: }
202: else if((/mozilla/i.test(u) && !/(compati)/.test(u)) || (/opera/i.test(u))) {
203: document.addEventListener("DOMContentLoaded",i,false);
204: } else if(e) {
205: (function() {
206: var t=document.createElement('doc:rdy');
207: try{
208: t.doScroll('left');
209: i();
210: t=null;
211: }
212: catch(e) {
213: st(arguments.callee,0);
214: }
215: })();
216: }
217: else{
218: window.onload=i;
219: }}
220: )(generated_toc.init);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.