Reputation: 445
I want to search for a text in HTML element and return the Range object for the text. I wanted to use the range to do some manipulation like highlighting and replacing the text. Similar to Grammarly's error highlighting feature.
What I have tried so far:
a. it's very slow (350ms) and
b.fails to find some texts
const getRangeofText = (text:string) => {
const children = document.activeElement;
let finalNode;
let parent = children;
let i = 12;
let isFound = false;
while (parent.children.length > 0 && i > 0) {
i--;
console.log("I: ", i);
console.log("traversing through: ", parent.childNodes);
for (const item of Array.from(parent.childNodes)) {
console.log("item: ", item);
if (item.nodeType === 3 && item.textContent.includes(text)) {
console.log("found in TEXT NODE");
finalNode = item;
isFound = true;
}
if (item.nodeType === 1 && item.textContent.includes(text)) {
console.log("found in ELEMENT NODE");
parent = item as Element;
finalNode = item;
isFound = true;
}
}
}
console.log("final node: ", finalNode);
// console.log("node type: ", finalNode.nodeType);
const range = new Range();
let startNode;
let endNode;
let arr = text.split(" ");
let startWord = arr[0];
let endWord = arr[arr.length - 1];
if (finalNode) {
if (finalNode.nodeType === 1) {
let childNodes = finalNode.childNodes;
for (const item of Array.from(childNodes)) {
if (item.textContent.includes(startWord)) {
startNode = item;
}
if (item.textContent.includes(endWord)) {
endNode = item;
}
}
range.setStart(startNode, 0);
range.setEndAfter(endNode);
} else {
range.setStart(finalNode, 0);
range.setEnd(finalNode, text.length);
}
window.getSelection().addRange(range);
}
};
Here is the Codesandbox for the above code.
What other options do I have? Or how can optimize these functions?
Upvotes: 1
Views: 453
Reputation: 445
function getRanges(a) {
let ranges = [];
const scrollTop = document.documentElement.scrollTop;
while (window.find(a)) {
var rng = window.getSelection().getRangeAt(0);
ranges = [...ranges, rng];
document.documentElement.scrollTop = scrollTop;
}
return ranges;
}
const getRangeElements = (str) => {
window.getSelection().removeAllRanges();
const ranges = getRanges(str);
window.getSelection().removeAllRanges();
return ranges;
};
getRangeElements("Text to search for")
This works but it blurs out the page and whatever element (eg. text input) that was focus will get blurred. Any way we can avoid the blur?
Upvotes: 0