vditor
Version:
♏ 易于使用的 Markdown 编辑器,为适配不同的应用场景而生
149 lines (140 loc) • 6.16 kB
text/typescript
import {Constants} from "../constants";
import {addScript, addScriptSync} from "../util/addScript";
import {addStyle} from "../util/addStyle";
import {code160to32} from "../util/code160to32";
import {mathRenderAdapter} from "./adapterRender";
declare const katex: {
renderToString(math: string, option: {
displayMode: boolean;
output: string;
macros: object;
}): string;
};
declare global {
interface Window {
MathJax: any;
}
}
export const mathRender = (element: (HTMLElement | Document) = document, options?: { cdn?: string, math?: IMath }) => {
const mathElements = mathRenderAdapter.getElements(element);
if (mathElements.length === 0) {
return;
}
const defaultOptions = {
cdn: Constants.CDN,
math: {
engine: "KaTeX",
inlineDigit: false,
macros: {},
},
};
if (options && options.math) {
options.math =
Object.assign({}, defaultOptions.math, options.math);
}
options = Object.assign({}, defaultOptions, options);
if (options.math.engine === "KaTeX") {
addStyle(`${options.cdn}/dist/js/katex/katex.min.css?v=0.16.9`, "vditorKatexStyle");
addScript(`${options.cdn}/dist/js/katex/katex.min.js?v=0.16.9`, "vditorKatexScript").then(() => {
addScript(`${options.cdn}/dist/js/katex/mhchem.min.js?v=0.16.9`, "vditorKatexChemScript").then(() => {
mathElements.forEach((mathElement) => {
if (mathElement.parentElement.classList.contains("vditor-wysiwyg__pre") ||
mathElement.parentElement.classList.contains("vditor-ir__marker--pre")) {
return;
}
if (mathElement.getAttribute("data-math")) {
return;
}
const math = code160to32(mathRenderAdapter.getCode(mathElement));
mathElement.setAttribute("data-math", math);
try {
mathElement.innerHTML = katex.renderToString(math, {
displayMode: mathElement.tagName === "DIV",
output: "html",
macros: options.math.macros,
});
} catch (e) {
mathElement.innerHTML = e.message;
mathElement.className = "language-math vditor-reset--error";
}
mathElement.addEventListener("copy", (event: ClipboardEvent) => {
event.stopPropagation();
event.preventDefault();
const vditorMathElement = (event.currentTarget as HTMLElement).closest(".language-math");
event.clipboardData.setData("text/html", vditorMathElement.innerHTML);
event.clipboardData.setData("text/plain",
vditorMathElement.getAttribute("data-math"));
});
});
});
});
} else if (options.math.engine === "MathJax") {
const chainAsync = (fns: any) => {
if (fns.length === 0) {
return;
}
let curr = 0;
const last = fns[fns.length - 1];
const next = () => {
const fn = fns[curr++];
fn === last ? fn() : fn(next);
};
next();
};
if (!window.MathJax) {
window.MathJax = {
loader: {
paths: {mathjax: `${options.cdn}/dist/js/mathjax`},
},
startup: {
typeset: false,
},
tex: {
macros: options.math.macros,
},
};
// https://github.com/Vanessa219/vditor/issues/1453
Object.assign(window.MathJax, options.math.mathJaxOptions);
}
// 循环加载会抛异常
addScriptSync(`${options.cdn}/dist/js/mathjax/tex-svg-full.js`, "protyleMathJaxScript");
const renderMath = (mathElement: Element, next?: () => void) => {
const math = code160to32(mathElement.textContent).trim();
const mathOptions = window.MathJax.getMetricsFor(mathElement);
mathOptions.display = mathElement.tagName === "DIV";
window.MathJax.tex2svgPromise(math, mathOptions).then((node: Element) => {
mathElement.innerHTML = "";
mathElement.setAttribute("data-math", math);
mathElement.append(node);
window.MathJax.startup.document.clear();
window.MathJax.startup.document.updateDocument();
const errorTextElement = node.querySelector('[data-mml-node="merror"]');
if (errorTextElement && errorTextElement.textContent.trim() !== "") {
mathElement.innerHTML = errorTextElement.textContent.trim();
mathElement.className = "vditor-reset--error";
}
if (next) {
next();
}
});
};
window.MathJax.startup.promise.then(() => {
const chains: any[] = [];
for (let i = 0; i < mathElements.length; i++) {
const mathElement = mathElements[i];
if (!mathElement.parentElement.classList.contains("vditor-wysiwyg__pre") &&
!mathElement.parentElement.classList.contains("vditor-ir__marker--pre") &&
!mathElement.getAttribute("data-math") && code160to32(mathElement.textContent).trim()) {
chains.push((next: () => void) => {
if (i === mathElements.length - 1) {
renderMath(mathElement);
} else {
renderMath(mathElement, next);
}
});
}
}
chainAsync(chains);
});
}
};