One of the features I need to rebuild for Octopress was the ability to generate a table of contents (like the one for this article), for some of the larger articles.
This article describes how I accomplished that goal.
I wanted the generated table of contents to meet the following requirements:
- It should be easy to style. In particular, I want it to look different on the screen and printer-friendly versions of a page.
- It should be implemented as an HTML unnumbered list (i.e., a <ul>), for maximum styling flexibility.
- It should be automatic: The code should generate the table of contents from the headings (<H1>, <H2>, etc.) in the document, without my having to mark the headings in some way.
- It should be optional: I should be able to enable or disable it, on a per-article basis.
- If I accidentally enable it on an article that has no heading elements, I don’t want to see an empty table of contents in the document.
Server-side or client-side?
Ideally, since Octopress generates static HTML, I’d like to have a Liquid tag to embed in the appropriate place inside one of my templates. Something like this would be perfect:
You can either download jQuery and install it directly in the source tree for your Octopress blog, or you can use it from one of the public CDNs, like Google. See http://docs.jquery.com/Downloading_jQuery for a list of CDNs.
If you elect to download it and install it locally, copy the appropriate
jquery-1.7.1.min.js) to your blog’s
You’ll also need the jQuery table of contents plugin. Download it and
put it somewhere within your blog’s source. I stored it in
source/_includes/custom/head.html to include
<script> tags for
jQuery and the table of contents plugin. For a local install, use this code:
If you’re using the version of jQuery hosted on Google, use this code:
You also have to use
jQuery.noConflict(), to prevent conflicts between
jQuery’s use of the ‘$’ alias and the ‘$’ used in
ender.js, which is
automatically included by Octopress. So, regardless of where you source
jQuery, add this code, right after the
<script> tag that pulls jQuery in:
1 2 3 4 5
Generating the Table of Contents
generate-toc.js. (You can see the source for that file in my
blog’s GitHub repo. I’ve also reproduced it, below.)
1 2 3 4 5 6 7 8 9 10 11 12 13
insertBefore parameter is a jQuery string selector for the element to
search for the table of content headings. The optional
specifies the heading to precede the table of contents.
The next step is to call
generateTOC() at the right time. The following hunk
of code goes at the bottom of
1 2 3 4 5 6 7 8 9 10 11 12 13
Things to note:
Octopress sets the
index variable if it’s generating the index page; if that
variable is set, we don’t want to generate a table of contents.
Note, too, that the code only generates the table of contents if the
variable is set to “true”.
page.toc will be true only if the following line
is in the YAML front matter of an article:
1 2 3 4 5 6 7 8
toc line is missing or set to something other than “true”, the
table of contents is skipped.
jQuery(document).ready() hook. Octopress assigns the
.entry-hook class to
<div> element that contains the generated article content. Passing that
selector string to
generateTOC() ensures that we don’t pick up any heading
elements that happen to live somewhere else in the HTML. The second parameter,
the string “Table of Contents”, puts a heading above the generated table of
I’m using a few locally-defined mixins within my Sass files. You may wish to use something like Bourbon, instead, since it provides these capabilities, and more. (I may switch to Bourbon myself, at some point.) However, for this article, let’s assume you’re using locally-defined ones.
Store the following definitions in
sass/custom/_mixins.scss. (The source
is available at
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
sass/custom/_styles.scss to import the mixins:
Screen versus Print
generateTOC() puts the table of contents inside a
<ul> element, which tells
the jQuery Table of Contents plugin to generate a nested list. I chose to
style that list one way for the screen and another way for the printed page.
(You can see the difference by printing this article.)
Octopress already has a
sass/screen.scss file, but I want to keep my local
screen-specific stylings in a custom file. So, I created
sass/custom/_screen.scss for my screen-specific rules, and added this line to
sass/custom/_screen.scss, I put the following rules:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
- causes the table of contents to float to the right of the text
- gives it a light gray background
- ensures that the nested lists don’t have too much indentation
- forces all lists to use disc bullets, regardless of nesting level.
Octopress does not (yet) ship with a
sass/print.scss file, so I created one.
For consistency with the screen styling (and the rest of the SASS files), that
file just includes a custom
sass/custom/_print.scss file. Here’s
sass/custom/_print.scss, I put the following rules:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
The result of all that work is a table of contents that looks like this: