Skip to content

Commit d3cc534

Browse files
jeremymanningclaude
andcommitted
Fix LaTeX currency rendering bug
Fixed issue where currency amounts like "$1.0 billion" were incorrectly interpreted as LaTeX delimiters, causing text to run together without spaces. Solution: 1. Detect currency patterns ($1.0$B, $2.0$ billion, etc.) 2. Replace with placeholders during text processing 3. Wrap currency in <span class="no-katex"> elements 4. Configure KaTeX to ignore elements with 'no-katex' class The fix preserves actual LaTeX expressions (like $r=5\%$) which contain operators that don't match the currency pattern. Fixes rendering issue reported in screenshot where text displayed as "1.0billiontodaybutwouldirreversibly..." instead of "$1.0 billion today..." 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 7018ca3 commit d3cc534

File tree

1 file changed

+42
-6
lines changed

1 file changed

+42
-6
lines changed

index.html

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2321,27 +2321,61 @@ <h3>Error Loading Questions</h3>
23212321

23222322
// Render LaTeX with KaTeX after DOM update
23232323
if (typeof renderMathInElement !== 'undefined') {
2324-
// Pre-process text to escape currency patterns before KaTeX processes them
2325-
// Matches patterns like "$1.0$B" or "$2.0$ billion" where the $ delimiters
2326-
// immediately surround just a number (likely currency, not math)
2324+
// Pre-process text to replace currency patterns with HTML entities
2325+
// This prevents KaTeX from treating "$1.0$B" as LaTeX delimiters
23272326
const escapeCurrency = (element) => {
2327+
console.log('escapeCurrency called on:', element.innerHTML.substring(0, 200));
2328+
23282329
// Walk through all text nodes
23292330
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);
23302331
const textNodes = [];
23312332
while (walker.nextNode()) {
23322333
textNodes.push(walker.currentNode);
23332334
}
23342335

2336+
console.log('Found', textNodes.length, 'text nodes');
2337+
23352338
// Process each text node
23362339
textNodes.forEach(node => {
23372340
const original = node.textContent;
2338-
// Match $number$ patterns followed by optional B/billion/million etc.
2339-
// These are likely currency amounts, not mathematical expressions
2340-
let modified = original.replace(/\$(\d+(?:\.\d+)?)\$\s*([BbMmKk]|billion|million|thousand)?/g, '\\$$1 $2');
2341+
// Match $number$ patterns (with or without space) followed by B/billion/etc
2342+
// IMPORTANT: We need to replace with HTML entity $ (which becomes $ in the DOM)
2343+
// BUT we're working with textContent, not innerHTML, so we can't use HTML entities!
2344+
// Instead, we'll use a placeholder that we convert after
2345+
let modified = original.replace(/\$(\d+(?:\.\d+)?)\$\s*([BbMmKk]|billion|million|thousand)/g, (match, number, suffix) => {
2346+
console.log('Matched currency pattern:', match, '-> replacing with placeholder');
2347+
return '___DOLLAR___' + number + ' ' + suffix;
2348+
});
2349+
2350+
// Also handle standalone $number$ that's likely currency (no suffix)
2351+
// Only if it's a simple number without operators
2352+
modified = modified.replace(/\$(\d+(?:\.\d+)?)\$/g, (match, number, offset, string) => {
2353+
// Check if this looks like currency (simple number, not part of math expression)
2354+
// Don't replace if it's followed by math operators or surrounded by backslashes
2355+
const before = string[offset - 1] || '';
2356+
const after = string[offset + match.length] || '';
2357+
2358+
if (before !== '\\' && after !== '\\' && !/[+\-*/^_=<>\\]/.test(after)) {
2359+
console.log('Matched standalone currency:', match, '-> replacing with placeholder');
2360+
return '___DOLLAR___' + number;
2361+
}
2362+
return match;
2363+
});
2364+
23412365
if (modified !== original) {
2366+
console.log('Text changed from:', original.substring(0, 100));
2367+
console.log(' to:', modified.substring(0, 100));
23422368
node.textContent = modified;
23432369
}
23442370
});
2371+
2372+
// After KaTeX won't see them, replace placeholders with actual $ via innerHTML
2373+
// This is safe because we're only replacing our own placeholders
2374+
const tempHTML = element.innerHTML;
2375+
if (tempHTML.includes('___DOLLAR___')) {
2376+
element.innerHTML = tempHTML.replace(/___DOLLAR___([\d.]+(?:\s+(?:[BbMmKk]|billion|million|thousand))?)/g, '<span class="no-katex">$$$1</span>');
2377+
console.log('Replaced placeholders with currency spans (no-katex class)');
2378+
}
23452379
};
23462380

23472381
// Escape currency patterns in question and options
@@ -2354,6 +2388,7 @@ <h3>Error Loading Questions</h3>
23542388
{left: '$', right: '$', display: false}
23552389
],
23562390
ignoredTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'],
2391+
ignoredClasses: ['no-katex'],
23572392
throwOnError: false
23582393
});
23592394

@@ -2367,6 +2402,7 @@ <h3>Error Loading Questions</h3>
23672402
{left: '$', right: '$', display: false}
23682403
],
23692404
ignoredTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'],
2405+
ignoredClasses: ['no-katex'],
23702406
throwOnError: false
23712407
});
23722408
});

0 commit comments

Comments
 (0)