Generating Automatic Website Footnotes with jQuery

I spent a lot of time (7 long years) in academia, writing about technical communication and new media. During that time, I created many academic documents for the web. A lot of those documents had footnotes. Generating footnotes for HTML documents in the past was always a slow, painful task — and every time I did it, I wondered why there wasn’t a better, easier way.

Join us in our newest publication:

Today, I’m happy to announce that I’ve come up with a better solution to web footnotes using the jQuery JavaScript framework and a few tags and attributes that already exist in XHTML. And I’m even happier to show you how to do it! If you’d like to see it in action before we begin, go here.

The Problem:

  • Many websites could benefit from having footnotes, but…
  • Manually creating footnotes for web documents is a slow process.

The Requirements:

  • Creating the footnotes should be as painless as possible (i.e., make use of as many standard tags/attributes as possible).
  • Users should be able to create footnotes that are pure commentary, book citation, web reference, or any combination thereof.

The Solution:

I decided to make use of the two most common XHTML tags that might need footnote information: blockquotes and quotations (<q>). Both of those tags can take the “cite” attribute, whose value is the URL from which the quoted material originated.

<q cite="http://cssnewbie.com/">
	Rob Glazebrook of CSSnewbie is imminently quoatable.
</q>

That takes care of the URL portion of our requirements… but what about commentary-type asides or non-web citations? You can’t put those in the cite attribute, because the only acceptable value for that attribute is a URL, and any comments you put in will be rendered as such in the output (it’s ugly… trust me). So for comments and other reference material, let’s turn to the “title” attribute instead.

<q title="Done with your TPS reports?">
	Is this good for the company?
</q>

And if you’d like your footnote to look more like a standard-issue reference citation, you could even put markup inside your title.

<q title="Zeldman, Jeffrey. <em>Designing with 
Web Standards</em> New Riders, 2003.">
	We build only to rebuild.
</q>

Admittedly, sticking XHTML markup in your title tag is pretty bad practice, so I can’t say that I 100% recommend this tactic… but I’ve tested it, and it works (at least in XHTML Transitional).

So now that we know what our XHTML looks like, let’s turn to the jQuery!

$(document).ready(function() {
	$("#wrap").append("<ol id=\"footnotes\"></ol>");
	footnote = 1;
	$("q[cite],q[title],blockquote[cite],blockquote[title]").addClass("footnote");
	$(".footnote").each(function() {
		$(this).append("<sup>"+footnote+"</sup>");
		cite="<li>";
		url=$(this).attr("cite");
		title=$(this).attr("title");
		if(title && url) {
			cite+="<a href=\""+url+"\">"+title+"</a>";
		} else if(title) {
			cite+=title;
		} else if(url) {
			cite+="<a href=\""+url+"\">"+url+"</a>";
		}
		cite+="</li>";
		$("#footnotes").append(cite);
		footnote++;
	});
});

And now, so that everyone understands exactly what this script is doing, I’ll walk you through each section of code.

$(document).ready(function() {
});

This bit of jQuery is saying “wait until the document is fully loaded (“ready”), then run the following function. This prevents our script from running while the document is only half-loaded.

$("#wrap").append("<ol id=\"footnotes\"></ol>");
footnote = 1;

The first line finds my element with an ID of “wrap” (you could use whatever element you wanted, such as the body tag), and appends (adds something to the end of) an ordered list with an ID of “footnotes.” This is where our script will stick all of our footnotes. The second line is just setting a variable, “footnote,” to a value of 1. This is the number we want our footnotes to start on.

$("q[cite],q[title],blockquote[cite],
blockquote[title]").addClass("footnote");

This line is going through our entire document and finding every q and blockquote element with either a “cite” or “title” attribute set, and giving them all a class of “footnote.”

This is a workaround to a problem I uncovered while building the script. Originally, I was just cycling through the document, grabbing all q and blockquote elements and checking for their attributes later, using jQuery’s “each” function (which we’ll see in a moment). The problem is, if you specify more than one element in an “each” function, jQuery will build an array (good) of all of your first elements first, and your second elements second, and so on (bad, in our case). Which meant that when I went through and numbered my footnotes later in the script, all the <q> tags would get numbered, and then the script would start over at the top of the page and number all my <blockquote> tags. That resulted in all my footnotes being out of order. This fixes that problem.

$(".footnote").each(function() {
});

Here’s the “each” function I mentioned previously. This line goes through the document and finds every instance of an item with a “footnote” class (which we just dynamically applied to all the appropriate elements), and then executes the contained function on every element it finds. It’s a cheap and easy “foreach” loop, basically.

$(this).append("<sup>"+footnote+"</sup>");

The first thing we do in our main function is append a footnote number to the end of the element. We put the footnote in a “sup” (superscript) tag to make it look like a footnote tag by default. You could use a different element if you so chose, and then use CSS to style it however you wish.

cite="<li>";
url=$(this).attr("cite");
title=$(this).attr("title");

I’m setting three variables here. The first, “cite,” is the foundation for our footnote at the bottom of the page. Since I’m building my footnote list using an ordered list, every element within will be wrapped with <li> tags. Next, I’m creating a variable called “url” which contains the “cite” attribute, and a variable called “title” which contains the “title” attribute. If the attribute exists on our particular quote, the variable will be set with that attribute’s contents. If the attribute isn’t set, the variable will be a Boolean “false.”

if(title && url) {
	cite+="<a href=\""+url+"\">"+title+"</a>";
} else if(title) {
	cite+=title;
} else if(url) {
	cite+="<a href=\""+url+"\">"+url+"</a>";
}

We have three “if” checks and three possible outcomes here. If both the “title” and “url” variables are set, we wrap the “title” content in an anchor tag with an href of the “url” content, and add it to the end of our “cite” variable. If just the title is set, we just output the title. And if just the url variable is set, we output the url, wrapped in an anchor tag so it’s active.

cite+="</li>";
$("#footnotes").append(cite);
footnote++;

Now we just need to wrap up our script. First, we close the list item in our cite variable, now that the rest of its content has been filled. Then we append the contents of our cite variable to the end of the “footnotes” ordered list that we created at the beginning of our script. And last but not least, we increase the number of our footnote by one, so that the next footnote will be one larger than the last.

That’s all there is to it! You can see this script in action here. Be sure to view the source code so you can see that there is no footnote list in the code… it’s being automatically generated by our script. And of course, you’ll need to include the jQuery framework at the top of your document before you can run this script (view the source on the example page for a demonstration on how to do that). And you could style your footnotes any way you please: my example page contains some rudimentary styles you can feel free to borrow.

This script could probably be made more advanced fairly easily, and I might write another article in the future on expanding this script for added functionality. If you have any suggestions on other things you’d like to see this script do, don’t hesitate to share them in the comments! I’d also love to hear if you’re planning to use this script anywhere, if you know of a better way to write my jQuery (I’m new to the framework, so it’s possible), or anything else of that nature.

Share and Enjoy !

0Shares
0 0