feat: add PHP preprocessing for Mermaid code blocks
- Add argon_format_mermaid_code filter in functions.php - Decode WP-Markdown escape characters in PHP - Auto-add newlines for single-line mermaid code - Simplify JavaScript rendering logic - Use data-mermaid-code attribute for preprocessed code - Remove debug console.log statements
This commit is contained in:
216
footer.php
216
footer.php
@@ -187,252 +187,74 @@
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理 WP-Markdown 生成的特殊格式:<div class="mermaid"><scr'+'ipt>document.write("...")</scr'+'ipt>...</div>
|
// 处理 WP-Markdown 生成的特殊格式
|
||||||
|
document.querySelectorAll('div.mermaid').forEach(function(mermaidDiv) {
|
||||||
document.querySelectorAll('div.mermaid script[type="text/javascript"]').forEach(function(scriptElement) {
|
|
||||||
|
|
||||||
let mermaidDiv = scriptElement.parentElement;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 检查是否已经处理过
|
// 检查是否已经处理过
|
||||||
|
|
||||||
if (mermaidDiv.classList.contains('mermaid-processed')) {
|
if (mermaidDiv.classList.contains('mermaid-processed')) {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mermaidDiv.classList.add('mermaid-processed');
|
mermaidDiv.classList.add('mermaid-processed');
|
||||||
|
|
||||||
|
// 优先使用 PHP 预处理的 data 属性
|
||||||
|
let code = mermaidDiv.getAttribute('data-mermaid-code');
|
||||||
|
|
||||||
|
if (!code) {
|
||||||
// 从 script 标签中提取代码
|
// 如果没有 data 属性,尝试从 script 标签提取
|
||||||
|
let scriptElement = mermaidDiv.querySelector('script[type="text/javascript"]');
|
||||||
|
if (scriptElement) {
|
||||||
let scriptContent = scriptElement.textContent;
|
let scriptContent = scriptElement.textContent;
|
||||||
|
|
||||||
console.log('=== WP-Markdown Debug ===');
|
|
||||||
|
|
||||||
console.log('Script content (first 300 chars):', scriptContent.substring(0, 300));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let match = scriptContent.match(/document\.write\("(.*)"\)/s);
|
let match = scriptContent.match(/document\.write\("(.*)"\)/s);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (match && match[1]) {
|
if (match && match[1]) {
|
||||||
|
code = match[1]
|
||||||
let rawCode = match[1];
|
|
||||||
|
|
||||||
console.log('Raw code (first 300 chars):', rawCode.substring(0, 300));
|
|
||||||
|
|
||||||
console.log('Contains literal backslash-n:', rawCode.includes('\\n'));
|
|
||||||
|
|
||||||
console.log('Contains actual newline:', rawCode.includes('\n'));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 解码转义字符
|
|
||||||
|
|
||||||
let code = rawCode
|
|
||||||
|
|
||||||
.replace(/\\n/g, '\n')
|
.replace(/\\n/g, '\n')
|
||||||
|
|
||||||
.replace(/\\"/g, '"')
|
.replace(/\\"/g, '"')
|
||||||
|
|
||||||
.replace(/\\'/g, "'")
|
.replace(/\\'/g, "'")
|
||||||
|
|
||||||
.replace(/</g, '<')
|
.replace(/</g, '<')
|
||||||
|
|
||||||
.replace(/>/g, '>')
|
.replace(/>/g, '>')
|
||||||
|
|
||||||
.replace(/&/g, '&');
|
.replace(/&/g, '&');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log('After decode (first 300 chars):', code.substring(0, 300));
|
|
||||||
|
|
||||||
console.log('After decode contains newline:', code.includes('\n'));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 检查前20个字符的详细信息
|
|
||||||
|
|
||||||
console.log('First 20 chars with codes:');
|
|
||||||
|
|
||||||
for (let i = 0; i < Math.min(20, code.length); i++) {
|
|
||||||
|
|
||||||
console.log(' [' + i + '] "' + code[i] + '" (code: ' + code.charCodeAt(i) + ')');
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!code) {
|
||||||
|
console.warn('No mermaid code found in div');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空 div 内容
|
||||||
console.log('WP-Markdown Mermaid code found (length: ' + code.length + ')');
|
|
||||||
|
|
||||||
console.log('Contains newlines:', code.indexOf('\n') !== -1);
|
|
||||||
|
|
||||||
console.log('First 100 chars:', code.substring(0, 100));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 清空 div 内容并设置新内容
|
|
||||||
|
|
||||||
mermaidDiv.innerHTML = '';
|
mermaidDiv.innerHTML = '';
|
||||||
|
|
||||||
// 使用 pre 标签包裹以保留换行符和空格
|
// 渲染 Mermaid 图表
|
||||||
|
|
||||||
let pre = document.createElement('pre');
|
|
||||||
|
|
||||||
pre.textContent = code;
|
|
||||||
|
|
||||||
pre.style.display = 'none';
|
|
||||||
|
|
||||||
mermaidDiv.appendChild(pre);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 同时设置为 data 属性
|
|
||||||
|
|
||||||
mermaidDiv.setAttribute('data-mermaid-code', code);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
console.log('Code set to div, checking...');
|
|
||||||
|
|
||||||
console.log('div.textContent (first 100):', mermaidDiv.textContent.substring(0, 100));
|
|
||||||
|
|
||||||
console.log('div.textContent contains newline:', mermaidDiv.textContent.includes('\n'));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 再次验证代码字符串
|
|
||||||
|
|
||||||
console.log('About to render, code char 12:', code.charCodeAt(12), '(should be 10 for newline)');
|
|
||||||
|
|
||||||
console.log('Code split by newline, first 3 lines:', code.split('\n').slice(0, 3));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 如果代码看起来像是一行(前100个字符中换行符很少),尝试智能添加换行
|
|
||||||
|
|
||||||
let first100 = code.substring(0, 100);
|
|
||||||
|
|
||||||
let newlineCount = (first100.match(/\n/g) || []).length;
|
|
||||||
|
|
||||||
console.log('Newline count in first 100 chars:', newlineCount);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (newlineCount < 2) {
|
|
||||||
|
|
||||||
console.log('Code appears to be on one line, attempting to add newlines...');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 简单粗暴的方法:在每个箭头和节点后添加换行
|
|
||||||
|
|
||||||
// 先移除所有现有的换行和多余空格,重新格式化
|
|
||||||
|
|
||||||
let lines = code.split(/\s*\n\s*/);
|
|
||||||
|
|
||||||
let formatted = lines[0]; // flowchart TD
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 处理剩余内容:在箭头前添加换行
|
|
||||||
|
|
||||||
let rest = lines.slice(1).join(' ');
|
|
||||||
|
|
||||||
rest = rest
|
|
||||||
|
|
||||||
.replace(/\s+/g, ' ') // 统一空格
|
|
||||||
|
|
||||||
.replace(/\s*-->\s*/g, '\n --> ') // 箭头前后换行
|
|
||||||
|
|
||||||
.replace(/\s*style\s+/g, '\nstyle '); // style 前换行
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
code = formatted + '\n' + rest;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
console.log('After adding newlines, first 300 chars:', code.substring(0, 300));
|
|
||||||
|
|
||||||
console.log('Newline count after fix:', (code.match(/\n/g) || []).length);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 立即渲染这个图表
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// 直接使用 mermaid.render 而不是 init
|
|
||||||
|
|
||||||
let id = 'mermaid-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
|
let id = 'mermaid-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
|
||||||
|
|
||||||
mermaid.render(id, code).then(function(result) {
|
mermaid.render(id, code).then(function(result) {
|
||||||
|
|
||||||
mermaidDiv.innerHTML = result.svg;
|
mermaidDiv.innerHTML = result.svg;
|
||||||
|
|
||||||
console.log('Mermaid diagram rendered successfully');
|
|
||||||
|
|
||||||
}).catch(function(e) {
|
}).catch(function(e) {
|
||||||
|
|
||||||
console.error('Mermaid rendering error:', e);
|
console.error('Mermaid rendering error:', e);
|
||||||
|
mermaidDiv.innerHTML = '<pre style="color: red;">Mermaid 渲染失败: ' + e.message + '</pre>';
|
||||||
console.error('Code that failed:', code.substring(0, 200));
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
||||||
console.error('Mermaid rendering error:', e);
|
console.error('Mermaid rendering error:', e);
|
||||||
|
mermaidDiv.innerHTML = '<pre style="color: red;">Mermaid 渲染失败: ' + e.message + '</pre>';
|
||||||
console.error('Code that failed:', code.substring(0, 200));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 递归获取所有文本节点,保留换行符
|
// 递归获取所有文本节点,保留换行符
|
||||||
|
|
||||||
function getTextWithLineBreaks(element) {
|
function getTextWithLineBreaks(element) {
|
||||||
|
|
||||||
let text = '';
|
let text = '';
|
||||||
|
|
||||||
for (let node of element.childNodes) {
|
for (let node of element.childNodes) {
|
||||||
|
|
||||||
if (node.nodeType === Node.TEXT_NODE) {
|
if (node.nodeType === Node.TEXT_NODE) {
|
||||||
|
|
||||||
text += node.textContent;
|
text += node.textContent;
|
||||||
|
|
||||||
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
||||||
|
|
||||||
if (node.tagName === 'BR') {
|
if (node.tagName === 'BR') {
|
||||||
|
|
||||||
text += '\n';
|
text += '\n';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
text += getTextWithLineBreaks(node);
|
text += getTextWithLineBreaks(node);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理标准格式的 mermaid 代码块
|
// 处理标准格式的 mermaid 代码块
|
||||||
|
|
||||||
document.querySelectorAll('pre code.language-mermaid, pre code.mermaid').forEach(function(element) {
|
document.querySelectorAll('pre code.language-mermaid, pre code.mermaid').forEach(function(element) {
|
||||||
|
|||||||
@@ -3607,6 +3607,52 @@ function the_content_filter($content){
|
|||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
add_filter('the_content' , 'the_content_filter',20);
|
add_filter('the_content' , 'the_content_filter',20);
|
||||||
|
|
||||||
|
// Mermaid 代码块预处理
|
||||||
|
function argon_format_mermaid_code($content) {
|
||||||
|
if (!get_option('argon_mermaid_enable', 'false') == 'true') {
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配 WP-Markdown 生成的 mermaid 代码块格式
|
||||||
|
$pattern = '/<div class="mermaid">(.*?)<\/div>/s';
|
||||||
|
|
||||||
|
$content = preg_replace_callback($pattern, function($matches) {
|
||||||
|
$div_content = $matches[1];
|
||||||
|
|
||||||
|
// 检查是否包含 script 标签(WP-Markdown 格式)
|
||||||
|
if (preg_match('/<script[^>]*>document\.write\("(.*)"\)<\/script>/s', $div_content, $script_match)) {
|
||||||
|
$mermaid_code = $script_match[1];
|
||||||
|
|
||||||
|
// 解码转义字符
|
||||||
|
$mermaid_code = str_replace('\\n', "\n", $mermaid_code);
|
||||||
|
$mermaid_code = str_replace('\\"', '"', $mermaid_code);
|
||||||
|
$mermaid_code = str_replace("\\'", "'", $mermaid_code);
|
||||||
|
$mermaid_code = html_entity_decode($mermaid_code);
|
||||||
|
|
||||||
|
// 如果代码看起来像一行(前100个字符中换行符很少),添加换行
|
||||||
|
$first_100 = substr($mermaid_code, 0, 100);
|
||||||
|
$newline_count = substr_count($first_100, "\n");
|
||||||
|
|
||||||
|
if ($newline_count < 2) {
|
||||||
|
// 在箭头前添加换行
|
||||||
|
$mermaid_code = preg_replace('/\s*-->\s*/', "\n --> ", $mermaid_code);
|
||||||
|
// 在 style 语句前添加换行
|
||||||
|
$mermaid_code = preg_replace('/\s*style\s+/', "\nstyle ", $mermaid_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回带 data 属性的 div
|
||||||
|
return '<div class="mermaid" data-mermaid-code="' . esc_attr($mermaid_code) . '">' . $div_content . '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不是 WP-Markdown 格式,保持原样
|
||||||
|
return $matches[0];
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
add_filter('the_content', 'argon_format_mermaid_code', 25);
|
||||||
|
|
||||||
//使用 CDN 加速 gravatar
|
//使用 CDN 加速 gravatar
|
||||||
function gravatar_cdn($url){
|
function gravatar_cdn($url){
|
||||||
$cdn = get_option('argon_gravatar_cdn', 'gravatar.pho.ink/avatar/');
|
$cdn = get_option('argon_gravatar_cdn', 'gravatar.pho.ink/avatar/');
|
||||||
|
|||||||
Reference in New Issue
Block a user