Files
argon-theme/.kiro/specs/mermaid-codeblock-magic/requirements.md
nanhaoluo 29bfd284e0 feat: 实现 Mermaid 代码块魔改支持
- 添加 convertMermaidCodeblocks() 函数,在代码高亮前拦截 mermaid 代码块
- 支持标准 Markdown 代码块 (\\\mermaid) 渲染
- 更新 detectMermaidBlocks() 添加 mermaid-from-codeblock 选择器
- 更新 extractMermaidCode() 支持新容器类型
- 创建测试文件 test-codeblock-magic.html
- 更新用户文档、开发者文档和 FAQ
- 完全绕过代码高亮和 WordPress 格式化
- 支持 PJAX 页面切换
- 特殊字符和换行符正确保留
2026-01-24 21:35:12 +08:00

502 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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><code class="language-mermaid">` 格式
- 支持 `<pre><code class="mermaid">` 格式
- 支持 `<code class="language-mermaid">` 格式(无 pre 包裹)
- 支持 `<pre data-lang="mermaid">` 格式
## 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()`
- 不进行任何字符转换(保持原始内容)
- 检查代码是否为空
**特殊处理**
- 如果代码块包含 `<script>` 标签WP-Markdown 生成),先移除
- 如果代码块被其他元素包裹,递归查找 `code` 元素
### 3.3 容器创建
**需求描述**:创建 Mermaid 渲染容器,替换原始代码块
**容器结构**
```html
<div class="mermaid-from-codeblock" data-processed="true">
flowchart TD
A --> B
</div>
```
**容器属性**
- `class="mermaid-from-codeblock"`:标识来源于代码块
- `data-processed="true"`:标记已处理,避免重复
- `textContent`:纯文本 Mermaid 代码(不使用 `innerHTML`
**替换逻辑**
- 使用 `replaceWith()` 替换原始元素
- 如果原始元素在 `<pre>` 中,替换整个 `<pre>` 元素
- 保留原始元素的位置和上下文
### 3.4 渲染检测
**需求描述**:在 Mermaid 渲染时检测新的容器类型
**实现位置**`argontheme.js``detectMermaidBlocks()` 函数(第 4430 行)
**参考实现**:类似数学公式的自动检测机制
**修改内容**
```javascript
const selectors = [
'div.mermaid-shortcode', // Shortcode 格式
'div.mermaid-from-codeblock', // 代码块魔改格式(新增)
'div.mermaid', // 标准格式
'pre code.language-mermaid', // Markdown 格式(降级)
'pre[data-lang="mermaid"]', // 自定义属性格式
'code.mermaid' // 简化格式
];
```
**优先级说明**
- `mermaid-from-codeblock` 优先级高于标准 `mermaid`
- 避免与其他检测逻辑冲突
- 如果代码块转换失败,仍可通过降级选择器检测
### 3.5 代码提取适配
**需求描述**:在 `extractMermaidCode()` 函数中支持新的容器类型
**实现位置**`argontheme.js``extractMermaidCode()` 函数(第 4650 行)
**参考实现**:类似 Shortcode 格式的处理方式
**处理逻辑**
```javascript
// 处理代码块魔改格式
if (element.classList.contains('mermaid-from-codeblock')) {
code = element.textContent;
this.logDebug('从代码块魔改格式提取代码');
}
```
**提取方式**
- 直接使用 `textContent` 获取纯文本
- 不进行任何转换或清理
- 保持与其他格式一致的处理方式
### 3.6 PJAX 兼容
**需求描述**:确保在 PJAX 页面切换后仍能正常工作
**实现位置**PJAX 加载完成回调(第 2862-2890 行)
**参考实现**:数学公式在 PJAX 后重新渲染
**处理逻辑**
- 代码块转换在 `highlightJsRender()` 中执行
- `highlightJsRender()` 已在 PJAX 回调中调用(第 2887 行)
- 无需额外修改,自动支持 PJAX
**验证要点**
- PJAX 切换后,新页面的 mermaid 代码块能正确转换
- 已转换的代码块不会重复处理
- Mermaid 图表能正确渲染
## 4. 非功能需求
### 4.1 性能要求
- 拦截处理应在 10ms 内完成(单个代码块)
- 不影响页面加载速度
- 不增加额外的 HTTP 请求
### 4.2 兼容性要求
- 兼容 WordPress 5.0+
- 兼容 WP-Markdown 插件
- 兼容其他 Markdown 插件Jetpack Markdown 等)
- 兼容主题的代码高亮功能
### 4.3 可维护性要求
- 代码逻辑清晰,易于理解
- 添加详细的注释说明
- 使用统一的命名规范
- 遵循主题现有的代码风格
### 4.4 调试支持
- 使用 `this.logDebug()` 输出调试信息
- 记录处理的代码块数量
- 记录提取的代码内容(前 100 字符)
- 记录容器创建和替换过程
## 5. 技术约束
### 5.1 代码风格
- 使用 Tab 缩进
- 使用单引号 `'`
- 使用严格相等 `===`
- 函数名使用驼峰命名
- 添加 JSDoc 注释
### 5.2 jQuery 使用
- 优先使用原生 JavaScript
- 仅在必要时使用 jQuery
- 避免混用原生和 jQuery 方法
### 5.3 错误处理
- 使用 try-catch 包裹关键代码
- 捕获异常后记录日志
- 不中断其他代码块的处理
- 提供降级方案
### 5.4 执行顺序约束(关键)
**必须严格遵守以下执行顺序**
1. **代码块转换**`convertMermaidCodeblocks()`
-`highlightJsRender()` 函数开始处执行
-`<pre><code class="language-mermaid">` 转换为 `<div class="mermaid-from-codeblock">`
- 必须在代码高亮之前完成
2. **代码高亮**`highlightJsRender()`
- 处理所有代码块,但跳过 mermaid 相关的
- 已有跳过逻辑(第 3963-3970 行)
- 不会处理已转换的 `<div>` 元素
3. **Mermaid 检测**`detectMermaidBlocks()`
- 在页面加载完成后执行
- 检测所有 Mermaid 容器(包括新的 `mermaid-from-codeblock`
- 提取代码并准备渲染
4. **Mermaid 渲染**`mermaid.init()`
- 最后执行
- 将代码渲染为 SVG 图表
**参考实现**
```javascript
// PJAX 加载完成后的执行顺序(第 2862-2890 行)
try { waterflowInit(); } catch (err) { ... }
try { lazyloadInit(); } catch (err) { ... }
try { zoomifyInit(); } catch (err) { ... }
try { highlightJsRender(); } catch (err) { ... } // 代码高亮(包含代码块转换)
try { panguInit(); } catch (err) { ... }
// ... 其他初始化
// Mermaid 渲染在单独的地方调用
```
## 6. 测试需求
### 6.1 单元测试
- 测试代码块检测逻辑
- 测试代码提取逻辑
- 测试容器创建逻辑
- 测试替换逻辑
### 6.2 集成测试
- 测试与代码高亮的集成
- 测试与 Mermaid 渲染的集成
- 测试与 WP-Markdown 的集成
- 测试与 WordPress 的集成
### 6.3 浏览器测试
- Chrome 最新版
- Firefox 最新版
- Safari 最新版
- Edge 最新版
### 6.4 测试用例
创建测试文件 `tests/test-codeblock-magic.html`,包含:
- 标准 Markdown 代码块
- 多个代码块
- 嵌套代码块
- 空代码块
- 特殊字符代码块
- 多行代码块
## 7. 文档需求
### 7.1 用户文档
- 更新 `docs/mermaid-usage-guide.md`
- 添加代码块魔改方式的说明
- 提供使用示例
- 说明优缺点
### 7.2 开发者文档
- 更新 `docs/mermaid-developer-guide.md`
- 说明实现原理
- 提供代码示例
- 说明扩展方式
### 7.3 FAQ 文档
- 更新 `docs/mermaid-faq.md`
- 添加常见问题
- 提供解决方案
- 说明注意事项
## 8. 验收标准
### 8.1 功能验收
- [ ] 可以使用 ` ```mermaid ` 代码块编写图表
- [ ] 代码块不会被代码高亮处理
- [ ] 图表正确渲染
- [ ] 特殊字符不被转换
- [ ] 换行符正确保留
### 8.2 性能验收
- [ ] 单个代码块处理时间 < 10ms
- [ ] 页面加载时间无明显增加
- [ ] 无额外的 HTTP 请求
### 8.3 兼容性验收
- [ ] 兼容 WordPress 5.0+
- [ ] 兼容 WP-Markdown 插件
- [ ] 兼容主题代码高亮
- [ ] 兼容所有主流浏览器
### 8.4 代码质量验收
- [ ] 代码风格符合规范
- [ ] 添加详细注释
- [ ] 无 ESLint 错误
- [ ] 无 console 错误
## 9. 风险评估
### 9.1 技术风险
- **风险**:可能与其他插件冲突
- **影响**:中等
- **缓解措施**:添加兼容性检测,提供降级方案
### 9.2 性能风险
- **风险**:大量代码块可能影响性能
- **影响**:低
- **缓解措施**:优化选择器,使用缓存
### 9.3 兼容性风险
- **风险**:不同插件生成的 HTML 结构不同
- **影响**:中等
- **缓解措施**:支持多种选择器,添加降级逻辑
## 10. 后续优化
### 10.1 短期优化1-2 周)
- 添加配置选项(是否启用代码块魔改)
- 优化性能(缓存、批量处理)
- 完善错误处理
### 10.2 中期优化1-2 月)
- 支持更多 Mermaid 配置选项
- 添加编辑器预览功能
- 优化移动端显示
### 10.3 长期优化3-6 月)
- 支持其他图表库PlantUML、GraphViz 等)
- 添加图表编辑器
- 支持图表导出
## 11. 参考资料
### 11.1 主题现有实现
- **数学公式渲染**`footer.php` 第 36-147 行):
- MathJax 3使用 `$...$``\(...\)` 分隔符
- MathJax 2使用 `$...$``\(...\)` 分隔符
- KaTeX使用 `$$...$$``$...$` 分隔符
- 渲染时机:页面加载完成后自动扫描
- PJAX 支持:在 PJAX 回调中重新调用渲染函数(第 2862-2880 行)
- **代码高亮**`argontheme.js` 第 3942-4000 行):
- 使用 highlight.js 库
- 处理 `<pre><code>` 元素
- 添加行号、控制按钮、复制功能
- 跳过 `.no-hljs``.mermaid` 类的代码块
- **Mermaid 渲染**`argontheme.js` 第 4430-4750 行):
- 检测多种格式的 Mermaid 代码块
- 提取代码内容
- 调用 `mermaid.init()` 渲染图表
- 支持容器语法和 Shortcode
### 11.2 实现对比
| 特性 | 数学公式 | Mermaid当前 | Mermaid魔改后 |
|------|----------|----------------|------------------|
| 标记方式 | 内联分隔符 `$...$` | 代码块 ` ```mermaid ` | 代码块 ` ```mermaid ` |
| WordPress 干扰 | 无(分隔符不被转换) | 有(特殊字符被转换) | 无(提前拦截) |
| 代码高亮干扰 | 无(不是代码块) | 有(被当作代码块) | 无(提前转换) |
| 渲染时机 | 页面加载后自动 | 页面加载后手动检测 | 页面加载后手动检测 |
| PJAX 支持 | 是(重新调用渲染) | 是(重新检测) | 是(重新转换+检测) |
| 编辑器可见性 | 可见(内联文本) | 可见(代码块) | 可见(代码块) |
| 标准兼容性 | LaTeX 标准 | Markdown 标准 | Markdown 标准 |
### 11.3 相关文档
- [Mermaid 官方文档](https://mermaid.js.org/)
- [WP-Markdown 插件文档](https://wordpress.org/plugins/wp-markdown/)
- [WordPress Codex](https://codex.wordpress.org/)
### 11.2 相关代码
- `argontheme.js` - 主题核心 JS
- `functions.php` - WordPress 函数
- `style.css` - 主题样式
### 11.3 相关 Issue
- 代码高亮干扰 Mermaid 渲染
- WordPress 自动转换特殊字符
- 容器语法空行截断问题