Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Shared/Article Rendering/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,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: <sup><a href="#fn…">. Substack-style: a bare
// <a id="footnote-anchor-N" href="#footnote-N"> with no <sup> 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");
}
Expand Down
41 changes: 35 additions & 6 deletions Shared/Article Rendering/newsfoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,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 <a id="footnote-anchor-N" href="#footnote-N">
// points at a backlink <a id="footnote-N">N</a> 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;
}
}
];
Expand All @@ -138,22 +163,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
Expand Down
Loading