|
|
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.