I have an array of terms(Objects) containing term.name, term.id and term.description so it looks like this:
const terms = [{id: 1, name: "First", description: "First Item"}, {id: 2, name: "Second", description: "Second Item"}, {id: 3, name: "Knowledge Base", description: "Test"}, {id: 4, name: "Base", description: "Another Test"}]
And I have an HTML looking like this:
<div class="parent">
<p>This is the first text node containing First and Second term name.</p>
<div>
<h1>Title</h1>
<p>Knowledge Base is important. First is also important, base should be good</p>
</div>
</div>
What I'm trying to accomplish is to loop through each textNode and check if any of the terms from array are present in the node, if the term is present wrap that word in a tag. Also if we have two terms like knowledge base and base then just wrap longest term and skip the shortest. So for example:
<p>Knowledge Base</p> should look like <p><span>Knowledge Base</span></p>
and not like:
<p>Knowledge Base</p> should look like <p><span>Knowledge <span>Base</span></span></p>
Here is the function to get all text nodes and what I have done so far:
getAllTextNodes(element) {
let node;
let nodes = [];
let walk = document.createTreeWalker(element,NodeFilter.SHOW_TEXT,null,false);
while (node = walk.nextNode()) nodes.push(node);
return nodes;
}
const allNodes = getAllTextNodes(document.querySelector('.parent'));
const terms = [{id: 1, name: "First"}, {id: 2, name: "Second"}, {id: 3, name: "Knowledge Base"}, {id: 4, name: "Base"}]
Array.from(allNodes).forEach(node => {
terms.forEach(term => {
if (node.parentNode.textContent.includes(term.name)) {
node.parentNode.innerHTML = node.parentNode.innerHTML.replace(term.name, `<span>${term.name}</span>`)
}
})
})
<div class="parent">
<p>This is the first text node containing First and Second term name.</p>
<div>
<h1>Title</h1>
<p>Knowledge Base is important. First is also important, base should be good</p>
</div>
</div>