wyc
wyc

Reputation: 55323

Highlight matched text instead of the whole the text

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)?

Upvotes: 0

Views: 67

Answers (2)

Jash1395
Jash1395

Reputation: 248

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 position of the substring that you're searching for.

Start by splitting the node into an array

matchingNode.wholeText.split("")

Then find the index position, insert markElement at that position, and go from there.

Upvotes: 1

Gaspard Merten
Gaspard Merten

Reputation: 1233

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 :)

Upvotes: 1

Related Questions