Thursday, October 2, 2014

Javascript TOC Robot

The list of books on Required Reading is starting to get a bit long, so I decided to add a table of contents (TOC). It's a drag to update the TOC everytime I add a book, so of course Javascript (JS) came to mind. But I didn't know whether Blogger uses jQuery so I decided to go old school and do puro JS.

First I added an id attribute to the book headers that I could use to link to them. At first I also thought that I could just grab all of the headers of type h2 but it turns out, duh, that there were a lot of h2 headers already in the template for the page, so I got a bunch of unrelated TOC entries. So instead I created a class that I could use to identify my book headers. Probably other ways I could have resolved that conundrum, so if you, yes you, have any bright ideas, please enlighten us! Thanks!

One cool thing I learned from pure JS is that document has an attribute similar to jQuery's $(Document).ready() function called document.body.onload, altho now I see in jQuery's documentation that the difference is that jQuery runs your JS as soon as the DOM is loaded and doesn't wait for assets like images to load as well, since they take longer.

Source

Here is the Gist of it.
<html>
<head>
<!-- either head or body -->
<style type="text/css">
.toc_item {
color: green;
}
</style>
<!-- css class -->
</head>
<body>
<div id="toc">
</div>
<!-- TOC -->
<h2 class="toc_item">item #1</h2>
<p>Item 1 is very cool.</p>
<!-- item #1 -->
<h3 class="toc_item">item #2</h3>
<p>Item 2 is super fun.</p>
<!-- item #2 -->
<h2 class="toc_item"><a href="http://www.example.com">item #3</a></h2>
<p>Item 3 is awesome.</p>
<!-- item #3 -->
<!-- content -->
<script>
/* Generate TOC
*
* :param classname: Class to which all TOC items belong.
* :param tocID: ID of the TOC element, should be <div></div>.
*/
function gen_toc(classname, tocID) {
var alltags = document.getElementsByClassName(classname); // all TOC items
var toc_content = "<h2>Table of Contents</h2><ol>"; // inner HTML content of TOC element
var toc_link = ' <a href="#' + tocID + '">(' + tocID + ')</a>'; // link to TOC element for each TOC item
for (var i = 0; i < alltags.length; i++) {
var toc_item = alltags[i].innerText; // just the inner text from the TOC item's element, ie: no links
var toc_item_enc = encodeURIComponent(toc_item).replace(" ", "-").toLowerCase(); // make URL safe ID string
alltags[i].setAttribute("id", toc_item_enc); // set ID of TOC item
alltags[i].innerHTML += toc_link; // add back link to TOC from TOC item
toc_content += '<li><a href="#';
toc_content += toc_item_enc;
toc_content += '">';
toc_content += toc_item;
toc_content += '</a></li>';
};
toc_content += '</ol>';
console.log(toc_content);
var toc = document.getElementById(tocID); // TOC element
toc.innerHTML = toc_content;
};
document.body.onload = gen_toc("toc_item", "toc");
</script>
<!-- toc script -->
</body>
</html>
view raw gen_toc.html hosted with ❤ by GitHub

No comments:

Post a Comment

Fork me on GitHub