Download
We're evolving to serve you better! This current forum has transitioned to read-only mode. For new discussions, support, and engagement, we've moved to GitHub Discussions.

“Improve” the table of contents generator

  • #4953
    Avatar photo[anonymous]

    Hello everyone, happy new year.

    I was wondering if it would be possible for them to add the html details and summary tags to generate the table of contents within the article. I do not know if it contributes any semantic value to the structure (I am not an expert) the plus of hiding and expanding the content of the toc is a good thing and with a little css it could be styled to give it a better visual appearance.

    <summary>: The Disclosure Summary element

    I did this example in codepen

    If this is not possible, could you tell me which files I should modify to implement it on my own.

    Thank you.

    #4986
    Avatar photo[anonymous]

    In your theme templates. For example, post.hbs.

    #4988
    Avatar photo[anonymous]

    Hi cumlaude, happpy new year to you too!

    Curiously, this very morning I found myself in the same situation as yours,  looking for a way to restyle my blog’s tables of content and make them more semantically meaningful.

    Beware that this is a quick and dirty solution…The proper way would be to attach some script to the rendering process that wold be notified when the toc is being renderend thus being able to change its layout. Actually I don’t know if that’s even possible yet!

    So here it goes…

    Provided that you already have your “default” toc placed inside your posts, you can change your post.hbs file and do the following:

    <!-- Replace the following -->
    {{{ text }}}
    
    <!-- With this -->
    {{{ addCustomToc text }}}

    add then, append the “addCustomToc” helper code to your helpers.js file as follows:

    /*
     * Custom theme helpers for Handlebars.js
     */
    
    const htmlParser = require("node-html-parser");
    
    let themeHelpers = {
      addCustomToc: function (postHtml) {
        const parsedHtml = htmlParser.parse(postHtml);
        const defaultToc = parsedHtml.querySelector(".post__toc");
        defaultToc.insertAdjacentHTML("afterend", customTocHtml(defaultToc).toString());
        defaultToc.remove();
        return parsedHtml.toString();
      }
    };
    
    const customTocHtml = function (defaultToc) {
      const summary = defaultToc.querySelector("h3")
        ? ` 
          <summary class="toc__sumary" title="Click to expand">
              ${defaultToc.querySelector("h3").toString()}
          </summary>
        `
        : "";
      return `
          <nav class="toc">
          <details>
            ${summary}
            <ol>
              ${defaultToc
                .querySelectorAll("li")
                .map((item) => {
                  return `
      ${ item.rawText }
    `; }) .join("")} </ol> </details> </nav> `; }; module.exports = themeHelpers;
    #4990
    Avatar photo[anonymous]
    const customTocHtml = function (defaultToc) {
      const summary = defaultToc.querySelector("h3")
        ? ` 
          <summary class="toc__sumary" title="Click to expand">
              ${defaultToc.querySelector("h3").toString()}
          </summary>
        `
        : "";
      return `
          <nav class="toc">
          <details>
            ${summary}
            <ol>
              ${defaultToc
                .querySelectorAll("li")
                .map((item) => {
                  return `
  • ${ item.rawText }
  • `; }) .join("")} </ol> </details> </nav> `; };

    This is correct…😅

#4996
Avatar photo[anonymous]

That seems like an overly complicated solution. If you want your toc to be inside a <details> element, edit the template .hbs file where that toc appears. I don’t have a theme that generates a toc, so I’m guessing that there’s a handlebars tag of some sort, maybe {{ toc }}? So if your template is currently

{{ toc }}

change it to this:

<details>
  <summary>view table of contents</summary>
  {{ toc }}
</details>

That’s really all you need to do. If your template has more granular control, say something like this which I found in a “knowledge based theme”:

<h2>table of contents</h2> {{ toc }}

then change it to this:

<details class="post__toc">
  <summary>table of contents</summary>
  {{ toc }}
</details>

If the handlebars table-of-contents tag is different, or if your template is different, you can almost certainly adapt it to a <details> element. Feel free to show what is currently in your .hbs files that generates the toc and I’ll have a look.

#5057
Avatar photo[anonymous]
[anonymous] wrote:

That seems like an overly complicated solution. If you want your toc to be inside a <details> element, edit the template .hbs file where that toc appears. I don’t have a theme that generates a toc, so I’m guessing that there’s a handlebars tag of some sort, maybe {{ toc }}? So if your template is currently

<span class=”enlighter-g1″><</span><span class=”enlighter-text”>div</span><span class=”enlighter-g1″>></span>
<span class=”enlighter-g1″>{{</span><span class=”enlighter-text”> toc </span><span class=”enlighter-g1″>}}</span>
<span class=”enlighter-g1″><</span><span class=”enlighter-text”>/div</span><span class=”enlighter-g1″>></span>
{{ toc }}
{{ toc }}

change it to this:

<span class=”enlighter-g1″><</span><span class=”enlighter-text”>details</span><span class=”enlighter-g1″>></span>
<span class=”enlighter-g1″><</span><span class=”enlighter-text”>summary</span><span class=”enlighter-g1″>></span><span class=”enlighter-text”>view table </span><span class=”enlighter-k1″>of</span><span class=”enlighter-text”> contents</span><span class=”enlighter-g1″><</span><span class=”enlighter-text”>/summary</span><span class=”enlighter-g1″>></span>
<span class=”enlighter-g1″>{{</span><span class=”enlighter-text”> toc </span><span class=”enlighter-g1″>}}</span>
<span class=”enlighter-g1″><</span><span class=”enlighter-text”>/details</span><span class=”enlighter-g1″>></span>
<details> <summary>view table of contents</summary> {{ toc }} </details>

<details> <summary>view table of contents</summary> {{ toc }} </details> That’s really all you need to do. If your template has more granular control, say something like this which I found in a “knowledge based theme”:

<span class=”enlighter-g1″><</span><span class=”enlighter-text”>div </span><span class=”enlighter-k1″>class</span><span class=”enlighter-text”>=</span><span class=”enlighter-s0″>”post__toc”</span><span class=”enlighter-g1″>></span>
<span class=”enlighter-g1″><</span><span class=”enlighter-text”>h2</span><span class=”enlighter-g1″>></span><span class=”enlighter-text”>table </span><span class=”enlighter-k1″>of</span><span class=”enlighter-text”> contents</span><span class=”enlighter-g1″><</span><span class=”enlighter-text”>/h2</span><span class=”enlighter-g1″>></span>
<span class=”enlighter-g1″>{{</span><span class=”enlighter-text”> toc </span><span class=”enlighter-g1″>}}</span>
<span class=”enlighter-g1″><</span><span class=”enlighter-text”>/div</span><span class=”enlighter-g1″>></span>
<h2>table of contents</h2> {{ toc }}
<h2>table of contents</h2> {{ toc }}

then change it to this:

<span class=”enlighter-g1″><</span><span class=”enlighter-text”>details </span><span class=”enlighter-k1″>class</span><span class=”enlighter-text”>=</span><span class=”enlighter-s0″>”post__toc”</span><span class=”enlighter-g1″>></span>
<span class=”enlighter-g1″><</span><span class=”enlighter-text”>summary</span><span class=”enlighter-g1″>></span><span class=”enlighter-text”>table </span><span class=”enlighter-k1″>of</span><span class=”enlighter-text”> contents</span><span class=”enlighter-g1″><</span><span class=”enlighter-text”>/summary</span><span class=”enlighter-g1″>></span>
<span class=”enlighter-g1″>{{</span><span class=”enlighter-text”> toc </span><span class=”enlighter-g1″>}}</span>
<span class=”enlighter-g1″><</span><span class=”enlighter-text”>/details</span><span class=”enlighter-g1″>></span>
<details class=”post__toc”> <summary>table of contents</summary> {{ toc }} </details>

<details class=”post__toc”> <summary>table of contents</summary> {{ toc }} </details> If the handlebars table-of-contents tag is different, or if your template is different, you can almost certainly adapt it to a <details> element. Feel free to show what is currently in your .hbs files that generates the toc and I’ll have a look.

I use the TechNews theme, I searched all the hbs files and found nothing that refers to the tables of contents. I guess it’s Publii’s core that generates that element.

Thanks for your answers.

#5058
Avatar photoBob

The TOC is generated by Tiny WYSIWYG and by Block Editor, there is no easy way to change its structure. @ kettleblaze shows how this can be done.

An ordered list is the right and semantic HTML element used to generate the table of contents; I really don’t see any benefit in changing its HTML structure.