73 lines
1.8 KiB
TypeScript
73 lines
1.8 KiB
TypeScript
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<void> => {
|
|
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;
|
|
}
|