jonschlinkert / markdown-toc

API and CLI for generating a markdown TOC (table of contents) for a README or any markdown files. Uses Remarkable to parse markdown. Used by NASA/openmct, Prisma, Joi, Mocha, Sass, Prettier, Orbit DB, FormatJS, Raneto, hapijs/code, webpack-flow, docusaurus, release-it, ts-loader, json-server, reactfire, bunyan, husky, react-easy-state, react-snap, chakra-ui, carbon, alfresco, repolinter, Assemble, Verb, and thousands of other projects.
https://github.com/jonschlinkert
MIT License
1.66k stars 710 forks source link

Need example for custom TOC #106

Open flamusdiu opened 7 years ago

flamusdiu commented 7 years ago

I am creating a custom TOC to fix #104 for me; however, it's not that easy.

var toc = require('markdown-toc');
var md = '# heading\n## heading 2\n### heading 3';
var result = toc(md); // links are incorrect in the toc for Angular

var correct_toc = [];
result.json.forEach(function(h) {
    // fixed h.content
    correct_toc.push(new_h);
}

var toc_md = toc.bullets(correct_toc)
var toc = require('markdown-toc');

This fails due to https://github.com/jonschlinkert/markdown-toc/blob/e10f43ed5b38bc5c3fa87bbeedeaf9825898d33b/index.js#L156-L157

Calling the function, toc.bullets() directly doesn't work for me unless I remove L156 and change lvl to ele.i then it work.

I think an example or something documented to show how to actually create custom TOCs.

doowb commented 7 years ago

try changing this line:

var toc_md = toc.bullets(correct_toc);

to:

var toc_md = toc.bullets(correct_toc, {highest: result.highest});

What might be easier is to pass a custom linkify function on the options and create the links however you want.

var result = toc(md, {
  linkify: function(tok, text, slug options) {
    // update tok.content to how you want it
    tok.content = `[${text}](something/#${slug})`;
    return tok;
  }
});

I'm going to leave this opened for now as a reminder to document the linkify option.

flamusdiu commented 7 years ago

Ahh, that's much easier. Why does it strip spaces in the title but then when you slugify it, it adds the dashes at for the empty spaces? For example: Heading <a href="heading"></a> gives a title of Heading but a slug of heading-- due to the extra spaces after the title.

flamusdiu commented 7 years ago

This is what I have from what you pointed out:

var result = toc('# me  <a href="me"></a>\n## me two\n### me three', {
 linkify: function(tok, text, slug, options) {
    const regex = /(.+\b)(.*)$/

    slug = slug.replace(regex, function(str, g1) { return g1; });
    tok.content = `[${text}](/articles#${slug})`;
    return tok;
 }
});
flamusdiu commented 7 years ago

So, that fixes the links but still doesn't work for Angular. I guess I need a custom renderer to add the proper syntax for the a tags.

flamusdiu commented 7 years ago

I ended up just changing the rules:

md.renderer.rules.link_open = function(tokens, idx, options /* env */) {
  var title = tokens[idx].title ? (' title="' + Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(tokens[idx].title)) + '"') : '';
  var target = options.linkTarget ? (' target="' + options.linkTarget + '"') : '';

  return '<a [routerLink]="[\'/articles\']" fragment="' + Remarkable.utils.escapeHtml(tokens[idx].href.substr(1)) + '"' + title + target + '>';
};

Still doesn't work but it's an Angular issue atm.

flamusdiu commented 7 years ago

Just a note: I ended up using <a data-link="my-frag">My Link Text</a> and a custom onClick method to use the Angular Router process to get to the right page locations. I would think it would be easier with Angular.

adamsoffer commented 4 years ago

json rendering ignore options :(