Created
October 28, 2021 07:44
-
-
Save Sebas-h/66ba95ba016b22335936c9bcb419622f to your computer and use it in GitHub Desktop.
Userscript - mdBook Page ToC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function populatePageToc() { | |
// Source: https://github.com/JorelAli/mdBook-pagetoc | |
// Modified: | |
// Un-active everything when you click it | |
Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function (el) { | |
el.addEventHandler("click", function () { | |
Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function (el) { | |
el.classList.remove("active"); | |
}); | |
el.classList.add("active"); | |
}); | |
}); | |
var updateFunction = function () { | |
var id; | |
var elements = document.getElementsByClassName("header"); | |
Array.prototype.forEach.call(elements, function (el) { | |
if (window.pageYOffset >= el.offsetTop) { | |
id = el; | |
} | |
}); | |
Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function (el) { | |
el.classList.remove("active"); | |
}); | |
Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function (el) { | |
if (id.href.localeCompare(el.href) == 0) { | |
el.classList.add("active"); | |
} | |
}); | |
}; | |
// Populate sidebar on load | |
function populate() { | |
var pagetoc = document.getElementsByClassName("pagetoc")[0]; | |
var elements = document.getElementsByClassName("header"); | |
Array.prototype.forEach.call(elements, function (el) { | |
var link = document.createElement("a"); | |
// Indent shows hierarchy | |
var indent = ""; | |
switch (el.parentElement.tagName) { | |
case "H2": | |
indent = "20px"; | |
break; | |
case "H3": | |
indent = "40px"; | |
break; | |
case "H4": | |
indent = "60px"; | |
break; | |
case "H5": | |
indent = "80px"; | |
break; | |
default: | |
break; | |
} | |
link.appendChild(document.createTextNode(el.text)); | |
link.style.paddingLeft = indent; | |
link.href = el.href; | |
pagetoc.appendChild(link); | |
}); | |
updateFunction.call(); | |
} | |
// window.addEventListener('load', populate); | |
populate(); // For Firefox | |
// Handle active elements on scroll | |
window.addEventListener("scroll", updateFunction); | |
} | |
// Source: https://github.com/JorelAli/mdBook-pagetoc | |
// Modified: | |
const css = ` | |
@media only screen and (max-width:1110px) { | |
.sidetoc { | |
display: none; | |
} | |
} | |
@media only screen and (min-width:440px) { | |
main { | |
position: relative; | |
} | |
.sidetoc { | |
margin-left: auto; | |
margin-right: auto; | |
left: calc(100% + (var(--content-max-width))/4 - 140px); | |
position: absolute; | |
} | |
.pagetoc { | |
position: fixed; | |
width: 300px; | |
height: calc(100vh - var(--menu-bar-height) - 0.67em * 6); | |
overflow: auto; | |
} | |
.pagetoc a { | |
border-left: 1px solid var(--sidebar-bg); | |
color: var(--fg) !important; | |
display: block; | |
padding-bottom: 5px; | |
padding-top: 5px; | |
padding-left: 10px; | |
text-align: left; | |
text-decoration: none; | |
} | |
.pagetoc a:hover, | |
.pagetoc a.active { | |
background: var(--sidebar-bg); | |
color: var(--sidebar-fg) !important; | |
} | |
.pagetoc .active { | |
background: var(--sidebar-bg); | |
color: var(--sidebar-fg); | |
} | |
} | |
.custom-btn { | |
text-decoration: none; | |
display: inline-block; | |
padding-left: 8px; | |
padding-right: 8px; | |
border-radius: 12px; | |
cursor: pointer; | |
} | |
.custom-btn:hover { | |
background-color:gray; | |
} | |
`; | |
(function () { | |
'use strict'; | |
// Add style sheet to page | |
let head = document.head || document.getElementsByTagName('head')[0]; | |
let style = document.createElement('style'); | |
head.appendChild(style); | |
style.appendChild(document.createTextNode(css)); | |
// Add nested divs to be populated with headers | |
let pageToc = document.createElement("nav"); | |
pageToc.className = "pagetoc"; | |
let sideNav = document.createElement("div"); | |
sideNav.className = "sidetoc"; | |
sideNav.appendChild(pageToc) | |
let mainEl = document.getElementsByTagName("main")[0]; | |
mainEl.insertBefore(sideNav, mainEl.firstChild); | |
// Run code to extract page headers, populate the page toc and activate | |
// event listener to highlight correct page toc item. | |
populatePageToc() | |
// Disable big nav buttons | |
// (i.e. <nav class="nav-wide-wrapper" aria-label="Page navigation">) | |
let bigNavElement = document.querySelectorAll('nav.nav-wide-wrapper')[0]; | |
bigNavElement.style.display = "none"; | |
// Extract previous and next href links: | |
const prevHref = document.querySelectorAll('a.nav-chapters.previous')[0].href; | |
const nextHref = document.querySelectorAll('a.nav-chapters.next')[0].href; | |
// Remove left side big margin | |
mainEl.style.marginLeft = 0; | |
// Create 'Previous' Chapter Button | |
let prevEl = document.createElement("a"); | |
prevEl.className = "custom-btn"; | |
prevEl.innerText = "<"; | |
prevEl.setAttribute("href", prevHref || "") | |
// Create 'Next' Chapter Button | |
let nextEl = document.createElement("a"); | |
nextEl.className = "custom-btn"; | |
nextEl.innerText = ">"; | |
nextEl.setAttribute("href", nextHref || "") | |
// Add Prev and Next to title bar | |
let titleEl = document.getElementsByClassName("menu-title")[0]; | |
titleEl.insertBefore(prevEl, titleEl.firstChild); | |
titleEl.appendChild(nextEl); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Screenshot
Source
ToC CSS and JS to populate it comes from this mdBook plugin:
https://github.com/JorelAli/mdBook-pagetoc
Used with Tampermokey
Chromium-based browsers
Enable this option in the extension's settings:
Firefox
I believe it is not possible to open a local file like this in Firefox so
@require
won't work.Remove the
@require
comment/tag in from the userscript in Tampermokey and simply copy and paste thejs
code into the Tampermokey script directly.When does Tampermokey run the script
By default
The script will be injected after the DOMContentLoaded event was dispatched
.See: https://www.tampermonkey.net/documentation.php#_run_at
Tweaks
max-width
andmin-width
values to match your display properties.