import { MarkdownRenderer } from "obsidian"; import type { App, Component } from "obsidian"; export interface MarkdownOptions { app: App; component: Component; sourcePath: string; text: string; } function unwrap(node: HTMLElement): void { let child = node.firstElementChild; while ( node.childElementCount === 1 && child && (child.tagName === "P" || child.tagName === "DIV") ) { child.replaceWith(...child.childNodes); child = node.firstElementChild; } } export function markdown(node: HTMLElement, options: MarkdownOptions) { let current = options; let generation = 0; const render = async (): Promise => { const mine = (generation += 1); const { app, component, sourcePath, text } = current; if (typeof MarkdownRenderer?.render !== "function") { node.textContent = text; return; } const staging = document.createElement("div"); await MarkdownRenderer.render(app, text, staging, sourcePath, component); if (mine !== generation) return; unwrap(staging); node.replaceChildren(...staging.childNodes); }; void render(); return { update(next: MarkdownOptions) { const changed = next.text !== current.text || next.sourcePath !== current.sourcePath; current = next; if (changed) void render(); }, destroy() { generation += 1; }, }; } export function followLink( app: App, event: MouseEvent, sourcePath: string, ): boolean { const anchor = (event.target as HTMLElement).closest("a"); if (!anchor) return false; event.preventDefault(); event.stopPropagation(); const href = anchor.getAttribute("href") ?? ""; if (anchor.classList.contains("internal-link")) { void app.workspace.openLinkText(href, sourcePath, event.ctrlKey || event.metaKey); } else if (href) { window.open(href, "_blank"); } return true; }