← Files DefuddleARCHIVED FILE
skills/defuddle-web-content/references/source/src/elements/math.full.ts
3.02 KB · Oct 2, 2026 · 00:35 UTC
import { MathMLToLaTeX } from 'mathml-to-latex';
import {
MathData,
getMathMLFromElement,
getBasicLatexFromElement,
isBlockDisplay,
mathSelectors,
mathFastCheck
} from './math.base';
import { parseHTML, transferContent } from '../utils/dom';
export const getLatexFromElement = (el: Element): string | null => {
// First try basic LaTeX extraction
const basicLatex = getBasicLatexFromElement(el);
if (basicLatex) {
return basicLatex;
}
// If no LaTeX found but we have MathML, convert it
const mathData = getMathMLFromElement(el);
if (mathData?.mathml) {
try {
return MathMLToLaTeX.convert(mathData.mathml);
} catch (e) {
console.warn('Failed to convert MathML to LaTeX:', e);
}
}
return null;
};
export const createCleanMathEl = (mathData: MathData | null, latex: string | null, isBlock: boolean, doc: Document): Element => {
const cleanMathEl = doc.createElement('math');
cleanMathEl.setAttribute('xmlns', 'http://www.w3.org/1998/Math/MathML');
cleanMathEl.setAttribute('display', isBlock ? 'block' : 'inline');
cleanMathEl.setAttribute('data-latex', latex || '');
// First try to use existing MathML content
if (mathData?.mathml) {
const fragment = parseHTML(doc, mathData.mathml);
const mathContent = fragment.querySelector('math');
if (mathContent) {
transferContent(mathContent, cleanMathEl);
}
}
// If no MathML but we have LaTeX, convert it
else if (latex) {
try {
const temml = require('temml');
const mathml = temml.renderToString(latex, {
displayMode: isBlock,
throwOnError: false
});
const fragment = parseHTML(doc, mathml);
const mathContent = fragment.querySelector('math');
if (mathContent) {
while (mathContent.firstChild) {
cleanMathEl.appendChild(mathContent.firstChild);
}
} else {
cleanMathEl.textContent = latex; // Fallback to LaTeX as text
}
} catch (e) {
console.warn('Failed to convert LaTeX to MathML:', e);
cleanMathEl.textContent = latex; // Fallback to LaTeX as text
}
}
return cleanMathEl;
};
export const mathRules = [
{
selector: mathSelectors,
element: 'math',
fastCheck: mathFastCheck,
transform: (el: Element): Element => {
if (!('classList' in el) || !('getAttribute' in el) || !('querySelector' in el)) {
return el;
}
const mathData = getMathMLFromElement(el);
const latex = getLatexFromElement(el);
const isBlock = isBlockDisplay(el);
const cleanMathEl = createCleanMathEl(mathData, latex, isBlock, el.ownerDocument);
// Clean up any associated math scripts after we've extracted their content.
// Skip when el itself is a math script — it will be replaced by the
// caller, and removing siblings here would destroy unprocessed scripts.
if (el.parentElement && !el.matches('script[type^="math/"]')) {
const mathElements = el.parentElement.querySelectorAll(
'script[type^="math/"], .MathJax_Preview, script[type="text/javascript"][src*="mathjax"], script[type="text/javascript"][src*="katex"]'
);
mathElements.forEach(el => el.remove());
}
return cleanMathEl;
}
}
]; SHA-256: aebc6ccc9e407c1b307a9d80ae9263b5d0056fdff922fbd430f1c987122cda7b