|
| 1 | +// Initialize KaTeX auto-render on page content with CSP-friendly external script |
| 2 | +(function(){ |
| 3 | + function safeContainer(el){ |
| 4 | + return !(el.closest('pre, code')); |
| 5 | + } |
| 6 | + function tokenizeMath(text){ |
| 7 | + var tokens = []; |
| 8 | + var i = 0; |
| 9 | + var dels = [ |
| 10 | + {l:'$$', r:'$$', d:true}, |
| 11 | + {l:'\\[', r:'\\]', d:true}, |
| 12 | + {l:'\\(', r:'\\)', d:false}, |
| 13 | + {l:'$', r:'$', d:false}, |
| 14 | + ]; |
| 15 | + while (i < text.length){ |
| 16 | + // find earliest delimiter occurrence |
| 17 | + var best = null, bestIdx = -1; |
| 18 | + for (var di=0; di<dels.length; di++){ |
| 19 | + var idx = text.indexOf(dels[di].l, i); |
| 20 | + if (idx !== -1 && (bestIdx === -1 || idx < bestIdx)) { best = dels[di]; bestIdx = idx; } |
| 21 | + } |
| 22 | + if (bestIdx === -1){ |
| 23 | + tokens.push({t:'t', s:text.slice(i)}); |
| 24 | + break; |
| 25 | + } |
| 26 | + if (bestIdx > i){ tokens.push({t:'t', s:text.slice(i, bestIdx)}); } |
| 27 | + var start = bestIdx + best.l.length; |
| 28 | + var end = text.indexOf(best.r, start); |
| 29 | + if (end === -1){ |
| 30 | + // unmatched: treat as text |
| 31 | + tokens.push({t:'t', s:text.slice(bestIdx)}); |
| 32 | + break; |
| 33 | + } |
| 34 | + var content = text.slice(start, end); |
| 35 | + tokens.push({t:'m', d:best.d, s:content}); |
| 36 | + i = end + best.r.length; |
| 37 | + } |
| 38 | + return tokens; |
| 39 | + } |
| 40 | + function escapeUnderscoresInTextCommand(str){ |
| 41 | + return str.replace(/\\text\{([^}]*)\}/g, function(_, inner){ |
| 42 | + var out = ''; |
| 43 | + for (var i=0;i<inner.length;i++){ |
| 44 | + var ch = inner[i]; |
| 45 | + if (ch === '_' && (i===0 || inner[i-1] !== '\\')){ out += '\\\\_'; } |
| 46 | + else { out += ch; } |
| 47 | + } |
| 48 | + return '\\\\text{' + out + '}'; |
| 49 | + }); |
| 50 | + } |
| 51 | + function rebuildWithKatex(el){ |
| 52 | + if (!window.katex) return; |
| 53 | + var txt = el.textContent; |
| 54 | + if (!(/[\$]/.test(txt) || /\\\(|\\\)|\\\[|\\\]/.test(txt))) return; |
| 55 | + var tokens = tokenizeMath(txt); |
| 56 | + if (!tokens.some(function(x){return x.t==='m';})) return; |
| 57 | + while (el.firstChild) el.removeChild(el.firstChild); |
| 58 | + tokens.forEach(function(tok){ |
| 59 | + if (tok.t==='t'){ |
| 60 | + el.appendChild(document.createTextNode(tok.s)); |
| 61 | + } else if (tok.t==='m'){ |
| 62 | + var content = escapeUnderscoresInTextCommand(tok.s); |
| 63 | + var span = document.createElement('span'); |
| 64 | + try { window.katex.render(content, span, {displayMode: tok.d}); } catch(_) { span.textContent = tok.s; } |
| 65 | + el.appendChild(span); |
| 66 | + } |
| 67 | + }); |
| 68 | + el.setAttribute('data-katex-rebuilt','1'); |
| 69 | + } |
| 70 | + function init(){ |
| 71 | + if (typeof renderMathInElement === 'function') { |
| 72 | + try { |
| 73 | + renderMathInElement(document.body, { |
| 74 | + delimiters: [ |
| 75 | + {left: "$$", right: "$$", display: true}, |
| 76 | + {left: "\\(", right: "\\)", display: false}, |
| 77 | + {left: "\\[", right: "\\]", display: true} |
| 78 | + ], |
| 79 | + ignoredTags: ["script","noscript","style","textarea","pre","code","option"], |
| 80 | + }); |
| 81 | + } catch (_) {} |
| 82 | + } |
| 83 | + if (window.katex) { |
| 84 | + document.querySelectorAll('.math-katex').forEach(function(el){ |
| 85 | + try { window.katex.render(el.textContent, el, { displayMode: (el.dataset.display === 'true') }); } catch (_) {} |
| 86 | + }); |
| 87 | + // Fallback fix: rebuild math in common containers, avoiding code blocks |
| 88 | + document.querySelectorAll('.e-content.body p, .e-content.body li, .e-content.body h1, .e-content.body h2, .e-content.body h3, .e-content.body h4, .e-content.body blockquote, .e-content.body td, .e-content.body th, .e-content.body dd, .e-content.body dt, .e-content.body figcaption').forEach(function(el){ |
| 89 | + if (safeContainer(el) && el.getAttribute('data-katex-rebuilt') !== '1') rebuildWithKatex(el); |
| 90 | + }); |
| 91 | + } |
| 92 | + } |
| 93 | + if (document.readyState === 'loading') { |
| 94 | + document.addEventListener('DOMContentLoaded', init); |
| 95 | + } else { |
| 96 | + init(); |
| 97 | + } |
| 98 | +})(); |
0 commit comments