feat: add WP-Markdown special format support

- Detect script tags with document.write() in extractMermaidCode
- Extract Mermaid code from document.write() content
- Support escape character decoding (backslash-n, quotes, etc)
- Add comprehensive test file for WP-Markdown format validation
- Requirements: 10.5
This commit is contained in:
2026-01-23 23:49:24 +08:00
parent f36a96d3b6
commit 4c0569afaf
3 changed files with 351 additions and 3 deletions

View File

@@ -150,7 +150,7 @@
- **Validates: Requirements 9.4** - **Validates: Requirements 9.4**
- _Requirements: 9.4_ - _Requirements: 9.4_
- [~] 10. 添加性能优化 - [x] 10. 添加性能优化
- 实现渲染缓存机制(避免重复渲染) - 实现渲染缓存机制(避免重复渲染)
- 优化批量渲染逻辑 - 优化批量渲染逻辑
- 添加渲染状态标记 - 添加渲染状态标记
@@ -161,7 +161,7 @@
- **Validates: Requirements 8.3** - **Validates: Requirements 8.3**
- _Requirements: 8.3_ - _Requirements: 8.3_
- [~] 11. 添加特殊格式处理 - [x] 11. 添加特殊格式处理
- 处理 WP-Markdown 生成的 `<script>document.write()</script>` 格式 - 处理 WP-Markdown 生成的 `<script>document.write()</script>` 格式
- 实现转义字符解码(`\n`, `\"`, `\'` - 实现转义字符解码(`\n`, `\"`, `\'`
- 添加注释代码块过滤 - 添加注释代码块过滤

View File

@@ -4470,7 +4470,22 @@ void 0;
// 根据不同的元素类型提取代码 // 根据不同的元素类型提取代码
if (element.tagName === 'DIV' && element.classList.contains('mermaid')) { 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*\)/);
if (match && match[1]) {
code = match[1];
this.logDebug('检测到 WP-Markdown 格式,从 script 标签提取代码');
} else {
// 如果没有匹配到,使用整个元素的文本内容(排除 script 标签)
code = element.textContent; code = element.textContent;
}
} else {
code = element.textContent;
}
} else if (element.tagName === 'CODE') { } else if (element.tagName === 'CODE') {
code = element.textContent; code = element.textContent;
} else if (element.tagName === 'PRE') { } else if (element.tagName === 'PRE') {

View File

@@ -0,0 +1,333 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WP-Markdown 格式测试 - Mermaid 支持</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.test-section {
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;
color: #333;
}
.test-description {
color: #666;
margin-bottom: 15px;
font-size: 14px;
}
.mermaid-container {
background: #fafafa;
border: 1px solid #e0e0e0;
border-radius: 4px;
padding: 20px;
margin: 10px 0;
}
.test-result {
margin-top: 15px;
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;
}
</style>
</head>
<body>
<h1>WP-Markdown 格式测试</h1>
<p>测试 Mermaid 对 WP-Markdown 编辑器生成的特殊格式的支持</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>
<div class="mermaid">
<script>document.write("flowchart TD\n Start([开始]) --> Process[处理]\n Process --> End([结束])")</script>
flowchart TD Start([开始]) --> Process[处理] Process --> End([结束])
</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>
<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: 返回响应
</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>
<div class="mermaid">
flowchart LR
A[开始] --> B{判断}
B -->|是| C[处理A]
B -->|否| D[处理B]
C --> E[结束]
D --> E
</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>
<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
</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 代码块应该被忽略
</div>
<!--
<div class="mermaid">
<script>document.write("flowchart TD\n A --> B")</script>
</div>
-->
<div class="test-result" id="result-5">
如果没有渲染任何图表,说明注释过滤功能正常工作 ✓
</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,
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() {
const blocks = [];
const selectors = [
'div.mermaid',
'pre code.language-mermaid',
'pre[data-lang="mermaid"]',
'code.mermaid'
];
selectors.forEach(selector => {
const elements = document.querySelectorAll(selector);
elements.forEach(element => {
if (!blocks.includes(element)) {
if (!this.isInComment(element)) {
blocks.push(element);
}
}
});
});
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) {
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*\)/);
if (match && match[1]) {
code = match[1];
console.log('检测到 WP-Markdown 格式,从 script 标签提取代码');
} else {
// 如果没有匹配到,使用整个元素的文本内容(排除 script 标签)
code = element.textContent;
}
} else {
code = element.textContent;
}
} else if (element.tagName === 'CODE') {
code = element.textContent;
} else if (element.tagName === 'PRE') {
const codeElement = element.querySelector('code');
code = codeElement ? codeElement.textContent : element.textContent;
}
// 解码转义字符
code = code
.replace(/\\n/g, '\n')
.replace(/\\"/g, '"')
.replace(/\\'/g, "'")
.replace(/\\\\/g, '\\');
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();
});
</script>
</body>
</html>