| import { parseHTML } from "linkedom"; | |
| import type { Transformer } from "./types.js"; | |
| /** | |
| * Add id anchors to bibliography entries so inline citations can link to them. | |
| * citation-js outputs entries as `<div class="csl-entry">` elements; we tag each | |
| * with `id="ref-<key>"` in the order specified by `citationData.orderedKeys`. | |
| */ | |
| function addBibliographyAnchors(html: string, orderedKeys: string[]): string { | |
| const { document } = parseHTML(`<!DOCTYPE html><html><body>${html}</body></html>`); | |
| const entries = document.querySelectorAll(".csl-entry"); | |
| entries.forEach((entry, idx) => { | |
| const key = orderedKeys[idx] || `entry-${idx}`; | |
| entry.setAttribute("id", `ref-${key}`); | |
| }); | |
| return document.body.innerHTML; | |
| } | |
| /** | |
| * Inject the pre-formatted bibliography HTML into the placeholder | |
| * `<div data-type="bibliography">` left by the TipTap extension. | |
| * Falls back to an empty-state message when there are no citations. | |
| */ | |
| export const bibliographyTransformer: Transformer = { | |
| name: "bibliography", | |
| apply(document, ctx) { | |
| for (const div of [...document.querySelectorAll('div[data-type="bibliography"]')]) { | |
| div.removeAttribute("renderedhtml"); | |
| if (ctx.biblioHtml) { | |
| let enriched = ctx.biblioHtml; | |
| if (ctx.citationData && ctx.citationData.orderedKeys.length > 0) { | |
| enriched = addBibliographyAnchors(ctx.biblioHtml, ctx.citationData.orderedKeys); | |
| } | |
| div.innerHTML = `<h2 class="bibliography-title">References</h2><div class="bibliography-content">${enriched}</div>`; | |
| } else { | |
| div.innerHTML = `<p class="bibliography-empty">No citations</p>`; | |
| } | |
| } | |
| }, | |
| }; | |