fix: 修复代码高亮和容器语法的两个关键问题
- 代码高亮排除 mermaid 代码块,避免干扰渲染 - 容器语法正确处理空行,不再截断内容 - 添加测试页面验证修复效果
This commit is contained in:
@@ -3,330 +3,205 @@
|
||||
<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 生成的格式包含 <script>document.write()</script> 标签
|
||||
</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([结束])
|
||||
</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">
|
||||
如果没有渲染任何图表,说明注释过滤功能正常工作 ✓
|
||||
<script>document.write("flowchart TD\nA[开始] --> B[处理]\nB --> C[结束]")</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 测试用例 2: document.write 格式(多行,带转义) -->
|
||||
<div class="test-case">
|
||||
<h2>测试 2: document.write 格式(多行,带转义)</h2>
|
||||
<div class="mermaid">
|
||||
<script>document.write("graph LR\n A[\"用户输入\"] --> B[\"数据验证\"]\n B --> C{\"是否有效?\"}\n C -->|是| D[\"保存数据\"]\n C -->|否| E[\"显示错误\"]")</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 测试用例 3: document.write 格式(包含 HTML 实体) -->
|
||||
<div class="test-case">
|
||||
<h2>测试 3: document.write 格式(包含 HTML 实体)</h2>
|
||||
<div class="mermaid">
|
||||
<script>document.write("sequenceDiagram\n Alice->>Bob: Hello Bob!\n Bob-->>Alice: Hi Alice!")</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 测试用例 4: 纯文本格式(无 script 标签) -->
|
||||
<div class="test-case">
|
||||
<h2>测试 4: 纯文本格式(无 script 标签)</h2>
|
||||
<div class="mermaid">
|
||||
flowchart TD
|
||||
Start --> Stop
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 测试用例 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("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');
|
||||
|
||||
// 检测所有 Mermaid 代码块
|
||||
function detectMermaidBlocks() {
|
||||
const blocks = [];
|
||||
const selectors = [
|
||||
'div.mermaid',
|
||||
'pre code.language-mermaid',
|
||||
'pre[data-lang="mermaid"]',
|
||||
'code.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() {
|
||||
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;
|
||||
selectors.forEach(selector => {
|
||||
const elements = document.querySelectorAll(selector);
|
||||
elements.forEach(element => {
|
||||
if (!blocks.includes(element)) {
|
||||
blocks.push(element);
|
||||
}
|
||||
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} 个图表`);
|
||||
},
|
||||
console.log(`[测试] 检测到 ${blocks.length} 个 Mermaid 代码块`);
|
||||
return blocks;
|
||||
}
|
||||
|
||||
renderChart(element, index) {
|
||||
const chartId = `mermaid-chart-${Date.now()}-${index}`;
|
||||
const testNumber = index + 1;
|
||||
// 提取代码块内容
|
||||
function extractMermaidCode(element) {
|
||||
let code = '';
|
||||
|
||||
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);
|
||||
if (element.tagName === 'DIV' && element.classList.contains('mermaid')) {
|
||||
const scriptTag = element.querySelector('script');
|
||||
if (scriptTag) {
|
||||
const scriptContent = scriptTag.textContent || scriptTag.innerText;
|
||||
console.log('[测试] 原始 script 内容:', scriptContent);
|
||||
|
||||
const resultDiv = document.getElementById(`result-${testNumber}`);
|
||||
if (resultDiv) {
|
||||
resultDiv.className = 'test-result error';
|
||||
resultDiv.textContent = `✗ 处理失败: ${error.message}`;
|
||||
// 匹配 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('[测试] 提取到的代码(转义前):', code);
|
||||
} else {
|
||||
const clonedElement = element.cloneNode(true);
|
||||
const scripts = clonedElement.querySelectorAll('script');
|
||||
scripts.forEach(script => script.remove());
|
||||
code = clonedElement.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;
|
||||
}
|
||||
};
|
||||
|
||||
// 页面加载完成后初始化
|
||||
// 解码 HTML 实体
|
||||
code = code
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/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();
|
||||
}
|
||||
|
||||
// 初始化并渲染
|
||||
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>
|
||||
|
||||
Reference in New Issue
Block a user