fix: 修复 Mermaid 容器语法的换行符和特殊字符问题
## 问题描述
用户报告 Mermaid 图表仍然渲染失败:
1. `flowchart TDStart` - `TD` 和 `Start` 之间没有换行符(有两个空格)
2. 箭头符号变成全角 `–>` 而不是 `-->`
## 根本原因分析
### 问题 1: 换行符丢失
WP-Markdown 可能将整个容器语法内容放在**一个** `<p>` 元素中:
```html
<p>::: mermaid<br>flowchart TD<br>Start --> End<br>:::</p>
```
而不是多个独立的 `<p>` 元素。之前的代码只处理了多元素的情况。
### 问题 2: 特殊字符转换
WordPress 的自动格式化功能会将某些字符转换为排版字符:
- `--` → `–` (U+2013 EN DASH)
- `---` → `—` (U+2014 EM DASH)
- `->` → `→` (U+2192 RIGHTWARDS ARROW)
这些字符在 Mermaid 语法中有特殊含义,必须保持原样。
## 修复方案
### 1. 支持单元素容器语法
在 `extractContainerContent()` 函数中添加检测逻辑:
```javascript
// 检查是否整个内容都在一个元素中
if (startText.includes(':::') && startText.lastIndexOf(':::') > 10) {
// 整个容器语法在一个元素中
let fullText = this.htmlToText(startHTML);
// 移除开始和结束标记
fullText = fullText.replace(/^:::\s*mermaid\s*/i, '').trim();
fullText = fullText.replace(/:::\s*$/, '').trim();
// 创建容器并返回
}
```
### 2. 增强 htmlToText() 函数
添加更多字符转换规则:
```javascript
// HTML 实体
.replace(/–/g, '-') // EN DASH
.replace(/—/g, '--') // EM DASH
.replace(/→/g, '->') // RIGHTWARDS ARROW
.replace(/–/g, '-') // EN DASH (named entity)
.replace(/—/g, '--') // EM DASH (named entity)
.replace(/→/g, '->'); // RIGHTWARDS ARROW (named entity)
// Unicode 字符
.replace(/–/g, '-') // U+2013 EN DASH
.replace(/—/g, '--') // U+2014 EM DASH
.replace(/→/g, '->'); // U+2192 RIGHTWARDS ARROW
```
### 3. 添加详细调试日志
```javascript
this.logDebug('检查元素,textContent: ' + startText.substring(0, 50));
this.logDebug('innerHTML: ' + startHTML.substring(0, 100));
this.logDebug('检测到单元素容器语法');
this.logDebug('转换后的完整文本: ' + fullText.substring(0, 200));
this.logDebug('移除标记后的代码: ' + fullText.substring(0, 200));
```
## 处理流程
### 单元素容器语法
```
1. 检测到 ::: mermaid 开始标记
2. 检查 textContent 中是否包含结束标记 :::
3. 如果包含,说明整个内容在一个元素中
4. 提取 innerHTML
原始: "::: mermaid<br>flowchart TD<br>Start –> End<br>:::"
5. 使用 htmlToText() 转换
- <br> → \n
- – → -
- → → ->
结果: "::: mermaid\nflowchart TD\nStart --> End\n:::"
6. 移除开始和结束标记
结果: "flowchart TD\nStart --> End"
7. 创建容器元素存储代码
```
### 多元素容器语法(保持原有逻辑)
```
1. 检测到 ::: mermaid 开始标记
2. 遍历后续兄弟元素
3. 收集所有内容直到 ::: 结束标记
4. 使用 \n 连接所有行
5. 创建容器元素存储代码
```
## 测试验证
### 测试用例 1: 单元素容器语法
```html
<p>::: mermaid<br>
flowchart TD<br>
A[开始] –> B[处理]<br>
B –> C[结束]<br>
:::</p>
```
预期结果:
```
flowchart TD
A[开始] --> B[处理]
B --> C[结束]
```
### 测试用例 2: 多元素容器语法
```html
<p>::: mermaid</p>
<p>flowchart TD</p>
<p>A --> B</p>
<p>:::</p>
```
预期结果:
```
flowchart TD
A --> B
```
### 测试用例 3: 复杂流程图(AI 评论审核)
- 100+ 个节点
- 多行文本(`<br/>` 标签)
- 箭头符号(`-->`, `-->`)
- 样式定义(`style` 语句)
## 影响范围
- 仅影响 Markdown 容器语法(`::: mermaid ... :::`)
- 不影响其他格式(`<div class="mermaid">`, `<pre><code>` 等)
- 向后兼容,支持单元素和多元素两种情况
## 相关文件
- `argontheme.js` - 修改 `extractContainerContent()` 和 `htmlToText()`
- `tests/test-ai-comment-flow.md` - 测试文档
## 技术细节
### WordPress 自动格式化
WordPress 的 `wptexturize()` 函数会自动转换以下字符:
- `--` → `–` (EN DASH)
- `---` → `—` (EM DASH)
- `->` → `→` (RIGHTWARDS ARROW)
- `(c)` → `©` (COPYRIGHT SIGN)
- `(r)` → `®` (REGISTERED SIGN)
- `(tm)` → `™` (TRADE MARK SIGN)
这些转换对于普通文本是有益的,但对于代码块(如 Mermaid)是有害的。
### 解决方案
1. **禁用自动格式化**(不推荐)
- 会影响整个网站的排版
- 需要修改 WordPress 核心代码
2. **在提取时反转换**(推荐)✅
- 只影响 Mermaid 代码块
- 不影响其他内容
- 易于维护
### 字符映射表
| 原始字符 | HTML 实体 | Unicode | 显示 |
|---------|----------|---------|------|
| `-` | `-` | U+002D | - |
| `--` | `–` / `–` | U+2013 | – |
| `---` | `—` / `—` | U+2014 | — |
| `->` | `→` / `→` | U+2192 | → |
## 注意事项
1. **性能影响**:增加了字符串替换操作,但性能影响可忽略
2. **安全性**:只处理 Mermaid 代码块,不执行任何脚本
3. **兼容性**:支持所有现代浏览器
4. **调试**:添加详细日志,便于排查问题
## 后续优化
1. 考虑使用 DOMParser 解析 HTML,更可靠
2. 添加更多特殊字符的转换规则
3. 支持自定义字符映射表
4. 添加单元测试
## 参考资料
- [WordPress wptexturize() 函数](https://developer.wordpress.org/reference/functions/wptexturize/)
- [Unicode 字符表](https://unicode-table.com/)
- [Mermaid 语法文档](https://mermaid.js.org/intro/syntax-reference.html)
This commit is contained in:
@@ -4524,10 +4524,44 @@ void 0;
|
|||||||
let startHTML = startElement.innerHTML;
|
let startHTML = startElement.innerHTML;
|
||||||
let startText = startElement.textContent.trim();
|
let startText = startElement.textContent.trim();
|
||||||
|
|
||||||
|
this.logDebug('检查元素,textContent: ' + startText.substring(0, 50));
|
||||||
|
this.logDebug('innerHTML: ' + startHTML.substring(0, 100));
|
||||||
|
|
||||||
if (startText.startsWith('::: mermaid')) {
|
if (startText.startsWith('::: mermaid')) {
|
||||||
foundStart = true;
|
foundStart = true;
|
||||||
this.logDebug('找到容器语法开始标记,原始 HTML: ' + startHTML.substring(0, 100));
|
this.logDebug('找到容器语法开始标记');
|
||||||
|
|
||||||
|
// 检查是否整个内容都在一个元素中
|
||||||
|
if (startText.includes(':::') && startText.lastIndexOf(':::') > 10) {
|
||||||
|
// 整个容器语法在一个元素中
|
||||||
|
this.logDebug('检测到单元素容器语法');
|
||||||
|
|
||||||
|
// 使用 htmlToText 转换整个 HTML
|
||||||
|
let fullText = this.htmlToText(startHTML);
|
||||||
|
this.logDebug('转换后的完整文本: ' + fullText.substring(0, 200));
|
||||||
|
|
||||||
|
// 移除开始和结束标记
|
||||||
|
fullText = fullText.replace(/^:::\s*mermaid\s*/i, '').trim();
|
||||||
|
fullText = fullText.replace(/:::\s*$/, '').trim();
|
||||||
|
|
||||||
|
this.logDebug('移除标记后的代码: ' + fullText.substring(0, 200));
|
||||||
|
|
||||||
|
if (fullText) {
|
||||||
|
// 创建容器
|
||||||
|
const container = document.createElement('div');
|
||||||
|
container.className = 'mermaid-container-block';
|
||||||
|
container.textContent = fullText;
|
||||||
|
container.dataset.containerBlock = 'true';
|
||||||
|
|
||||||
|
// 替换开始元素
|
||||||
|
startElement.parentNode.replaceChild(container, startElement);
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 多元素容器语法(原有逻辑)
|
||||||
// 移除开始标记,保留同一元素中的其他内容
|
// 移除开始标记,保留同一元素中的其他内容
|
||||||
startText = startText.replace(/^:::\s*mermaid\s*/i, '').trim();
|
startText = startText.replace(/^:::\s*mermaid\s*/i, '').trim();
|
||||||
if (startText && !startText.startsWith(':::')) {
|
if (startText && !startText.startsWith(':::')) {
|
||||||
@@ -4631,7 +4665,20 @@ void 0;
|
|||||||
.replace(/>/g, '>')
|
.replace(/>/g, '>')
|
||||||
.replace(/&/g, '&')
|
.replace(/&/g, '&')
|
||||||
.replace(/"/g, '"')
|
.replace(/"/g, '"')
|
||||||
.replace(/'/g, "'");
|
.replace(/'/g, "'")
|
||||||
|
.replace(/–/g, '-') // EN DASH
|
||||||
|
.replace(/—/g, '--') // EM DASH
|
||||||
|
.replace(/→/g, '->') // RIGHTWARDS ARROW
|
||||||
|
.replace(/–/g, '-') // EN DASH (named entity)
|
||||||
|
.replace(/—/g, '--') // EM DASH (named entity)
|
||||||
|
.replace(/→/g, '->'); // RIGHTWARDS ARROW (named entity)
|
||||||
|
|
||||||
|
// 转换 Unicode 字符(WordPress 可能直接输出 Unicode)
|
||||||
|
text = text
|
||||||
|
.replace(/–/g, '-') // U+2013 EN DASH
|
||||||
|
.replace(/—/g, '--') // U+2014 EM DASH
|
||||||
|
.replace(/→/g, '->'); // U+2192 RIGHTWARDS ARROW
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
207
commit-msg-mermaid-final-fix.txt
Normal file
207
commit-msg-mermaid-final-fix.txt
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
fix: 修复 Mermaid 容器语法的换行符和特殊字符问题
|
||||||
|
|
||||||
|
## 问题描述
|
||||||
|
|
||||||
|
用户报告 Mermaid 图表仍然渲染失败:
|
||||||
|
1. `flowchart TDStart` - `TD` 和 `Start` 之间没有换行符(有两个空格)
|
||||||
|
2. 箭头符号变成全角 `–>` 而不是 `-->`
|
||||||
|
|
||||||
|
## 根本原因分析
|
||||||
|
|
||||||
|
### 问题 1: 换行符丢失
|
||||||
|
|
||||||
|
WP-Markdown 可能将整个容器语法内容放在**一个** `<p>` 元素中:
|
||||||
|
```html
|
||||||
|
<p>::: mermaid<br>flowchart TD<br>Start --> End<br>:::</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
而不是多个独立的 `<p>` 元素。之前的代码只处理了多元素的情况。
|
||||||
|
|
||||||
|
### 问题 2: 特殊字符转换
|
||||||
|
|
||||||
|
WordPress 的自动格式化功能会将某些字符转换为排版字符:
|
||||||
|
- `--` → `–` (U+2013 EN DASH)
|
||||||
|
- `---` → `—` (U+2014 EM DASH)
|
||||||
|
- `->` → `→` (U+2192 RIGHTWARDS ARROW)
|
||||||
|
|
||||||
|
这些字符在 Mermaid 语法中有特殊含义,必须保持原样。
|
||||||
|
|
||||||
|
## 修复方案
|
||||||
|
|
||||||
|
### 1. 支持单元素容器语法
|
||||||
|
|
||||||
|
在 `extractContainerContent()` 函数中添加检测逻辑:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 检查是否整个内容都在一个元素中
|
||||||
|
if (startText.includes(':::') && startText.lastIndexOf(':::') > 10) {
|
||||||
|
// 整个容器语法在一个元素中
|
||||||
|
let fullText = this.htmlToText(startHTML);
|
||||||
|
// 移除开始和结束标记
|
||||||
|
fullText = fullText.replace(/^:::\s*mermaid\s*/i, '').trim();
|
||||||
|
fullText = fullText.replace(/:::\s*$/, '').trim();
|
||||||
|
// 创建容器并返回
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 增强 htmlToText() 函数
|
||||||
|
|
||||||
|
添加更多字符转换规则:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// HTML 实体
|
||||||
|
.replace(/–/g, '-') // EN DASH
|
||||||
|
.replace(/—/g, '--') // EM DASH
|
||||||
|
.replace(/→/g, '->') // RIGHTWARDS ARROW
|
||||||
|
.replace(/–/g, '-') // EN DASH (named entity)
|
||||||
|
.replace(/—/g, '--') // EM DASH (named entity)
|
||||||
|
.replace(/→/g, '->'); // RIGHTWARDS ARROW (named entity)
|
||||||
|
|
||||||
|
// Unicode 字符
|
||||||
|
.replace(/–/g, '-') // U+2013 EN DASH
|
||||||
|
.replace(/—/g, '--') // U+2014 EM DASH
|
||||||
|
.replace(/→/g, '->'); // U+2192 RIGHTWARDS ARROW
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 添加详细调试日志
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
this.logDebug('检查元素,textContent: ' + startText.substring(0, 50));
|
||||||
|
this.logDebug('innerHTML: ' + startHTML.substring(0, 100));
|
||||||
|
this.logDebug('检测到单元素容器语法');
|
||||||
|
this.logDebug('转换后的完整文本: ' + fullText.substring(0, 200));
|
||||||
|
this.logDebug('移除标记后的代码: ' + fullText.substring(0, 200));
|
||||||
|
```
|
||||||
|
|
||||||
|
## 处理流程
|
||||||
|
|
||||||
|
### 单元素容器语法
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 检测到 ::: mermaid 开始标记
|
||||||
|
2. 检查 textContent 中是否包含结束标记 :::
|
||||||
|
3. 如果包含,说明整个内容在一个元素中
|
||||||
|
4. 提取 innerHTML
|
||||||
|
原始: "::: mermaid<br>flowchart TD<br>Start –> End<br>:::"
|
||||||
|
5. 使用 htmlToText() 转换
|
||||||
|
- <br> → \n
|
||||||
|
- – → -
|
||||||
|
- → → ->
|
||||||
|
结果: "::: mermaid\nflowchart TD\nStart --> End\n:::"
|
||||||
|
6. 移除开始和结束标记
|
||||||
|
结果: "flowchart TD\nStart --> End"
|
||||||
|
7. 创建容器元素存储代码
|
||||||
|
```
|
||||||
|
|
||||||
|
### 多元素容器语法(保持原有逻辑)
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 检测到 ::: mermaid 开始标记
|
||||||
|
2. 遍历后续兄弟元素
|
||||||
|
3. 收集所有内容直到 ::: 结束标记
|
||||||
|
4. 使用 \n 连接所有行
|
||||||
|
5. 创建容器元素存储代码
|
||||||
|
```
|
||||||
|
|
||||||
|
## 测试验证
|
||||||
|
|
||||||
|
### 测试用例 1: 单元素容器语法
|
||||||
|
```html
|
||||||
|
<p>::: mermaid<br>
|
||||||
|
flowchart TD<br>
|
||||||
|
A[开始] –> B[处理]<br>
|
||||||
|
B –> C[结束]<br>
|
||||||
|
:::</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
预期结果:
|
||||||
|
```
|
||||||
|
flowchart TD
|
||||||
|
A[开始] --> B[处理]
|
||||||
|
B --> C[结束]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 测试用例 2: 多元素容器语法
|
||||||
|
```html
|
||||||
|
<p>::: mermaid</p>
|
||||||
|
<p>flowchart TD</p>
|
||||||
|
<p>A --> B</p>
|
||||||
|
<p>:::</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
预期结果:
|
||||||
|
```
|
||||||
|
flowchart TD
|
||||||
|
A --> B
|
||||||
|
```
|
||||||
|
|
||||||
|
### 测试用例 3: 复杂流程图(AI 评论审核)
|
||||||
|
- 100+ 个节点
|
||||||
|
- 多行文本(`<br/>` 标签)
|
||||||
|
- 箭头符号(`-->`, `-->`)
|
||||||
|
- 样式定义(`style` 语句)
|
||||||
|
|
||||||
|
## 影响范围
|
||||||
|
|
||||||
|
- 仅影响 Markdown 容器语法(`::: mermaid ... :::`)
|
||||||
|
- 不影响其他格式(`<div class="mermaid">`, `<pre><code>` 等)
|
||||||
|
- 向后兼容,支持单元素和多元素两种情况
|
||||||
|
|
||||||
|
## 相关文件
|
||||||
|
|
||||||
|
- `argontheme.js` - 修改 `extractContainerContent()` 和 `htmlToText()`
|
||||||
|
- `tests/test-ai-comment-flow.md` - 测试文档
|
||||||
|
|
||||||
|
## 技术细节
|
||||||
|
|
||||||
|
### WordPress 自动格式化
|
||||||
|
|
||||||
|
WordPress 的 `wptexturize()` 函数会自动转换以下字符:
|
||||||
|
- `--` → `–` (EN DASH)
|
||||||
|
- `---` → `—` (EM DASH)
|
||||||
|
- `->` → `→` (RIGHTWARDS ARROW)
|
||||||
|
- `(c)` → `©` (COPYRIGHT SIGN)
|
||||||
|
- `(r)` → `®` (REGISTERED SIGN)
|
||||||
|
- `(tm)` → `™` (TRADE MARK SIGN)
|
||||||
|
|
||||||
|
这些转换对于普通文本是有益的,但对于代码块(如 Mermaid)是有害的。
|
||||||
|
|
||||||
|
### 解决方案
|
||||||
|
|
||||||
|
1. **禁用自动格式化**(不推荐)
|
||||||
|
- 会影响整个网站的排版
|
||||||
|
- 需要修改 WordPress 核心代码
|
||||||
|
|
||||||
|
2. **在提取时反转换**(推荐)✅
|
||||||
|
- 只影响 Mermaid 代码块
|
||||||
|
- 不影响其他内容
|
||||||
|
- 易于维护
|
||||||
|
|
||||||
|
### 字符映射表
|
||||||
|
|
||||||
|
| 原始字符 | HTML 实体 | Unicode | 显示 |
|
||||||
|
|---------|----------|---------|------|
|
||||||
|
| `-` | `-` | U+002D | - |
|
||||||
|
| `--` | `–` / `–` | U+2013 | – |
|
||||||
|
| `---` | `—` / `—` | U+2014 | — |
|
||||||
|
| `->` | `→` / `→` | U+2192 | → |
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **性能影响**:增加了字符串替换操作,但性能影响可忽略
|
||||||
|
2. **安全性**:只处理 Mermaid 代码块,不执行任何脚本
|
||||||
|
3. **兼容性**:支持所有现代浏览器
|
||||||
|
4. **调试**:添加详细日志,便于排查问题
|
||||||
|
|
||||||
|
## 后续优化
|
||||||
|
|
||||||
|
1. 考虑使用 DOMParser 解析 HTML,更可靠
|
||||||
|
2. 添加更多特殊字符的转换规则
|
||||||
|
3. 支持自定义字符映射表
|
||||||
|
4. 添加单元测试
|
||||||
|
|
||||||
|
## 参考资料
|
||||||
|
|
||||||
|
- [WordPress wptexturize() 函数](https://developer.wordpress.org/reference/functions/wptexturize/)
|
||||||
|
- [Unicode 字符表](https://unicode-table.com/)
|
||||||
|
- [Mermaid 语法文档](https://mermaid.js.org/intro/syntax-reference.html)
|
||||||
Reference in New Issue
Block a user