Created
June 27, 2013 08:30
-
-
Save Coconuthack/5874891 to your computer and use it in GitHub Desktop.
JS Def Guide : 15.7 Example: Dynamically Generating a Table of Contents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* TOC.js: create a table of contents for a document. | |
* | |
* This module registers an anonymous function that runs automatically | |
* when the document finishes loading. When it runs, the function first | |
* looks for a document element with an id of "TOC". If there is no | |
* such element it creates one at the start of the document. | |
* | |
* Next, the function finds all <h1> through <h6> tags, treats them as | |
* section titles, and creates a table of contents within the TOC | |
* element. The function adds section numbers to each section heading | |
* and wraps the headings in named anchors so that the TOC can link to | |
* them. The generated anchors have names that begin with "TOC", so | |
* you should avoid this prefix in your own HTML. | |
* | |
* The entries in the generated TOC can be styled with CSS. All entries have | |
* a class "TOCEntry". Entries also have a class that corresponds to the level | |
* of the section heading. <h1> tags generate entries of class "TOCLevel1", | |
* <h2> tags generate entries of class "TOCLevel2", and so on. Section numbers | |
* inserted into headings have class "TOCSectNum". | |
* | |
* You might use this module with a stylesheet like this: | |
* | |
* #TOC { border: solid black 1px; margin: 10px; padding: 10px; } | |
* .TOCEntry { font-family: sans-serif; } | |
* .TOCEntry a { text-decoration: none; } | |
* .TOCLevel1 { font-size: 16pt; font-weight: bold; } | |
* .TOCLevel2 { font-size: 12pt; margin-left: .5in; } | |
* .TOCSectNum:after { content: ": "; } | |
* | |
* That final line generates a colon and space after section numbers. To hide | |
* the section numbers, use this: | |
* | |
* .TOCSectNum { display: none } | |
* | |
* This module requires the onLoad() utility function. | |
**/ | |
onLoad(function() { // Anonymous function defines a local scope | |
// Find the TOC container element. | |
// If there isn't one, create one at the start of the document. | |
var toc = document.getElementById("TOC"); | |
if (!toc) { | |
toc = document.createElement("div"); | |
toc.id = "TOC"; | |
document.body.insertBefore(toc, document.body.firstChild); | |
} | |
// Find all section heading elements | |
var headings; | |
if (document.querySelectorAll) // Can we do it the easy way? | |
headings = document.querySelectorAll("h1,h2,h3,h4,h5,h6"); | |
else // Otherwise, find the headings the hard way | |
headings = findHeadings(document.body, []); | |
// Recursively traverse the document body looking for headings | |
function findHeadings(root, sects) { | |
for(var c = root.firstChild; c != null; c = c.nextSibling) { | |
if (c.nodeType !== 1) continue; | |
if (c.tagName.length == 2 && c.tagName.charAt(0) == "H") | |
sects.push(c); | |
else | |
findHeadings(c, sects); | |
} | |
return sects; | |
} | |
// Initialize an array that keeps track of section numbers. | |
var sectionNumbers = [0,0,0,0,0,0]; | |
// Now loop through the section header elements we found. | |
for(var h = 0; h < headings.length; h++) { | |
var heading = headings[h]; | |
// Skip the section heading if it is inside the TOC container. | |
if (heading.parentNode == toc) continue; | |
// Figure out what level heading it is. | |
var level = parseInt(heading.tagName.charAt(1)); | |
if (isNaN(level) || level < 1 || level > 6) continue; | |
// Increment the section number for this heading level | |
// and reset all lower heading level numbers to zero. | |
sectionNumbers[level-1]++; | |
for(var i = level; i < 6; i++) sectionNumbers[i] = 0; | |
// Now combine section numbers for all heading levels | |
// to produce a section number like 2.3.1. | |
var sectionNumber = sectionNumbers.slice(0,level).join(".") | |
// Add the section number to the section header title. | |
// We place the number in a <span> to make it styleable. | |
var span = document.createElement("span"); | |
span.className = "TOCSectNum"; | |
span.innerHTML = sectionNumber; | |
heading.insertBefore(span, heading.firstChild); | |
// Wrap the heading in a named anchor so we can link to it. | |
var anchor = document.createElement("a"); | |
anchor.name = "TOC"+sectionNumber; | |
heading.parentNode.insertBefore(anchor, heading); | |
anchor.appendChild(heading); | |
// Now create a link to this section. | |
var link = document.createElement("a"); | |
link.href = "#TOC" + sectionNumber; // Link destination | |
link.innerHTML = heading.innerHTML; // Link text is same as heading | |
// Place the link in a div that is styleable based on the level. | |
var entry = document.createElement("div"); | |
entry.className = "TOCEntry TOCLevel" + level; | |
entry.appendChild(link); | |
// And add the div to the TOC container. | |
toc.appendChild(entry); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment