|
|
@@ -25,10 +25,7 @@
|
|
|
</div>
|
|
|
<div class="kp-section-body">
|
|
|
@if(!empty($kp['explanation']))
|
|
|
- {{-- 隐藏容器存储原始 Markdown --}}
|
|
|
- <div class="kp-markdown-source" style="display:none;">{!! $kp['explanation'] !!}</div>
|
|
|
- {{-- 渲染容器 --}}
|
|
|
- <div class="kp-markdown-container kp-markdown-content"></div>
|
|
|
+ {!! $kp['explanation'] !!}
|
|
|
@endif
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -36,116 +33,5 @@
|
|
|
</div>
|
|
|
@endif
|
|
|
</div>
|
|
|
-
|
|
|
- {{-- 引入脚本 --}}
|
|
|
- <script src="/js/markdown-it.min.js"></script>
|
|
|
- <script src="/js/katex.min.js"></script>
|
|
|
-
|
|
|
- <script>
|
|
|
- (function() {
|
|
|
- 'use strict';
|
|
|
-
|
|
|
- function waitForLibs(callback) {
|
|
|
- let attempts = 0;
|
|
|
- const maxAttempts = 50;
|
|
|
- const interval = setInterval(function() {
|
|
|
- attempts++;
|
|
|
- if (typeof window.markdownit === 'function') {
|
|
|
- clearInterval(interval);
|
|
|
- callback();
|
|
|
- } else if (attempts >= maxAttempts) {
|
|
|
- clearInterval(interval);
|
|
|
- console.error('[Render] Libraries failed to load after', maxAttempts, 'attempts');
|
|
|
- console.log('[Render] markdownit:', typeof window.markdownit);
|
|
|
- callback();
|
|
|
- }
|
|
|
- }, 100);
|
|
|
- }
|
|
|
-
|
|
|
- function renderMarkdown(md, targetEl) {
|
|
|
- if (!md) return;
|
|
|
-
|
|
|
- if (typeof window.markdownit !== 'function') {
|
|
|
- targetEl.textContent = md;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const mdParser = window.markdownit({
|
|
|
- html: false,
|
|
|
- breaks: false,
|
|
|
- linkify: true,
|
|
|
- typographer: false
|
|
|
- });
|
|
|
-
|
|
|
- let html = mdParser.render(md);
|
|
|
-
|
|
|
- if (typeof window.katex !== 'undefined') {
|
|
|
- const katexOptions = {
|
|
|
- throwOnError: false,
|
|
|
- displayMode: false
|
|
|
- };
|
|
|
-
|
|
|
- function decodeEntities(input) {
|
|
|
- return input
|
|
|
- .replace(/>/g, '>')
|
|
|
- .replace(/</g, '<')
|
|
|
- .replace(/&/g, '&')
|
|
|
- .replace(/"/g, '"')
|
|
|
- .replace(/'/g, "'");
|
|
|
- }
|
|
|
-
|
|
|
- // 先渲染块级公式 $$...$$
|
|
|
- html = html.replace(/\$\$([\s\S]*?)\$\$/g, function(_, tex) {
|
|
|
- try {
|
|
|
- const cleaned = decodeEntities(tex.trim());
|
|
|
- return window.katex.renderToString(cleaned, { ...katexOptions, displayMode: true });
|
|
|
- } catch (e) {
|
|
|
- return '<span style="color:red">[KaTeX error]</span>';
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- // 再渲染行内公式 $...$
|
|
|
- html = html.replace(/\$([^\$\n]+?)\$/g, function(_, tex) {
|
|
|
- try {
|
|
|
- const cleaned = decodeEntities(tex.trim());
|
|
|
- return window.katex.renderToString(cleaned, { ...katexOptions, displayMode: false });
|
|
|
- } catch (e) {
|
|
|
- return '<span style="color:red">[KaTeX error]</span>';
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- targetEl.innerHTML = html;
|
|
|
- }
|
|
|
-
|
|
|
- function renderAll() {
|
|
|
- const containers = document.querySelectorAll('.kp-markdown-container');
|
|
|
- containers.forEach((container) => {
|
|
|
- const sourceEl = container.previousElementSibling;
|
|
|
- let markdown = '';
|
|
|
- if (sourceEl && sourceEl.classList.contains('kp-markdown-source')) {
|
|
|
- markdown = sourceEl.textContent.trim();
|
|
|
- }
|
|
|
- if (!markdown) return;
|
|
|
- renderMarkdown(markdown, container);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- if (document.readyState === 'loading') {
|
|
|
- document.addEventListener('DOMContentLoaded', function() {
|
|
|
- waitForLibs(renderAll);
|
|
|
- });
|
|
|
- } else {
|
|
|
- waitForLibs(renderAll);
|
|
|
- }
|
|
|
-
|
|
|
- document.addEventListener('livewire:initialized', function() {
|
|
|
- waitForLibs(renderAll);
|
|
|
- });
|
|
|
- document.addEventListener('livewire:navigated', () => setTimeout(function() {
|
|
|
- waitForLibs(renderAll);
|
|
|
- }, 100));
|
|
|
- })();
|
|
|
- </script>
|
|
|
</body>
|
|
|
</html>
|