fix: 修复代码高亮和容器语法的两个关键问题

- 代码高亮排除 mermaid 代码块,避免干扰渲染
- 容器语法正确处理空行,不再截断内容
- 添加测试页面验证修复效果
This commit is contained in:
2026-01-24 20:14:48 +08:00
parent 4c0569afaf
commit 0ac57949ae
4 changed files with 895 additions and 287 deletions

View File

@@ -3959,6 +3959,14 @@ function highlightJsRender(){
if ($(block).hasClass("no-hljs")){
return;
}
// 跳过 mermaid 代码块(避免代码高亮干扰 mermaid 渲染)
if ($(block).hasClass("language-mermaid") || $(block).hasClass("mermaid")){
return;
}
// 跳过在 .mermaid 容器内的代码块
if ($(block).closest('.mermaid').length > 0){
return;
}
$(block).parent().attr("id", randomString());
hljs.highlightBlock(block);
hljs.lineNumbersBlock(block, {singleLine: true});
@@ -4440,6 +4448,10 @@ void 0;
});
});
// 检测 Markdown 容器语法的 Mermaid 代码块
// 格式: ::: mermaid ... :::
this.detectContainerBlocks(blocks);
this.logDebug(`检测到 ${blocks.length} 个 Mermaid 代码块`);
return blocks;
},
@@ -4460,6 +4472,79 @@ void 0;
return false;
},
/**
* 检测 Markdown 容器语法的 Mermaid 代码块
* 格式: ::: mermaid ... :::
* @param {Array} blocks - 代码块数组
*/
detectContainerBlocks(blocks) {
// 查找所有包含 ::: mermaid 的文本节点或 pre/code 元素
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT,
{
acceptNode: function(node) {
// 检查 pre 或 code 元素
if (node.tagName === 'PRE' || node.tagName === 'CODE') {
const text = node.textContent;
if (text && text.trim().startsWith('::: mermaid')) {
return NodeFilter.FILTER_ACCEPT;
}
}
// 检查 p 元素(可能被 Markdown 解析器包裹)
if (node.tagName === 'P') {
const text = node.textContent;
if (text && text.trim().startsWith('::: mermaid')) {
return NodeFilter.FILTER_ACCEPT;
}
}
return NodeFilter.FILTER_SKIP;
}
},
false
);
while (walker.nextNode()) {
const element = walker.currentNode;
const container = this.extractContainerContent(element);
if (container && !blocks.includes(container)) {
blocks.push(container);
this.logDebug('检测到 Markdown 容器语法的 Mermaid 代码块');
}
}
},
/**
* 提取 Markdown 容器语法的内容
* @param {HTMLElement} element - 包含容器语法的元素
* @returns {HTMLElement|null} 包含代码的容器元素
*/
extractContainerContent(element) {
let text = element.textContent.trim();
// 移除开始标记 ::: mermaid保留后面的换行符和空行
text = text.replace(/^:::\s*mermaid\s*\n?/i, '');
// 移除结束标记 :::(保留前面的换行符和空行)
text = text.replace(/\n?:::\s*$/i, '');
// 不要 trim保留代码中的空行
if (!text) {
return null;
}
// 创建一个新的容器来存储代码
const container = document.createElement('div');
container.className = 'mermaid-container-block';
container.textContent = text;
container.dataset.containerBlock = 'true';
// 替换原始元素
element.parentNode.replaceChild(container, element);
return container;
},
/**
* 提取代码块内容
* @param {HTMLElement} element - 代码块元素
@@ -4468,23 +4553,46 @@ void 0;
extractMermaidCode(element) {
let code = '';
// 处理 Markdown 容器语法格式
if (element.classList.contains('mermaid-container-block')) {
code = element.textContent;
this.logDebug('从 Markdown 容器语法提取代码');
}
// 根据不同的元素类型提取代码
if (element.tagName === 'DIV' && element.classList.contains('mermaid')) {
else if (element.tagName === 'DIV' && element.classList.contains('mermaid')) {
// 检查是否包含 WP-Markdown 生成的 script 标签
const scriptTag = element.querySelector('script');
if (scriptTag) {
// 提取 document.write() 中的内容
const scriptContent = scriptTag.textContent || scriptTag.innerText;
const match = scriptContent.match(/document\.write\s*\(\s*["'](.+?)["']\s*\)/);
this.logDebug('检测到 script 标签,原始内容: ' + scriptContent.substring(0, 100));
// 使用更精确的正则:匹配 document.write() 中的字符串内容
// 支持双引号和单引号,支持转义字符
// 使用贪婪匹配 [\s\S]* 来匹配包括换行在内的所有字符
let match = scriptContent.match(/document\.write\s*\(\s*["']([\s\S]*?)["']\s*\)/);
if (match && match[1]) {
code = match[1];
this.logDebug('检测到 WP-Markdown 格式,从 script 标签提取代码');
this.logDebug('从 document.write() 提取代码,长度: ' + code.length);
} else {
// 如果没有匹配到,使用整个元素的文本内容(排除 script 标签)
code = element.textContent;
// 如果没有匹配到 document.write(),尝试直接提取引号内的内容
match = scriptContent.match(/["']([\s\S]*?)["']/);
if (match && match[1]) {
code = match[1];
this.logDebug('从引号内提取到代码,长度: ' + code.length);
} else {
// 最后的降级方案:获取除 script 标签外的文本内容
const clonedElement = element.cloneNode(true);
const scripts = clonedElement.querySelectorAll('script');
scripts.forEach(script => script.remove());
code = clonedElement.textContent;
this.logDebug('使用降级方案提取代码');
}
}
} else {
code = element.textContent;
this.logDebug('从纯文本提取代码');
}
} else if (element.tagName === 'CODE') {
code = element.textContent;
@@ -4493,13 +4601,24 @@ void 0;
code = codeElement ? codeElement.textContent : element.textContent;
}
// 解码转义字符
// 解码 HTML 实体WordPress 可能会转义 HTML
code = code
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
.replace(/&quot;/g, '"')
.replace(/&#039;/g, "'");
// 解码转义字符(必须在 HTML 实体解码之后)
code = code
.replace(/\\n/g, '\n')
.replace(/\\t/g, '\t')
.replace(/\\r/g, '\r')
.replace(/\\"/g, '"')
.replace(/\\'/g, "'")
.replace(/\\\\/g, '\\');
this.logDebug('最终提取的代码: ' + code.substring(0, 100) + (code.length > 100 ? '...' : ''));
return code.trim();
},

338
docs/mermaid-usage-guide.md Normal file
View File

@@ -0,0 +1,338 @@
# Argon 主题 Mermaid 图表使用指南
## 推荐的标记方式
### Markdown 容器语法(推荐)⭐
```markdown
::: mermaid
flowchart TD
A[开始] --> B[处理]
B --> C[结束]
:::
```
**优点**
- ✅ 符合 Markdown 扩展规范VuePress、Docusaurus 等使用相同语法)
- ✅ 不会被 WP-Markdown 当作代码块处理,避免嵌套问题
- ✅ 语法简洁,易于编写和阅读
- ✅ 支持所有 Mermaid 图表类型
- ✅ 在纯文本编辑器中也很清晰
- ✅ 易于迁移到其他平台
### 为什么使用容器语法?
**Markdown 容器语法** (`::: mermaid ... :::`) 是现代 Markdown 扩展的标准方式:
- **VuePress** 使用这种语法
- **Docusaurus** 使用这种语法
- **MkDocs** 使用类似语法
- **符合 CommonMark 扩展规范**
这种语法不会被 WP-Markdown 插件当作代码块处理,因此:
- 不会被套上代码高亮窗口
- 不会有嵌套结构问题
- 不会有字符转义问题
---
## 使用示例
### 流程图
```markdown
::: mermaid
flowchart LR
A[用户] --> B{登录?}
B -->|是| C[显示首页]
B -->|否| D[跳转登录页]
:::
```
### 时序图
```markdown
::: mermaid
sequenceDiagram
Alice->>Bob: Hello Bob!
Bob-->>Alice: Hi Alice!
Alice->>Bob: How are you?
:::
```
### 类图
```markdown
::: mermaid
classDiagram
class Animal {
+String name
+int age
+makeSound()
}
class Dog {
+String breed
+bark()
}
Animal <|-- Dog
:::
```
### 甘特图
```markdown
::: mermaid
gantt
title 项目进度
dateFormat YYYY-MM-DD
section 设计
需求分析 :a1, 2024-01-01, 7d
UI设计 :a2, after a1, 5d
section 开发
前端开发 :b1, after a2, 10d
后端开发 :b2, after a2, 12d
:::
```
### 状态图
```markdown
::: mermaid
stateDiagram-v2
[*] --> 待审核
待审核 --> 已通过: 审核通过
待审核 --> 已拒绝: 审核拒绝
已通过 --> [*]
已拒绝 --> [*]
:::
```
### 饼图
```markdown
::: mermaid
pie title 宠物分布
"狗" : 386
"猫" : 85
"兔子" : 15
:::
```
---
## 常见问题
### 1. 如何在 WordPress 编辑器中使用?
**在经典编辑器中:**
1. 切换到"文本"模式(不是"可视化"模式)
2. 直接输入容器语法
3. 保存并预览
**在 Gutenberg 编辑器中:**
1. 添加"自定义 HTML"块或"代码"块
2. 输入容器语法
3. 保存并预览
### 2. 已有文章如何迁移?
如果你的文章使用了传统的 Markdown 代码块,可以批量替换:
**查找:**
```
三个反引号mermaid
```
**替换为:**
```
::: mermaid
```
**查找:**
```
三个反引号(代码块结束)
```
**替换为:**
```
:::
```
### 3. 容器语法不生效怎么办?
**可能的原因:**
- 其他插件或主题处理了容器语法
- WP-Markdown 插件版本过旧
**解决方案:**
1. 检查是否有其他 Markdown 插件冲突
2. 更新 WP-Markdown 插件到最新版本
3. 查看浏览器控制台的错误信息
### 4. 渲染失败怎么办?
**排查步骤:**
1. **检查语法**
- 访问 [Mermaid Live Editor](https://mermaid.live/) 验证语法
- 确保图表类型正确
2. **查看控制台**
- 按 F12 打开开发者工具
- 查看 Console 标签页
- 搜索 `[Argon Mermaid]` 日志
3. **检查主题设置**
- WordPress 后台 → 外观 → Argon 主题选项
- 找到"Mermaid 图表"分类
- 确认"启用 Mermaid 支持"已开启
4. **测试 CDN 连接**
- 访问测试页面验证 CDN 是否可用
- 如果 CDN 失败,尝试切换到其他 CDN
---
## 最佳实践
### 1. 使用容器语法
**推荐:**
```markdown
::: mermaid
flowchart TD
A --> B
:::
```
**不推荐:**
```
三个反引号mermaid
flowchart TD
A --> B
三个反引号
```
### 2. 避免特殊字符
如果图表中包含特殊字符,使用引号包裹:
```markdown
::: mermaid
flowchart TD
A["包含 <特殊> 字符"] --> B["使用引号包裹"]
:::
```
### 3. 测试复杂图表
对于复杂的图表:
1. 先在 [Mermaid Live Editor](https://mermaid.live/) 中测试
2. 确认语法正确后再粘贴到文章中
3. 发布前预览文章
### 4. 启用调试模式
如果遇到问题:
1. 主题设置 → Mermaid 图表 → 基本设置
2. 开启"调试模式"
3. 刷新页面查看控制台日志
### 5. 保持代码简洁
- 使用有意义的节点 ID
- 添加适当的注释
- 保持图表结构清晰
---
## 技术细节
### 支持的标记格式
Argon 主题支持以下格式(按优先级排序):
1. `::: mermaid ... :::` - Markdown 容器语法 ⭐(推荐)
2. `<div class="mermaid">` - 标准格式WPMD 生成)
3. `<pre><code class="language-mermaid">` - Markdown 格式
4. `<pre data-lang="mermaid">` - 自定义属性格式
5. `<code class="mermaid">` - 简化格式
### 代码提取逻辑
1. **检测代码块**
- CSS 选择器查找标准格式
- TreeWalker 查找容器语法
2. **提取代码**
- 容器语法:移除 `::: mermaid``:::`
- WPMD 格式:正则提取 `document.write()` 内容
- 标准格式:直接提取文本内容
3. **解码处理**
- 先解码 HTML 实体(`&lt;``<`
- 再解码转义字符(`\n` → 换行符)
4. **渲染图表**
- 使用 Mermaid.js 库渲染为 SVG
- 应用主题样式(夜间模式适配)
- 错误时显示友好提示
---
## 故障排除
### 问题:容器语法被显示为普通文本
**症状**`::: mermaid` 被显示在页面上
**原因**:可能被其他插件或主题处理为普通文本
**解决**
- 检查是否有其他 Markdown 插件冲突
- 确认 Argon 主题已更新到最新版本
- 查看浏览器控制台是否有 JavaScript 错误
### 问题:只显示第一个单词
**症状**:图表渲染失败,错误信息显示 `"text": "flowchart"`
**原因**:代码提取不完整
**解决**
- 确保使用最新版本的 Argon 主题
- 使用容器语法而不是传统代码块
- 查看控制台日志确认提取到的完整代码
### 问题HTML 实体未解码
**症状**:图表中显示 `&lt;` 而不是 `<`
**原因**HTML 实体解码失败
**解决**
- Argon 主题会自动解码 HTML 实体
- 使用容器语法可避免此问题
- 在 Mermaid 代码中使用引号包裹特殊字符
---
## 相关资源
- [Mermaid 官方文档](https://mermaid.js.org/)
- [Mermaid Live Editor](https://mermaid.live/)
- [VuePress 容器语法](https://vuepress.vuejs.org/guide/markdown.html#custom-containers)
- [CommonMark 规范](https://commonmark.org/)
---
## 更新日志
### 2026-01-24
- ✅ 添加 Markdown 容器语法支持(`::: mermaid ... :::`
- ✅ 修复 WP-Markdown 格式的代码提取问题
- ✅ 改进正则表达式,支持多行代码
- ✅ 添加降级方案和详细日志
- ✅ 简化标记方式,只保留容器语法作为推荐方式
- ✅ 修复代码高亮干扰 mermaid 渲染的问题(排除 mermaid 代码块)
- ✅ 修复容器语法中空行导致内容被截断的问题

View File

@@ -0,0 +1,276 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mermaid 修复测试</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.test-section {
background: white;
padding: 20px;
margin-bottom: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.test-section h2 {
color: #5e72e4;
border-bottom: 2px solid #5e72e4;
padding-bottom: 10px;
}
.test-case {
margin: 15px 0;
padding: 15px;
background: #f8f9fa;
border-left: 4px solid #5e72e4;
}
.test-case h3 {
margin-top: 0;
color: #333;
}
.expected {
color: #28a745;
font-weight: bold;
}
.code-block {
background: #2d2d2d;
color: #d4d4d4;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
font-family: 'Courier New', monospace;
font-size: 14px;
}
.mermaid {
background: white;
padding: 20px;
border: 1px solid #ddd;
border-radius: 4px;
margin: 10px 0;
}
pre code.language-mermaid {
display: block;
background: #f8f9fa;
padding: 15px;
border: 2px dashed #5e72e4;
border-radius: 4px;
}
</style>
</head>
<body>
<h1>🧪 Mermaid 修复测试页面</h1>
<p>本页面用于测试两个关键修复:</p>
<ol>
<li><strong>代码高亮排除 mermaid</strong>mermaid 代码块不应被代码高亮处理</li>
<li><strong>容器语法处理空行</strong>:容器语法中的空行应被正确保留</li>
</ol>
<!-- 测试 1: 代码高亮排除 -->
<div class="test-section">
<h2>测试 1: 代码高亮排除 Mermaid</h2>
<div class="test-case">
<h3>测试 1.1: 标准 Markdown 格式(应该被排除)</h3>
<p class="expected">✅ 预期:不应出现代码高亮窗口,直接渲染为 Mermaid 图表</p>
<pre><code class="language-mermaid">
flowchart TD
A[开始] --> B[处理]
B --> C[结束]
</code></pre>
</div>
<div class="test-case">
<h3>测试 1.2: 标准 div.mermaid 格式(应该被排除)</h3>
<p class="expected">✅ 预期:不应出现代码高亮窗口,直接渲染为 Mermaid 图表</p>
<div class="mermaid">
flowchart LR
A[用户] --> B{登录?}
B -->|是| C[显示首页]
B -->|否| D[跳转登录页]
</div>
</div>
<div class="test-case">
<h3>测试 1.3: 普通代码块(应该被高亮)</h3>
<p class="expected">✅ 预期:应该出现代码高亮窗口</p>
<pre><code class="language-javascript">
function hello() {
console.log('Hello World');
}
</code></pre>
</div>
</div>
<!-- 测试 2: 容器语法空行处理 -->
<div class="test-section">
<h2>测试 2: 容器语法空行处理</h2>
<div class="test-case">
<h3>测试 2.1: 包含空行的流程图</h3>
<p class="expected">✅ 预期:空行应被保留,图表正常渲染</p>
<div class="code-block">
::: mermaid
flowchart TD
A[开始]
B[处理步骤1]
C[处理步骤2]
D[结束]
A --> B
B --> C
C --> D
:::
</div>
<p>实际渲染:</p>
<p>
::: mermaid
flowchart TD
A[开始]
B[处理步骤1]
C[处理步骤2]
D[结束]
A --> B
B --> C
C --> D
:::
</p>
</div>
<div class="test-case">
<h3>测试 2.2: 包含空行的时序图</h3>
<p class="expected">✅ 预期:空行应被保留,图表正常渲染</p>
<div class="code-block">
::: mermaid
sequenceDiagram
participant A as Alice
participant B as Bob
A->>B: Hello Bob!
Note over A,B: 这是一个注释
B-->>A: Hi Alice!
:::
</div>
<p>实际渲染:</p>
<p>
::: mermaid
sequenceDiagram
participant A as Alice
participant B as Bob
A->>B: Hello Bob!
Note over A,B: 这是一个注释
B-->>A: Hi Alice!
:::
</p>
</div>
<div class="test-case">
<h3>测试 2.3: 包含多个连续空行</h3>
<p class="expected">✅ 预期:多个空行应被保留,图表正常渲染</p>
<div class="code-block">
::: mermaid
flowchart LR
A[步骤A]
B[步骤B]
C[步骤C]
A --> B --> C
:::
</div>
<p>实际渲染:</p>
<p>
::: mermaid
flowchart LR
A[步骤A]
B[步骤B]
C[步骤C]
A --> B --> C
:::
</p>
</div>
</div>
<!-- 测试 3: WP-Markdown 格式 -->
<div class="test-section">
<h2>测试 3: WP-Markdown 格式兼容性</h2>
<div class="test-case">
<h3>测试 3.1: document.write 格式</h3>
<p class="expected">✅ 预期:正确提取代码并渲染</p>
<div class="mermaid">
<script>document.write("flowchart TD\n A[开始] --> B[结束]")</script>
</div>
</div>
</div>
<!-- 测试结果说明 -->
<div class="test-section">
<h2>📋 测试检查清单</h2>
<ul>
<li>
<input type="checkbox" id="check1">
<label for="check1">测试 1.1: Markdown 格式的 mermaid 代码块没有代码高亮窗口</label>
</li>
<li>
<input type="checkbox" id="check2">
<label for="check2">测试 1.2: div.mermaid 格式没有代码高亮窗口</label>
</li>
<li>
<input type="checkbox" id="check3">
<label for="check3">测试 1.3: 普通 JavaScript 代码有代码高亮窗口</label>
</li>
<li>
<input type="checkbox" id="check4">
<label for="check4">测试 2.1: 包含空行的流程图正常渲染</label>
</li>
<li>
<input type="checkbox" id="check5">
<label for="check5">测试 2.2: 包含空行的时序图正常渲染</label>
</li>
<li>
<input type="checkbox" id="check6">
<label for="check6">测试 2.3: 包含多个连续空行的图表正常渲染</label>
</li>
<li>
<input type="checkbox" id="check7">
<label for="check7">测试 3.1: WP-Markdown 格式正常渲染</label>
</li>
</ul>
</div>
<script>
// 简单的日志输出
console.log('[Mermaid Test] 测试页面已加载');
console.log('[Mermaid Test] 请检查:');
console.log('[Mermaid Test] 1. mermaid 代码块是否被代码高亮处理');
console.log('[Mermaid Test] 2. 容器语法中的空行是否被正确保留');
console.log('[Mermaid Test] 3. 所有图表是否正常渲染');
</script>
</body>
</html>

View File

@@ -3,183 +3,102 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WP-Markdown 格式测试 - Mermaid 支持</title>
<title>WP-Markdown Mermaid 格式测试</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.test-section {
.test-case {
background: white;
padding: 20px;
margin: 20px 0;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.test-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
h2 {
color: #333;
border-bottom: 2px solid #007bff;
padding-bottom: 10px;
}
.test-description {
color: #666;
margin-bottom: 15px;
font-size: 14px;
}
.mermaid-container {
background: #fafafa;
border: 1px solid #e0e0e0;
.mermaid {
background: #f9f9f9;
padding: 15px;
border: 1px solid #ddd;
border-radius: 4px;
padding: 20px;
margin: 10px 0;
}
.test-result {
margin-top: 15px;
pre {
background: #f4f4f4;
padding: 10px;
border-radius: 4px;
font-size: 14px;
}
.test-result.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.test-result.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.code-preview {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 4px;
padding: 10px;
margin: 10px 0;
font-family: 'Courier New', monospace;
font-size: 12px;
white-space: pre-wrap;
word-break: break-all;
overflow-x: auto;
}
</style>
</head>
<body>
<h1>WP-Markdown 格式测试</h1>
<p>测试 Mermaid 对 WP-Markdown 编辑器生成的特殊格式的支持</p>
<h1>WP-Markdown Mermaid 格式测试</h1>
<p>本页面测试 WP-Markdown 插件生成的各种 Mermaid 代码块格式</p>
<!-- 测试 1: 标准 WP-Markdown 格式 -->
<div class="test-section">
<div class="test-title">测试 1: 标准 WP-Markdown 格式(带 script 标签</div>
<div class="test-description">
WP-Markdown 生成的格式包含 &lt;script&gt;document.write()&lt;/script&gt; 标签
</div>
<!-- 测试用例 1: 标准 document.write 格式(单行) -->
<div class="test-case">
<h2>测试 1: 标准 document.write 格式(单行</h2>
<div class="mermaid">
<script>document.write("flowchart TD\n Start([开始]) --> Process[处理]\n Process --> End([结束])")</script>
flowchart TD Start([开始]) --> Process[处理] Process --> End([结束])
<script>document.write("flowchart TD\nA[开始] --> B[处理]\nB --> C[结束]")</script>
</div>
<div class="test-result" id="result-1">等待渲染...</div>
</div>
<!-- 测试 2: 带转义字符的 WP-Markdown 格式 -->
<div class="test-section">
<div class="test-title">测试 2: 带转义字符的复杂格式</div>
<div class="test-description">
测试转义字符的正确解码:\n换行、\"(引号)、\'(单引号)
</div>
<!-- 测试用例 2: document.write 格式(多行,带转义) -->
<div class="test-case">
<h2>测试 2: document.write 格式(多行,带转义)</h2>
<div class="mermaid">
<script>document.write("sequenceDiagram\n participant A as \"用户\"\n participant B as '服务器'\n A->>B: 发送请求\n B->>A: 返回响应")</script>
sequenceDiagram participant A as "用户" participant B as '服务器' A->>B: 发送请求 B->>A: 返回响应
<script>document.write("graph LR\n A[\"用户输入\"] --> B[\"数据验证\"]\n B --> C{\"是否有效?\"}\n C -->|是| D[\"保存数据\"]\n C -->|否| E[\"显示错误\"]")</script>
</div>
<div class="test-result" id="result-2">等待渲染...</div>
</div>
<!-- 测试 3: 标准格式(无 script 标签 -->
<div class="test-section">
<div class="test-title">测试 3: 标准格式(无 script 标签</div>
<div class="test-description">
确保标准格式仍然正常工作
</div>
<!-- 测试用例 3: document.write 格式(包含 HTML 实体 -->
<div class="test-case">
<h2>测试 3: document.write 格式(包含 HTML 实体</h2>
<div class="mermaid">
flowchart LR
A[开始] --> B{判断}
B -->|是| C[处理A]
B -->|否| D[处理B]
C --> E[结束]
D --> E
<script>document.write("sequenceDiagram\n Alice-&gt;&gt;Bob: Hello Bob!\n Bob--&gt;&gt;Alice: Hi Alice!")</script>
</div>
<div class="test-result" id="result-3">等待渲染...</div>
</div>
<!-- 测试 4: 复杂的 WP-Markdown 格式 -->
<div class="test-section">
<div class="test-title">测试 4: 复杂流程图WP-Markdown 格式</div>
<div class="test-description">
测试包含多种节点类型和连接的复杂流程图
</div>
<!-- 测试用例 4: 纯文本格式(无 script 标签) -->
<div class="test-case">
<h2>测试 4: 纯文本格式(无 script 标签</h2>
<div class="mermaid">
<script>document.write("flowchart TD\n Start([用户提交评论]) --> PreProcess[preprocess_comment 钩子]\n PreProcess --> CheckEnabled{启用 AI 检测?}\n CheckEnabled -->|否| SaveComment[保存评论]\n CheckEnabled -->|是| CheckMode{检测模式}\n CheckMode -->|实时检测| RealTime[实时 AI 检测]\n CheckMode -->|批量扫描| BatchScan[批量扫描]\n RealTime --> IsSpam{是否垃圾?}\n IsSpam -->|是| MarkSpam[标记为垃圾]\n IsSpam -->|否| SaveComment\n BatchScan --> SaveComment")</script>
flowchart TD Start([用户提交评论]) --> PreProcess[preprocess_comment 钩子] PreProcess --> CheckEnabled{启用 AI 检测?} CheckEnabled -->|否| SaveComment[保存评论] CheckEnabled -->|是| CheckMode{检测模式} CheckMode -->|实时检测| RealTime[实时 AI 检测] CheckMode -->|批量扫描| BatchScan[批量扫描] RealTime --> IsSpam{是否垃圾?} IsSpam -->|是| MarkSpam[标记为垃圾] IsSpam -->|否| SaveComment BatchScan --> SaveComment
flowchart TD
Start --> Stop
</div>
<div class="test-result" id="result-4">等待渲染...</div>
</div>
<!-- 测试 5: 注释中的代码块(应该被忽略) -->
<div class="test-section">
<div class="test-title">测试 5: 注释中的代码块(应该被忽略)</div>
<div class="test-description">
被 HTML 注释包裹的 Mermaid 代码块应该被忽略
<!-- 测试用例 5: pre code 格式 -->
<div class="test-case">
<h2>测试 5: pre code 格式</h2>
<pre><code class="language-mermaid">graph TD
A --> B
B --> C</code></pre>
</div>
<!--
<!-- 测试用例 6: 复杂图表(类图) -->
<div class="test-case">
<h2>测试 6: 复杂图表(类图)</h2>
<div class="mermaid">
<script>document.write("flowchart TD\n A --> B")</script>
</div>
-->
<div class="test-result" id="result-5">
如果没有渲染任何图表,说明注释过滤功能正常工作 ✓
<script>document.write("classDiagram\n class Animal {\n +String name\n +int age\n +makeSound()\n }\n class Dog {\n +String breed\n +bark()\n }\n Animal <|-- Dog")</script>
</div>
</div>
<!-- 加载 Mermaid 库 -->
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<!-- 模拟 Argon 主题的 Mermaid 模块 -->
<script>
// 简化版的 Mermaid 模块(用于测试)
const ArgonMermaid = {
config: {
theme: 'default'
},
initialized: false,
// 模拟 Argon 主题的 Mermaid 初始化逻辑
console.log('[测试] 开始初始化 Mermaid');
init() {
if (typeof window.mermaid === 'undefined') {
console.error('Mermaid 库未加载');
return;
}
// 初始化 Mermaid
window.mermaid.initialize({
startOnLoad: false,
theme: this.getMermaidTheme(),
securityLevel: 'loose',
logLevel: 'error'
});
this.initialized = true;
console.log('Mermaid 初始化完成');
// 渲染所有图表
this.renderAllCharts();
},
getMermaidTheme() {
return this.config.theme;
},
detectMermaidBlocks() {
// 检测所有 Mermaid 代码块
function detectMermaidBlocks() {
const blocks = [];
const selectors = [
'div.mermaid',
@@ -192,45 +111,39 @@ flowchart LR
const elements = document.querySelectorAll(selector);
elements.forEach(element => {
if (!blocks.includes(element)) {
if (!this.isInComment(element)) {
blocks.push(element);
}
}
});
});
console.log(`检测到 ${blocks.length} 个 Mermaid 代码块`);
console.log(`[测试] 检测到 ${blocks.length} 个 Mermaid 代码块`);
return blocks;
},
isInComment(element) {
let node = element.parentNode;
while (node) {
if (node.nodeType === Node.COMMENT_NODE) {
return true;
}
node = node.parentNode;
}
return false;
},
extractMermaidCode(element) {
// 提取代码块内容
function extractMermaidCode(element) {
let code = '';
// 根据不同的元素类型提取代码
if (element.tagName === 'DIV' && element.classList.contains('mermaid')) {
// 检查是否包含 WP-Markdown 生成的 script 标签
const scriptTag = element.querySelector('script');
if (scriptTag) {
// 提取 document.write() 中的内容
const scriptContent = scriptTag.textContent || scriptTag.innerText;
const match = scriptContent.match(/document\.write\s*\(\s*["'](.+?)["']\s*\)/);
console.log('[测试] 原始 script 内容:', scriptContent);
// 匹配 document.write("...") 或 document.write('...')
let match = scriptContent.match(/document\.write\s*\(\s*"((?:[^"\\]|\\.)*)"\s*\)/s);
if (!match) {
match = scriptContent.match(/document\.write\s*\(\s*'((?:[^'\\]|\\.)*)'\s*\)/s);
}
if (match && match[1]) {
code = match[1];
console.log('检测到 WP-Markdown 格式,从 script 标签提取代码');
console.log('[测试] 提取到的代码(转义前):', code);
} else {
// 如果没有匹配到,使用整个元素的文本内容(排除 script 标签)
code = element.textContent;
const clonedElement = element.cloneNode(true);
const scripts = clonedElement.querySelectorAll('script');
scripts.forEach(script => script.remove());
code = clonedElement.textContent;
}
} else {
code = element.textContent;
@@ -242,91 +155,53 @@ flowchart LR
code = codeElement ? codeElement.textContent : element.textContent;
}
// 解码 HTML 实体
code = code
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
.replace(/&quot;/g, '"')
.replace(/&#039;/g, "'");
// 解码转义字符
code = code
.replace(/\\n/g, '\n')
.replace(/\\t/g, '\t')
.replace(/\\r/g, '\r')
.replace(/\\"/g, '"')
.replace(/\\'/g, "'")
.replace(/\\\\/g, '\\');
console.log('[测试] 最终提取的代码:', code);
return code.trim();
},
renderAllCharts() {
if (!this.initialized) {
console.log('Mermaid 未初始化,跳过渲染');
return;
}
const blocks = this.detectMermaidBlocks();
if (blocks.length === 0) {
console.log('未找到 Mermaid 代码块');
return;
}
blocks.forEach((block, index) => {
this.renderChart(block, index);
});
console.log(`完成渲染 ${blocks.length} 个图表`);
},
renderChart(element, index) {
const chartId = `mermaid-chart-${Date.now()}-${index}`;
const testNumber = index + 1;
try {
const code = this.extractMermaidCode(element);
if (!code) {
console.log(`代码块为空,跳过: ${chartId}`);
return;
}
console.log(`提取的代码 (测试 ${testNumber}):`, code);
const container = document.createElement('div');
container.className = 'mermaid-container';
container.id = chartId;
window.mermaid.render(`mermaid-svg-${chartId}`, code).then(result => {
container.innerHTML = result.svg;
element.parentNode.replaceChild(container, element);
// 更新测试结果
const resultDiv = document.getElementById(`result-${testNumber}`);
if (resultDiv) {
resultDiv.className = 'test-result success';
resultDiv.textContent = '✓ 渲染成功';
}
console.log(`图表渲染成功: ${chartId}`);
}).catch(error => {
console.error(`图表渲染失败: ${chartId}`, error);
const resultDiv = document.getElementById(`result-${testNumber}`);
if (resultDiv) {
resultDiv.className = 'test-result error';
resultDiv.innerHTML = `✗ 渲染失败: ${error.message}<br><div class="code-preview">${code}</div>`;
}
});
} catch (error) {
console.error(`处理图表失败: ${chartId}`, error);
const resultDiv = document.getElementById(`result-${testNumber}`);
if (resultDiv) {
resultDiv.className = 'test-result error';
resultDiv.textContent = `✗ 处理失败: ${error.message}`;
}
}
}
};
// 页面加载完成后初始化
// 初始化并渲染
document.addEventListener('DOMContentLoaded', function() {
console.log('页面加载完成,初始化 Mermaid');
ArgonMermaid.init();
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose'
});
const blocks = detectMermaidBlocks();
blocks.forEach((block, index) => {
const code = extractMermaidCode(block);
const chartId = `mermaid-chart-${index}`;
console.log(`[测试] 渲染图表 ${index}:`, code);
mermaid.render(chartId, code).then(result => {
const container = document.createElement('div');
container.innerHTML = result.svg;
block.parentNode.replaceChild(container, block);
console.log(`[测试] 图表 ${index} 渲染成功`);
}).catch(error => {
console.error(`[测试] 图表 ${index} 渲染失败:`, error);
block.style.border = '2px solid red';
block.innerHTML = `<strong style="color: red;">渲染失败: ${error.message}</strong><br><pre>${code}</pre>`;
});
});
});
</script>
</body>