Skip to content

Instantly share code, notes, and snippets.

@andreasvirkus
Last active May 22, 2017 18:04
Show Gist options
  • Save andreasvirkus/3a196e6b02f238f0db596be0149b4b2a to your computer and use it in GitHub Desktop.
Save andreasvirkus/3a196e6b02f238f0db596be0149b4b2a to your computer and use it in GitHub Desktop.
This plugin loops over a markdown file's headings and creates a ToC in the metadata. Example template and build file included.
var Metalsmith = require('metalsmith'),
markdown = require('metalsmith-markdown'),
layouts = require('metalsmith-layouts'),
tocTask = require('./metalsmithTableOfContentsTask.js');
var ms = Metalsmith(__dirname)
.source('./src')
.use(markdown())
.use(tableOfContentsTask())
.use(layouts({
engine: 'handlebars',
directory: 'layouts',
partials: 'layouts/partials',
default: 'default.hbs'
}))
.destination('./build')
.build(function (err) {
if (err) throw err;
});
const cheerio = require('cheerio');
/**
* Generate table of contents in the file's metadata based on heading elements found in content
*
* @returns {function} Metalsmith build step
*/
const tableOfContentsTask = function () {
var selectors = 'h2[id], h3[id]',
data, contents, $, lastIndex, $headings, $heading;
return function(files, metalsmith, done) {
Object.keys(files).forEach(function(file) {
if (extname(file) !== '.html') return;
data = files[file];
contents = data.contents.toString();
$ = cheerio.load(contents);
lastIndex = 0;
$headings = $(selectors);
data.headings = [];
$headings.each(function(i) {
$heading = $headings[i];
if ($heading.attribs.id) {
if ($heading.name === 'h2') {
data.headings.push({
id: $heading.attribs.id,
tag: $heading.name,
text: $heading.children[0].data,
haveChildren: false,
children: []
});
lastIndex = data.headings.length - 1;
} else {
data.headings[lastIndex].children.push({
id: $heading.attribs.id,
tag: $heading.name,
text: $heading.children[0].data
});
data.headings[lastIndex].haveChildren = true;
}
}
});
});
done();
};
};
module.exports = tableOfContentsTask;
{{#if headings}}
<ul class="ui-lab toc" id="js-toc">
{{#each headings}}
<li><a href="#{{this.id}}">{{this.text}}</a>
{{#if this.haveChildren}}
<ul>
{{#each this.children}}
<li><a href="#{{this.id}}">{{this.text}}</a></li>
{{/each}}
</ul>
{{/if}}
</li>
{{/each}}
</ul>
{{/if}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment