Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

82
Visualizações
Wrap text in HTML tags if not already wrapped in a tag

I need to wrap specific terms in a string of text with <span> tags only if the term isn't already wrapped in a <span> tag.

For example I have a string of text:

Test string of text containing foo bar and baz.

And an object with key value pairs to search for in the string:

toolTips = {
  foo: 'tooltip for foo',
  bar: 'problematic tooltip that also contains baz',
  baz: 'tooltip for baz'
}

I need to iterate over the object keys and wrap matching terms with <span> tags to add the tool tip text.

So after the first iteration of the loop the string would be:

Test string of text containing
  <span class="tooltip">foo
    <span class="tooltip-text">tooltip for foo</span>
  </span>
bar and baz.

After the second it would be:

Test string of text containing
  <span class="tooltip">foo
    <span class="tooltip-text">tooltip for foo</span>
  </span>
  <span class="tooltip">bar
    <span class="tooltip-text">problematic tooltip that also contains baz</span>
  </span> 
and baz.

And after the third it would be:

Test string of text containing
  <span class="tooltip">foo
    <span class="tooltip-text">tooltip for foo</span>
  </span>
  <span class="tooltip">bar
    <span class="tooltip-text">problematic tooltip that also contains baz</span>
  </span> 
and
  <span class="tooltip">baz
    <span class="tooltip-text">tooltip for baz</span>
  </span>
.

I've tried doing this with string.replace() and with various regex patterns but I haven't been able to get it to fully work. Either the text inside of a previously added <span> gets matched and replaced or I do a negative look ahead for a closing </span tag in the regex and then text that comes before any span doesn't get matched.

Would appreciate ideas on how to handle this.

about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

It is not the most efficient idea, but you can try using placeholders, in order to not have phrases which overlap themselves.

let string = "Test string of text containing foo bar and baz.";

const toolTips = {
  foo: 0,
  bar: 1,
  baz: 2
}

const toolTipsPlaceholders = {
  0: {key: 'foo', value: 'tooltip for foo'},
  1: {key: 'bar', value: 'problematic tooltip that also contains baz'},
  2: {key: 'baz', value: 'tooltip for baz'}
}

const keys = Object.keys(toolTips)

keys.forEach(k => string = string.replaceAll(k, toolTips[k]))

const keysPlaceholders = Object.keys(toolTipsPlaceholders)

keysPlaceholders.forEach(k => string = string.replaceAll(k, `<span class="tooltip">${toolTipsPlaceholders[k].key}<span class="tooltip-text">${toolTipsPlaceholders[k].value}</span></span>`))

document.getElementById("test").innerHTML = string;
.tooltip {
  color: red;
}

.tooltip-text {
  color: blue;
}
<div id="test"></div>

about 4 years ago · Juan Pablo Isaza Relatório

0

Below is an approach that should let you take care of it.

You can use a really complicated regex to check if the key is already in elements, but that can be a pain to write, understand, and maintain.

Instead, the trick is to loop over each node in an element. If it is a text node, you know there is no HTML in there, so any replacements are safe. If it is an element node, then recurse through, looking for text nodes, and skip over tooltip elements.

This, in my opinion, makes it easier to understand and maintain going forward.

In the replacement, I just replaced the key with the tooltip value, which isn't exactly what you want, but can easily be tweaked to your liking.

document.querySelector('button').addEventListener('click', () => {
  const root = document.querySelector('div');
  
  applyTooltips(root);
});

const tooltips = {
  foo: 'hello bar and baz',
  bar: 'goodbye',
  baz: 'cake and foo'
};

// Regex that can match all of the keys at the same time
//  so we don't risk getting weirdness if one tooltip 
//  contains another key
const matchRegex = new RegExp(`(${Object.keys(tooltips).join('|')})`, 'g');

const tooltipSelector = '.tooltip';
const applyTooltips = element => {
  // Loop over each childNode, which might be a text or element node.
  [...element.childNodes].forEach(child => {
    // If it is a text node, we'll apply the tooltip logic
    if (child.nodeType === Node.TEXT_NODE) {
      // Get the text
      const text = child.wholeText;
      
      // Replace the text with the HTML
      newText = text.replaceAll(matchRegex, key => `<div class="tooltip">${tooltips[key]}</div>`);
      
      // Create a temp element we can assign the
      //  HTML text to to get actual elements
      const temp = document.createElement('div');
      temp.innerHTML = newText;
      
      // Apply each new node before the text child
      [...temp.childNodes].forEach(node => 
        element.insertBefore(node, child)
      );
      
      // Remove the old text child
      element.removeChild(child);
    } else if (!child.matches(tooltipSelector)) {
      // If it is an element that isn't a tooltip element, we'll recurse on it.
      applyTooltips(child);
    }
  });
};
.tooltip { color: #F00; }
<div>
  Test string of text containing foo bar and baz.
  
  This <div class="tooltip">foo</div> is already wrapped and won't get wrapped again.
</div>
<button>Apply</button>

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda