Table of Contents with jQuery

While reading my RSS feeds I noticed Chris Heilmann's post on his blog a couple of days ago about building a script that would generate a table of contents from a html document. He presented several solutions on his post, some using plain javascript, others using YUI and a couple of others using php. So I thought I'd make one with jQuery, just to see how I could use the framework on this particular case.

The jQuery solution

So, first I established a few guidelines:

  • Must work with headings from 1 to 6.
  • Only one h1 allowed.
  • The document must have a clean structure of headings. That means no jumps from h3 to h5 for instance.
  • Jumps on the reverse order is ok though, so it is possible to go from a h5 to a h3.

With those points in mind, I started to code and came up with the following code:

$(document).ready(function(){
	$("#content").prepend("<ul id=\"toc\"></ul>");
	var title = 0;
	var output = "";
	$("h1,h2,h3,h4,h5,h6").each(function(){
		var htitle = $(this).text();
		var hid = $(this).attr("id");
		title = $(this).attr("tagName").substr(1,1);
		var next = parseInt(title) + 1;
		if ($(this).nextAll("h2,h3,h4,h5,h6").eq(0).length){
			var nextel = parseInt($(this).nextAll("h2,h3,h4,h5,h6").eq(0).attr("tagName").substr(1,1));
			var last = false; 
		}
		else{
			var last = true; 
		}
		if (nextel >= next){
			output += "<li><a href=\"#" + hid + "\">" + htitle + "</a><ul>";	
		}
		else if (nextel < title){
			output += "<li><a href=\"#" + hid + "\">" + htitle + "</a>";
			for ( var i = nextel; i < title; i++) {
				output += "</li></ul>";
			}
		}
		else if (last == true){
			output += "<li><a href=\"#" + hid + "\">" + htitle + "</a></li></ul>";
			for ( var i = 1; i < title; i++) {
				output += "</li></ul>";
			}
		}
		else{
			output += "<li><a href=\"#" + hid + "\">" + htitle + "</a></li>";
		}
	});
	$("#toc").append(output);
});

You can see a demo here.

I was able to successfully follow the four guidelines above, and it works with any markup that is along the way, although, a modification to allow more than one h1 requires only a change on the selector, but that goes against HTML rules. As far as the script goes, getting the headings in order is pretty easy with jQuery, and thankfully, the framework provided ways to iterate over those and get the next heading pretty easily. The rest was figuring a way to close the lists neatly.

The code can probably be optimized for speed but as it stands, it seems to work pretty well. I guess also, that ideally, this should be done as a jQuery plugin instead of direct javascript, but as a proof of concept, it does the job. I might write the plugin later on, just for kicks.

If you have any suggestions to improve the code though, please do leave a comment below.

Trackback URL for this post:

http://lab.diogovincenzi.com/trackback/7

uebernachtung guenstig

[...] It was an attempt by the British government to achieve a geo-political end by technological means. Below,fully Poindexter and Secord weren't immediately available for comment. Below,fully [...]