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

16 KiB
Raw Blame History

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.jshighlightJsRender() 函数开始处(第 3942 行)

参考实现:类似数学公式在 PJAX 加载后的处理方式(第 2862-2880 行)

处理流程

  1. highlightJsRender() 函数开始处添加预处理
  2. 查找所有 mermaid 代码块(多种选择器)
  3. 遍历每个代码块
  4. 提取纯文本代码
  5. 创建 Mermaid 渲染容器
  6. 替换原始代码块元素
  7. 标记已处理(避免重复处理)

选择器优先级

const selectors = [
	'pre > code.language-mermaid',  // 标准格式(最常见)
	'pre > code.mermaid',           // 简化格式
	'code.language-mermaid',        // 无 pre 包裹
	'pre[data-lang="mermaid"]'      // 自定义属性格式
];

实现示例

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 渲染容器,替换原始代码块

容器结构

<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.jsdetectMermaidBlocks() 函数(第 4430 行)

参考实现:类似数学公式的自动检测机制

修改内容

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.jsextractMermaidCode() 函数(第 4650 行)

参考实现:类似 Shortcode 格式的处理方式

处理逻辑

// 处理代码块魔改格式
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 图表

参考实现

// 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 相关文档

11.2 相关代码

  • argontheme.js - 主题核心 JS
  • functions.php - WordPress 函数
  • style.css - 主题样式

11.3 相关 Issue

  • 代码高亮干扰 Mermaid 渲染
  • WordPress 自动转换特殊字符
  • 容器语法空行截断问题