# 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 自动转换特殊字符
- 容器语法空行截断问题
