Original implementation was only aware of multimarkdown style footnote markup.

This commit includes support for DaringFireball style footnotes
This commit is contained in:
Andrew Brehaut 2019-09-26 20:20:53 +12:00
parent b721f74e17
commit f25c0e0b57
3 changed files with 86 additions and 30 deletions

View File

@ -225,10 +225,19 @@ img[src*="share-buttons"] {
margin-bottom: 0; margin-bottom: 0;
} }
.newsfoot-footnote-popover .reversefootnote { .newsfoot-footnote-popover .reversefootnote,
.newsfoot-footnote-popover .footnoteBackLink,
.newsfoot-footnote-popover .footnote-return {
display: none; display: none;
} }
a.footnote {
sup[id^='fn'] {
vertical-align: baseline;
}
a.footnote,
sup > a[href^='#fn'],
sup > div > a[href^='#fn'] {
display: inline-block; display: inline-block;
text-decoration: none; text-decoration: none;
padding: 0.05em 0.75em; padding: 0.05em 0.75em;
@ -257,13 +266,17 @@ a.footnote {
} }
body a.footnote, body a.footnote,
body a.footnote:visited, body a.footnote:visited,
.newsfoot-footnote-popover + a.footnote:hover { .newsfoot-footnote-popover + a.footnote:hover,
sup > a[href^='#fn'],
sup > div > a[href^='#fn'] {
background: #aaa; background: #aaa;
color: white; color: white;
transition: background-color 200ms ease-out; transition: background-color 200ms ease-out;
} }
a.footnote:hover, a.footnote:hover,
.newsfoot-footnote-popover + a.footnote { .newsfoot-footnote-popover + a.footnote,
sup > a[href^='#fn']:hover,
sup > div > a[href^='#fn']:hover {
background: #666; background: #666;
transition: background-color 200ms ease-out; transition: background-color 200ms ease-out;
} }
@ -284,13 +297,17 @@ a.footnote:hover,
} }
body a.footnote, body a.footnote,
body a.footnote:visited, body a.footnote:visited,
.newsfoot-footnote-popover + a.footnote:hover { .newsfoot-footnote-popover + a.footnote:hover,
sup > a[href^='#fn'],
sup > div > a[href^='#fn'] {
background: #aaa; background: #aaa;
color: white; color: white;
transition: background-color 200ms ease-out; transition: background-color 200ms ease-out;
} }
a.footnote:hover, a.footnote:hover,
.newsfoot-footnote-popover + a.footnote { .newsfoot-footnote-popover + a.footnote,
sup > a[href^='#fn']:hover,
sup > div > a[href^='#fn']:hover {
background: #666; background: #666;
transition: background-color 200ms ease-out; transition: background-color 200ms ease-out;
} }

View File

@ -1,5 +1,5 @@
// @ts-check
(function () { (function () {
// @ts-check
/** @param {Node | null} el */ /** @param {Node | null} el */
const remove = (el) => { if (el) el.parentElement.removeChild(el) }; const remove = (el) => { if (el) el.parentElement.removeChild(el) };
@ -33,7 +33,7 @@
const POPOVER_ARROW_CLS = `${clsPrefix}popover-arrow`; const POPOVER_ARROW_CLS = `${clsPrefix}popover-arrow`;
/** /**
* @param {Node} content * @param {string} content
* @returns {HTMLElement} * @returns {HTMLElement}
*/ */
function footnoteMarkup(content) { function footnoteMarkup(content) {
@ -42,13 +42,13 @@
const inner = newEl("div", POPOVER_INNER_CLS); const inner = newEl("div", POPOVER_INNER_CLS);
popover.appendChild(inner); popover.appendChild(inner);
popover.appendChild(arrow); popover.appendChild(arrow);
inner.appendChild(content); inner.innerHTML = content;
return popover; return popover;
} }
class Footnote { class Footnote {
/** /**
* @param {Node} content * @param {string} content
* @param {Element} fnref * @param {Element} fnref
*/ */
constructor(content, fnref) { constructor(content, fnref) {
@ -56,6 +56,8 @@
this.style = window.getComputedStyle(this.popover); this.style = window.getComputedStyle(this.popover);
this.fnref = fnref; this.fnref = fnref;
this.fnref.closest(`.${CONTAINER_CLS}`).insertBefore(this.popover, fnref); this.fnref.closest(`.${CONTAINER_CLS}`).insertBefore(this.popover, fnref);
/** @type {HTMLElement} */
this.arrow = this.popover.querySelector(`.${POPOVER_ARROW_CLS}`);
this.reposition(); this.reposition();
/** @type {(ev:MouseEvent) => void} */ /** @type {(ev:MouseEvent) => void} */
@ -101,17 +103,10 @@
offset = (popoverHalfWidth + marginLeft) - center; offset = (popoverHalfWidth + marginLeft) - center;
} }
this.popover.style.transform = `translate(${offset}px)`; this.popover.style.transform = `translate(${offset}px)`;
this.popover.querySelector(`.${POPOVER_ARROW_CLS}`).style.transform = `translate(${-offset}px) rotate(45deg)`; this.arrow.style.transform = `translate(${-offset}px) rotate(45deg)`;
} }
} }
/** @param {Node} n */
function fragFromContents(n) {
const frag = document.createDocumentFragment();
n.childNodes.forEach((ch) => frag.appendChild(ch));
return frag;
}
/** @param {HTMLAnchorElement} a */ /** @param {HTMLAnchorElement} a */
function installContainer(a) { function installContainer(a) {
if (!a.parentElement.matches(`.${CONTAINER_CLS}`)) { if (!a.parentElement.matches(`.${CONTAINER_CLS}`)) {
@ -120,23 +115,50 @@
container.appendChild(a); container.appendChild(a);
} }
} }
function idFromHash(target) {
if (!target.hash) return;
return target.hash.substring(1);
}
/** @type {{fnref(target:HTMLAnchorElement): string|undefined}[]} */
const footnoteFormats = [
{ // Multimarkdown
fnref(target) {
if (!target.matches(".footnote")) return;
return idFromHash(target);
}
},
{// Daring Fireball
fnref(target) {
if (!target.matches("sup > a[href^='#fn'], sup > div > a[href^='#fn']")) return;
return idFromHash(target);
}
}
];
// Handle clicks on the footnote reference // Handle clicks on the footnote reference
document.addEventListener("click", (ev) => { document.addEventListener("click", (ev) => {
if (!(ev.target && ev.target instanceof HTMLAnchorElement)) return; if (!(ev.target && ev.target instanceof HTMLAnchorElement)) return;
if (!ev.target.matches(".footnote")) return;
let targetId = undefined;
for(const f of footnoteFormats) {
targetId = f.fnref(ev.target);
if (targetId) break;
}
if (targetId === undefined) return;
ev.preventDefault(); ev.preventDefault();
const content = document.querySelector(`[id='${ev.target.hash.substring(1)}']`).cloneNode(true);
installContainer(ev.target); installContainer(ev.target);
void new Footnote(fragFromContents(content), ev.target); const content = document.querySelector(`[id='${targetId}']`).innerHTML;
void new Footnote(content, ev.target);
}); });
// Handle clicks on the footnote reverse link // Handle clicks on the footnote reverse link
document.addEventListener("click", (ev) => document.addEventListener("click", (ev) =>
{ {
if (!(ev.target && ev.target instanceof HTMLAnchorElement)) return; if (!(ev.target && ev.target instanceof HTMLAnchorElement)) return;
if (!ev.target.matches(".footnotes .reversefootnote")) return; if (!ev.target.matches(".footnotes .reversefootnote, .footnotes .footnoteBackLink, footnotes .footnote-return")) return;
const hash = ev.target.hash; const hash = ev.target.hash;
if (!hash) return; if (!hash) return;
const fnref = document.getElementById(hash.substring(1)); const fnref = document.getElementById(hash.substring(1));

View File

@ -201,6 +201,7 @@ img[src*="share-buttons"] {
border-radius: 0.3em; border-radius: 0.3em;
box-sizing: border-box; box-sizing: border-box;
} }
.newsfoot-footnote-popover-arrow { .newsfoot-footnote-popover-arrow {
content: ''; content: '';
display: block; display: block;
@ -226,10 +227,19 @@ img[src*="share-buttons"] {
margin-bottom: 0; margin-bottom: 0;
} }
.newsfoot-footnote-popover .reversefootnote { .newsfoot-footnote-popover .reversefootnote,
.newsfoot-footnote-popover .footnoteBackLink,
.newsfoot-footnote-popover .footnote-return {
display: none; display: none;
} }
a.footnote {
sup[id^='fn'] {
vertical-align: baseline;
}
a.footnote,
sup > a[href^='#fn'],
sup > div > a[href^='#fn'] {
display: inline-block; display: inline-block;
text-decoration: none; text-decoration: none;
padding: 0.05em 0.75em; padding: 0.05em 0.75em;
@ -258,13 +268,17 @@ a.footnote {
} }
body a.footnote, body a.footnote,
body a.footnote:visited, body a.footnote:visited,
.newsfoot-footnote-popover + a.footnote:hover { .newsfoot-footnote-popover + a.footnote:hover,
sup > a[href^='#fn'],
sup > div > a[href^='#fn'] {
background: #aaa; background: #aaa;
color: white; color: white;
transition: background-color 200ms ease-out; transition: background-color 200ms ease-out;
} }
a.footnote:hover, a.footnote:hover,
.newsfoot-footnote-popover + a.footnote { .newsfoot-footnote-popover + a.footnote,
sup > a[href^='#fn']:hover,
sup > div > a[href^='#fn']:hover {
background: #666; background: #666;
transition: background-color 200ms ease-out; transition: background-color 200ms ease-out;
} }
@ -285,16 +299,19 @@ a.footnote:hover,
} }
body a.footnote, body a.footnote,
body a.footnote:visited, body a.footnote:visited,
.newsfoot-footnote-popover + a.footnote:hover { .newsfoot-footnote-popover + a.footnote:hover,
sup > a[href^='#fn'],
sup > div > a[href^='#fn'] {
background: #aaa; background: #aaa;
color: white; color: white;
transition: background-color 200ms ease-out; transition: background-color 200ms ease-out;
} }
a.footnote:hover, a.footnote:hover,
.newsfoot-footnote-popover + a.footnote { .newsfoot-footnote-popover + a.footnote,
sup > a[href^='#fn']:hover,
sup > div > a[href^='#fn']:hover {
background: #666; background: #666;
transition: background-color 200ms ease-out; transition: background-color 200ms ease-out;
} }
} }