Add tag to all repetitions of a given word

Asked

Viewed 240 times

3

Look at the code below:

<style type="text/css">
    .format{
        color: red;
        font-style: italic;
    }
</style>

<div>
     <p>texto texto texto 'palavra-chave'. texto 'palavra-chave', texto texto.<p>
</div>

Within the div, ignoring tags, I want whenever a 'keyword' is found to put it inside <span class="format">

What would be the best solution for this using Pure Javascript?

  • @Laerte why deleted his reply?

  • Why you asked for the solution in pure Javascript.

  • @Laerte ah yes.

  • It’s the "same" (see I quote) question you posted about Javascript’s "reserved words"?

  • @Guilhermenascimento is the same algorithm

  • 1

    In matters of security I personally I disagree with this method of limiting the user, as there are more effective and less "limiting" ways to make safe an online text editor. However, as this is currently out of focus current, Please test my answer.

  • 1

    You only have one div or it could be multiple Ivs?

  • @Sergio My intention is to repeat this same field several times. It’s a Javascript editor actually, so it’s just a simple text editable div.

Show 3 more comments

1 answer

2


This functionality is simple, you can use .split().join() or regex to replace content with .replace().

In its simplest version it would be:

var editavel = document.querySelector('div[contenteditable="true"]');
var novoConteudo = '<span class="format">palavra-chave</span>';
editavel.innerHTML = editavel.innerHTML.split('palavra-chave').join(novoConteudo);

jsFiddle: http://jsfiddle.net/u68b6tz8/

If you want to make that substitution on the fly, with each new letter inserted, then the thing gets more interesting. You can add a Event Listener when a key is released (keyup) and check the content:

var editavel = document.querySelector('div[contenteditable="true"]');
editavel.addEventListener('keyup', function (e) {
    var novoConteudo = '<span class="format">palavra-chave</span>';
    this.innerHTML = this.innerHTML.split('palavra-chave').join(novoConteudo);

});

The problem now that remains to be solved is the careto/cursor, which moves out of position when HTML is replaced. On Soen I found two questions about this where Tim Down answers about how to read and how to set the cursor/careto. These answers do not solve the problem directly but led me to this solution:

Three steps!

#1 - replace all words when the code first runs. This way we know that when we type it will only appear one new at a time.

#2 - Use replace, with function! This way we can insert a span and to solve the problem of careto we give that span a secret ID.

#3 - So we can select this element and point the gap to the start of the next sibling.

Applied to this case the code would look like this:

var palavraChave = 'palavra-chave';

// fazer substituições antes de começar a escrever
var editavel = document.querySelector('div[contenteditable="true"]');
var novoConteudo = '<span class="format">palavra-chave</span>';
editavel.innerHTML = editavel.innerHTML.split('palavra-chave').join(novoConteudo);

var editavel = document.querySelector('div[contenteditable="true"]');
editavel.addEventListener('keyup', function (e) {
    var regExp = new RegExp('(' + palavraChave + ')(?!<)', 'g');
    // se não houver nada para substituir, sair
    if (!this.innerHTML.match(regExp)) return;
    var novoConteudo = this.innerHTML.replace(regExp, function () {
        // trocar o match pelo novo conteudo
        return '<span id="span_secreto">' + palavraChave + '</span>';
    });
    this.innerHTML = novoConteudo;
    // ir buscar o elemento secreto criado para lhe retirar a ID e colocar a classe
    var span = document.getElementById('span_secreto');
    span.removeAttribute('id');
    span.classList.add('format');
    colocarCareto(span);
});

function colocarCareto(node) {
    // defenir que elemento o careto deve seguir. Criar um novo placebo se o span fôr o ultimo
    var target = node.nextSibling ? node.nextSibling : (function (el) {
        var novoTextNode = document.createTextNode(' ');
        el.appendChild(novoTextNode);
        return novoTextNode
    })(node);
    // colocar o careto no inicio do proximo elemento
    var range = document.createRange();
    range.setStart(target, 1);
    range.setEnd(target, 1);
    var selection = window.getSelection();
    selection.removeAllRanges();
    selection.addRange(range);
}
.format {
    color: red;
    font-style: italic;
}
span.format {
    color: #aad;
}
<div contenteditable="true">
    texto texto texto palavra-chave. texto palavra-chav, texto texto.
</div>

The code still needs more tuning, and maybe later you can shorten it. But the main idea and the functionality is.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.