diff --git a/Mac/MainWindow/Detail/styleSheet.css b/Mac/MainWindow/Detail/styleSheet.css index 9de39cabe..380633ce4 100644 --- a/Mac/MainWindow/Detail/styleSheet.css +++ b/Mac/MainWindow/Detail/styleSheet.css @@ -225,10 +225,19 @@ img[src*="share-buttons"] { margin-bottom: 0; } -.newsfoot-footnote-popover .reversefootnote { +.newsfoot-footnote-popover .reversefootnote, +.newsfoot-footnote-popover .footnoteBackLink, +.newsfoot-footnote-popover .footnote-return { display: none; } -a.footnote { + +sup[id^='fn'] { + vertical-align: baseline; +} + +a.footnote, +sup > a[href^='#fn'], +sup > div > a[href^='#fn'] { display: inline-block; text-decoration: none; padding: 0.05em 0.75em; @@ -257,13 +266,17 @@ a.footnote { } body a.footnote, 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; color: white; transition: background-color 200ms ease-out; } 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; transition: background-color 200ms ease-out; } @@ -284,13 +297,17 @@ a.footnote:hover, } body a.footnote, 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; color: white; transition: background-color 200ms ease-out; } 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; transition: background-color 200ms ease-out; } diff --git a/Shared/Article Rendering/newsfoot.js b/Shared/Article Rendering/newsfoot.js index 81a285354..e841d3365 100644 --- a/Shared/Article Rendering/newsfoot.js +++ b/Shared/Article Rendering/newsfoot.js @@ -1,5 +1,5 @@ +// @ts-check (function () { - // @ts-check /** @param {Node | null} el */ const remove = (el) => { if (el) el.parentElement.removeChild(el) }; @@ -33,7 +33,7 @@ const POPOVER_ARROW_CLS = `${clsPrefix}popover-arrow`; /** - * @param {Node} content + * @param {string} content * @returns {HTMLElement} */ function footnoteMarkup(content) { @@ -42,13 +42,13 @@ const inner = newEl("div", POPOVER_INNER_CLS); popover.appendChild(inner); popover.appendChild(arrow); - inner.appendChild(content); + inner.innerHTML = content; return popover; } class Footnote { /** - * @param {Node} content + * @param {string} content * @param {Element} fnref */ constructor(content, fnref) { @@ -56,6 +56,8 @@ this.style = window.getComputedStyle(this.popover); this.fnref = fnref; this.fnref.closest(`.${CONTAINER_CLS}`).insertBefore(this.popover, fnref); + /** @type {HTMLElement} */ + this.arrow = this.popover.querySelector(`.${POPOVER_ARROW_CLS}`); this.reposition(); /** @type {(ev:MouseEvent) => void} */ @@ -101,17 +103,10 @@ offset = (popoverHalfWidth + marginLeft) - center; } 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 */ function installContainer(a) { if (!a.parentElement.matches(`.${CONTAINER_CLS}`)) { @@ -120,23 +115,50 @@ 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 document.addEventListener("click", (ev) => { 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(); - const content = document.querySelector(`[id='${ev.target.hash.substring(1)}']`).cloneNode(true); 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 document.addEventListener("click", (ev) => { 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; if (!hash) return; const fnref = document.getElementById(hash.substring(1)); diff --git a/iOS/Resources/styleSheet.css b/iOS/Resources/styleSheet.css index 2c7ba293a..d6d61b7ae 100644 --- a/iOS/Resources/styleSheet.css +++ b/iOS/Resources/styleSheet.css @@ -201,6 +201,7 @@ img[src*="share-buttons"] { border-radius: 0.3em; box-sizing: border-box; } + .newsfoot-footnote-popover-arrow { content: ''; display: block; @@ -226,10 +227,19 @@ img[src*="share-buttons"] { margin-bottom: 0; } -.newsfoot-footnote-popover .reversefootnote { +.newsfoot-footnote-popover .reversefootnote, +.newsfoot-footnote-popover .footnoteBackLink, +.newsfoot-footnote-popover .footnote-return { display: none; } -a.footnote { + +sup[id^='fn'] { + vertical-align: baseline; +} + +a.footnote, +sup > a[href^='#fn'], +sup > div > a[href^='#fn'] { display: inline-block; text-decoration: none; padding: 0.05em 0.75em; @@ -258,13 +268,17 @@ a.footnote { } body a.footnote, 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; color: white; transition: background-color 200ms ease-out; } 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; transition: background-color 200ms ease-out; } @@ -285,16 +299,19 @@ a.footnote:hover, } body a.footnote, 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; color: white; transition: background-color 200ms ease-out; } 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; transition: background-color 200ms ease-out; } } -