From 33a8e7494012d9e2e393e5c4dda9cd567315b9df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E5=BF=83=E5=AE=87?= Date: Fri, 23 Jan 2026 10:50:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=8D=E6=AC=A1=E4=BC=98=E5=8C=96=E5=85=AC?= =?UTF-8?q?=E5=BC=8F=E6=B8=B2=E6=9F=93=EF=BC=8C=E4=BC=98=E5=8C=96mermaid?= =?UTF-8?q?=E5=9B=BE=E6=B8=B2=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/js/editormd/editormd.min.js | 131 +++++++++++++++-------------- src/common/marked.js | 107 +++++++++++------------ src/components/render-html.jsx | 2 +- 3 files changed, 124 insertions(+), 116 deletions(-) diff --git a/public/js/editormd/editormd.min.js b/public/js/editormd/editormd.min.js index e6b9b60fb..eba570da0 100755 --- a/public/js/editormd/editormd.min.js +++ b/public/js/editormd/editormd.min.js @@ -1860,71 +1860,76 @@ } var marked = editormd.$marked; - const kateX = { - name: 'kateX', - level: 'block', // Is this a block-level or inline-level tokenizer? - start(src) { - // 匹配以 $$ 开头和结尾的 KaTeX 表达式 - const startRegex = /^\$\$[^$]+?\$\$(?:\n|$)/; - - // 匹配以 $ 开头和结尾的 KaTeX 表达式 - const inlineRegex = /^\$[^$]+?\$(?:\n|$)/; - - // 检查是否有块级 KaTeX 表达式 - const blockMatch = src.match(startRegex); - if (blockMatch) { - return blockMatch.index; - } - - // 检查是否有行内 KaTeX 表达式 - const inlineMatch = src.match(inlineRegex); - if (inlineMatch) { - return inlineMatch.index; - } - - // 如果没有匹配的内容,则返回 null 或 undefined - return null; - }, - tokenizer(src, tokens) { - const match = src.match(/^\$([^\$]+)\$/); - if (match) { - return { - type: 'kateX', - raw: match[0], - text: match[1].trim(), - displayMode: false - }; - } - const matchDisplay = src.match(/^\$\$([^\$]+)\$\$/); - if (matchDisplay) { - return { - type: 'kateX', - raw: matchDisplay[0], - text: matchDisplay[1].trim(), - displayMode: true - }; - } - return false; - }, - renderer(token) { - let renderString = '' - try { - renderString = katex.renderToString(token.text, { - displayMode: token.displayMode, - macros: { - "\\mbox": "\\text{#1}", - "\\textrm": "\\text{#1}", - "\\textnormal": "\\text{#1}", - }, - trust: false - }) - } catch (error) { - renderString = `

${ token.raw }` - } - return `

${renderString}

` + // 块级 KaTeX: $$ ... $$ + const katexBlock = { + name: 'katexBlock', + level: 'block', + start(src) { + const match = src.match(/\$\$/); + return match ? match.index : null; + }, + tokenizer(src) { + const match = src.match(/^\$\$([\s\S]*?)\$\$/); + if (match) { + return { + type: 'katexBlock', + raw: match[0], + text: match[1].trim(), + displayMode: true + }; } + return false; + }, + renderer(token) { + return renderKatex(token.text, true); + } }; + // 行内 KaTeX: $ ... $ + const katexInline = { + name: 'katexInline', + level: 'inline', + start(src) { + // 找到 $ 且后面不是 $ + const match = src.match(/\$(?!\$)/); + return match ? match.index : null; + }, + tokenizer(src) { + const match = src.match(/^\$([^$]*?)\$(?!\$)/); + if (match) { + return { + type: 'katexInline', + raw: match[0], + text: match[1].trim(), + displayMode: false + }; + } + return false; + }, + renderer(token) { + return renderKatex(token.text, false); + } + }; + + // 公共渲染函数 + function renderKatex(text, displayMode) { + try { + const html = renderToString(text, { + displayMode, + throwOnError: false, + macros: { + "\\mbox": "\\text{#1}", + "\\textrm": "\\text{#1}", + "\\textnormal": "\\text{#1}", + }, + trust: false + }); + return displayMode ? `

${html}

` : html; + } catch (error) { + return `${text}`; + } + } + var markdownToC = this.markdownToC = []; var rendererOptions = this.markedRendererOptions = { toc: settings.toc, @@ -1953,7 +1958,7 @@ }; if (editormd.kaTeXLoaded) { - marked.use({ extensions: [kateX] }); + marked.use({ extensions: [katexBlock, katexInline] }); } marked.setOptions(markedOptions); diff --git a/src/common/marked.js b/src/common/marked.js index 99a2ab332..6424c9ebe 100644 --- a/src/common/marked.js +++ b/src/common/marked.js @@ -181,74 +181,77 @@ marked.setOptions({ pedantic: false }) -const kateX = { - name: 'kateX', - level: 'block', // Is this a block-level or inline-level tokenizer? +// 块级 KaTeX: $$ ... $$ +const katexBlock = { + name: 'katexBlock', + level: 'block', start(src) { - // 匹配以 $$ 开头和结尾的 KaTeX 表达式 - const startRegex = /^\$\$[^$]+?\$\$(?:\n|$)/; - - // 匹配以 $ 开头和结尾的 KaTeX 表达式 - const inlineRegex = /^\$[^$]+?\$(?:\n|$)/; - - // 检查是否有块级 KaTeX 表达式 - const blockMatch = src.match(startRegex); - if (blockMatch) { - return blockMatch.index; - } - - // 检查是否有行内 KaTeX 表达式 - const inlineMatch = src.match(inlineRegex); - if (inlineMatch) { - return inlineMatch.index; - } - - // 如果没有匹配的内容,则返回 null 或 undefined - return null; + const match = src.match(/\$\$/); + return match ? match.index : null; }, - tokenizer(src, tokens) { - const match = src.match(/^\$([^\$]+)\$/); + tokenizer(src) { + const match = src.match(/^\$\$([\s\S]*?)\$\$/); if (match) { return { - type: 'kateX', + type: 'katexBlock', raw: match[0], text: match[1].trim(), - displayMode: false - }; - } - const matchDisplay = src.match(/^\$\$([^\$]+)\$\$/); - if (matchDisplay) { - return { - type: 'kateX', - raw: matchDisplay[0], - text: matchDisplay[1].trim(), displayMode: true }; } return false; }, renderer(token) { - let renderString = '' - try { - renderString = renderToString(token.text || '', { - displayMode: token.displayMode, - throwOnError: false, - macros: { - "\\mbox": "\\text{#1}", - "\\textrm": "\\text{#1}", - "\\textnormal": "\\text{#1}", - }, - trust: false - }) - } catch (error) { - renderString = `

${ token.raw }` - } - return `

${renderString}

` + return renderKatex(token.text, true); } }; +// 行内 KaTeX: $ ... $ +const katexInline = { + name: 'katexInline', + level: 'inline', + start(src) { + // 找到 $ 且后面不是 $ + const match = src.match(/\$(?!\$)/); + return match ? match.index : null; + }, + tokenizer(src) { + const match = src.match(/^\$([^$]*?)\$(?!\$)/); + if (match) { + return { + type: 'katexInline', + raw: match[0], + text: match[1].trim(), + displayMode: false + }; + } + return false; + }, + renderer(token) { + return renderKatex(token.text, false); + } +}; -marked.use({ extensions: [kateX] }); +// 公共渲染函数 +function renderKatex(text, displayMode) { + try { + const html = renderToString(text, { + displayMode, + throwOnError: false, + macros: { + "\\mbox": "\\text{#1}", + "\\textrm": "\\text{#1}", + "\\textnormal": "\\text{#1}", + }, + trust: false + }); + return displayMode ? `

${html}

` : html; + } catch (error) { + return `${text}`; + } +} + +marked.use({ extensions: [katexBlock, katexInline] }); marked.use({ tokenizer, renderer }); diff --git a/src/components/render-html.jsx b/src/components/render-html.jsx index bc8237c9f..0ce8112f0 100644 --- a/src/components/render-html.jsx +++ b/src/components/render-html.jsx @@ -65,7 +65,7 @@ useEffect(() => { .catch(err => { console.error('Failed to load Mermaid:', err); }); -}, [html]); +}, [html, value]); function getIssueList(){ let matchQuote = str.match(quoteRegex); -- 2.34.1