diff --git a/Shared/Article Rendering/main.js b/Shared/Article Rendering/main.js index 4edbac86b7..73bbca4df7 100644 --- a/Shared/Article Rendering/main.js +++ b/Shared/Article Rendering/main.js @@ -171,11 +171,13 @@ function error() { // Takes into account absoluting of URLs. function isLocalFootnote(target) { - return target.hash.startsWith("#fn") && target.href.indexOf(document.baseURI) === 0; + return (target.hash.startsWith("#fn") || target.hash.startsWith("#footnote")) && target.href.indexOf(document.baseURI) === 0; } function styleLocalFootnotes() { - for (elem of document.querySelectorAll("sup > a[href*='#fn'], sup > div > a[href*='#fn']")) { + // Multimarkdown-style: . Substack-style: a bare + // with no wrapper. + for (elem of document.querySelectorAll("sup > a[href*='#fn'], sup > div > a[href*='#fn'], a[id^='footnote-anchor-']")) { if (isLocalFootnote(elem)) { elem.classList.add("footnote"); } diff --git a/Shared/Article Rendering/newsfoot.js b/Shared/Article Rendering/newsfoot.js index 9f1dae3f6d..765c06bd04 100644 --- a/Shared/Article Rendering/newsfoot.js +++ b/Shared/Article Rendering/newsfoot.js @@ -125,12 +125,37 @@ if (!target.hash) return; return decodeURIComponent(target.hash.substring(1)); } - /** @type {{fnref(target:HTMLAnchorElement): string|undefined}[]} */ + /** + * @type {{ + * fnref(target:HTMLAnchorElement): string|undefined, + * content(targetElement:HTMLElement): string + * }[]} + */ const footnoteFormats = [ + { // Substack: the ref + // points at a backlink N whose note text lives + // in the sibling elements that follow it, not inside the anchor. + fnref(target) { + if (!target.matches("a[id^='footnote-anchor-']")) return; + return idFromHash(target); + }, + content(targetElement) { + let html = ""; + let node = targetElement.nextElementSibling; + while (node && !node.matches("a[id^='footnote-']")) { + html += node.outerHTML; + node = node.nextElementSibling; + } + return html; + } + }, { // Multimarkdown fnref(target) { if (!target.matches(".footnote")) return; return idFromHash(target); + }, + content(targetElement) { + return targetElement.innerHTML; } } ]; @@ -140,22 +165,26 @@ if (!(ev.target && ev.target instanceof HTMLAnchorElement)) return; let targetId = undefined; + let format = undefined; for(const f of footnoteFormats) { targetId = f.fnref(ev.target); - if (targetId) break; + if (targetId) { + format = f; + break; + } } if (targetId === undefined) return; - + // Only override the default behaviour when we know we can find the // target element const targetElement = document.getElementById(targetId); if (targetElement === null) return; - + ev.preventDefault(); installContainer(ev.target); - - void new Footnote(targetElement.innerHTML, ev.target); + + void new Footnote(format.content(targetElement), ev.target); }); // Handle clicks on the footnote reverse link