# Mermaid 代码块魔改支持 - 需求文档 ## 1. 项目概述 ### 1.1 背景 当前 Argon 主题支持 Mermaid 图表渲染,但存在多个标记方式的兼容性问题: - **标准 Markdown 代码块** (` ```mermaid `):被 WP-Markdown 插件和代码高亮干扰 - **容器语法** (`::: mermaid ... :::`):空行导致内容截断 - **Shortcode** (`[mermaid]...[/mermaid]`):可用但不符合 Markdown 标准 用户希望使用标准 Markdown 语法 ` ```mermaid `,但需要绕过所有干扰。 ### 1.2 核心问题 1. WP-Markdown 插件会将 ` ```mermaid ` 代码块用 `document.write()` 包裹 2. WordPress 的 `wptexturize()` 会自动转换特殊字符(`--` → `–`) 3. 主题的代码高亮会处理 mermaid 代码块,添加行号和控制按钮 4. 三方冲突导致 Mermaid 代码无法正确渲染 ### 1.3 解决方案 **魔改代码块显示**:在代码高亮之前拦截 mermaid 代码块,将其转换为 Mermaid 渲染容器,完全绕过代码高亮和 WordPress 格式化。 ### 1.4 参考实现 主题中数学公式的实现方式可以作为参考: - **MathJax/KaTeX**:使用特定分隔符(`$...$`、`\(...\)`)标记数学公式 - **渲染时机**:在 PJAX 加载完成后调用 `MathJax.typeset()` 或 `renderMathInElement()` - **不干扰代码高亮**:数学公式使用特殊标记,不会被代码高亮处理 - **WordPress 兼容**:数学公式分隔符不会被 WordPress 自动转换 **关键差异**: - 数学公式使用**内联标记**(`$...$`),不需要代码块 - Mermaid 需要使用**代码块**(` ```mermaid `),需要在代码高亮前拦截 - 数学公式库自动扫描页面,Mermaid 需要手动检测和渲染 ## 2. 用户故事 ### 2.1 作为博客作者 **我想要**:使用标准 Markdown 语法 ` ```mermaid ` 编写流程图 **以便**:在原生编辑器中清晰可见,符合 Markdown 标准,无需学习特殊语法 **验收标准**: - 可以使用 ` ```mermaid ` 代码块编写 Mermaid 图表 - 代码块不会被代码高亮处理(无行号、无控制按钮) - 代码块会被正确转换为 Mermaid 图表 - 支持所有 Mermaid 语法(flowchart, sequence, class, state 等) ### 2.2 作为博客作者 **我想要**:Mermaid 代码中的特殊字符不被 WordPress 转换 **以便**:箭头符号 `-->` 不会变成 `–>`,图表能正确渲染 **验收标准**: - 箭头符号 `-->` 保持不变 - 双横线 `--` 保持不变 - 其他特殊字符(`==`, `~~`, `::` 等)保持不变 - 换行符正确保留 ### 2.3 作为博客作者 **我想要**:Mermaid 代码块在编辑器中显示为代码块 **以便**:编辑时能清晰看到代码结构,方便修改 **验收标准**: - 在 WordPress 原生编辑器中显示为代码块 - 在 WP-Markdown 编辑器中显示为代码块 - 代码块有语法高亮(编辑器层面) - 保存后前端正确渲染为图表 ### 2.4 作为开发者 **我想要**:拦截逻辑在代码高亮之前执行 **以便**:避免代码高亮干扰 Mermaid 渲染 **验收标准**: - 在 `highlightJsRender()` 函数开始处添加预处理 - 查找所有 `pre > code.language-mermaid` 元素 - 提取纯文本代码(不经过任何处理) - 创建 Mermaid 渲染容器 - 替换原始代码块元素 ### 2.5 作为开发者 **我想要**:支持多种 Mermaid 代码块格式 **以便**:兼容不同插件和编辑器生成的 HTML 结构 **验收标准**: - 支持 `
` 格式
- 支持 `` 格式
- 支持 `` 格式(无 pre 包裹)
- 支持 `` 格式
## 3. 功能需求
### 3.1 代码块拦截(核心功能)
**需求描述**:在代码高亮之前拦截 mermaid 代码块
**实现位置**:`argontheme.js` 的 `highlightJsRender()` 函数开始处(第 3942 行)
**参考实现**:类似数学公式在 PJAX 加载后的处理方式(第 2862-2880 行)
**处理流程**:
1. 在 `highlightJsRender()` 函数开始处添加预处理
2. 查找所有 mermaid 代码块(多种选择器)
3. 遍历每个代码块
4. 提取纯文本代码
5. 创建 Mermaid 渲染容器
6. 替换原始代码块元素
7. 标记已处理(避免重复处理)
**选择器优先级**:
```javascript
const selectors = [
'pre > code.language-mermaid', // 标准格式(最常见)
'pre > code.mermaid', // 简化格式
'code.language-mermaid', // 无 pre 包裹
'pre[data-lang="mermaid"]' // 自定义属性格式
];
```
**实现示例**:
```javascript
function highlightJsRender(){
// 在代码高亮之前,先处理 Mermaid 代码块
convertMermaidCodeblocks();
// 原有的代码高亮逻辑
if (typeof(hljs) == "undefined"){
return;
}
// ...
}
function convertMermaidCodeblocks(){
// 查找所有 mermaid 代码块
const selectors = [
'pre > code.language-mermaid',
'pre > code.mermaid',
'code.language-mermaid',
'pre[data-lang="mermaid"]'
];
selectors.forEach(selector => {
document.querySelectorAll(selector).forEach(element => {
// 避免重复处理
if (element.dataset.mermaidProcessed) {
return;
}
// 提取代码
let code = element.textContent.trim();
if (!code) {
return;
}
// 创建容器
const container = document.createElement('div');
container.className = 'mermaid-from-codeblock';
container.textContent = code;
container.dataset.processed = 'true';
// 替换元素
const targetElement = element.closest('pre') || element;
targetElement.parentNode.replaceChild(container, targetElement);
});
});
}
```
### 3.2 代码提取
**需求描述**:从不同格式的代码块中提取纯文本代码
**处理逻辑**:
- 使用 `textContent` 获取纯文本(避免 HTML 实体)
- 移除前后空白字符(`trim()`)
- 不进行任何字符转换(保持原始内容)
- 检查代码是否为空
**特殊处理**:
- 如果代码块包含 `