# Table of Contents (nesting) Eleventy Plugin

This Eleventy plugin will generate a (property nested) TOC from page content using an Eleventy filter.

HTML:
```html
<h1>Hello, World</h1>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad animi assumenda consequuntur debitis ea eligendi eos hic necessitatibus, odio recusandae rem similique, totam unde. Asperiores cumque facere nisi quibusdam vitae.

<h2 id="greetings-from-mars">Greetings from Mars</h2>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus aperiam at blanditiis dolorem ea, eius impedit maxime non omnis quia repudiandae sit, suscipit vel veniam voluptas. Dignissimos eos porro sit.

<h3 id="the-red-planet">The red planet</h3>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aut consequatur dicta doloremque est iure minima placeat recusandae sit. Dolorum quis quod sequi! Commodi cupiditate debitis, dolore error excepturi nulla optio.

<h2 id="greetings-from-pluto">Greetings from Pluto</h2>

```

Generated TOC:
* [Greetings from Mars](#greetings-from-mars)
  * [The red planet](#the-red-planet)
* [Greetings from Pluto](#greetings-from-pluto)
```html
<nav class="toc">
<ol>
    <li><a href="#greetings-from-mars">Greetings from Mars</a></li>
    <ol>
        <li><a href="#the-red-planet">The red planet</a></li>
    </ol>
    <li><a href="#greetings-from-pluto">Greetings from Pluto</a></li>
</ol>
</nav>

```

<hr>

# This Readme

* [Options](#options)
* [Install](#install)
  * [Adding it to Eleventy](#adding-it-to-the-eleventy-engine)
  * [Using the filter](#using-the-provided-filter)
  * [Configuring](#configuring)
* [Gotchyas](#gotchyas)


## Options

```javascript
const defaults = {
  tags: ['h2', 'h3', 'h4'], // Which heading tags are selected (headings must each have an ID attribute)
  ignoredElements: [],  // Elements to ignore when constructing the label for every header (useful for ignoring permalinks, must be selectors)
  wrapper: 'nav',       // Element to put around the root `ol`
  wrapperClass: 'toc',  // Class for the element around the root `ol`
  headingText: '',      // Optional text to show in heading above the wrapper element
  headingTag: 'h2'      // Heading tag when showing heading above the wrapper element
}
```

## Install

```sh
npm i --save eleventy-plugin-nesting-toc
```

## Usage

### Adding it to the Eleventy Engine

**IMPORTANT NOTE**: Your heading tags will need to have `id`s on them, so that the TOC can provide proper anchor links to them. Eleventy does not do this for you ootb. You can use a plugin like [markdown-it-anchor](https://www.npmjs.com/package/markdown-it-anchor) to add those `id`s to the headings automagically

```diff
// .eleventy.js
module.exports = function (eleventyConfig) {
  //...
+ const pluginTOC = require('eleventy-plugin-nesting-toc');
+ eleventyConfig.addPlugin(pluginTOC);

  // Example Markdown configuration (to add IDs to the headers)
  const markdownIt = require('markdown-it');
  const markdownItAnchor = require('markdown-it-anchor');
  eleventyConfig.setLibrary("md",
      markdownIt({
          html: true,
          linkify: true,
          typographer: true,
      }).use(markdownItAnchor, {})
  );
  //...
}
```

### Using the provided filter

```nunjucks
<aside>
  {{ content | toc | safe }}
</aside>
<article>
  {{ content }}
</article>
```

### Configuring

You can override any of the [options](#options) at the time that you call it, or when you add it to the eleventy engine. All the options will be merged together, with the precedence being `when invoking the filter > .eleventy.js > defaults`.

Override the defaults for your whole site:

```diff
module.exports = function (eleventyConfig) {
  //...
+ const pluginTOC = require('eleventy-plugin-nesting-toc');
+ eleventyConfig.addPlugin(pluginTOC, {tags: ['h2']});
  //...
}
```

And override those just for one template, as it's being invoked

```nunjucks
<aside>
  {{ content | toc(tags=['h2', 'h3'], wrapperClass='fixed toc') | safe }}
</aside>
```

If you have specific headings which you don't want to be included in the TOC, you can add the `data-toc-exclude` attribute to exclude these headings.

One way to add this attribute is via the use of the <a href="https://www.npmjs.com/package/markdown-it-attrs" target="_blank" rel="noopener">markdown-it-attrs</a> npm package.
```markdown
### Level 3 heading to ignore {data-toc-exclude}
```


## Gotchyas

A few things must be in place for this to work properly, and provide the proper nested structure

* The first matched heading on the page should be the topmost. _Don't put an h3 before an h2_.
* you can only use actual heading tags. _Don't use `tags=['section']`, etc._
