import { apiFetch } from "./api.js"; import { dom } from "./dom.js"; import { state } from "./state.js"; function escapeHtml(text) { return text .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">"); } function slugify(text) { return text .toLowerCase() .trim() .replace(/[^\w\u4e00-\u9fa5]+/g, "-") .replace(/^-+|-+$/g, ""); } function parseMarkdown(text) { const lines = text.split(/\r?\n/); const blocks = []; const headings = []; let inCode = false; let codeBuffer = []; let paragraph = []; const flushParagraph = () => { if (!paragraph.length) { return; } blocks.push(`

${escapeHtml(paragraph.join(" "))}

`); paragraph = []; }; const flushCode = () => { if (!codeBuffer.length) { return; } blocks.push(`
${escapeHtml(codeBuffer.join("\n"))}
`); codeBuffer = []; }; lines.forEach((line) => { if (line.startsWith("```")) { if (inCode) { flushCode(); } else { flushParagraph(); } inCode = !inCode; return; } if (inCode) { codeBuffer.push(line); return; } const heading = line.match(/^(#{1,4})\s+(.*)$/); if (heading) { flushParagraph(); const level = heading[1].length; const textValue = heading[2].trim(); const id = slugify(textValue); headings.push({ level, text: textValue, id }); blocks.push(`${escapeHtml(textValue)}`); return; } if (!line.trim()) { flushParagraph(); return; } paragraph.push(line.trim()); }); flushParagraph(); flushCode(); return { html: blocks.join(""), headings }; } async function loadDoc(url, emptyMessage) { const text = await apiFetch(url); const { html, headings } = parseMarkdown(text || ""); dom.apiDocContent.innerHTML = html || `

${emptyMessage}

`; dom.apiDocToc.innerHTML = headings.length ? headings .map( (item) => `${escapeHtml(item.text)}`, ) .join("") : "
未解析到标题
"; dom.apiDocToc.querySelectorAll("a").forEach((link) => { link.addEventListener("click", (event) => { event.preventDefault(); const id = link.getAttribute("href")?.slice(1); if (!id) { return; } const target = dom.apiDocContent.querySelector(`#${CSS.escape(id)}`); if (target) { const offset = target.getBoundingClientRect().top - dom.apiDocContent.getBoundingClientRect().top; dom.apiDocContent.scrollBy({ top: offset, behavior: "smooth" }); } }); }); } export async function openApiDocDrawer() { const title = dom.apiDocDrawer.querySelector("h3"); if (title) title.textContent = "API.md"; dom.apiDocDrawer.classList.remove("hidden"); if (state.docDrawerSource !== "api") { state.docDrawerSource = "api"; await loadDoc("/api/docs/api-md", "API.md 为空"); } } export async function openReadmeDrawer() { const title = dom.apiDocDrawer.querySelector("h3"); if (title) title.textContent = "README.md"; dom.apiDocDrawer.classList.remove("hidden"); if (state.docDrawerSource !== "readme") { state.docDrawerSource = "readme"; await loadDoc("/api/docs/readme-md", "README.md 为空"); } } export function closeApiDocDrawer() { dom.apiDocDrawer.classList.add("hidden"); }