in packages/dom/src/highlight-text.ts [75:125]
function textNodesInRange(range: Range): Text[] {
// If the start or end node is a text node and only partly in the range, split it.
if (isTextNode(range.startContainer) && range.startOffset > 0) {
const endOffset = range.endOffset; // (this may get lost when the splitting the node)
const createdNode = range.startContainer.splitText(range.startOffset);
if (range.endContainer === range.startContainer) {
// If the end was in the same container, it will now be in the newly created node.
range.setEnd(createdNode, endOffset - range.startOffset);
}
range.setStart(createdNode, 0);
}
if (
isTextNode(range.endContainer) &&
range.endOffset < range.endContainer.length
) {
range.endContainer.splitText(range.endOffset);
}
// Collect the text nodes.
const walker = ownerDocument(range).createTreeWalker(
range.commonAncestorContainer,
NodeFilter.SHOW_TEXT,
{
acceptNode: (node) =>
range.intersectsNode(node)
? NodeFilter.FILTER_ACCEPT
: NodeFilter.FILTER_REJECT,
},
);
walker.currentNode = range.startContainer;
// // Optimise by skipping nodes that are explicitly outside the range.
// const NodeTypesWithCharacterOffset = [
// Node.TEXT_NODE,
// Node.PROCESSING_INSTRUCTION_NODE,
// Node.COMMENT_NODE,
// ];
// if (!NodeTypesWithCharacterOffset.includes(range.startContainer.nodeType)) {
// if (range.startOffset < range.startContainer.childNodes.length) {
// walker.currentNode = range.startContainer.childNodes[range.startOffset];
// } else {
// walker.nextSibling(); // TODO verify this is correct.
// }
// }
const nodes: Text[] = [];
if (isTextNode(walker.currentNode)) nodes.push(walker.currentNode);
while (walker.nextNode() && range.comparePoint(walker.currentNode, 0) !== 1)
nodes.push(walker.currentNode as Text);
return nodes;
}