/* Bludit ToC Plugin — toc.js Reads config from window.BLTOC (injected inline by plugin.php). No dependencies; works with any Bludit theme that wraps the article body in a .content element (Bludit's default page template does this). */ (function () { 'use strict'; var cfg = window.BLTOC || {}; var TITLE = cfg.title || 'On this page'; var NAVBAR_HEIGHT = cfg.navbarHeight != null ? cfg.navbarHeight : 80; var MIN_WIDTH = cfg.minWidth != null ? cfg.minWidth : 1280; /* ---- Inject the dynamic min-width media query for the sidebar ---- */ var styleEl = document.createElement('style'); styleEl.textContent = '@media (min-width: ' + MIN_WIDTH + 'px) { .bltoc-sidebar.bltoc-ready { display: block; } }' + '@media (max-width: ' + (MIN_WIDTH - 1) + 'px) { .bltoc-fab.bltoc-ready { display: flex; } }'; document.head.appendChild(styleEl); /* ---- Find the article content area ---- */ var content = document.querySelector('.content') || document.querySelector('article .entry-content') || document.querySelector('.entry-content') || document.querySelector('.post-content') || document.querySelector('article') || document.querySelector('main'); if (!content) return; /* ---- Collect headings ---- */ var headings = content.querySelectorAll('h2, h3, h4'); if (!headings.length) return; /* ---- Assign stable IDs to any heading that lacks one ---- */ var usedIds = {}; Array.prototype.forEach.call(headings, function (h) { if (h.id) { usedIds[h.id] = true; } else { var base = h.textContent.trim().toLowerCase() .replace(/[^a-z0-9\s-]/g, '') .replace(/\s+/g, '-') .replace(/^-+|-+$/g, '') || 'heading'; var id = base, n = 2; while (usedIds[id]) { id = base + '-' + (n++); } usedIds[id] = true; h.id = id; } /* Offset anchor jumps so the heading clears the fixed navbar */ h.style.scrollMarginTop = NAVBAR_HEIGHT + 'px'; }); /* ---- Build the