-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Table of contents #545
Comments
Just define custom renderer. Like this: var renderer = new marked.Renderer();
var toc = [];
renderer.heading = function(text, level, raw) {
var anchor = this.options.headerPrefix + raw.toLowerCase().replace(/[^\w]+/g, '-');
toc.push({
anchor: anchor,
level: level,
text: text
});
return '<h'
+ level
+ ' id="'
+ anchor
+ '">'
+ text
+ '</h'
+ level
+ '>\n';
};
marked.setOptions({
renderer: renderer
}); |
Worked great for me, thanks!
|
Closing as out of scope based on current focus. See #956 |
Those answers above, only support English, do not support Chinese.So I add some rules based on the example above: var anchor = this.options.headerPrefix + raw.toLowerCase().replace(/[^\w\\u4e00-\\u9fa5]]+/g, '-'); Hope it can help we Chinese. |
@UziTech and @Feder1co5oave: Check the pseudo PR from @yzfdjzwl. This intrigues me. I know I made the comment in #1043 about possibly deprecating the header |
Those answers above,do not support multi-level tree TOC. So I add some code based on the example above:
var toc = [];
var renderer = (function () {
var renderer = new marked.Renderer();
renderer.heading = function (text, level, raw) {
var anchor = this.options.headerPrefix + raw.toLowerCase().replace(/[^\w\\u4e00-\\u9fa5]]+/g, '-');
toc.push({
anchor: anchor,
level: level,
text: text
});
return '<h'
+ level
+ ' id="'
+ anchor
+ '">'
+ text
+ '</h'
+ level
+ '>\n'
+ '<a href="#table-of-contents">Table of Contents<a>\n';
};
return renderer;
})();
marked.setOptions({
renderer: renderer,
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: true,
smartLists: true,
smartypants: false
});
function build(coll, k, level, ctx) {
if (k >= coll.length || coll[k].level <= level) { return k; }
var node = coll[k];
ctx.push("<li><a href='#" + node.anchor + "'>" + node.text + "</a>");
k++;
var childCtx = [];
k = build(coll, k, node.level, childCtx);
if (childCtx.length > 0) {
ctx.push("<ul>");
childCtx.forEach(function (idm) {
ctx.push(idm);
});
ctx.push("</ul>");
}
ctx.push("</li>");
k = build(coll, k, level, ctx);
return k;
}
var html = marked(data);
var ctx = [];
ctx.push('<h1 id="table-of-contents">Table of Contents</h1>\n<ul>');
build(toc, 0, 0, ctx);
ctx.push("</ul>");
document.querySelector('#content').innerHTML = ctx.join("") + html; |
I've made a TOC solution where the javascript is less complicated but still supports nesting, at least visually. Javascript I did not need clickable headings, but if you need it, look at the first comment in this issue. const renderer = new marked.Renderer();
const r = {
heading: renderer.heading.bind(renderer),
};
let toc = [];
renderer.heading = (text, level, raw, slugger) => {
toc.push({
level: level,
text: text
});
return r.heading(text, level, raw, slugger);
}; I use Vue so I output the data in a template like this. <h3>Table of contents</h3>
<div class="list">
<component class="h" v-for="h, index in toc" :is="'h' + h.level" :key="index" :title="'h' + h.level">
{{ h.text }}
</component>
</div> SCSS The nesting is made with pure CSS (SCSS). The different heading tags have different margins. .list {
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: 13px;
font-weight: normal;
display: flex;
&:before {
width: 20px;
min-width: 20px;
display: block;
opacity: .5;
}
}
h1 {
&:before {
content: '1\00a0 ';
}
}
h2 {
&:before {
content: '2\00a0 ';
margin-right: 1rem;
}
}
h3 {
&:before {
content: '3\00a0 ';
margin-right: 2rem;
}
}
h4 {
&:before {
content: '4\00a0 ';
margin-right: 3rem;
}
}
h5 {
&:before {
content: '5\00a0 ';
margin-right: 4rem;
}
}
h6 {
&:before {
content: '6\00a0 ';
margin-right: 5rem;
}
}
} |
the last label a should be /a Otherwise, the following text parsing will be abnormal |
I usually don't need to change whole marked for table of contents (like sidebar with toc and all text rendered) This is an example on how to apply this toc on fly. If you have a div
|
Generate TOC with indentation import { marked } from 'marked';
function createToc(mdText: string) {
const stack = [document.createElement('ul')];
for (const heading of marked.lexer(mdText).filter(x => x.type === 'heading') as marked.Tokens.Heading[]) {
if (heading.depth < stack.length) {
stack.length = heading.depth;
} else {
while (heading.depth > stack.length) {
const ul = document.createElement('ul');
stack.at(-1).append(ul);
stack.push(ul);
}
}
const prefix = marked.getDefaults().headerPrefix || '';
const anchor = prefix + heading.text.replaceAll('.', '').replaceAll(' ', '-');
stack.at(-1).insertAdjacentHTML('beforeend', `<li><a href="#${anchor}">${heading.text}</a></li>`);
}
return stack[0];
} |
Is it possible to get a list of all headers in order to create a table of contents?
The text was updated successfully, but these errors were encountered: