fix(auto-render): concatenate content of successive text nodes (#3422)

* fix(auto-render): concatenate text nodes

Concatenate successive text nodes to prevent auto-render from skipping
math input when browsers split text nodes with long textContent.

* Remove siblings only when math found

Only remove siblings when math expressions were found to prevent removal
of nodes that do not contain math.

* Skip siblings if they do not contain math

* Fixed typo in comments

* Added first tests for large test nodes

* Expanded testing to compare renderMathInElement with renderMathInText

* Simplified text node test

* Change description of test

* Update contrib/auto-render/auto-render.js

Co-authored-by: marcoesters <marco.esters@duke.edu>
Co-authored-by: ylemkimon <y@ylem.kim>
This commit is contained in:
Marco Esters
2022-08-29 14:50:14 -07:00
committed by GitHub
parent 99be728a78
commit 4d3fdd8647
2 changed files with 59 additions and 1 deletions

View File

@@ -55,10 +55,29 @@ const renderElem = function(elem, optionsCopy) {
const childNode = elem.childNodes[i]; const childNode = elem.childNodes[i];
if (childNode.nodeType === 3) { if (childNode.nodeType === 3) {
// Text node // Text node
const frag = renderMathInText(childNode.textContent, optionsCopy); // Concatenate all sibling text nodes.
// Webkit browsers split very large text nodes into smaller ones,
// so the delimiters may be split across different nodes.
let textContentConcat = childNode.textContent;
let sibling = childNode.nextSibling;
let nSiblings = 0;
while (sibling && (sibling.nodeType === Node.TEXT_NODE)) {
textContentConcat += sibling.textContent;
sibling = sibling.nextSibling;
nSiblings++;
}
const frag = renderMathInText(textContentConcat, optionsCopy);
if (frag) { if (frag) {
// Remove extra text nodes
for (let j = 0; j < nSiblings; j++) {
childNode.nextSibling.remove();
}
i += frag.childNodes.length - 1; i += frag.childNodes.length - 1;
elem.replaceChild(frag, childNode); elem.replaceChild(frag, childNode);
} else {
// If the concatenated text does not contain math
// the siblings will not either
i += nSiblings;
} }
} else if (childNode.nodeType === 1) { } else if (childNode.nodeType === 1) {
// Element node // Element node

View File

@@ -322,3 +322,42 @@ describe("Pre-process callback", function() {
expect(el1.innerHTML).toEqual(el2.innerHTML); expect(el1.innerHTML).toEqual(el2.innerHTML);
}); });
}); });
describe("Parse adjacent text nodes", function() {
it("parse adjacent text nodes with math", function() {
const textNodes = ['\\[',
'x^2 + y^2 = r^2',
'\\]'];
const el = document.createElement('div');
for (let i = 0; i < textNodes.length; i++) {
const txt = document.createTextNode(textNodes[i]);
el.appendChild(txt);
}
const el2 = document.createElement('div');
const txt = document.createTextNode(textNodes.join(''));
el2.appendChild(txt);
const delimiters = [{left: "\\[", right: "\\]", display: true}];
renderMathInElement(el, {delimiters});
renderMathInElement(el2, {delimiters});
expect(el).toStrictEqual(el2);
});
it("parse adjacent text nodes without math", function() {
const textNodes = ['Lorem ipsum dolor',
'sit amet',
'consectetur adipiscing elit'];
const el = document.createElement('div');
for (let i = 0; i < textNodes.length; i++) {
const txt = document.createTextNode(textNodes[i]);
el.appendChild(txt);
}
const el2 = document.createElement('div');
for (let i = 0; i < textNodes.length; i++) {
const txt = document.createTextNode(textNodes[i]);
el2.appendChild(txt);
}
const delimiters = [{left: "\\[", right: "\\]", display: true}];
renderMathInElement(el, {delimiters});
expect(el).toStrictEqual(el2);
});
});