import { marked } from "https://esm.sh/marked@15"; import markedKatex from "https://esm.sh/marked-katex-extension@5?deps=marked@15,katex@0.16"; import hljs from "https://esm.sh/highlight.js@11"; import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs"; marked.use( markedKatex({ throwOnError: false, nonStandard: true }) ); // breaks: true — 段内单换行渲染为
,与 Obsidian 等编辑器的换行习惯一致(CommonMark 默认会把单换行当成空格) marked.setOptions({ gfm: true, breaks: true }); function decodeHtmlEntities(str) { return String(str) .replace(/ /g, "\u00a0") .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, '"') .replace(/'/g, "'") .replace(/&#(\d+);/g, (_, n) => { const code = Number(n); return code >= 0 && code <= 0x10ffff ? String.fromCharCode(code) : ""; }) .replace(/&#x([0-9a-fA-F]+);/g, (_, h) => { const code = parseInt(h, 16); return code >= 0 && code <= 0x10ffff ? String.fromCharCode(code) : ""; }); } function escapeHtml(s) { return String(s) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } function mermaidFencedToDiv(html) { return html.replace( /
([\s\S]*?)<\/code><\/pre>/gi,
    (_, inner) => {
      const raw = decodeHtmlEntities(inner);
      return `
${escapeHtml(raw)}
`; } ); } function decodeMdFromB64(b64) { return decodeURIComponent(escape(atob(b64))); } async function renderOne(el) { const b64 = el.getAttribute("data-b64-md"); if (!b64) return; let md; try { md = decodeMdFromB64(b64); } catch { el.innerHTML = "

正文解码失败。

"; el.classList.remove("markdown-pending"); return; } el.removeAttribute("data-b64-md"); let html = marked.parse(md, { async: false }); if (typeof html !== "string") html = ""; html = mermaidFencedToDiv(html); el.innerHTML = html; el.classList.remove("markdown-pending"); el.querySelectorAll("pre code").forEach((block) => { try { hljs.highlightElement(block); } catch { /* ignore unknown languages */ } }); const mNodes = el.querySelectorAll(".mermaid"); if (mNodes.length) { mermaid.initialize({ startOnLoad: false, theme: "neutral" }); await mermaid.run({ nodes: mNodes }); } } function run() { document.querySelectorAll(".markdown-body[data-b64-md]").forEach((el) => { renderOne(el).catch(() => { el.innerHTML = "

渲染失败。

"; el.classList.remove("markdown-pending"); }); }); } if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", run); else run();