Automatic footnote generation with jQuery


In my recent article about scale invariance, I needed some footnotes. The requirement was that as result in the text a number should appear which links to the bottom of the page1 where the user can find the content of the footnote. As a small gimmick, I wanted a small tooltip to appear if the user hovers over the footnote link so that the content of the footnote is visible without moving to the bottom of the page. I didn't want to do the footnote generation (numbering, linking etc.) by hand, so I wrote a small jQuery-script to do the job for me.

From the editors perspective, it should be similar to \(\LaTeX\): the footnote is directly written in the code where it should appear. More precisely, I used a span element to mark the footnote. An example usage could be as follow


<p>
    This is a paragraph with a footnote
    <span class="footnote">
        Further information visible in the footnote.
    </span>
</p>

If this is the first occurrence of a footnote in the document, my script would transfer it to something like


<p>
    This is a paragraph with a footnote
    <span class="footnote">
        <sup>
            <a href="#ftn_1_1">1</a>
        </sup>
    </span>
</p>

Two numbers are part of the ID: the first 1 notes that this is the first footnote on the current page and the second 1 notes that it is the first footnote in the current article. This is required to make footnotes unique when multiple articles are shown on the same page. The sup tag (superscript) is responsible for setting the element raised up. A link tag is inserted which points to a location at the bottom of the page. The footnote text itself is gone and moved also to the bottom of the page, which in turn looks like


<hr>
<sup id="ftn_1_1">
    1. Further information visible in the footnote.
</sup>
<br>

An hr line separates the text from the footnotes. The footnote itself is just again a sup tag with the id as the target location for the link. The br tag allows having multiple footnotes in the text which would appear underneath each other at the bottom of the page.

Next to the script which generates the previous html snippets:


$(document).ready(function () {                                         // Proceed further when all necessary information is loaded
    var ctnFootnotesGlobal = 1;

    $("article div.entry").each(function () {                           // Handle each article individually
        var ctnFootnotes = 1;                                           // Counter for the footnotes inside the current article
        $(this).find("span.footnote").each(function () {                // Traverse through each footnote element inside the article
            var id = "ftn_" + ctnFootnotesGlobal + "_" + ctnFootnotes;  // Automatic id generation for the links
            var html = $(this).html();                                  // Content of the footnote element (contains the footnote text)

            if (ctnFootnotes === 1) {
                $(this).parents(".entry").append("<hr />");             // Add a horizontal line before the first footnote after the article text (only for the article where the span element is located)
            }

            $(this).html("<sup><a href='#" + id + "'>" + ctnFootnotes + "</a></sup>");                                  // Add the footnote number to the text
            $(this).parents(".entry").append("<sup id='" + id + "'>" + ctnFootnotes + ". " + html + "</sup><br />");    // Add the footnote text to the bottom of the current article

            /* Show tooltip on mouse hover (https://www.alessioatzeni.com/blog/simple-tooltip-with-jquery-only-text) */
            $(this).hover(function () {               // Hover in
                var $tooltip = $("<p class='tooltip'></p>");
                $tooltip.html(html).appendTo("body").fadeIn("slow");        // Add paragraph
                MathJax.Hub.Queue(["Typeset", MathJax.Hub, $tooltip[0]]);   // Re-run MathJax typesetting on the new element
            }, function () {                          // Hover out
                $(".tooltip").fadeOut().remove();     // Remove paragraph
            }).mousemove(function (e) {               // Move the box with the mouse while still hovering over the link
                var mouseX = e.pageX + 20;            // Get X coordinates
                var mouseY = e.pageY + 10;            // Get Y coordinates
                $(".tooltip").css({top: mouseY, left: mouseX});
            });

            ctnFootnotes++;
            ctnFootnotesGlobal++;
        });
    });
});

Basically, each footnote is processed by putting the content in the bottom of the current article and adjusting the links. The .entry class points to a div containing all the blog content (on this website). The div container is located relative to the current span element so that it doesn't affect other articles.

The hover part is inspired by Alessio Atzeni and adds a paragraph whenever the user hovers with the mouse over the link element (the number) by position it at the current mouse location. If the mouse hovers no longer over the link, the paragraph will be removed. There is also some small css formatting to let the paragraph look like a box:


.tooltip {
    display: none;
    position: absolute;
    border: 1px solid #333;
    background-color: #eee;
    border-radius: 5px;
    padding: 2px 7px 2px 7px;
    box-shadow: 2px 2px 10px #999;
}

You might think: why not using the title attribute of the link? It would show the footnote content in a standard browser box. It is easily done by just adding title='" + $(this).text() + "' to the link element. This has the disadvantage though that links inside the footnote are not visible as links anymore (it just shows text) and so I decided against it.


1. Like this element here.