Adding Permalinks To Headers
You can let nanoc add permalinks to headers, so that linking to specific sections of a HTML document is a lot easier. Rather than generating these links by hand, you can let nanoc do this automatically.
The easiest way to do this is using a custom filter. For this, you'll need Hpricot.
This tip assumes that your HTML file is structured in a certain way (similar to HTML5's usage of <section> and <h1-6>). First of all, each section should be a div with a "section" class. Each section should have a header. Additionally, each section must have an id. For example:
<div class="section" id="foo">
<h1>Foo</h1>
...
<div class="section" id="foo-bar">
<h2>Bar</h2>
...
</div>
<div class="section" id="foo-baz">
<h2>Baz</h2>
...
<div class="section" id="foo-baz-quux">
<h3>Quux</h3>
...
</div>
</div>
</div>
This filter should do the following:
- Find all sections
- For all sections:
- Get the section ID
- Find the section header
- Append the permalink to the section with the given ID to the header
Its implementation looks like this:
class AddLinksToHeadersFilter < Nanoc::Filter
identifiers :add_links_to_headers
def run(content)
nanoc_require 'hpricot'
# Parse with Hpricot
doc = Hpricot(content)
# Find all sections
doc.search('.section').each do |section|
# Find ID
section_id = section['id']
next if section_id.nil?
# Add permalink to header
section_header = section.search((1..6).map { |i| "> h#{i}" }.join(', '))
section_header.append(permalink_for(section_id))
end
doc.to_s
end
private
# Creates a permalink for the given section ID
def permalink_for(section_id)
%[ <a class="permalink" rel="bookmark" href="##{section_id}" title="Permanent link to this section">¶</a>]
end
end
Some remarks/ideas/tips:
- This code returns XHTML, not HTML (seems to be a bug or a feature in Hpricot). If you need HTML, you need to manually fix Hpricot's output. You can do so by replacing doc.to_s with doc.to_s.gsub(' />', '>'). (This is not really an elegant solution, so I'm open for feedback!)
- If you're one of those HTML5 geeks, you can easy adapt the code to use the HTML5 <section> element instead of div's with a "section" class. Simply replace doc.search('.section') with doc.search('section').
- The permalink uses the rel-bookmark microformat.
- If you don't like manually assigning section IDs, you could let nanoc automatically generate the section IDs based off the text of the section header.
- The permalink uses the paragraph symbol (¶). You may want to change this into something else, or even replace it with an image.
