Action
Table of Contents
UPDATES
over 3 years ago
- If you don’t use a placeholder, the table of contents will be inserted before the first non-title header.
- Helpful error messages that make the Action easier to use.
- Checking header levels to make sure nested lists in the table of contents are possible.
Insert a table of contents based on Markdown headers.
Put the placeholder <!– start toc –><!– end toc –> where you want the table of contents to appear.
You can run it multiple times and it will update the table of contents.
If you don’t use a placeholder, the table of contents will be inserted before the first non-title header.
This is similar to the {{TOC}} feature if you are using the MultiMarkdown renderer (the default), except it will put your table of contents in the Draft, not just previews.
Steps
-
script
// See online documentation for examples // https://docs.getdrafts.com/docs/actions/scripting const addToc = content => { const headerLines = content.split('\n').filter(line => /^#+\s+[^\s]+/.test(line)) if (headerLines.length == 0) { alert("No Markdown headers (e.g. ## Header) found") return } const tocLines = [] let lastLevel = 0 for (let i = 0; i < headerLines.length; i++) { const splitMatch = headerLines[i].match(/^(#+)\s+(.*)$/) // - 2 assumes the first header is h2 const level = splitMatch[1].length - 2 if (level < 0) { alert("h1 headers (#) are not compatible with Table of Contents. Please use h2 headers (##) and below.") return null } if (level > lastLevel + 1) { alert("Cannot make a table of contents if header levels are skipped, e.g. ## followed by ####") return } lastLevel = level const headerText = splitMatch[2] tocLines.push(" ".repeat(level) + "* " + headerText) } if (tocLines[0][0] != "*") { alert("The first header must be a h2 (##)") return } let startMatch = content.match(/<!-- toc start -->/) let endMatch = content.match(/<!-- toc end -->/) if (startMatch == null && endMatch == null) { const firstHeaderMatch = content.match(/^(#+)\s+(.*)$/m) content = `${content.substring(0, firstHeaderMatch.index)}<!-- toc start --><!-- toc end -->\n\n${content.substring(firstHeaderMatch.index)}` startMatch = content.match(/<!-- toc start -->/) endMatch = content.match(/<!-- toc end -->/) } if (startMatch == null || endMatch == null) { alert("You need both <!-- toc start --> and <!-- toc end --> in your draft to place a table of contents") return } if (endMatch.index < startMatch.index) { alert("<!-- toc start --> must come before <!-- toc end -->") return } const startPos = startMatch.index + startMatch[0].length const endPos = endMatch.index return `${content.substring(0, startPos)}\n${tocLines.join("\n")}\n${content.substring(endPos)}` } const newBody = addToc(draft.lines.slice(1).join("\n")) if (newBody != null) { draft.content = `${draft.lines[0]}\n${newBody}` draft.update() }
Options
-
After Success Default Notification Info Log Level Info
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.