再次优化公式渲染,优化mermaid图渲染 #818
|
|
@ -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 = `<p style="color:#cc0000" title="${ error.message }">${ token.raw }`
|
||||
}
|
||||
return `<p class='editormd-tex'>${renderString}</p>`
|
||||
// 块级 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 ? `<p class='editormd-tex'>${html}</p>` : html;
|
||||
} catch (error) {
|
||||
return `<span style="color:#c00" title="${error.message}">${text}</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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 = `<p style="color:#cc0000" title="${ error.message }">${ token.raw }`
|
||||
}
|
||||
return `<p class='editormd-tex'>${renderString}</p>`
|
||||
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 ? `<p class='editormd-tex'>${html}</p>` : html;
|
||||
} catch (error) {
|
||||
return `<span style="color:#c00" title="${error.message}">${text}</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
marked.use({ extensions: [katexBlock, katexInline] });
|
||||
|
||||
marked.use({ tokenizer, renderer });
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ useEffect(() => {
|
|||
.catch(err => {
|
||||
console.error('Failed to load Mermaid:', err);
|
||||
});
|
||||
}, [html]);
|
||||
}, [html, value]);
|
||||
|
||||
function getIssueList(){
|
||||
let matchQuote = str.match(quoteRegex);
|
||||
|
|
|
|||
Loading…
Reference in New Issue