More fixes for math

pull/1214/head
Lim Chee Aun 2025-07-16 18:16:42 +08:00
rodzic a5b0754110
commit 6079cbff64
3 zmienionych plików z 225 dodań i 154 usunięć

Wyświetl plik

@ -2970,7 +2970,7 @@ a.card:is(:hover, :focus):visited {
--padding: 8px;
background-position: center var(--padding);
&:has(mrow) {
&:has(> mrow) {
/* 0.5ex is for mrow from Temml-Local.css */
background-position-y: calc(var(--padding) + 0.5ex);
}

Wyświetl plik

@ -237,14 +237,85 @@ const DELIMITERS_PATTERNS = [
];
const DELIMITERS_REGEX = new RegExp(DELIMITERS_PATTERNS.join('|'), 'g');
function cleanDOMForTemml(dom) {
// Define start and end delimiter patterns
const START_DELIMITERS = ['\\\\\\[', '\\\\\\(']; // \[ and \(
const startRegex = new RegExp(`(${START_DELIMITERS.join('|')})`);
// Walk through all text nodes
const walker = document.createTreeWalker(dom, NodeFilter.SHOW_TEXT);
const textNodes = [];
let node;
while ((node = walker.nextNode())) {
textNodes.push(node);
}
for (const textNode of textNodes) {
const text = textNode.textContent;
const startMatch = text.match(startRegex);
if (!startMatch) continue; // No start delimiter in this text node
// Find the matching end delimiter
const startDelimiter = startMatch[0];
const endDelimiter = startDelimiter === '\\[' ? '\\]' : '\\)';
// Collect nodes from start delimiter until end delimiter
const nodesToCombine = [textNode];
let currentNode = textNode;
let foundEnd = false;
let combinedText = text;
// Check if end delimiter is in the same text node
if (text.includes(endDelimiter)) {
foundEnd = true;
} else {
// Look through sibling nodes
while (currentNode.nextSibling && !foundEnd) {
const nextSibling = currentNode.nextSibling;
if (nextSibling.nodeType === Node.TEXT_NODE) {
nodesToCombine.push(nextSibling);
combinedText += nextSibling.textContent;
if (nextSibling.textContent.includes(endDelimiter)) {
foundEnd = true;
}
} else if (
nextSibling.nodeType === Node.ELEMENT_NODE &&
nextSibling.tagName === 'BR'
) {
nodesToCombine.push(nextSibling);
combinedText += '\n';
} else {
// Found a non-BR element, stop and don't process
break;
}
currentNode = nextSibling;
}
}
// Only process if we found the end delimiter and have nodes to combine
if (foundEnd && nodesToCombine.length > 1) {
// Replace the first text node with combined text
textNode.textContent = combinedText;
// Remove the other nodes
for (let i = 1; i < nodesToCombine.length; i++) {
nodesToCombine[i].remove();
}
}
}
}
const MathBlock = ({ content, contentRef, onRevert }) => {
DELIMITERS_REGEX.lastIndex = 0; // Reset index to prevent g trap
const hasLatexContent = DELIMITERS_REGEX.test(content);
if (!hasLatexContent) return null;
const { t } = useLingui();
const [mathRendered, setMathRendered] = useState(false);
const hasLatexContent = useMemo(
() => DELIMITERS_REGEX.test(content),
[content],
);
const toggleMathRendering = useCallback(
async (e) => {
e.preventDefault();
@ -259,7 +330,8 @@ const MathBlock = ({ content, contentRef, onRevert }) => {
const temml =
window.temml || (window.temml = (await import('temml'))?.default);
const oriignalContentRefHTML = contentRef.current.innerHTML;
cleanDOMForTemml(contentRef.current);
const originalContentRefHTML = contentRef.current.innerHTML;
temml.renderMathInElement(contentRef.current, {
fences: '(', // This should sync with DELIMITERS_REGEX
annotate: true,
@ -271,12 +343,13 @@ const MathBlock = ({ content, contentRef, onRevert }) => {
const hasMath = contentRef.current.querySelector('math.tml-display');
const htmlChanged =
contentRef.current.innerHTML !== oriignalContentRefHTML;
contentRef.current.innerHTML !== originalContentRefHTML;
if (hasMath && htmlChanged) {
setMathRendered(true);
} else {
showToast(t`Unable to format math`);
setMathRendered(false);
onRevert(); // Revert because DOM modified by cleanDOMForTemml
}
} catch (e) {
console.error('Failed to LaTeX:', e);
@ -286,8 +359,6 @@ const MathBlock = ({ content, contentRef, onRevert }) => {
[mathRendered],
);
if (!hasLatexContent) return null;
return (
<div class="math-block">
<Icon icon="formula" size="s" /> <span>{t`Math expressions found.`}</span>{' '}

288
src/locales/en.po wygenerowano
Wyświetl plik

@ -34,7 +34,7 @@ msgstr ""
#: src/components/account-block.jsx:170
#: src/components/account-info.jsx:715
#: src/components/status.jsx:666
#: src/components/status.jsx:737
msgid "Group"
msgstr ""
@ -111,11 +111,11 @@ msgstr ""
#: src/components/compose.jsx:2792
#: src/components/media-alt-modal.jsx:55
#: src/components/media-modal.jsx:363
#: src/components/status.jsx:1916
#: src/components/status.jsx:1933
#: src/components/status.jsx:2058
#: src/components/status.jsx:2687
#: src/components/status.jsx:2690
#: src/components/status.jsx:1987
#: src/components/status.jsx:2004
#: src/components/status.jsx:2129
#: src/components/status.jsx:2758
#: src/components/status.jsx:2761
#: src/pages/account-statuses.jsx:531
#: src/pages/accounts.jsx:118
#: src/pages/hashtag.jsx:203
@ -203,7 +203,7 @@ msgid "Original"
msgstr ""
#: src/components/account-info.jsx:946
#: src/components/status.jsx:2471
#: src/components/status.jsx:2542
#: src/pages/catchup.jsx:71
#: src/pages/catchup.jsx:1448
#: src/pages/catchup.jsx:2061
@ -329,30 +329,30 @@ msgid "Add/Remove from Lists"
msgstr ""
#: src/components/account-info.jsx:1490
#: src/components/status.jsx:1338
#: src/components/status.jsx:1409
msgid "Link copied"
msgstr ""
#: src/components/account-info.jsx:1493
#: src/components/status.jsx:1341
#: src/components/status.jsx:1412
msgid "Unable to copy link"
msgstr ""
#: src/components/account-info.jsx:1499
#: src/components/shortcuts-settings.jsx:1059
#: src/components/status.jsx:1347
#: src/components/status.jsx:3465
#: src/components/status.jsx:1418
#: src/components/status.jsx:3536
msgid "Copy"
msgstr ""
#: src/components/account-info.jsx:1514
#: src/components/shortcuts-settings.jsx:1077
#: src/components/status.jsx:1363
#: src/components/status.jsx:1434
msgid "Sharing doesn't seem to work."
msgstr ""
#: src/components/account-info.jsx:1520
#: src/components/status.jsx:1369
#: src/components/status.jsx:1440
msgid "Share…"
msgstr ""
@ -466,9 +466,9 @@ msgstr ""
#: src/components/shortcuts-settings.jsx:230
#: src/components/shortcuts-settings.jsx:583
#: src/components/shortcuts-settings.jsx:783
#: src/components/status.jsx:3189
#: src/components/status.jsx:3429
#: src/components/status.jsx:3938
#: src/components/status.jsx:3260
#: src/components/status.jsx:3500
#: src/components/status.jsx:4009
#: src/pages/accounts.jsx:45
#: src/pages/catchup.jsx:1584
#: src/pages/filters.jsx:225
@ -718,7 +718,7 @@ msgid "Attachment #{i} failed"
msgstr "Attachment #{i} failed"
#: src/components/compose.jsx:1221
#: src/components/status.jsx:2246
#: src/components/status.jsx:2317
#: src/components/timeline.jsx:1023
msgid "Content warning"
msgstr ""
@ -754,7 +754,7 @@ msgstr ""
#: src/components/compose.jsx:1288
#: src/components/status.jsx:103
#: src/components/status.jsx:2122
#: src/components/status.jsx:2193
msgid "Private mention"
msgstr ""
@ -791,10 +791,10 @@ msgstr "Schedule"
#: src/components/compose.jsx:1677
#: src/components/keyboard-shortcuts-help.jsx:155
#: src/components/status.jsx:1110
#: src/components/status.jsx:1896
#: src/components/status.jsx:1897
#: src/components/status.jsx:2591
#: src/components/status.jsx:1181
#: src/components/status.jsx:1967
#: src/components/status.jsx:1968
#: src/components/status.jsx:2662
msgid "Reply"
msgstr ""
@ -1016,7 +1016,7 @@ msgstr ""
#: src/components/drafts.jsx:128
#: src/components/list-add-edit.jsx:188
#: src/components/status.jsx:1513
#: src/components/status.jsx:1584
#: src/pages/filters.jsx:603
#: src/pages/scheduled-posts.jsx:369
msgid "Delete…"
@ -1225,10 +1225,10 @@ msgid "<0>l</0> or <1>f</1>"
msgstr ""
#: src/components/keyboard-shortcuts-help.jsx:176
#: src/components/status.jsx:1118
#: src/components/status.jsx:2618
#: src/components/status.jsx:2641
#: src/components/status.jsx:2642
#: src/components/status.jsx:1189
#: src/components/status.jsx:2689
#: src/components/status.jsx:2712
#: src/components/status.jsx:2713
msgid "Boost"
msgstr ""
@ -1237,9 +1237,9 @@ msgid "<0>Shift</0> + <1>b</1>"
msgstr ""
#: src/components/keyboard-shortcuts-help.jsx:184
#: src/components/status.jsx:1181
#: src/components/status.jsx:2666
#: src/components/status.jsx:2667
#: src/components/status.jsx:1252
#: src/components/status.jsx:2737
#: src/components/status.jsx:2738
msgid "Bookmark"
msgstr ""
@ -1304,14 +1304,14 @@ msgid "Media description"
msgstr ""
#: src/components/media-alt-modal.jsx:67
#: src/components/status.jsx:1224
#: src/components/status.jsx:1233
#: src/components/status.jsx:1295
#: src/components/status.jsx:1304
#: src/components/translation-block.jsx:239
msgid "Translate"
msgstr ""
#: src/components/media-alt-modal.jsx:78
#: src/components/status.jsx:1252
#: src/components/status.jsx:1323
msgid "Speak"
msgstr ""
@ -1348,9 +1348,9 @@ msgid "Filtered: {filterTitleStr}"
msgstr ""
#: src/components/media-post.jsx:133
#: src/components/status.jsx:3768
#: src/components/status.jsx:3864
#: src/components/status.jsx:3942
#: src/components/status.jsx:3839
#: src/components/status.jsx:3935
#: src/components/status.jsx:4013
#: src/components/timeline.jsx:1012
#: src/pages/catchup.jsx:75
#: src/pages/catchup.jsx:1880
@ -1662,8 +1662,8 @@ msgid "[Unknown notification type: {type}]"
msgstr ""
#: src/components/notification.jsx:451
#: src/components/status.jsx:1195
#: src/components/status.jsx:1205
#: src/components/status.jsx:1266
#: src/components/status.jsx:1276
msgid "Boosted/Liked by…"
msgstr ""
@ -1689,7 +1689,7 @@ msgid "View #Wrapstodon"
msgstr "View #Wrapstodon"
#: src/components/notification.jsx:801
#: src/components/status.jsx:404
#: src/components/status.jsx:475
msgid "Read more →"
msgstr ""
@ -1993,7 +1993,7 @@ msgid "Move down"
msgstr ""
#: src/components/shortcuts-settings.jsx:379
#: src/components/status.jsx:1475
#: src/components/status.jsx:1546
#: src/pages/list.jsx:195
msgid "Edit"
msgstr ""
@ -2192,362 +2192,362 @@ msgstr ""
msgid "Import/export settings from/to instance server (Very experimental)"
msgstr ""
#: src/components/status.jsx:278
#: src/components/status.jsx:350
msgid "Unable to format math"
msgstr "Unable to format math"
#: src/components/status.jsx:293
#: src/components/status.jsx:364
msgid "Math expressions found."
msgstr "Math expressions found."
#: src/components/status.jsx:295
#: src/components/status.jsx:366
msgid "Show markup"
msgstr "Show markup"
#: src/components/status.jsx:295
#: src/components/status.jsx:366
msgid "Format math"
msgstr "Format math"
#: src/components/status.jsx:690
#: src/components/status.jsx:761
msgid "<0/> <1>boosted</1>"
msgstr "<0/> <1>boosted</1>"
#: src/components/status.jsx:793
#: src/components/status.jsx:864
msgid "Sorry, your current logged-in instance can't interact with this post from another instance."
msgstr ""
#. placeholder {0}: username || acct
#: src/components/status.jsx:947
#: src/components/status.jsx:1018
msgid "Unliked @{0}'s post"
msgstr ""
#. placeholder {0}: username || acct
#: src/components/status.jsx:948
#: src/components/status.jsx:1019
msgid "Liked @{0}'s post"
msgstr "Liked @{0}'s post"
#. placeholder {0}: username || acct
#: src/components/status.jsx:987
#: src/components/status.jsx:1058
msgid "Unbookmarked @{0}'s post"
msgstr "Unbookmarked @{0}'s post"
#. placeholder {0}: username || acct
#: src/components/status.jsx:988
#: src/components/status.jsx:1059
msgid "Bookmarked @{0}'s post"
msgstr "Bookmarked @{0}'s post"
#: src/components/status.jsx:1087
#: src/components/status.jsx:1158
msgid "Some media have no descriptions."
msgstr ""
#. placeholder {0}: rtf.format(-statusMonthsAgo, 'month')
#: src/components/status.jsx:1094
#: src/components/status.jsx:1165
msgid "Old post (<0>{0}</0>)"
msgstr ""
#: src/components/status.jsx:1118
#: src/components/status.jsx:1158
#: src/components/status.jsx:2618
#: src/components/status.jsx:2641
#: src/components/status.jsx:1189
#: src/components/status.jsx:1229
#: src/components/status.jsx:2689
#: src/components/status.jsx:2712
msgid "Unboost"
msgstr ""
#: src/components/status.jsx:1134
#: src/components/status.jsx:2633
#: src/components/status.jsx:1205
#: src/components/status.jsx:2704
msgid "Quote"
msgstr ""
#. placeholder {0}: username || acct
#: src/components/status.jsx:1146
#: src/components/status.jsx:1612
#: src/components/status.jsx:1217
#: src/components/status.jsx:1683
msgid "Unboosted @{0}'s post"
msgstr "Unboosted @{0}'s post"
#. placeholder {0}: username || acct
#: src/components/status.jsx:1147
#: src/components/status.jsx:1613
#: src/components/status.jsx:1218
#: src/components/status.jsx:1684
msgid "Boosted @{0}'s post"
msgstr "Boosted @{0}'s post"
#: src/components/status.jsx:1159
#: src/components/status.jsx:1230
msgid "Boost…"
msgstr ""
#: src/components/status.jsx:1171
#: src/components/status.jsx:1906
#: src/components/status.jsx:2654
#: src/components/status.jsx:1242
#: src/components/status.jsx:1977
#: src/components/status.jsx:2725
msgid "Unlike"
msgstr ""
#: src/components/status.jsx:1172
#: src/components/status.jsx:1906
#: src/components/status.jsx:1907
#: src/components/status.jsx:2654
#: src/components/status.jsx:2655
#: src/components/status.jsx:1243
#: src/components/status.jsx:1977
#: src/components/status.jsx:1978
#: src/components/status.jsx:2725
#: src/components/status.jsx:2726
msgid "Like"
msgstr ""
#: src/components/status.jsx:1181
#: src/components/status.jsx:2666
#: src/components/status.jsx:1252
#: src/components/status.jsx:2737
msgid "Unbookmark"
msgstr ""
#: src/components/status.jsx:1264
#: src/components/status.jsx:1335
msgid "Post text copied"
msgstr "Post text copied"
#: src/components/status.jsx:1267
#: src/components/status.jsx:1338
msgid "Unable to copy post text"
msgstr "Unable to copy post text"
#: src/components/status.jsx:1273
#: src/components/status.jsx:1344
msgid "Copy post text"
msgstr "Copy post text"
#. placeholder {0}: username || acct
#: src/components/status.jsx:1291
#: src/components/status.jsx:1362
msgid "View post by <0>@{0}</0>"
msgstr ""
#: src/components/status.jsx:1312
#: src/components/status.jsx:1383
msgid "Show Edit History"
msgstr ""
#: src/components/status.jsx:1315
#: src/components/status.jsx:1386
msgid "Edited: {editedDateText}"
msgstr ""
#: src/components/status.jsx:1382
#: src/components/status.jsx:3434
#: src/components/status.jsx:1453
#: src/components/status.jsx:3505
msgid "Embed post"
msgstr ""
#: src/components/status.jsx:1396
#: src/components/status.jsx:1467
msgid "Conversation unmuted"
msgstr ""
#: src/components/status.jsx:1396
#: src/components/status.jsx:1467
msgid "Conversation muted"
msgstr ""
#: src/components/status.jsx:1402
#: src/components/status.jsx:1473
msgid "Unable to unmute conversation"
msgstr ""
#: src/components/status.jsx:1403
#: src/components/status.jsx:1474
msgid "Unable to mute conversation"
msgstr ""
#: src/components/status.jsx:1412
#: src/components/status.jsx:1483
msgid "Unmute conversation"
msgstr ""
#: src/components/status.jsx:1419
#: src/components/status.jsx:1490
msgid "Mute conversation"
msgstr ""
#: src/components/status.jsx:1435
#: src/components/status.jsx:1506
msgid "Post unpinned from profile"
msgstr ""
#: src/components/status.jsx:1436
#: src/components/status.jsx:1507
msgid "Post pinned to profile"
msgstr ""
#: src/components/status.jsx:1441
#: src/components/status.jsx:1512
msgid "Unable to unpin post"
msgstr ""
#: src/components/status.jsx:1441
#: src/components/status.jsx:1512
msgid "Unable to pin post"
msgstr ""
#: src/components/status.jsx:1450
#: src/components/status.jsx:1521
msgid "Unpin from profile"
msgstr ""
#: src/components/status.jsx:1457
#: src/components/status.jsx:1528
msgid "Pin to profile"
msgstr ""
#: src/components/status.jsx:1486
#: src/components/status.jsx:1557
msgid "Delete this post?"
msgstr ""
#: src/components/status.jsx:1502
#: src/components/status.jsx:1573
msgid "Post deleted"
msgstr ""
#: src/components/status.jsx:1505
#: src/components/status.jsx:1576
msgid "Unable to delete post"
msgstr ""
#: src/components/status.jsx:1533
#: src/components/status.jsx:1604
msgid "Report post…"
msgstr ""
#: src/components/status.jsx:1907
#: src/components/status.jsx:1943
#: src/components/status.jsx:2655
#: src/components/status.jsx:1978
#: src/components/status.jsx:2014
#: src/components/status.jsx:2726
msgid "Liked"
msgstr ""
#: src/components/status.jsx:1940
#: src/components/status.jsx:2642
#: src/components/status.jsx:2011
#: src/components/status.jsx:2713
msgid "Boosted"
msgstr ""
#: src/components/status.jsx:1950
#: src/components/status.jsx:2667
#: src/components/status.jsx:2021
#: src/components/status.jsx:2738
msgid "Bookmarked"
msgstr ""
#: src/components/status.jsx:1954
#: src/components/status.jsx:2025
msgid "Pinned"
msgstr ""
#: src/components/status.jsx:2000
#: src/components/status.jsx:2479
#: src/components/status.jsx:2071
#: src/components/status.jsx:2550
msgid "Deleted"
msgstr ""
#: src/components/status.jsx:2041
#: src/components/status.jsx:2112
msgid "{repliesCount, plural, one {# reply} other {# replies}}"
msgstr ""
#. placeholder {0}: snapStates.statusThreadNumber[sKey] ? ` ${snapStates.statusThreadNumber[sKey]}/X` : ''
#: src/components/status.jsx:2131
#: src/components/status.jsx:2202
msgid "Thread{0}"
msgstr ""
#: src/components/status.jsx:2209
#: src/components/status.jsx:2271
#: src/components/status.jsx:2375
#: src/components/status.jsx:2280
#: src/components/status.jsx:2342
#: src/components/status.jsx:2446
msgid "Show less"
msgstr ""
#: src/components/status.jsx:2209
#: src/components/status.jsx:2271
#: src/components/status.jsx:2280
#: src/components/status.jsx:2342
msgid "Show content"
msgstr ""
#. placeholder {0}: filterInfo.titlesStr
#. placeholder {0}: filterInfo?.titlesStr
#: src/components/status.jsx:2371
#: src/components/status.jsx:2442
#: src/pages/catchup.jsx:1879
msgid "Filtered: {0}"
msgstr "Filtered: {0}"
#: src/components/status.jsx:2375
#: src/components/status.jsx:2446
msgid "Show media"
msgstr ""
#: src/components/status.jsx:2515
#: src/components/status.jsx:2586
msgid "Edited"
msgstr ""
#: src/components/status.jsx:2592
#: src/components/status.jsx:2663
msgid "Comments"
msgstr ""
#. More from [Author]
#: src/components/status.jsx:2892
#: src/components/status.jsx:2963
msgid "More from <0/>"
msgstr "More from <0/>"
#: src/components/status.jsx:3194
#: src/components/status.jsx:3265
msgid "Edit History"
msgstr ""
#: src/components/status.jsx:3198
#: src/components/status.jsx:3269
msgid "Failed to load history"
msgstr ""
#: src/components/status.jsx:3203
#: src/components/status.jsx:3274
#: src/pages/annual-report.jsx:45
msgid "Loading…"
msgstr ""
#: src/components/status.jsx:3439
#: src/components/status.jsx:3510
msgid "HTML Code"
msgstr ""
#: src/components/status.jsx:3456
#: src/components/status.jsx:3527
msgid "HTML code copied"
msgstr ""
#: src/components/status.jsx:3459
#: src/components/status.jsx:3530
msgid "Unable to copy HTML code"
msgstr ""
#: src/components/status.jsx:3471
#: src/components/status.jsx:3542
msgid "Media attachments:"
msgstr ""
#: src/components/status.jsx:3493
#: src/components/status.jsx:3564
msgid "Account Emojis:"
msgstr ""
#: src/components/status.jsx:3524
#: src/components/status.jsx:3569
#: src/components/status.jsx:3595
#: src/components/status.jsx:3640
msgid "static URL"
msgstr ""
#: src/components/status.jsx:3538
#: src/components/status.jsx:3609
msgid "Emojis:"
msgstr ""
#: src/components/status.jsx:3583
#: src/components/status.jsx:3654
msgid "Notes:"
msgstr ""
#: src/components/status.jsx:3587
#: src/components/status.jsx:3658
msgid "This is static, unstyled and scriptless. You may need to apply your own styles and edit as needed."
msgstr ""
#: src/components/status.jsx:3593
#: src/components/status.jsx:3664
msgid "Polls are not interactive, becomes a list with vote counts."
msgstr ""
#: src/components/status.jsx:3598
#: src/components/status.jsx:3669
msgid "Media attachments can be images, videos, audios or any file types."
msgstr ""
#: src/components/status.jsx:3604
#: src/components/status.jsx:3675
msgid "Post could be edited or deleted later."
msgstr ""
#: src/components/status.jsx:3610
#: src/components/status.jsx:3681
msgid "Preview"
msgstr ""
#: src/components/status.jsx:3619
#: src/components/status.jsx:3690
msgid "Note: This preview is lightly styled."
msgstr ""
#. [Name] [Visibility icon] boosted
#: src/components/status.jsx:3872
#: src/components/status.jsx:3943
msgid "<0/> <1/> boosted"
msgstr "<0/> <1/> boosted"
#: src/components/status.jsx:3974
#: src/components/status.jsx:4045
msgid "Post hidden by your filters"
msgstr "Post hidden by your filters"
#: src/components/status.jsx:3975
#: src/components/status.jsx:4046
msgid "Post removed by author."
msgstr "Post removed by author."
#: src/components/status.jsx:3976
#: src/components/status.jsx:4047
msgid "Youre not authorized to view this post."
msgstr "Youre not authorized to view this post."
#: src/components/status.jsx:3977
#: src/components/status.jsx:4048
msgid "Post pending author approval."
msgstr "Post pending author approval."
#: src/components/status.jsx:3978
#: src/components/status.jsx:3979
#: src/components/status.jsx:4049
#: src/components/status.jsx:4050
msgid "Quoting not allowed by the author."
msgstr "Quoting not allowed by the author."