@@ -15,7 +15,7 @@ export async function renderLatex(properties: Properties, root: HTMLElement) {
15
15
if ( properties . viewer !== "image" && properties . viewer !== "latex" ) {
16
16
return ;
17
17
}
18
- const latexNodes = findLatexTextNodes ( root ) ;
18
+ const latexNodes = findLatexTextNodes ( root , properties . ignored_containers ) ;
19
19
20
20
for ( const latexNode of latexNodes ) {
21
21
await replaceLatexInTextNode ( properties , latexNode ) ;
@@ -36,55 +36,82 @@ async function replaceLatexInTextNode(properties: Properties, node: Node) {
36
36
if ( nextLatexPosition ) {
37
37
// Get left non LaTeX text.
38
38
const leftText : string = textContent . substring ( pos , nextLatexPosition . start ) ;
39
- const leftTextNode = document . createTextNode ( leftText ) ;
40
- // Create a node with left text.
41
- node . parentNode ?. insertBefore ( leftTextNode , node ) ;
42
- node . nodeValue = node . nodeValue ?. substring ( pos , nextLatexPosition . start ) ?? "" ;
39
+ if ( leftText ) {
40
+ const leftTextNode = document . createTextNode ( leftText ) ;
41
+ // Create a node with left text.
42
+ node . parentNode ?. insertBefore ( leftTextNode , node ) ;
43
+ }
43
44
44
45
// Get LaTeX text.
45
46
const latex = textContent . substring ( nextLatexPosition . start + "$$" . length , nextLatexPosition . end ) ;
46
- // Convert LaTeX to mathml .
47
+ // Convert LaTeX to MathML .
47
48
const response = await latexToMathml ( latex , properties . editorServicesRoot , properties . editorServicesExtension ) ;
48
- // Insert mathml node.
49
+ // Insert MathML node.
49
50
const fragment = document . createRange ( ) . createContextualFragment ( response . text ) ;
50
-
51
51
node . parentNode ?. insertBefore ( fragment , node ) ;
52
- node . nodeValue = node . nodeValue . substring ( nextLatexPosition . start , nextLatexPosition . end ) ;
53
52
53
+ // Update pos to search for next LaTeX instance.
54
54
pos = nextLatexPosition . end + "$$" . length ;
55
55
} else {
56
- // No more LaTeX node found.
57
- const text = textContent . substring ( pos ) ;
58
- const textNode = document . createTextNode ( text ) ;
59
- node . parentNode ?. insertBefore ( textNode , node ) ;
60
- node . nodeValue = "" ;
61
- pos = textContent . length ;
56
+ // If no more LaTeX found, append the rest of the text as a new text node and break the loop.
57
+ const remainingText = textContent . substring ( pos ) ;
58
+ if ( remainingText ) {
59
+ const remainingTextNode = document . createTextNode ( remainingText ) ;
60
+ node . parentNode ?. insertBefore ( remainingTextNode , node ) ;
61
+ }
62
+ break ; // Exit the loop as we've processed all text.
62
63
}
63
64
}
64
-
65
- // Delete original text node.
65
+ // Remove the original node after processing.
66
66
node . parentNode ?. removeChild ( node ) ;
67
67
}
68
68
69
69
/**
70
- * Returns an array with all HTML LaTeX nodes.
71
- * @param {HTMLElement } root - Any DOM element that can contain LaTeX.
72
- * @returns {Node[] } Array with all HTML LaTeX nodes inside root.
70
+ * Finds and returns an array of text nodes containing LaTeX expressions.
71
+ *
72
+ * @param properties - The properties object.
73
+ * @param root - The root element to search within.
74
+ * @returns An array of text nodes containing LaTeX expressions.
73
75
*/
74
- function findLatexTextNodes ( root : any ) : Node [ ] {
75
- const nodeIterator : NodeIterator = document . createNodeIterator ( root , NodeFilter . SHOW_TEXT , ( node ) =>
76
- / ( \$ \$ ) ( .* ) ( \$ \$ ) / . test ( node . nodeValue || "" ) ? NodeFilter . FILTER_ACCEPT : NodeFilter . FILTER_REJECT ,
77
- ) ;
76
+ function findLatexTextNodes ( root : any , ignored_latex_containers : string | null ) : Node [ ] {
77
+ const nodeIterator : NodeIterator = createNodeIterator ( root ) ;
78
+ const blackListedNodes = root . querySelectorAll ( ignored_latex_containers ) ?? [ ] ;
78
79
const latexNodes : Node [ ] = [ ] ;
79
80
80
81
let currentNode : Node | null ;
81
82
while ( ( currentNode = nodeIterator . nextNode ( ) ) ) {
83
+ if ( blackListedNodes . length > 0 && isNodeBlacklisted ( currentNode , blackListedNodes ) ) {
84
+ continue ;
85
+ }
82
86
latexNodes . push ( currentNode ) ;
83
87
}
84
88
85
89
return latexNodes ;
86
90
}
87
91
92
+ /**
93
+ * Creates a NodeIterator to find text nodes containing LaTeX expressions.
94
+ *
95
+ * @param root - The root element to search within.
96
+ * @returns A NodeIterator for text nodes containing LaTeX expressions.
97
+ */
98
+ function createNodeIterator ( root : any ) : NodeIterator {
99
+ return document . createNodeIterator ( root , NodeFilter . SHOW_TEXT , ( node ) =>
100
+ / ( \$ \$ ) ( .* ) ( \$ \$ ) / . test ( node . nodeValue || "" ) ? NodeFilter . FILTER_ACCEPT : NodeFilter . FILTER_REJECT ,
101
+ ) ;
102
+ }
103
+
104
+ /**
105
+ * Checks if a node or any of its ancestors are in the blacklist.
106
+ *
107
+ * @param node - The node to check.
108
+ * @param blackListedNodes - The list of blacklisted nodes.
109
+ * @returns True if the node or any of its ancestors are blacklisted, false otherwise.
110
+ */
111
+ function isNodeBlacklisted ( node : Node , blackListedNodes : NodeListOf < Element > ) : boolean {
112
+ return Array . from ( blackListedNodes ) . some ( ( blackListedNode ) => blackListedNode . contains ( node ) ) ;
113
+ }
114
+
88
115
/**
89
116
* Returns an object {start, end} with the start and end latex position.
90
117
* @param {number } pos - Current position inside the text.
0 commit comments