cmaas / markdown-it-table-of-contents

A table of contents plugin for Markdown-it
MIT License
98 stars 33 forks source link

Add attributes to the TOC list #58

Closed nicofranzp closed 3 days ago

nicofranzp commented 2 years ago

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

cmaas commented 2 years ago

@nicofranzp Could you clarify which attributes you'd want to set to a list besides the class attribute?

nicofranzp commented 2 years ago

I thought it might be useful to have access to style and id

cmaas commented 2 years ago

🤔 hmm not sure about that. Lists are created recursively and listAttrs with an id would be applied to all lists, which doesn't make sense. Same with inline styles. They would be assigned to each list. Would this really be necessary or is it better to have a custom transform function for the container class and then target the rest via CSS selectors? This way, the API is way cleaner and can be understood better.

I think listClass and itemClass as options make sense, but more than that, I can't really see it. Would you actually need this in one of your projects and if so, why is there no other way to access or style lists in the TOC?

nicofranzp commented 2 years ago

What I ended up using is the following:

function tocItemToHtml(tocItem, options, md, counter = 0) {
  let extraAttributes = ''
  if (counter == 0){
    if (options.listAttrs !== '') { extraAttributes = ' ' + options.listAttrs }
  }
  return '<' + options.listType + extraAttributes + '>' + tocItem.children.map(childItem => {
    let li = '<li>';
    let anchor = childItem.anchor;
    if (options && options.transformLink) {
      anchor = options.transformLink(anchor);
    }

    let text = childItem.text ? options.format(childItem.text, md, anchor) : null;

    li += anchor ? `<a href="#${anchor}">${text}</a>` : (text || '');

    return li + (childItem.children.length > 0 ? tocItemToHtml(childItem, options, md, counter + 1) : '') + '</li>';
  }).join('') + '</' + options.listType + '>';
}

Which avoids adding the same attributes into sub-lists (and the unnecessary white space). Maybe this could be generalized to sublists, but there I understand the concern that the id would not be a goo idea

I had to get rid of the container since the people which I send the final HTML set that constraint. I don't know if that's to specific to be honest, haha

cmaas commented 2 years ago

That'd work, but before we talk about the actual implementation, please share more details about the scenario you wanna achieve.

What is the exact HTML output you desire? That would be your test case to test against.

Also, do you use markdown-it-table-of-contents in a dynamic context (JS on a website) or in a static context (JS used in a static site generator such as 11ty via node, which is my personal use case)?

nicofranzp commented 2 years ago

I use it in a static context (I use gulp to combine everything). The built HTML has to have a table of contents without container (which I ditch using md.renderer.rules.toc_open and close) and and set of classes and styles in the <ul> in particular:

<ul id="TOC" class="some clases" style="some styles">
    <li><a href="#S1">Section 1</a></li>
    <li><a href="#S2">Section 2</a></li>
   ...
</ul>
cmaas commented 3 days ago

I re-visited this issue and decided against it, because it gets quite confusing if you have several layers of <ul>s that would all be subject to custom formatting. There is now an option to modify the container element. Maybe this helps.