cmaas / markdown-it-table-of-contents Goto Github PK
View Code? Open in Web Editor NEWA table of contents plugin for Markdown-it
License: MIT License
A table of contents plugin for Markdown-it
License: MIT License
If the first heading in the page is h2 (say), if a h1 appear after it, headings h1 and below h1 are not rendered in the TOC.
Please try the below block of code in the URL: https://npm.runkit.com/markdown-it-table-of-contents
var MarkdownIt = require("markdown-it");
var md = new MarkdownIt();
md.use(require("markdown-it-table-of-contents"));
var content = "## h2 Heading\n" +
" [[toc]] \n" +
"# h1 heading 1\n" +
"Some nice text\n" +
"# h1 heading 2\n" +
"Some even nicer text\n"
md.render(content)
Expected TOC:
Actual TOC:
I am willing to submit a PR for this, just wanted to know if this issue is known and you would like this to be supported.
I'd like to be able to have more control in "format" function (or other) to generate more porwerfull output.
In particular, I'd like to be able to have the link to which the heading will point to available or the slug function used to generate it available.
Debugging shows that when I pass an object with options settings into the markdown-it constructor via
use(require("markdown-it-table-of-contents"), options);
the object does not get passed in.
module.exports = (md, o) => {
const options = Object.assign({}, defaults, o);
const tocRegexp = options.markerPattern;
In the code snippet above in index.js
, the object o
is undefined
in my debugging session.
I use this object:
{
"includeLevel": [2, 3, 4],
"containerClass": "table-of-contents",
"slugify": "(s) => encodeURIComponent(String(s).trim().toLowerCase().replace(/\s+/g, '-'))",
"markerPattern": "/^\\[\\[toc\\]\\]/im",
"listType": "ul",
"format": "",
"forceFullToc": false,
"containerHeaderHtml": "",
"containerFooterHtml": ""
}
I think it may be related to this issue:
Usage of arguments.callee is prohibited in strict mode chaijs/chai#384
Because I saw this Error in the debugger:
TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
I am unable to consume it as an AMD. Is that support present in this library? If not I can contribute to update the library to support both AMD and CommonJs.
parseInt(token.tag.substr(1, 1))
"at renderChildsTokens (markdown-it-table-of-contents\\index.js:79:37)",
"at Object.md.renderer.rules.toc_body (markdown-it-table-of-contents\\index.js:66:12)",
"at Renderer.renderInline (markdown-it\\lib\\renderer.js:271:28)",
"at Renderer.render (markdown-it\\lib\\renderer.js:324:22)",
"at MarkdownIt.render (markdown-it\\lib\\index.js:539:24)",
I am not sure when it happens because this is an error report from a user which send the error without additional description.
Input:
<nav>
[[toc]]
</nav>
Output:
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Some title</title>
</head>
<body>
<main>
<nav>
<p><div class="table-of-contents">...</div></p>
</nav>
</main>
</body>
</html>
This output doesn't pass https://validator.w3.org/nu/#textarea because <p> can't contain block-level elements.
Using markdown for code in the header generates an empty id tag when there is no other text in the header outside of the code block. See output
below.
input.md
# First header
Lorem ipsum.
[[toc]]
## Next section!
Integer posuere erat a ante venenatis dapibus posuere velit aliquet.
### Next Next section!
Maecenas faucibus mollis interdum.
#### `main.css`
Curabitur blandit tempus porttitor.
dependencies
"dependencies": {
"markdown-it": "^8.0.0",
"markdown-it-anchor": "^2.5.0",
"markdown-it-container": "^2.0.0",
"markdown-it-table-of-contents": "^0.2.2"
},
index.js
var fs = require("fs");
var MarkdownIt = require("markdown-it");
var md = new MarkdownIt();
var markdownItAnchor = require("markdown-it-anchor");
var markdownItToc = require('markdown-it-table-of-contents');
md.use(markdownItAnchor, {
level: 1
});
md.use(markdownItToc, {
includeLevel: [2,3]
});
const src = fs.readFileSync("input.md", "utf-8");
console.log(md.render(src));
output
<h1 id="first-header">First header</h1>
<p>Lorem ipsum.</p>
<p><div class="table-of-contents"><ul><li><a href="#next-section">Next section!</a><ul><li><a href="#next-next-section">Next Next section!</a></li></ul></li></ul></div></p>
<h2 id="next-section">Next section!</h2>
<p>Integer posuere erat a ante venenatis dapibus posuere velit aliquet.</p>
<h3 id="next-next-section">Next Next section!</h3>
<p>Maecenas faucibus mollis interdum.</p>
<h4 id=""><code>main.css</code></h4>
<p>Curabitur blandit tempus porttitor.</p>
I'm giving my headings custom ids via the plugin markdown-it-attrs
so that they stay the same, even if I change the text. Helpful for evergreen-content like FAQs etc.:
# FAQ
## What does it cost? {#price}
Unfortunately, slugify()
only receives the text content as parameter, not the id of the heading. So, there's no way to override this as far as I can see. Expected output: should use #price
as link target. Actual output: #what-does-it-cost
I think the code that searches for heading tokens should also look for 'headings_open' and check if there is an id-attribute and use this as a slug.
Issue:
Solution:
RunKit example. The highlighted "[" is causing the second TOC to be rendered.
Content links are not affected by the link_open rule whether is defined before .use or after.
md.renderer.rules.link_open = () => `<a class="sg-text--link sg-text--bold sg-text--blue-dark">`;
Expected result:
<ul>
<li>
<a href="#h1-heading" class="sg-text--link sg-text--bold sg-text--blue-dark">h1 Heading</a>
</li>
</ul>
Actual result
<ul>
<li>
<a href="#h1-heading">h1 Heading</a>
</li>
</ul>
Our application uses markdown-it-table-of-contents
and we are getting error reports from users with the following error. Unfortunately, I can't seem to find a way to replicate it. Maybe the author of this extension could have better idea of why this error could be thrown.
We are using version 0.2.2. We could update but I didn't seen any fix regarding something similar to this in the commits history.
{
"message": "Cannot read property 'type' of undefined",
"os": "Linux 4.8",
"path": "node_modules/markdown-it-table-of-contents/index.js",
"code": "(state.tokens.slice(-1)[0].type === \"softbreak\") ",
"line": 24,
"column": 36,
"stack": [
"at Array.toc (node_modules/markdown-it-table-of-contents/index.js:24:36)",
"at ParserInline.tokenize (node_modules/markdown-it/lib/parser_inline.js:135:22)",
"at ParserInline.parse (node_modules/markdown-it/lib/parser_inline.js:163:8)",
"at Array.inline (node_modules/markdown-it/lib/rules_core/inline.js:10:23)",
"at Core.process (node_modules/markdown-it/lib/parser_core.js:51:13)",
"at MarkdownIt.parse (node_modules/markdown-it/lib/index.js:519:13)",
"at MarkdownIt.render (node_modules/markdown-it/lib/index.js:539:36)"
]
}
I'd be interested maintaining this package. I started my blog recently using Vuepress and GitHub pages, which I've been publishing to pretty consistently.
After comparing this package (which seems to be included with Vuepress by default) with the alternative, vuepress-plugin-table-of-contents, I decided I preferred this package's TOC because it's strictly markdown and it doesn't require me to customize a Vue component.
I've opened PR #52 as one of my first open-source contributions, which I think is significant considering how long I've been using GitHub for. Between that and PR #51, the two issues I had with this package have been fixed, so I'd be happy to maintain it moving forward. :)
Source:
# A
[[toc]]
### B
## C
## D
Config:
includeLevel: [2,3]
Expected result:
<ul>
<li>
<ul>
<li>B</li>
</ul>
</li>
<li>C</li>
<li>D</li>
</ul>
Actual result: Shows only heading level 3 and nothing else.
Why would anyone do this? Because personally, I think level 1 is useless in a TOC, because that is the page header. I use level 2+3 only. I also use level 3 to have a heading in some kind of info box. The markup is like this:
# Nice article
[[toc]]
Blabla
<div class="infobox">
### Did you know?
Blabla
</div>
## Headline after info box
markdown-it-attrs makes it possible to define custom slugs for headers. For example,
# This is an example header { #foo-bar }
…becomes…
<h1 id="foo-bar">This is an example header</h1>
Is there a way to make markdown-it-table-of-contents recognize these pre-existing header IDs instead of making up its own?
I was expecting that using includeLevel: 3
would include both level 2 and level 3. Is there a way to achieve that with your plugin ?
Example: ## <span class="light">💀</span> Spiritual Skeleton
Doesn't match, bug?
Afaik,
md.use(require("markdown-it-table-of-contents", options));
should read
md.use(require("markdown-it-table-of-contents"), options);
instead. At least this is how I got the option 'includeLevel' to actually work.
Example content:
a
[[toc]]
b
# heading1
Expected HTML:
a
<div class="table-of-contents">
// list of headings
</div>
b
<h1>heading1</h1>
Actual HTML is as below: The TOC is getting rendered weirdly.
This is the sample runKit code I tried for this repro.
var MarkdownIt = require("markdown-it")
var md = new MarkdownIt();
md.use(require("markdown-it-anchor"));
md.use(require("markdown-it-table-of-contents"), {
markerPattern: /^\[\[toc\]\]/im
});
var content = "a\n" +
"[[toc]]\n" +
"b\n" +
"# Heading1\n" +
"## Sub heading 1\n" +
"Some even nicer text\n"
md.render(content);
I debugged and I could get the root cause. We are assuming that there could be no '\n' character before the [[toc]] syntax in the given state based on which we set the state.pos
. Hence the index we set for the next processing is incorrect and changes depending upon the position of the first '\n' in state.src. It works in if there is a line gap before the [[toc]] and after it.
I shall raise a PR trying to fix this issue.
There is a security vulnerability in [email protected] which causes it to be flagged by tools like snyk.
jprichardson/string.js#212
The vulnerable methods in [email protected] are not used by this project, however it still causes warnings from automated tooling. The issue has been discussed in the string.js repo for over 6 months and there is no traction there on a fix.
Consider switching to slugify (https://www.npmjs.com/package/slugify) instead, which does not have any open security vulnerabilities.
If the header is a also link, not normal header, like # header
, the href attribute in will be wrong. In addition, the mark link in Plugins has some weird behaviors.
Please check my demo. The markdown testing source is just the source used in markdown-it demo. The
screenshots are below.
In my opinion, the link header should be treated differently. The markdown-it-anchor plugin handles it well by using the link text in ### [link text](url)
as the id attribute. The TOC plugin perhaps should threat it in this way.
This is a feature request to support {{TOC}}
pattern additionally to [[TOC]]
.
One major benefit of Markdown is, that it's just plaintext --> cross platform
It would be great to start working on Mac/PC (e.g. VSCode or Atom) and continue working with mobile devices like iPad etc.
The AppStore has already mobile Apps with great Markdown support like 1Writer or iA Writer , but this Apps are using {{TOC}}
instead of [[TOC]]
.
When to try to generate TOC from empty markup we'll get this result
<p><div class="table-of-contents"><ul></li></ul></div></p>
Expected result is
<p><div class="table-of-contents"><ul></ul></div></p>
It seems that this does not work:
md.use(require("markdown-it-anchor"));
But this does:
md.use(require("markdown-it-anchor").default);
complete code example:
var hljs = require("highlight.js");
var MarkdownIt = require("markdown-it");
var md = new MarkdownIt({
html: true,
linkify: true,
typographer: true,
langPrefix: "code-block language-",
highlight: function(str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str, true).value;
} catch (__) {}
}
return md.utils.escapeHtml(str);
}
});
// md.use(require("markdown-it-anchor"));
md.use(require("markdown-it-anchor").default);
md.use(require("markdown-it-table-of-contents"));
The docs of markdown-it-anchor seem outdated. I recommend you test it out on your device as well.
Related: valeriangalliat/markdown-it-anchor#112
Currently, KaTeX-expressions aren't part of the anchor-links generated by this plugin.
It'd be awesome to either have the option to add custom token-types to be included in anchor-links or to have math_inline
added to this filter:
markdown-it-table-of-contents/index.js
Line 72 in 62bfc75
Thanks for your great work 😄
I think the problem is with encodeURIComponent in "slugify" option and IE can't handle this encoded string with diacritics after #.
For example: <a href="#z%C3%A1kladn%C3%A1-obrazovka">Základná obrazovka</a>
in typora, I user [toc]
to display table of contents,but when use markdown-it-table-of-contents, I need user [[toc]]
。
Is there any way to support typora style toc by using [toc]
If header contains emoji, plugin doesn't work as expected
Expected result
<ul>
<li>
<a href="#h1-heading-8-)">h1 Heading 8-)</a>
</li>
</ul>
<h1 id="h1-heading-8-)">h1 Heading <img class="emoji" draggable="false" alt="😎" src="https://twemoji.maxcdn.com/2/72x72/1f60e.png"></h1>
OR
Expected result
<ul>
<li>
<a href="#h1-heading">h1 Heading 8-)</a>
</li>
</ul>
<h1 id="h1-heading">h1 Heading <img class="emoji" draggable="false" alt="😎" src="https://twemoji.maxcdn.com/2/72x72/1f60e.png"></h1>
Actual result
<ul>
<li>
<a href="#h1-heading-8-)">h1 Heading 8-)</a>
</li>
</ul>
<h1 id="h1-heading">h1 Heading <img class="emoji" draggable="false" alt="😎" src="https://twemoji.maxcdn.com/2/72x72/1f60e.png"></h1>
It would be nice to have this functionality to allow more detailed and customized tocs.
Example:
md.use(require('markdown-it-table-of-contents'), {
includeLevel: [2, 3]
})
Expected output:
- h2
- h3
- h3
- h2
- h3
- h3
Hi I was wondering if it is possible to add an option to add attributes to the list in the TOC
i.e. add a default listAttrs: ''
--- around line 28 ---, and replace current line 181 for return '<' + options.listType + ' ' + options.listAttrs +'>' + tocItem.children.map(childItem => {
or something similar
example:
# My **bold** title
should render as:
<li>My <strong>bold</strong> title</li>
does render as:
<li>My **bold** title</li>
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.