A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
at lambda-fork/main 137 lines 8.6 kB view raw
1import {addScript} from "../util/addScript"; 2import {addStyle} from "../util/addStyle"; 3import {Constants} from "../../constants"; 4import {hasNextSibling, hasPreviousSibling} from "../wysiwyg/getBlock"; 5import {hasClosestBlock} from "../util/hasClosest"; 6import {looseJsonParse} from "../../util/functions"; 7import {genRenderFrame} from "./util"; 8 9export const mathRender = (element: Element, cdn = Constants.PROTYLE_CDN, maxWidth = false) => { 10 let mathElements: Element[] = []; 11 if (element.getAttribute("data-subtype") === "math") { 12 // 编辑器内代码块编辑渲染 13 mathElements = [element]; 14 } else { 15 mathElements = Array.from(element.querySelectorAll('[data-subtype="math"]')); 16 } 17 if (mathElements.length === 0) { 18 return; 19 } 20 addStyle(`${cdn}/js/katex/katex.min.css?v=0.16.9`, "protyleKatexStyle"); 21 addScript(`${cdn}/js/katex/katex.min.js?v=0.16.9`, "protyleKatexScript").then(() => { 22 addScript(`${cdn}/js/katex/mhchem.min.js?v=0.16.9`, "protyleKatexMhchemScript").then(() => { 23 mathElements.forEach((mathElement: HTMLElement) => { 24 if (mathElement.getAttribute("data-render") === "true") { 25 return; 26 } 27 mathElement.setAttribute("data-render", "true"); 28 let macros = {}; 29 try { 30 macros = looseJsonParse(window.siyuan.config.editor.katexMacros || "{}"); 31 } catch (e) { 32 console.warn("KaTex macros is not JSON", e); 33 } 34 const isBlock = mathElement.tagName === "DIV"; 35 try { 36 const mathHTML = window.katex.renderToString(Lute.UnEscapeHTMLStr(mathElement.getAttribute("data-content")), { 37 displayMode: isBlock, 38 output: "html", 39 macros, 40 trust: true, // REF: https://katex.org/docs/supported#html 41 strict: (errorCode) => errorCode === "unicodeTextInMathMode" ? "ignore" : "warn", 42 }); 43 const blockElement = hasClosestBlock(mathElement); 44 if (isBlock) { 45 genRenderFrame(mathElement); 46 mathElement.firstElementChild.firstElementChild.classList.remove("ft__error"); 47 mathElement.firstElementChild.firstElementChild.setAttribute("contenteditable", "false"); 48 mathElement.firstElementChild.firstElementChild.innerHTML = mathHTML; 49 // https://github.com/siyuan-note/siyuan/issues/3541 50 const baseElements = mathElement.querySelectorAll(".base"); 51 if (baseElements.length > 0) { 52 baseElements[baseElements.length - 1].insertAdjacentHTML("afterend", "<span class='fn__flex-1'></span>"); 53 } 54 // https://github.com/siyuan-note/siyuan/issues/4334 55 const newlineElement = mathElement.querySelector(".katex-html > .newline"); 56 if (newlineElement) { 57 newlineElement.parentElement.style.display = "block"; 58 } 59 } else { 60 mathElement.classList.remove("ft__error"); 61 mathElement.innerHTML = mathHTML; 62 if (blockElement && mathElement.getBoundingClientRect().width > blockElement.clientWidth) { 63 mathElement.style.maxWidth = "100%"; 64 mathElement.style.overflowX = "auto"; 65 mathElement.style.overflowY = "hidden"; 66 mathElement.style.display = "inline-block"; 67 } else { 68 mathElement.style.maxWidth = ""; 69 mathElement.style.overflowX = ""; 70 mathElement.style.overflowY = ""; 71 mathElement.style.display = ""; 72 } 73 const nextSibling = hasNextSibling(mathElement) as HTMLElement; 74 if (!nextSibling) { 75 // 表格编辑问题 https://ld246.com/article/1629191424824 76 if (mathElement.parentElement.tagName !== "TH" && mathElement.parentElement.tagName !== "TD") { 77 // 光标无法移动到末尾 https://github.com/siyuan-note/siyuan/issues/2112 78 mathElement.insertAdjacentText("afterend", "\n"); 79 } else { 80 // https://ld246.com/article/1651595975481,https://ld246.com/article/1658903123429 81 // 随着浏览器的升级,从 beforeend 修改为 afterend 82 mathElement.insertAdjacentText("afterend", Constants.ZWSP); 83 } 84 } else if (nextSibling && nextSibling.nodeType !== 3 && 85 ( 86 nextSibling.getAttribute("data-type")?.indexOf("inline-math") > -1 || 87 nextSibling.classList.contains("img") 88 )) { 89 // 相邻的数学公式删除或光标移动有问题 90 mathElement.after(document.createTextNode(Constants.ZWSP)); 91 } else if (nextSibling && 92 !nextSibling.textContent.startsWith("\n") && // https://github.com/siyuan-note/insider/issues/1089 93 // 输入 $a$ 后,光标移动到其他块,再点击 a 后,光标不显示 https://github.com/siyuan-note/insider/issues/1076#issuecomment-1253215515 94 nextSibling.textContent !== Constants.ZWSP) { 95 // 数学公式后一个字符删除多 br https://ld246.com/article/1647157880974 96 // 数学公式后有 \n 不能再添加 &#xFEFF; https://ld246.com/article/1647329437541 97 mathElement.insertAdjacentHTML("beforeend", "&#xFEFF;"); 98 } 99 // 光标无法移动到段首 https://ld246.com/article/1623551823742 100 if (mathElement.previousSibling?.textContent.endsWith("\n")) { 101 mathElement.insertAdjacentText("beforebegin", Constants.ZWSP); 102 } else if (!hasPreviousSibling(mathElement) && ["TH", "TD"].includes(mathElement.parentElement.tagName)) { 103 // 单元格中只有数学公式时,光标无法移动到数学公式前 104 mathElement.insertAdjacentText("afterbegin", Constants.ZWSP); 105 } 106 } 107 108 // export pdf 109 if (maxWidth) { 110 setTimeout(() => { 111 if (isBlock) { 112 const katexElement = mathElement.querySelector(".katex-display"); 113 if (katexElement.clientWidth < katexElement.scrollWidth) { 114 katexElement.firstElementChild.setAttribute("style", `font-size:${katexElement.clientWidth * 100 / katexElement.scrollWidth}%`); 115 } 116 } else { 117 if (blockElement && mathElement.offsetWidth > blockElement.clientWidth) { 118 mathElement.firstElementChild.setAttribute("style", `font-size:${blockElement.clientWidth * 100 / mathElement.offsetWidth}%`); 119 } 120 } 121 }); 122 } 123 } catch (e) { 124 if (isBlock) { 125 genRenderFrame(mathElement); 126 mathElement.firstElementChild.firstElementChild.setAttribute("contenteditable", "false"); 127 mathElement.firstElementChild.firstElementChild.innerHTML = e.message; 128 mathElement.firstElementChild.firstElementChild.classList.add("ft__error"); 129 } else { 130 mathElement.innerHTML = e.message; 131 mathElement.classList.add("ft__error"); 132 } 133 } 134 }); 135 }); 136 }); 137};