From f75fbba096e8fc1c775ea1c162fe1d3322cd5121 Mon Sep 17 00:00:00 2001 From: John Factotum <50942278+johnfactotum@users.noreply.github.com> Date: Sun, 12 Nov 2023 21:42:21 +0800 Subject: [PATCH] Foonotes: get note type Also rename footnote.js -> footnotes.js --- footnote.js => footnotes.js | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) rename footnote.js => footnotes.js (59%) diff --git a/footnote.js b/footnotes.js similarity index 59% rename from footnote.js rename to footnotes.js index ced3dbb..3f1050b 100644 --- a/footnote.js +++ b/footnotes.js @@ -1,17 +1,30 @@ -const refTypes = ['annoref', 'biblioref', 'glossref', 'noteref'] +const getTypes = el => new Set(el?.getAttributeNS?.('http://www.idpf.org/2007/ops', 'type')?.split(' ')) +const getRoles = el => new Set(el?.getAttribute?.('role')?.split(' ')) + +const refTypes = ['biblioref', 'glossref', 'noteref'] const refRoles = ['doc-biblioref', 'doc-glossref', 'doc-noteref'] -const isFootnote = a => { - const types = a.getAttributeNS('http://www.idpf.org/2007/ops', 'type')?.split(' ') - const roles = a.getAttribute('role')?.split(' ') +const isFootnoteReference = a => { + const types = getTypes(a) + const roles = getRoles(a) return { - yes: types?.some(t => refTypes.includes(t)) || roles?.some(r => refRoles.includes(r)), - maybe: () => !types?.includes('backlink') && !roles?.includes('doc-backlink') + yes: refRoles.some(r => roles.has(r)) || refTypes.some(t => types.has(t)), + maybe: () => !types.has('backlink') && !roles.has('doc-backlink') && (getComputedStyle(a).verticalAlign === 'super' || a.children.length === 1 && getComputedStyle(a.children[0]).verticalAlign === 'super') || getComputedStyle(a.parentElement).verticalAlign === 'super', } } +const getReferencedType = el => { + const types = getTypes(el) + const roles = getRoles(el) + return roles.has('doc-biblioentry') || types.has('biblioentry') ? 'biblioentry' + : roles.has('definition') || types.has('glossdef') ? 'definition' + : roles.has('doc-endnote') || types.has('endnote') || types.has('rearnote') ? 'endnote' + : roles.has('doc-footnote') || types.has('footnote') ? 'footnote' + : roles.has('note') || types.has('note') ? 'note' : null +} + const isInline = 'a, span, sup, sub, em, strong, i, b, small, big' const extractFootnote = (doc, anchor) => { let el = anchor(doc) @@ -25,11 +38,13 @@ const extractFootnote = (doc, anchor) => { export class FootnoteHandler extends EventTarget { detectFootnotes = true - #showFragment(book, { index, anchor }, getHref) { + #showFragment(book, { index, anchor }, href) { const view = document.createElement('foliate-view') view.addEventListener('load', e => { const { doc } = e.detail const el = anchor(doc) + const type = getReferencedType(el) + const hidden = el?.matches?.('aside') && type === 'footnote' if (el) { const range = el.startContainer ? el : doc.createRange() if (!el.startContainer) { @@ -40,7 +55,7 @@ export class FootnoteHandler extends EventTarget { doc.body.replaceChildren() doc.body.appendChild(frag) } - const detail = { view, href: getHref(el) } + const detail = { view, href, type, hidden, target: el } this.dispatchEvent(new CustomEvent('render', { detail })) }) view.open(book) @@ -49,17 +64,17 @@ export class FootnoteHandler extends EventTarget { } handle(book, e) { const { a, href } = e.detail - const { yes, maybe } = isFootnote(a) + const { yes, maybe } = isFootnoteReference(a) if (yes) { e.preventDefault() Promise.resolve(book.resolveHref(href)).then(target => - this.#showFragment(book, target, el => el?.matches?.('aside') ? null : href)) + this.#showFragment(book, target, href)) } else if (this.detectFootnotes && maybe()) { e.preventDefault() Promise.resolve(book.resolveHref(href)).then(({ index, anchor }) => { const target = { index, anchor: doc => extractFootnote(doc, anchor) } - this.#showFragment(book, target, () => href) + this.#showFragment(book, target, href) }) } }