- 68 exercises from UBA FCE chapters 1-3 - Step-by-step solutions with KaTeX rendering - Theory panels (26 topics) expandable per exercise - Matrix builder (2x2/3x3/4x4) with 7 operations - System solver (Gauss, Gauss-Jordan, Cramer, Rouché-Frobenius) - Glassmorphism UI with dark mode - Canvas particle background - ARIA accessibility (keyboard nav, screen reader) - Zero build step - open index.html directly
134 lines
4.0 KiB
JavaScript
134 lines
4.0 KiB
JavaScript
/**
|
|
* KaTeX Render Helper
|
|
* Wraps katex.render() with error handling for both display and inline modes.
|
|
* Security-hardened with strict mode and LaTeX sanitization.
|
|
*/
|
|
const KatexRenderer = {
|
|
/**
|
|
* Macro whitelist — only macros that KaTeX does NOT natively support.
|
|
* Prevents injection via \href, \url, \includegraphics, etc.
|
|
* REMOVED: Standard KaTeX commands (\vec, \overrightarrow, \cdot, \times,
|
|
* \sqrt, \frac, \pi, \alpha, \beta, \text, \implies, \neq, \infty, \lambda,
|
|
* \mu, \sum, \int, \dots, \vdots, \ddots, \hline, \det, \operatorname)
|
|
* — KaTeX already supports these natively; redefining them causes infinite
|
|
* recursion or strict mode violations.
|
|
*/
|
|
KATEX_MACROS: {
|
|
'\\ran': '\\text{ran}',
|
|
'\\nul': '\\text{nul}',
|
|
'\\rg': '\\text{rg}',
|
|
'\\sen': '\\sin',
|
|
'\\tg': '\\tan'
|
|
},
|
|
|
|
KATEX_OPTIONS: {
|
|
displayMode: true,
|
|
throwOnError: false,
|
|
trust: false,
|
|
strict: false,
|
|
macros: {}
|
|
},
|
|
|
|
/**
|
|
* Sanitize LaTeX input by removing potentially dangerous commands.
|
|
* @param {string} latex - Raw LaTeX string
|
|
* @returns {string} - Sanitized LaTeX safe for KaTeX
|
|
*/
|
|
sanitizeLatex(latex) {
|
|
if (!latex || typeof latex !== 'string') return '';
|
|
return latex
|
|
.replace(/\\href\{[^}]*\}\{[^}]*\}/g, '')
|
|
.replace(/\\url\{[^}]*\}/g, '')
|
|
.replace(/\\includegraphics\{[^}]*\}/g, '')
|
|
.replace(/\\write\{[^}]*\}/g, '')
|
|
.replace(/\\input\{[^}]*\}/g, '')
|
|
.replace(/\\include\{[^}]*\}/g, '')
|
|
.replace(/\\href\{[^}]*\}/g, '');
|
|
},
|
|
|
|
/**
|
|
* Render a LaTeX expression into a DOM element.
|
|
* @param {HTMLElement|string} el - Target element or CSS selector
|
|
* @param {string} latex - LaTeX string to render
|
|
* @param {Object} options - KaTeX options override
|
|
* @returns {boolean} true if rendered successfully
|
|
*/
|
|
render(el, latex, options = {}) {
|
|
const target = typeof el === 'string' ? document.querySelector(el) : el;
|
|
if (!target) {
|
|
console.warn('[KatexRenderer] Element not found:', el);
|
|
return false;
|
|
}
|
|
|
|
if (typeof katex === 'undefined') {
|
|
target.textContent = latex;
|
|
console.warn('[KatexRenderer] KaTeX not loaded');
|
|
return false;
|
|
}
|
|
|
|
const mergedOptions = Object.assign({}, this.KATEX_OPTIONS, {
|
|
macros: Object.assign({}, this.KATEX_MACROS, options.macros || {})
|
|
});
|
|
|
|
const sanitized = this.sanitizeLatex(latex);
|
|
|
|
try {
|
|
katex.render(sanitized, target, mergedOptions);
|
|
return true;
|
|
} catch (e) {
|
|
target.innerHTML = '<span style="color:#e17055;font-style:italic;">[Error LaTeX]</span>';
|
|
console.warn('[KatexRenderer] Parse error:', e.message, '\nLaTeX:', sanitized);
|
|
return false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Render LaTeX in display mode (centered block).
|
|
*/
|
|
renderDisplay(el, latex) {
|
|
return this.render(el, latex, { displayMode: true });
|
|
},
|
|
|
|
/**
|
|
* Render LaTeX in inline mode.
|
|
*/
|
|
renderInline(el, latex) {
|
|
return this.render(el, latex, { displayMode: false });
|
|
},
|
|
|
|
/**
|
|
* Render all math expressions inside a container element.
|
|
* Uses KaTeX auto-render extension for $...$ and $$...$$ delimiters.
|
|
* @param {HTMLElement} container - DOM element to scan for math
|
|
*/
|
|
renderAll(container) {
|
|
if (typeof renderMathInElement === 'undefined') {
|
|
console.warn('[KatexRenderer] auto-render extension not loaded');
|
|
return;
|
|
}
|
|
|
|
renderMathInElement(container || document.body, {
|
|
delimiters: [
|
|
{ left: '$$', right: '$$', display: true },
|
|
{ left: '$', right: '$', display: false },
|
|
{ left: '\\(', right: '\\)', display: false },
|
|
{ left: '\\[', right: '\\]', display: true }
|
|
],
|
|
throwOnError: false,
|
|
trust: false,
|
|
strict: false,
|
|
macros: this.KATEX_MACROS
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Create a span with rendered math and return it.
|
|
* Useful for building DOM fragments.
|
|
*/
|
|
createMathSpan(latex, displayMode = false) {
|
|
const span = document.createElement('span');
|
|
this.render(span, latex, { displayMode });
|
|
return span;
|
|
}
|
|
};
|