From ccd3cfa877fde603a416741a6bf8b42e490744d9 Mon Sep 17 00:00:00 2001 From: nanhaoluo <3075912108@qq.com> Date: Fri, 23 Jan 2026 21:56:30 +0800 Subject: [PATCH] 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 --- footer.php | 290 ++++++++++---------------------------------------- functions.php | 46 ++++++++ 2 files changed, 102 insertions(+), 234 deletions(-) diff --git a/footer.php b/footer.php index 18a20cc..a0521cc 100644 --- a/footer.php +++ b/footer.php @@ -187,252 +187,74 @@ }); - // 处理 WP-Markdown 生成的特殊格式:
document.write("...")...
- - document.querySelectorAll('div.mermaid script[type="text/javascript"]').forEach(function(scriptElement) { - - let mermaidDiv = scriptElement.parentElement; - - - + // 处理 WP-Markdown 生成的特殊格式 + document.querySelectorAll('div.mermaid').forEach(function(mermaidDiv) { // 检查是否已经处理过 - if (mermaidDiv.classList.contains('mermaid-processed')) { - return; - } - mermaidDiv.classList.add('mermaid-processed'); - - - // 从 script 标签中提取代码 - - let scriptContent = scriptElement.textContent; - - console.log('=== WP-Markdown Debug ==='); - - console.log('Script content (first 300 chars):', scriptContent.substring(0, 300)); - + // 优先使用 PHP 预处理的 data 属性 + let code = mermaidDiv.getAttribute('data-mermaid-code'); - - let match = scriptContent.match(/document\.write\("(.*)"\)/s); - - - - if (match && 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(/\\"/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) + ')'); - - } - - - - 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 = ''; - - // 使用 pre 标签包裹以保留换行符和空格 - - 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 { - - // 直接使用 mermaid.render 而不是 init - - let id = 'mermaid-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9); - - mermaid.render(id, code).then(function(result) { - - mermaidDiv.innerHTML = result.svg; - - console.log('Mermaid diagram rendered successfully'); - - }).catch(function(e) { - - console.error('Mermaid rendering error:', e); - - console.error('Code that failed:', code.substring(0, 200)); - - }); - - } catch (e) { - - console.error('Mermaid rendering error:', e); - - console.error('Code that failed:', code.substring(0, 200)); - - } - - } - - }); - - // 递归获取所有文本节点,保留换行符 - - function getTextWithLineBreaks(element) { - - let text = ''; - - for (let node of element.childNodes) { - - if (node.nodeType === Node.TEXT_NODE) { - - text += node.textContent; - - } else if (node.nodeType === Node.ELEMENT_NODE) { - - if (node.tagName === 'BR') { - - text += '\n'; - - } else { - - text += getTextWithLineBreaks(node); - + if (!code) { + // 如果没有 data 属性,尝试从 script 标签提取 + let scriptElement = mermaidDiv.querySelector('script[type="text/javascript"]'); + if (scriptElement) { + let scriptContent = scriptElement.textContent; + let match = scriptContent.match(/document\.write\("(.*)"\)/s); + if (match && match[1]) { + code = match[1] + .replace(/\\n/g, '\n') + .replace(/\\"/g, '"') + .replace(/\\'/g, "'") + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/&/g, '&'); + } + } + } + + if (!code) { + console.warn('No mermaid code found in div'); + return; + } + + // 清空 div 内容 + mermaidDiv.innerHTML = ''; + + // 渲染 Mermaid 图表 + try { + let id = 'mermaid-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9); + mermaid.render(id, code).then(function(result) { + mermaidDiv.innerHTML = result.svg; + }).catch(function(e) { + console.error('Mermaid rendering error:', e); + mermaidDiv.innerHTML = '
Mermaid 渲染失败: ' + e.message + '
'; + }); + } catch (e) { + console.error('Mermaid rendering error:', e); + mermaidDiv.innerHTML = '
Mermaid 渲染失败: ' + e.message + '
'; + } + }); + + // 递归获取所有文本节点,保留换行符 + function getTextWithLineBreaks(element) { + let text = ''; + for (let node of element.childNodes) { + if (node.nodeType === Node.TEXT_NODE) { + text += node.textContent; + } else if (node.nodeType === Node.ELEMENT_NODE) { + if (node.tagName === 'BR') { + text += '\n'; + } else { + text += getTextWithLineBreaks(node); } - } - } - return text; - } - // 处理标准格式的 mermaid 代码块 document.querySelectorAll('pre code.language-mermaid, pre code.mermaid').forEach(function(element) { diff --git a/functions.php b/functions.php index 1246934..81fa0b0 100644 --- a/functions.php +++ b/functions.php @@ -3607,6 +3607,52 @@ function the_content_filter($content){ return $content; } 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>/s'; + + $content = preg_replace_callback($pattern, function($matches) { + $div_content = $matches[1]; + + // 检查是否包含 script 标签(WP-Markdown 格式) + if (preg_match('/]*>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_content . '
'; + } + + // 不是 WP-Markdown 格式,保持原样 + return $matches[0]; + }, $content); + + return $content; +} +add_filter('the_content', 'argon_format_mermaid_code', 25); + //使用 CDN 加速 gravatar function gravatar_cdn($url){ $cdn = get_option('argon_gravatar_cdn', 'gravatar.pho.ink/avatar/');