2024-06-16 Show Table of Contents

I just finished this bookmarklet to dynamically insert a table of contents for pages that don't have one. Mostly for my own blog, to be honest.

Feel free to copy and paste from here into the URL of a bookmark.

1. bookmark this page

2. edit the properties of the new bookmark

3. change the name to “Show TOC”

4. change the location to the Javascript URL below

5. done!

Javascript URL to use:

javascript:(function(){const%20sn=document.evaluate('//h2|//h3|//h4|//h5|//h6',document.getRootNode(),null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);let%20s=[null,document.createElement('ul')];sn.snapshotItem(0).previousElementSibling.after(s.at(-1));let%20i=0;while(n=sn.snapshotItem(i++)){const%20d=n.tagName.charAt(1);if(d>s.length){const%20ul=document.createElement('ul');s.at(-1).appendChild(ul);s.push(ul);}while(d<s.length){s.pop()}const%20li=document.createElement('li');s.at(-1).appendChild(li);if(!n.hasAttribute('id'))n.setAttribute('id','__toc_'+i);const%20t=document.createElement('a');t.appendChild(document.createTextNode(n.textContent));t.setAttribute('href','#'+n.getAttribute('id'));li.appendChild(t);}})()

This is what it looks like:

javascript:(function() {
  const sn = document.evaluate('//h2|//h3|//h4|//h5|//h6', document.getRootNode(), null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  let s = [null, document.createElement('ul')];
  sn.snapshotItem(0).previousElementSibling.after(s.at(-1));
  let i = 0;
  while (n=sn.snapshotItem(i++)) {
    const d = n.tagName.charAt(1);
    if (d > s.length) {
      const ul = document.createElement('ul');
      s.at(-1).appendChild(ul);
      s.push(ul);
    }
    while (d < s.length) {
      s.pop()
    }
    const li = document.createElement('li');
    s.at(-1).appendChild(li);
    if (!n.hasAttribute('id')) {
      n.setAttribute('id', '__toc_' + i);
    }
    const t = document.createElement('a');
    t.appendChild(document.createTextNode(n.textContent));
    t.setAttribute('href', '#' + n.getAttribute('id'));
    li.appendChild(t);
  }
})()

​#Bookmarklet