views:

146

answers:

7

I have headers in <h1> through <h6> tags. Is there a way that I can use JavaScript to generate a table of contents for the contents that serves as anchor tags as well?

I would like the output to be something like:

<ol>
    <li>Header 1</li>
    <li>Header 1</li>
        <li>Header 2</li>
            <li>Header 3</li>
</ol>

I am not currently using a JavaScript framework, but I don't see why I couldn't use one.

I am also looking for something done, since I'm guessing this is a common problem, but if not, a starting point to roll my own would be good.

A: 

after page load, cycle through the DOM and look for the elements that interest you. build a nice list of anchors and add it to the document at the place of your desire.

Amir Arad
+1  A: 

Are you looking for a prepackaged solution or are you asking how this can be implemented?

For the latter, you could use getElementsByTagName() recursively on <h1> through <h6> XPath to iterate through all <h*> elements and construct the corresponding nested <ul> or <ol> lists. You'd also have to add the <a> tags to the headers.

Ates Goral
Using Xpath assumes the document will be well-form XHTML.
Diodeus
Yeah, and it also assumes that the browser supports XPath. Not the most universal solution I guess...
Ates Goral
+3  A: 

JQuery comes to mind as a fast and easy solution. A quick google search for jquery table of contents yields two promising results:

Francis Beaudet
So, these "solutions" do not do re-create the structure recursively (with all h1..h6), right? -
Sergey Ilinsky
A: 

I wrote something a while ago which does this... It will need some adjusting though: http://enhance.qd-creative.co.uk/2008/05/27/navigable-content/

J-P
A: 

You can, but it depends on your layout if it would be a good solution, because if you employ floats and absolute positioned elements, DOM might not have elements as your visual representation present them ...

roenving
A: 

Check out the component you are looking for on this page: Re-inventing XMLHttpRequest: Cross-browser implementation with sniffing capabilities

It walks over entire document and creates a TOC with all h1-h6 elements reflected in an openable (upon hover) structure. The component is standalone and it doesn't use any library.

Sergey Ilinsky
+3  A: 

I couldn't resist putting together a quick implementation.

Add the following script anywhere on your page:

window.onload = function () {
    var toc = "";
    var level = 0;

    document.getElementById("contents").innerHTML =
     document.getElementById("contents").innerHTML.replace(
      /<h([\d])>([^<]+)<\/h([\d])>/gi,
      function (str, openLevel, titleText, closeLevel) {
       if (openLevel != closeLevel) {
        return str;
       }

       if (openLevel > level) {
        toc += (new Array(openLevel - level + 1)).join("<ul>");
       } else if (openLevel < level) {
        toc += (new Array(level - openLevel + 1)).join("</ul>");
       }

       level = parseInt(openLevel);

       var anchor = titleText.replace(/ /g, "_");
       toc += "<li><a href=\"#" + anchor + "\">" + titleText
        + "</a></li>";

       return "<h" + openLevel + "><a name=\"" + anchor + "\">"
        + titleText + "</a></h" + closeLevel + ">";
      }
     );

    if (level) {
     toc += (new Array(level + 1)).join("</ul>");
    }

    document.getElementById("toc").innerHTML += toc;
};

Your page should be structured something like this:

<body>
    <div id="toc">
     <h3>Table of Contents</h3>
    </div>
    <hr/>
    <div id="contents">
     <h1>Fruits</h1>
     <h2>Red Fruits</h2>
     <h3>Apple</h3>
     <h3>Raspberry</h3>
     <h2>Orange Fruits</h2>
     <h3>Orange</h3>
     <h3>Tangerine</h3>
     <h1>Vegetables</h1>
     <h2>Vegetables Which Are Actually Fruits</h2>
     <h3>Tomato</h3>
     <h3>Eggplant</h3>
    </div>
</body>

You can see it in action at http://magnetiq.com/exports/toc.htm (Works in IE, FF, Safari, Opera)

Ates Goral
Not tested, but it looks somewhat solid.
Thomas Owens