wyc
wyc

Reputation: 55293

Replace method adding <strong>$1</strong> instead of the matched substring and bold text

The following code is recording which keys are being pressed. If the two first keys match the two first characters in a link, those characters will be highlighted. (In this case, "li" from "link.")

let keys = []

document.addEventListener('keypress', event => {
  keys.push(event.key)

  console.log(keys)

  const selector = 'a'
  let text = keys.join('')
  let element = [...document.querySelectorAll(selector)]
    .find(elements => elements.textContent.includes(text))

  if (keys.length === 2) {
    if (!element) {
      keys = []
      return
    }

    element.textContent = element.textContent.replace(text, `<strong>$1</strong>`)
  }
})
<a href="#">link</a>

I want to highlight the characters with <strong> tags.

I was expecting this:

link

But I got this instead:

<strong>$1</strong>nk

Steps:

  1. Press "Run code snippet"
  2. Type l then i.

Upvotes: 0

Views: 858

Answers (1)

vanowm
vanowm

Reputation: 10221

There are at least 2 issues: first you are inserting html into textContent which being inserted as text not html. second, since you have no capturing groups in your search you can't use $1 instead you either can use ${text} or $&:

let keys = []

document.addEventListener('keypress', event => {
  keys.push(event.key)

  console.log(keys)

  const selector = 'a'
  let text = keys.join('')
  let element = [...document.querySelectorAll(selector)]
    .find(elements => elements.textContent.includes(text))

  if (keys.length === 2) {
    if (!element) {
      keys = []
      return
    }
    element.innerHTML = element.innerHTML.replace(text, `<strong>$&</strong>`)
  }
})
<a href="#">link</a>

Here is a little "safer" version that doesn't affect html:

let keys = []

document.addEventListener('keypress', event => {
  keys.push(event.key)

  console.log(keys)

  const selector = 'a'
  let text = keys.join('')
  let element = [...document.querySelectorAll(selector)]
    .find(elements => elements.textContent.includes(text))

  if (keys.length === 2) {
    if (!element) {
      keys = []
      return
    }


    //make it html friendly
    text = text.replace(/&/g, "&amp;")
               .replace(/</g, "&lt;")
               .replace(/>/g, "&gt;")
                //make it regex friendly
               .replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');

    element.innerHTML = element.innerHTML
                  //remove old highlightings
                  .replace(/<mark>([^<]*)?<\/mark>/g, "$1")
                  // convert selected text into regex,
                  // search and enclose found strings with <mark></mark>
                  .replace(new RegExp("(" + text + ")", "gi"), '<mark>$1</mark>'); //add new highlighting
  }
})
mark
{
  background-color: inherit;
  font-weight: bold;
}
<a href="#">link</a>
<a href="#">href</a>

Upvotes: 3

Related Questions