I have a function, getTextNodes
, that searches text nodes recursively. Then I use a addHighlight
function to highlight the text with <mark>
tags:
const buttonEl = `<button>
<span>
Icon
</span>
Text
</button>
`;
document.body.innerHTML = buttonEl;
const foundButtonEl = document.querySelector("button");
const elements = [];
elements.push(foundButtonEl);
addHighlight(elements, "T");
function addHighlight(elements, text) {
elements.forEach((element, index) => {
const textNodes = getTextNodes(document.body);
const matchingNode = textNodes.find(node => node.textContent.includes(text));
const markElement = document.createElement('mark');
markElement.innerHTML = matchingNode.textContent;
matchingNode.replaceWith(markElement);
});
}
function getTextNodes(node) {
let textNodes = [];
if (node.nodeType === Node.TEXT_NODE) {
textNodes.push(node);
}
node.childNodes.forEach(childNode => {
textNodes.push(...getTextNodes(childNode));
});
return textNodes;
}
The problem is that addHighlight
is highlighing the whole text (in the example, Text
), instead of the matched text (in the example, T
).
How to change this code so that only the matched text is highlighted (text
)?
CodePudding user response:
The problem is that the node you match is the element of which the innerContent contains the string you want to highlight.
What you should do instead of :
markElement.innerHTML = matchingNode.textContent;
matchingNode.replaceWith(markElement);
is probably something like
markElement.innerHTML = text;
matchingNode.replaceTextWithHTML(text, markElement);
replaceTextWithHTML is a fictive function :)
CodePudding user response:
matchingNode
is the whole node so you're replacing everything. If you want to match just part of it, you need to iterate though the textnode and find the index positions of the substring that you're searching for.
Start by splitting the node into an array
matchingNode.split("")
Then find the index positions, insert markElement
at that position, and go from there.