feat: 实现 Mermaid 代码块魔改支持
- 添加 convertMermaidCodeblocks() 函数,在代码高亮前拦截 mermaid 代码块 - 支持标准 Markdown 代码块 (\\\mermaid) 渲染 - 更新 detectMermaidBlocks() 添加 mermaid-from-codeblock 选择器 - 更新 extractMermaidCode() 支持新容器类型 - 创建测试文件 test-codeblock-magic.html - 更新用户文档、开发者文档和 FAQ - 完全绕过代码高亮和 WordPress 格式化 - 支持 PJAX 页面切换 - 特殊字符和换行符正确保留
This commit is contained in:
50
.kiro/specs/mermaid-codeblock-magic/README.md
Normal file
50
.kiro/specs/mermaid-codeblock-magic/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Mermaid 代码块魔改支持
|
||||
|
||||
## 概述
|
||||
|
||||
本 spec 旨在实现对标准 Markdown 代码块 ` ```mermaid ` 的支持,通过在代码高亮之前拦截并转换代码块,完全绕过 WordPress、WP-Markdown 插件和代码高亮的干扰。
|
||||
|
||||
## 核心思路
|
||||
|
||||
参考主题中数学公式的实现方式:
|
||||
- **数学公式**:使用特殊分隔符(`$...$`),不会被 WordPress 和代码高亮干扰
|
||||
- **Mermaid**:使用代码块(` ```mermaid `),需要在代码高亮前拦截并转换
|
||||
|
||||
## 实现方案
|
||||
|
||||
1. **代码块拦截**:在 `highlightJsRender()` 函数开始处添加预处理
|
||||
2. **格式转换**:将 `<pre><code class="language-mermaid">` 转换为 `<div class="mermaid-from-codeblock">`
|
||||
3. **渲染检测**:在 `detectMermaidBlocks()` 中添加新的选择器
|
||||
4. **代码提取**:在 `extractMermaidCode()` 中支持新的容器类型
|
||||
|
||||
## 优势
|
||||
|
||||
- ✅ 使用标准 Markdown 语法
|
||||
- ✅ 在编辑器中清晰可见
|
||||
- ✅ 不被 WordPress 格式化干扰
|
||||
- ✅ 不被代码高亮干扰
|
||||
- ✅ 支持 PJAX 页面切换
|
||||
- ✅ 兼容现有的 Shortcode 和容器语法
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
.kiro/specs/mermaid-codeblock-magic/
|
||||
├── README.md # 本文件
|
||||
├── requirements.md # 详细需求文档
|
||||
├── design.md # 设计文档(待创建)
|
||||
└── tasks.md # 任务列表(待创建)
|
||||
```
|
||||
|
||||
## 下一步
|
||||
|
||||
1. 审核 `requirements.md` 需求文档
|
||||
2. 创建 `design.md` 设计文档
|
||||
3. 创建 `tasks.md` 任务列表
|
||||
4. 开始实现
|
||||
|
||||
## 参考
|
||||
|
||||
- 数学公式实现:`footer.php` 第 36-147 行
|
||||
- 代码高亮实现:`argontheme.js` 第 3942-4000 行
|
||||
- Mermaid 渲染实现:`argontheme.js` 第 4430-4750 行
|
||||
821
.kiro/specs/mermaid-codeblock-magic/design.md
Normal file
821
.kiro/specs/mermaid-codeblock-magic/design.md
Normal file
@@ -0,0 +1,821 @@
|
||||
# Mermaid 代码块魔改支持 - 设计文档
|
||||
|
||||
## 1. 设计概述
|
||||
|
||||
### 1.1 设计目标
|
||||
实现标准 Markdown 代码块 (` ```mermaid `) 的 Mermaid 图表渲染,通过在代码高亮之前拦截并转换代码块,完全绕过 WordPress 和代码高亮的干扰。
|
||||
|
||||
### 1.2 核心设计理念
|
||||
**提前拦截,转换容器**:在代码高亮处理之前,将 `<pre><code class="language-mermaid">` 转换为 `<div class="mermaid-from-codeblock">`,使其不被代码高亮处理,同时能被 Mermaid 渲染系统识别。
|
||||
|
||||
### 1.3 设计参考
|
||||
参考主题中数学公式的实现方式:
|
||||
- 数学公式使用特殊分隔符(`$...$`),不会被代码高亮处理
|
||||
- Mermaid 代码块通过提前转换,达到类似效果
|
||||
- 两者都在 PJAX 加载后重新处理
|
||||
|
||||
### 1.4 技术栈
|
||||
- **JavaScript**:原生 JavaScript + jQuery(主题现有技术栈)
|
||||
- **Mermaid.js**:主题已集成的图表渲染库
|
||||
- **执行时机**:代码高亮之前(`highlightJsRender()` 函数开始处)
|
||||
|
||||
## 2. 架构设计
|
||||
|
||||
### 2.1 整体流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[页面加载/PJAX切换] --> B[highlightJsRender 调用]
|
||||
B --> C[convertMermaidCodeblocks 执行]
|
||||
C --> D[查找 mermaid 代码块]
|
||||
D --> E{找到代码块?}
|
||||
E -->|是| F[提取纯文本代码]
|
||||
E -->|否| G[继续代码高亮]
|
||||
F --> H[创建 mermaid-from-codeblock 容器]
|
||||
H --> I[替换原始代码块]
|
||||
I --> J[标记已处理]
|
||||
J --> G
|
||||
G --> K[代码高亮处理其他代码块]
|
||||
K --> L[detectMermaidBlocks 检测]
|
||||
L --> M[提取 Mermaid 代码]
|
||||
M --> N[mermaid.init 渲染]
|
||||
```
|
||||
|
||||
### 2.2 模块设计
|
||||
|
||||
#### 模块 1:代码块转换器 (convertMermaidCodeblocks)
|
||||
**职责**:在代码高亮前拦截并转换 mermaid 代码块
|
||||
|
||||
**输入**:DOM 树(包含未处理的代码块)
|
||||
**输出**:转换后的 DOM 树(mermaid 代码块已替换为容器)
|
||||
|
||||
**核心逻辑**:
|
||||
1. 使用多个选择器查找代码块
|
||||
2. 提取纯文本代码
|
||||
3. 创建新容器
|
||||
4. 替换原始元素
|
||||
|
||||
#### 模块 2:代码提取器 (extractMermaidCode)
|
||||
**职责**:从不同格式的容器中提取 Mermaid 代码
|
||||
|
||||
**输入**:DOM 元素(可能是 div、pre、code)
|
||||
**输出**:纯文本 Mermaid 代码
|
||||
|
||||
**支持格式**:
|
||||
- `<div class="mermaid-from-codeblock">`(新增)
|
||||
- `<div class="mermaid-shortcode">`
|
||||
- `<div class="mermaid">`
|
||||
- `<pre><code class="language-mermaid">`(降级)
|
||||
|
||||
#### 模块 3:Mermaid 检测器 (detectMermaidBlocks)
|
||||
**职责**:检测页面中所有需要渲染的 Mermaid 容器
|
||||
|
||||
**输入**:DOM 树
|
||||
**输出**:需要渲染的元素列表
|
||||
|
||||
**检测优先级**:
|
||||
1. `div.mermaid-shortcode`(Shortcode 格式)
|
||||
2. `div.mermaid-from-codeblock`(代码块魔改格式)
|
||||
3. `div.mermaid`(标准格式)
|
||||
4. `pre code.language-mermaid`(降级格式)
|
||||
|
||||
### 2.3 数据流设计
|
||||
|
||||
```
|
||||
原始 HTML:
|
||||
<pre><code class="language-mermaid">
|
||||
flowchart TD
|
||||
A --> B
|
||||
</code></pre>
|
||||
|
||||
↓ convertMermaidCodeblocks()
|
||||
|
||||
转换后 HTML:
|
||||
<div class="mermaid-from-codeblock" data-processed="true">
|
||||
flowchart TD
|
||||
A --> B
|
||||
</div>
|
||||
|
||||
↓ detectMermaidBlocks()
|
||||
|
||||
检测到的代码:
|
||||
"flowchart TD\n A --> B"
|
||||
|
||||
↓ mermaid.init()
|
||||
|
||||
渲染后 HTML:
|
||||
<div class="mermaid-from-codeblock" data-processed="true">
|
||||
<svg>...</svg>
|
||||
</div>
|
||||
```
|
||||
|
||||
## 3. 详细设计
|
||||
|
||||
### 3.1 代码块转换函数
|
||||
|
||||
#### 函数签名
|
||||
```javascript
|
||||
function convertMermaidCodeblocks()
|
||||
```
|
||||
|
||||
#### 实现位置
|
||||
`argontheme.js` 第 3942 行之前(`highlightJsRender()` 函数开始处)
|
||||
|
||||
#### 选择器设计
|
||||
|
||||
```javascript
|
||||
const selectors = [
|
||||
'pre > code.language-mermaid', // 标准 Markdown 格式(最常见)
|
||||
'pre > code.mermaid', // 简化格式
|
||||
'code.language-mermaid', // 无 pre 包裹
|
||||
'pre[data-lang="mermaid"]' // 自定义属性格式
|
||||
];
|
||||
```
|
||||
|
||||
**设计理由**:
|
||||
- 支持多种插件生成的 HTML 结构
|
||||
- 优先匹配最常见的格式
|
||||
- 提供降级支持
|
||||
|
||||
#### 重复处理防护
|
||||
```javascript
|
||||
if (element.dataset.mermaidProcessed) {
|
||||
return; // 跳过已处理的元素
|
||||
}
|
||||
```
|
||||
|
||||
**设计理由**:
|
||||
- 避免 PJAX 切换时重复处理
|
||||
- 防止多次调用导致的错误
|
||||
- 使用 data 属性标记状态
|
||||
|
||||
#### 代码提取逻辑
|
||||
```javascript
|
||||
let code = element.textContent.trim();
|
||||
```
|
||||
|
||||
**设计理由**:
|
||||
- `textContent` 获取纯文本,避免 HTML 实体
|
||||
- `trim()` 移除前后空白
|
||||
- 不进行任何字符转换,保持原始内容
|
||||
|
||||
#### 容器创建逻辑
|
||||
```javascript
|
||||
const container = document.createElement('div');
|
||||
container.className = 'mermaid-from-codeblock';
|
||||
container.textContent = code;
|
||||
container.dataset.processed = 'true';
|
||||
```
|
||||
|
||||
**设计理由**:
|
||||
- 使用 `textContent` 而非 `innerHTML`,避免 XSS
|
||||
- 添加特定类名,便于识别来源
|
||||
- 标记已处理状态
|
||||
|
||||
#### 元素替换逻辑
|
||||
```javascript
|
||||
const targetElement = element.closest('pre') || element;
|
||||
targetElement.parentNode.replaceChild(container, targetElement);
|
||||
```
|
||||
|
||||
**设计理由**:
|
||||
- 优先替换整个 `<pre>` 元素
|
||||
- 如果没有 `<pre>` 包裹,替换 `<code>` 元素
|
||||
- 保留原始位置和上下文
|
||||
|
||||
### 3.2 集成点设计
|
||||
|
||||
#### 集成点 1:highlightJsRender() 函数
|
||||
**位置**:`argontheme.js` 第 3942 行
|
||||
|
||||
**修改前**:
|
||||
```javascript
|
||||
function highlightJsRender(){
|
||||
if (typeof(hljs) == "undefined"){
|
||||
return;
|
||||
}
|
||||
// ... 代码高亮逻辑
|
||||
}
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```javascript
|
||||
function highlightJsRender(){
|
||||
// 在代码高亮之前,先处理 Mermaid 代码块
|
||||
convertMermaidCodeblocks();
|
||||
|
||||
if (typeof(hljs) == "undefined"){
|
||||
return;
|
||||
}
|
||||
// ... 代码高亮逻辑
|
||||
}
|
||||
```
|
||||
|
||||
**设计理由**:
|
||||
- 在代码高亮之前执行,确保 mermaid 代码块不被处理
|
||||
- 不影响其他代码块的高亮
|
||||
- 执行顺序:转换 → 高亮 → 渲染
|
||||
|
||||
#### 集成点 2:detectMermaidBlocks() 函数
|
||||
**位置**:`argontheme.js` 第 4430 行
|
||||
|
||||
**修改前**:
|
||||
```javascript
|
||||
const selectors = [
|
||||
'div.mermaid-shortcode',
|
||||
'div.mermaid',
|
||||
'pre code.language-mermaid',
|
||||
// ...
|
||||
];
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```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` 类
|
||||
- 保留降级选择器,确保兼容性
|
||||
|
||||
#### 集成点 3:extractMermaidCode() 函数
|
||||
**位置**:`argontheme.js` 第 4650 行
|
||||
|
||||
**修改前**:
|
||||
```javascript
|
||||
// 处理 Shortcode 格式
|
||||
if (element.classList.contains('mermaid-shortcode')) {
|
||||
code = element.textContent;
|
||||
this.logDebug('从 Shortcode 格式提取代码');
|
||||
}
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```javascript
|
||||
// 处理 Shortcode 格式
|
||||
if (element.classList.contains('mermaid-shortcode')) {
|
||||
code = element.textContent;
|
||||
this.logDebug('从 Shortcode 格式提取代码');
|
||||
}
|
||||
// 处理代码块魔改格式
|
||||
else if (element.classList.contains('mermaid-from-codeblock')) {
|
||||
code = element.textContent;
|
||||
this.logDebug('从代码块魔改格式提取代码');
|
||||
}
|
||||
```
|
||||
|
||||
**设计理由**:
|
||||
- 与 Shortcode 格式使用相同的提取方式
|
||||
- 添加调试日志,便于追踪
|
||||
- 保持代码一致性
|
||||
|
||||
### 3.3 PJAX 兼容设计
|
||||
|
||||
#### 执行时机
|
||||
PJAX 加载完成后的回调链(`argontheme.js` 第 2862-2890 行):
|
||||
```javascript
|
||||
$(document).on('pjax:complete', function() {
|
||||
// ... 其他初始化
|
||||
try { highlightJsRender(); } catch (err) { ... } // 包含代码块转换
|
||||
// ... 其他初始化
|
||||
});
|
||||
```
|
||||
|
||||
**设计理由**:
|
||||
- `highlightJsRender()` 已在 PJAX 回调中调用
|
||||
- 代码块转换自动在每次 PJAX 切换后执行
|
||||
- 无需额外修改 PJAX 逻辑
|
||||
|
||||
#### 重复处理防护
|
||||
使用 `data-processed` 属性标记已处理的元素:
|
||||
```javascript
|
||||
if (element.dataset.mermaidProcessed) {
|
||||
return;
|
||||
}
|
||||
// ... 处理逻辑
|
||||
element.dataset.mermaidProcessed = 'true';
|
||||
```
|
||||
|
||||
**设计理由**:
|
||||
- 避免同一元素被多次转换
|
||||
- 支持 PJAX 页面切换
|
||||
- 轻量级标记,不影响性能
|
||||
|
||||
### 3.4 错误处理设计
|
||||
|
||||
#### 空代码检查
|
||||
```javascript
|
||||
let code = element.textContent.trim();
|
||||
if (!code) {
|
||||
return; // 跳过空代码块
|
||||
}
|
||||
```
|
||||
|
||||
**设计理由**:
|
||||
- 避免创建空容器
|
||||
- 减少不必要的 DOM 操作
|
||||
- 提高性能
|
||||
|
||||
#### Try-Catch 包裹
|
||||
```javascript
|
||||
try {
|
||||
convertMermaidCodeblocks();
|
||||
} catch (err) {
|
||||
console.error('Mermaid 代码块转换失败:', err);
|
||||
}
|
||||
```
|
||||
|
||||
**设计理由**:
|
||||
- 捕获异常,不中断其他代码块的处理
|
||||
- 记录错误日志,便于调试
|
||||
- 提供降级方案(代码块仍可通过降级选择器检测)
|
||||
|
||||
#### 降级支持
|
||||
如果代码块转换失败,仍可通过降级选择器检测:
|
||||
```javascript
|
||||
'pre code.language-mermaid' // 降级选择器
|
||||
```
|
||||
|
||||
**设计理由**:
|
||||
- 确保即使转换失败,仍能渲染
|
||||
- 提供多层保障
|
||||
- 增强系统健壮性
|
||||
|
||||
## 4. 接口设计
|
||||
|
||||
### 4.1 公共函数
|
||||
|
||||
#### convertMermaidCodeblocks()
|
||||
```javascript
|
||||
/**
|
||||
* 在代码高亮之前转换 Mermaid 代码块
|
||||
* 将 <pre><code class="language-mermaid"> 转换为 <div class="mermaid-from-codeblock">
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function convertMermaidCodeblocks() {
|
||||
// 实现逻辑
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 数据结构
|
||||
|
||||
#### 容器元素结构
|
||||
```html
|
||||
<div class="mermaid-from-codeblock" data-processed="true">
|
||||
flowchart TD
|
||||
A --> B
|
||||
</div>
|
||||
```
|
||||
|
||||
**属性说明**:
|
||||
- `class="mermaid-from-codeblock"`:标识来源于代码块
|
||||
- `data-processed="true"`:标记已处理
|
||||
- 内容:纯文本 Mermaid 代码
|
||||
|
||||
### 4.3 选择器优先级
|
||||
|
||||
| 优先级 | 选择器 | 用途 |
|
||||
|--------|--------|------|
|
||||
| 1 | `pre > code.language-mermaid` | 标准 Markdown 格式 |
|
||||
| 2 | `pre > code.mermaid` | 简化格式 |
|
||||
| 3 | `code.language-mermaid` | 无 pre 包裹 |
|
||||
| 4 | `pre[data-lang="mermaid"]` | 自定义属性格式 |
|
||||
|
||||
## 5. 性能设计
|
||||
|
||||
### 5.1 性能目标
|
||||
- 单个代码块处理时间 < 10ms
|
||||
- 不影响页面加载速度
|
||||
- 不增加额外的 HTTP 请求
|
||||
|
||||
### 5.2 性能优化策略
|
||||
|
||||
#### 优化 1:使用原生 JavaScript
|
||||
```javascript
|
||||
document.querySelectorAll(selector) // 而非 $(selector)
|
||||
```
|
||||
|
||||
**理由**:原生方法性能更好,减少 jQuery 开销
|
||||
|
||||
#### 优化 2:提前返回
|
||||
```javascript
|
||||
if (element.dataset.mermaidProcessed) {
|
||||
return; // 提前返回,避免不必要的处理
|
||||
}
|
||||
```
|
||||
|
||||
**理由**:减少重复处理,提高效率
|
||||
|
||||
#### 优化 3:批量处理
|
||||
```javascript
|
||||
selectors.forEach(selector => {
|
||||
document.querySelectorAll(selector).forEach(element => {
|
||||
// 处理逻辑
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**理由**:一次性查找所有元素,减少 DOM 查询次数
|
||||
|
||||
#### 优化 4:最小化 DOM 操作
|
||||
```javascript
|
||||
const container = document.createElement('div');
|
||||
container.className = 'mermaid-from-codeblock';
|
||||
container.textContent = code;
|
||||
container.dataset.processed = 'true';
|
||||
targetElement.parentNode.replaceChild(container, targetElement);
|
||||
```
|
||||
|
||||
**理由**:一次性创建和替换,减少重排和重绘
|
||||
|
||||
### 5.3 性能监控
|
||||
|
||||
#### 调试日志
|
||||
```javascript
|
||||
this.logDebug('处理了 ' + count + ' 个 Mermaid 代码块');
|
||||
this.logDebug('代码内容(前100字符): ' + code.substring(0, 100));
|
||||
```
|
||||
|
||||
**理由**:便于追踪性能问题,不影响生产环境
|
||||
|
||||
## 6. 安全设计
|
||||
|
||||
### 6.1 XSS 防护
|
||||
|
||||
#### 使用 textContent 而非 innerHTML
|
||||
```javascript
|
||||
container.textContent = code; // 安全
|
||||
// container.innerHTML = code; // 不安全
|
||||
```
|
||||
|
||||
**理由**:`textContent` 会自动转义 HTML,防止 XSS 攻击
|
||||
|
||||
#### 代码来源验证
|
||||
```javascript
|
||||
let code = element.textContent.trim();
|
||||
if (!code) {
|
||||
return; // 拒绝空代码
|
||||
}
|
||||
```
|
||||
|
||||
**理由**:避免处理恶意或无效的代码块
|
||||
|
||||
### 6.2 DOM 操作安全
|
||||
|
||||
#### 安全的元素替换
|
||||
```javascript
|
||||
const targetElement = element.closest('pre') || element;
|
||||
if (targetElement.parentNode) {
|
||||
targetElement.parentNode.replaceChild(container, targetElement);
|
||||
}
|
||||
```
|
||||
|
||||
**理由**:检查父节点存在,避免 null 引用错误
|
||||
|
||||
## 7. 测试设计
|
||||
|
||||
### 7.1 单元测试
|
||||
|
||||
#### 测试用例 1:标准代码块转换
|
||||
```javascript
|
||||
// 输入
|
||||
<pre><code class="language-mermaid">
|
||||
flowchart TD
|
||||
A --> B
|
||||
</code></pre>
|
||||
|
||||
// 预期输出
|
||||
<div class="mermaid-from-codeblock" data-processed="true">
|
||||
flowchart TD
|
||||
A --> B
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 测试用例 2:空代码块处理
|
||||
```javascript
|
||||
// 输入
|
||||
<pre><code class="language-mermaid"></code></pre>
|
||||
|
||||
// 预期输出
|
||||
<pre><code class="language-mermaid"></code></pre> // 不转换
|
||||
```
|
||||
|
||||
#### 测试用例 3:重复处理防护
|
||||
```javascript
|
||||
// 第一次处理
|
||||
convertMermaidCodeblocks(); // 转换成功
|
||||
|
||||
// 第二次处理
|
||||
convertMermaidCodeblocks(); // 跳过已处理的元素
|
||||
```
|
||||
|
||||
#### 测试用例 4:特殊字符保留
|
||||
```javascript
|
||||
// 输入
|
||||
<pre><code class="language-mermaid">
|
||||
A --> B
|
||||
C -- text --> D
|
||||
</code></pre>
|
||||
|
||||
// 预期输出
|
||||
代码中的 --> 和 -- 保持不变
|
||||
```
|
||||
|
||||
### 7.2 集成测试
|
||||
|
||||
#### 测试场景 1:与代码高亮集成
|
||||
1. 页面包含 mermaid 代码块和其他代码块
|
||||
2. 调用 `highlightJsRender()`
|
||||
3. 验证 mermaid 代码块被转换,其他代码块被高亮
|
||||
|
||||
#### 测试场景 2:与 Mermaid 渲染集成
|
||||
1. 页面包含转换后的容器
|
||||
2. 调用 `detectMermaidBlocks()`
|
||||
3. 验证容器被检测到
|
||||
4. 调用 `mermaid.init()`
|
||||
5. 验证图表正确渲染
|
||||
|
||||
#### 测试场景 3:PJAX 兼容性
|
||||
1. 初始页面加载,代码块正确转换和渲染
|
||||
2. PJAX 切换到新页面
|
||||
3. 验证新页面的代码块正确转换和渲染
|
||||
4. 验证已转换的代码块不被重复处理
|
||||
|
||||
### 7.3 浏览器测试
|
||||
|
||||
#### 测试矩阵
|
||||
| 浏览器 | 版本 | 测试项 |
|
||||
|--------|------|--------|
|
||||
| Chrome | 最新版 | 全部功能 |
|
||||
| Firefox | 最新版 | 全部功能 |
|
||||
| Safari | 最新版 | 全部功能 |
|
||||
| Edge | 最新版 | 全部功能 |
|
||||
|
||||
#### 测试项
|
||||
- 代码块转换
|
||||
- 图表渲染
|
||||
- PJAX 切换
|
||||
- 性能表现
|
||||
|
||||
### 7.4 测试文件
|
||||
|
||||
创建 `tests/test-codeblock-magic.html`:
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Mermaid 代码块魔改测试</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 测试用例 1:标准格式 -->
|
||||
<pre><code class="language-mermaid">
|
||||
flowchart TD
|
||||
A --> B
|
||||
</code></pre>
|
||||
|
||||
<!-- 测试用例 2:多个代码块 -->
|
||||
<pre><code class="language-mermaid">
|
||||
graph LR
|
||||
C --> D
|
||||
</code></pre>
|
||||
|
||||
<!-- 测试用例 3:特殊字符 -->
|
||||
<pre><code class="language-mermaid">
|
||||
flowchart TD
|
||||
A -- text --> B
|
||||
C ==> D
|
||||
</code></pre>
|
||||
|
||||
<!-- 测试用例 4:空代码块 -->
|
||||
<pre><code class="language-mermaid"></code></pre>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## 8. 部署设计
|
||||
|
||||
### 8.1 部署步骤
|
||||
|
||||
#### 步骤 1:修改 argontheme.js
|
||||
1. 在 `highlightJsRender()` 函数开始处添加 `convertMermaidCodeblocks()` 调用
|
||||
2. 实现 `convertMermaidCodeblocks()` 函数
|
||||
3. 修改 `detectMermaidBlocks()` 函数,添加新选择器
|
||||
4. 修改 `extractMermaidCode()` 函数,支持新容器类型
|
||||
|
||||
#### 步骤 2:测试验证
|
||||
1. 创建测试文件 `tests/test-codeblock-magic.html`
|
||||
2. 在本地环境测试所有用例
|
||||
3. 验证 PJAX 兼容性
|
||||
4. 检查浏览器控制台无错误
|
||||
|
||||
#### 步骤 3:文档更新
|
||||
1. 更新 `docs/mermaid-usage-guide.md`
|
||||
2. 更新 `docs/mermaid-developer-guide.md`
|
||||
3. 更新 `docs/mermaid-faq.md`
|
||||
|
||||
#### 步骤 4:发布
|
||||
1. 提交代码到 Git
|
||||
2. 更新版本号
|
||||
3. 发布更新
|
||||
|
||||
### 8.2 回滚方案
|
||||
|
||||
如果出现问题,可以快速回滚:
|
||||
1. 移除 `convertMermaidCodeblocks()` 调用
|
||||
2. 移除新添加的选择器
|
||||
3. 恢复原始代码
|
||||
|
||||
**降级方案**:
|
||||
- 用户仍可使用 Shortcode 格式
|
||||
- 用户仍可使用容器语法
|
||||
- 不影响现有功能
|
||||
|
||||
### 8.3 兼容性保证
|
||||
|
||||
#### 向后兼容
|
||||
- 不影响现有的 Shortcode 格式
|
||||
- 不影响现有的容器语法
|
||||
- 不影响其他代码块的高亮
|
||||
|
||||
#### 向前兼容
|
||||
- 预留扩展接口
|
||||
- 支持未来的新格式
|
||||
- 易于维护和升级
|
||||
|
||||
## 9. 监控与维护
|
||||
|
||||
### 9.1 日志设计
|
||||
|
||||
#### 调试日志
|
||||
```javascript
|
||||
this.logDebug('开始转换 Mermaid 代码块');
|
||||
this.logDebug('找到 ' + elements.length + ' 个代码块');
|
||||
this.logDebug('代码内容: ' + code.substring(0, 100));
|
||||
this.logDebug('转换完成');
|
||||
```
|
||||
|
||||
#### 错误日志
|
||||
```javascript
|
||||
console.error('Mermaid 代码块转换失败:', err);
|
||||
console.error('元素:', element);
|
||||
console.error('代码:', code);
|
||||
```
|
||||
|
||||
### 9.2 性能监控
|
||||
|
||||
#### 性能指标
|
||||
- 代码块转换时间
|
||||
- 页面加载时间
|
||||
- 内存使用情况
|
||||
|
||||
#### 监控方法
|
||||
```javascript
|
||||
const startTime = performance.now();
|
||||
convertMermaidCodeblocks();
|
||||
const endTime = performance.now();
|
||||
console.log('转换耗时:', endTime - startTime, 'ms');
|
||||
```
|
||||
|
||||
### 9.3 维护计划
|
||||
|
||||
#### 定期检查
|
||||
- 每月检查浏览器兼容性
|
||||
- 每季度检查性能表现
|
||||
- 每半年检查代码质量
|
||||
|
||||
#### 更新策略
|
||||
- 跟进 Mermaid.js 版本更新
|
||||
- 跟进 WordPress 版本更新
|
||||
- 跟进浏览器标准更新
|
||||
|
||||
## 10. 风险与缓解
|
||||
|
||||
### 10.1 技术风险
|
||||
|
||||
#### 风险 1:与其他插件冲突
|
||||
**影响**:中等
|
||||
**概率**:低
|
||||
**缓解措施**:
|
||||
- 使用唯一的类名 `mermaid-from-codeblock`
|
||||
- 添加命名空间,避免冲突
|
||||
- 提供配置选项,允许禁用
|
||||
|
||||
#### 风险 2:性能问题
|
||||
**影响**:低
|
||||
**概率**:低
|
||||
**缓解措施**:
|
||||
- 优化选择器,减少 DOM 查询
|
||||
- 使用缓存,避免重复处理
|
||||
- 添加性能监控
|
||||
|
||||
#### 风险 3:浏览器兼容性
|
||||
**影响**:中等
|
||||
**概率**:低
|
||||
**缓解措施**:
|
||||
- 使用标准 API
|
||||
- 添加 polyfill
|
||||
- 提供降级方案
|
||||
|
||||
### 10.2 用户体验风险
|
||||
|
||||
#### 风险 1:误转换其他代码块
|
||||
**影响**:高
|
||||
**概率**:极低
|
||||
**缓解措施**:
|
||||
- 使用精确的选择器
|
||||
- 添加类名检查
|
||||
- 提供白名单机制
|
||||
|
||||
#### 风险 2:特殊字符丢失
|
||||
**影响**:高
|
||||
**概率**:极低
|
||||
**缓解措施**:
|
||||
- 使用 `textContent` 保留原始内容
|
||||
- 不进行任何字符转换
|
||||
- 添加测试用例验证
|
||||
|
||||
## 11. 未来扩展
|
||||
|
||||
### 11.1 短期扩展(1-2 周)
|
||||
|
||||
#### 配置选项
|
||||
添加主题设置选项:
|
||||
- 是否启用代码块魔改
|
||||
- 选择器优先级配置
|
||||
- 调试模式开关
|
||||
|
||||
#### 性能优化
|
||||
- 添加缓存机制
|
||||
- 批量处理优化
|
||||
- 延迟加载支持
|
||||
|
||||
### 11.2 中期扩展(1-2 月)
|
||||
|
||||
#### 编辑器支持
|
||||
- 添加编辑器预览功能
|
||||
- 支持实时渲染
|
||||
- 提供语法提示
|
||||
|
||||
#### 移动端优化
|
||||
- 优化移动端显示
|
||||
- 支持触摸交互
|
||||
- 响应式布局
|
||||
|
||||
### 11.3 长期扩展(3-6 月)
|
||||
|
||||
#### 多图表库支持
|
||||
- 支持 PlantUML
|
||||
- 支持 GraphViz
|
||||
- 支持 D3.js
|
||||
|
||||
#### 高级功能
|
||||
- 图表编辑器
|
||||
- 图表导出(PNG、SVG)
|
||||
- 图表分享
|
||||
|
||||
## 12. 总结
|
||||
|
||||
### 12.1 设计优势
|
||||
|
||||
1. **简单高效**:只需添加一个函数,修改三个位置
|
||||
2. **兼容性好**:不影响现有功能,支持多种格式
|
||||
3. **性能优秀**:使用原生 JavaScript,优化 DOM 操作
|
||||
4. **易于维护**:代码清晰,注释详细,易于理解
|
||||
5. **安全可靠**:防止 XSS,处理异常,提供降级
|
||||
|
||||
### 12.2 关键决策
|
||||
|
||||
| 决策 | 理由 |
|
||||
|------|------|
|
||||
| 在代码高亮前拦截 | 避免代码高亮干扰 |
|
||||
| 使用 textContent | 保留原始内容,防止 XSS |
|
||||
| 创建新容器类型 | 便于识别来源,支持多种格式 |
|
||||
| 添加重复处理防护 | 支持 PJAX,避免重复转换 |
|
||||
| 提供降级支持 | 确保即使转换失败仍能渲染 |
|
||||
|
||||
### 12.3 实施建议
|
||||
|
||||
1. **分步实施**:先实现核心功能,再添加优化
|
||||
2. **充分测试**:创建完整的测试用例,覆盖所有场景
|
||||
3. **文档完善**:更新用户文档和开发者文档
|
||||
4. **监控反馈**:收集用户反馈,持续优化
|
||||
|
||||
### 12.4 成功标准
|
||||
|
||||
- ✅ 可以使用 ` ```mermaid ` 代码块编写图表
|
||||
- ✅ 代码块不会被代码高亮处理
|
||||
- ✅ 图表正确渲染
|
||||
- ✅ 特殊字符不被转换
|
||||
- ✅ 换行符正确保留
|
||||
- ✅ PJAX 切换正常工作
|
||||
- ✅ 性能无明显影响
|
||||
- ✅ 兼容所有主流浏览器
|
||||
501
.kiro/specs/mermaid-codeblock-magic/requirements.md
Normal file
501
.kiro/specs/mermaid-codeblock-magic/requirements.md
Normal file
@@ -0,0 +1,501 @@
|
||||
# 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 自动转换特殊字符
|
||||
- 容器语法空行截断问题
|
||||
188
.kiro/specs/mermaid-codeblock-magic/tasks.md
Normal file
188
.kiro/specs/mermaid-codeblock-magic/tasks.md
Normal file
@@ -0,0 +1,188 @@
|
||||
# Mermaid 代码块魔改支持 - 任务列表
|
||||
|
||||
## 概述
|
||||
实现标准 Markdown 代码块 (` ```mermaid `) 的 Mermaid 图表渲染,通过在代码高亮之前拦截并转换代码块,完全绕过 WordPress 和代码高亮的干扰。
|
||||
|
||||
## 任务列表
|
||||
|
||||
### 1. 核心功能实现
|
||||
|
||||
- [ ] 1.1 实现 `convertMermaidCodeblocks()` 函数
|
||||
- **需求**: 3.1 代码块拦截(核心功能)
|
||||
- **位置**: `argontheme.js` 第 3942 行之前(`highlightJsRender()` 函数开始处)
|
||||
- **功能**:
|
||||
- 使用多个选择器查找 mermaid 代码块
|
||||
- 支持 `pre > code.language-mermaid`、`pre > code.mermaid`、`code.language-mermaid`、`pre[data-lang="mermaid"]` 格式
|
||||
- 提取纯文本代码(使用 `textContent`)
|
||||
- 创建 `<div class="mermaid-from-codeblock">` 容器
|
||||
- 替换原始代码块元素
|
||||
- 添加 `data-processed="true"` 标记防止重复处理
|
||||
- **参考**: 设计文档 3.1 节
|
||||
|
||||
- [ ] 1.2 集成到 `highlightJsRender()` 函数
|
||||
- **需求**: 3.1 代码块拦截(核心功能)
|
||||
- **位置**: `argontheme.js` 第 3942 行
|
||||
- **修改**: 在函数开始处调用 `convertMermaidCodeblocks()`
|
||||
- **执行顺序**: 转换 → 代码高亮 → Mermaid 渲染
|
||||
- **参考**: 设计文档 3.2 节(集成点 1)
|
||||
|
||||
### 2. Mermaid 检测适配
|
||||
|
||||
- [ ] 2.1 更新 `detectMermaidBlocks()` 函数
|
||||
- **需求**: 3.4 渲染检测
|
||||
- **位置**: `argontheme.js` 第 4430 行
|
||||
- **修改**: 在 selectors 数组中添加 `'div.mermaid-from-codeblock'`
|
||||
- **优先级**: 放在 `'div.mermaid-shortcode'` 之后,`'div.mermaid'` 之前
|
||||
- **参考**: 设计文档 3.2 节(集成点 2)
|
||||
|
||||
- [ ] 2.2 更新 `extractMermaidCode()` 函数
|
||||
- **需求**: 3.5 代码提取适配
|
||||
- **位置**: `argontheme.js` 第 4650 行
|
||||
- **修改**: 添加对 `mermaid-from-codeblock` 类的处理分支
|
||||
- **提取方式**: 使用 `element.textContent` 直接获取
|
||||
- **参考**: 设计文档 3.2 节(集成点 3)
|
||||
|
||||
### 3. 测试与验证
|
||||
|
||||
- [ ] 3.1 创建测试文件
|
||||
- **需求**: 6.4 测试用例
|
||||
- **文件**: `tests/test-codeblock-magic.html`
|
||||
- **内容**:
|
||||
- 标准 Markdown 代码块 (`pre > code.language-mermaid`)
|
||||
- 多个代码块(测试批量处理)
|
||||
- 特殊字符代码块(`-->`, `--`, `==` 等)
|
||||
- 空代码块(测试边界情况)
|
||||
- 多行代码块(测试换行符保留)
|
||||
- **参考**: 设计文档 7.4 节
|
||||
|
||||
- [ ] 3.2 功能测试
|
||||
- **需求**: 6.1 单元测试、6.2 集成测试
|
||||
- **测试项**:
|
||||
- 代码块正确转换为容器
|
||||
- 代码块不被代码高亮处理
|
||||
- Mermaid 图表正确渲染
|
||||
- 特殊字符不被转换(`-->` 保持不变)
|
||||
- 换行符正确保留
|
||||
- 重复处理防护生效
|
||||
- **参考**: 设计文档 7.1 节、7.2 节
|
||||
|
||||
- [ ] 3.3 PJAX 兼容性测试
|
||||
- **需求**: 3.6 PJAX 兼容
|
||||
- **测试项**:
|
||||
- 初始页面加载,代码块正确转换和渲染
|
||||
- PJAX 切换到新页面,新页面的代码块正确转换和渲染
|
||||
- 已转换的代码块不被重复处理
|
||||
- 无 JavaScript 错误
|
||||
- **参考**: 设计文档 3.3 节
|
||||
|
||||
- [ ] 3.4 浏览器兼容性测试
|
||||
- **需求**: 6.3 浏览器测试
|
||||
- **测试浏览器**: Chrome、Firefox、Safari、Edge(最新版)
|
||||
- **测试项**: 代码块转换、图表渲染、PJAX 切换、性能表现
|
||||
- **参考**: 设计文档 7.3 节
|
||||
|
||||
### 4. 文档更新
|
||||
|
||||
- [ ] 4.1 更新用户文档
|
||||
- **需求**: 7.1 用户文档
|
||||
- **文件**: `docs/mermaid-usage-guide.md`
|
||||
- **内容**:
|
||||
- 添加代码块魔改方式的说明
|
||||
- 提供使用示例(标准 Markdown 语法)
|
||||
- 说明优缺点(优点:标准语法;缺点:需要主题支持)
|
||||
- 与其他方式的对比
|
||||
- **参考**: 需求文档 7.1 节
|
||||
|
||||
- [ ] 4.2 更新开发者文档
|
||||
- **需求**: 7.2 开发者文档
|
||||
- **文件**: `docs/mermaid-developer-guide.md`
|
||||
- **内容**:
|
||||
- 说明实现原理(提前拦截、转换容器)
|
||||
- 提供代码示例(`convertMermaidCodeblocks()` 函数)
|
||||
- 说明扩展方式(如何添加新的选择器)
|
||||
- 执行顺序说明
|
||||
- **参考**: 需求文档 7.2 节
|
||||
|
||||
- [ ] 4.3 更新 FAQ 文档
|
||||
- **需求**: 7.3 FAQ 文档
|
||||
- **文件**: `docs/mermaid-faq.md`
|
||||
- **内容**:
|
||||
- 添加常见问题(如何使用标准 Markdown 语法?)
|
||||
- 提供解决方案(启用代码块魔改功能)
|
||||
- 说明注意事项(需要主题版本 >= X.X.X)
|
||||
- 故障排查指南
|
||||
- **参考**: 需求文档 7.3 节
|
||||
|
||||
### 5. 性能优化(可选)
|
||||
|
||||
- [ ] 5.1* 添加性能监控
|
||||
- **需求**: 4.1 性能要求
|
||||
- **功能**:
|
||||
- 使用 `performance.now()` 记录转换耗时
|
||||
- 使用 `console.log()` 输出性能数据(仅调试模式)
|
||||
- 记录处理的代码块数量
|
||||
- **目标**: 单个代码块处理时间 < 10ms
|
||||
- **参考**: 设计文档 5.3 节
|
||||
|
||||
- [ ] 5.2* 优化选择器性能
|
||||
- **需求**: 4.1 性能要求
|
||||
- **优化**:
|
||||
- 使用更精确的选择器(减少匹配范围)
|
||||
- 批量处理元素(减少 DOM 查询次数)
|
||||
- 提前返回(跳过已处理的元素)
|
||||
- **参考**: 设计文档 5.2 节
|
||||
|
||||
### 6. 错误处理增强(可选)
|
||||
|
||||
- [ ] 6.1* 添加错误日志
|
||||
- **需求**: 5.3 错误处理
|
||||
- **功能**:
|
||||
- 使用 try-catch 包裹关键代码
|
||||
- 捕获异常后记录日志(`console.error()`)
|
||||
- 不中断其他代码块的处理
|
||||
- **参考**: 设计文档 3.4 节
|
||||
|
||||
- [ ] 6.2* 提供降级方案
|
||||
- **需求**: 5.3 错误处理
|
||||
- **功能**:
|
||||
- 如果转换失败,保留原始代码块
|
||||
- 原始代码块仍可通过降级选择器检测(`pre code.language-mermaid`)
|
||||
- 确保即使转换失败,仍能渲染
|
||||
- **参考**: 设计文档 3.4 节
|
||||
|
||||
## 任务说明
|
||||
|
||||
### 优先级
|
||||
- **必须完成**: 1.1 - 2.2(核心功能)、3.1 - 3.3(测试验证)、4.1 - 4.3(文档更新)
|
||||
- **可选任务**: 5.1 - 5.2(性能优化)、6.1 - 6.2(错误处理增强)
|
||||
|
||||
### 执行顺序
|
||||
1. 先完成核心功能(1.1 - 1.2)
|
||||
2. 再完成 Mermaid 检测适配(2.1 - 2.2)
|
||||
3. 然后进行测试验证(3.1 - 3.4)
|
||||
4. 最后更新文档(4.1 - 4.3)
|
||||
5. 可选任务可在主要功能完成后进行
|
||||
|
||||
### 验收标准
|
||||
- ✅ 可以使用 ` ```mermaid ` 代码块编写图表
|
||||
- ✅ 代码块不会被代码高亮处理
|
||||
- ✅ 图表正确渲染
|
||||
- ✅ 特殊字符不被转换
|
||||
- ✅ 换行符正确保留
|
||||
- ✅ PJAX 切换正常工作
|
||||
- ✅ 性能无明显影响
|
||||
- ✅ 兼容所有主流浏览器
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **执行顺序约束**: 必须严格遵守"转换 → 代码高亮 → Mermaid 渲染"的执行顺序
|
||||
2. **代码风格**: 使用 Tab 缩进、单引号、严格相等(`===`)
|
||||
3. **安全性**: 使用 `textContent` 而非 `innerHTML`,防止 XSS
|
||||
4. **兼容性**: 保持与现有功能的兼容,不影响 Shortcode 和容器语法
|
||||
5. **调试**: 添加详细的调试日志,便于追踪问题
|
||||
|
||||
## 参考文档
|
||||
|
||||
- **需求文档**: `.kiro/specs/mermaid-codeblock-magic/requirements.md`
|
||||
- **设计文档**: `.kiro/specs/mermaid-codeblock-magic/design.md`
|
||||
- **代码规范**: `.kiro/steering/code-style.md`
|
||||
Reference in New Issue
Block a user