Monsieur Zartosht

Monsieur Zartosht

Who am I?

A very simple blog that belongs to a very simple full-stack web developer about his daily life and struggles through coding. here you will find many things such as music, movies, and code (lots of codes!)


What I write about


Recent Posts

Auto generate table of contents for blogs

Do you ever wanted to have a table of contents for your blog posts? had a list of all topics that every link had its anchor? sounds nice? continue on reading then.

Table of contents

    Hi,

    Some days earlier I come across an idea to have a table of contents for my blog posts (if you already readen those, you know that I write a lot!). Imagine that all headings in your blog post extracted and all of them are linked to the appropriated heading! Magical?!

    If you are those kinds of programmers that just want to get the job done and not knowing how the job went done, skip to the last paragraph!

    Extracting all the headings from a DOM element

    The idea is that we have an HTML DOM filled with lots of elements (p, li, div, etc...). to get an element type you have to use tagName property of an element.

    var paragraph = document.getElementById("paragraph");
    console.log(paragraph.tagName);
    
    // output:
    // P

    Now, all we have to do is find a way to navigate through all elements in a DOM element! or achieving that I used document.getElementsByTagName("*"). the result is an array filled with every element on page!

    But we want to get all elements that are children of another element that holds blog post content and not all the headings that are presented on the page. for this first wrap your blog post inside a wrapper with a unique identifier, like postWrapper!

    <div class="postWrapper">
        ...
    </div>
    
    <script>
        var all = document.getElementsByClassName("postWrapper")[0].getElementsByTagName("*");
    </script>

    OR

    <div id="postWrapper">
        ...
    </div>
    
    <script>
        var all = document.getElementById("postWrapper").getElementsByTagName("*");
    </script>

    This all variable now is a collection of all children of that scope.

    Looping through extracted elements

    Now with that collection in hand, all we have to do is to loop through, so let's go loop!

    for (var i = 0; i < all.length; i++) {
        console.log(all[i]);
    }

    Use a simple switch to modify the desired elements. In this case: h1, h2, h3, h4, h5, h6.

    var output = "";
    for (var i = 0; i < all.length; i++) {
        switch (all[i].tagName) {
            case "H1":
                output += `<li class="my-1"><a href="#toc_${i}">${all[i].innerText}</a></li>`;
                all[i].setAttribute("id", `toc_${i}`);
                break;
            case "H2":
                output += `<li class="my-2"><a href="#toc_${i}">${all[i].innerText}</a></li>`;
                all[i].setAttribute("id", `toc_${i}`);
                break;
            case "H3":
                output += `<li class="my-3"><a href="#toc_${i}">${all[i].innerText}</a></li>`;
                all[i].setAttribute("id", `toc_${i}`);
                break;
            case "H4":
                output += `<li class="my-4"><a href="#toc_${i}">${all[i].innerText}</a></li>`;
                all[i].setAttribute("id", `toc_${i}`);
                break;
            case "H5":
                output += `<li class="my-5"><a href="#toc_${i}">${all[i].innerText}</a></li>`;
                all[i].setAttribute("id", `toc_${i}`);
                break;
            case "H6":
                output += `<li class="my-6"><a href="#toc_${i}">${all[i].innerText}</a></li>`;
                all[i].setAttribute("id", `toc_${i}`);
                break;
        }
    }

    In each case, I linked that to the ID that I set to the linked Heading! now you can put this output inside a ul or ol element and get yourself a nice looking Table of contents!

    Styling

    I already added some CSS classes to add padding to lower headings.

    Closing the case

    I made all of that inside a package and uploaded it to my Github account, you can Download it from here! or clone it:

    git clone https://github.com/zartosht/toc-creator.git

    How to use the package

    1. Add javascript and CSS your page. It doesn't require jQuery, so there is no need to require it after jQuery.
    <link rel="stylesheet" href="css/toc.css"/>
    <script src="js/toc.js"></script>
    1. Create an element with type of ul and add data-toc-creator to it:
    <ul data-toc-creator></ul>
    1. Find Unique Class name for your blog post wrapper. In the following example, this unique class name is markdown-body.
    <div class="markdown-body">
        ...
        <div class="post">
            <h2>Titr</h2>
            <div>CONTENT</div>
            ...
        </div>
        ...
    </div>
    1. In your Javascript code make add this:

    Without jQuery

    document.addEventListener("DOMContentLoaded", function(event){
        new TocCreator({
            scope: "markdown-body"
        })
    })

    With jQuery

    $(document).ready(function(){
        new TocCreator({
            scope: "markdown-body"
        })
    })

    Also, there is a scss file included if you wanted to change styles.

    Hope it helped!


    Posted in Front-end , Javascript , Web on by

    Share this post: