Условие замены текста на странице

Я работаю над простым плагином браузера, чтобы заменить одно слово другим, но с добавлением якоря для небольшой всплывающей подсказки. У меня это уже работает, но моя проблема в том, что если слово, которое нужно заменить, уже находится в якоре, то мой </a> закрывает уже открытый <a>,

Поэтому мне нужна помощь с тем, как заменить только слово, если оно не находится в открытом теге привязки. Следующим шагом является также убедиться, что целевое слово не находится в <input> или другие неподходящие теги.

Мой код:

var regex = new RegExp("\\b" + nativeWord + "\\b", "igm");
var body = $('body');

body.each(function() {
    $(this).html(
        $(this).html().replace(regex, function() {
            counter++;
            if(counter > wordSwapLimit) {
                return nativeWord;
            } else {
                return "<a class=\"tooltip\" href=\"#\">" + studyWord + "<span class=\"classic\">" + nativeWord + "</span></a>";            
            }
        })
    );
});

Я подозреваю, что мне может понадобиться написать более сложный RegExp, но это мой первый выход с ним, поэтому любые предложения будут с благодарностью!

Обновление Итак, у меня есть тестовая страница, с которой я работаю, чтобы посмотреть, как работает мой код. Это часть оригинального HTML-кода со страницы:

<p id="changeArea"> I <a href="http://www.chicken.com">love chicken but I hate</a> beef. </p>

Но с кодом, показанным выше, и заменой 'chicken' на 'kip', это изменяется на:

<p id="changeArea"> I <a href="http://www.&lt;a class=" tooltip"="">kip<span class="classic">chicken</span></a>.com"&gt;love <a class="tooltip" href="#">kip<span class="classic">chicken</span></a> but I hate beef. </p>

Если у меня нет якорей вокруг того, что я обмениваю, то это работает отлично, и я получаю хорошую подсказку при опрокидывании.

В очередной раз благодарим за помощь!

Обновление 2 По запросу, вот "необработанные" примеры, с которыми мой плагин может столкнуться при замене "курицы" на "kip":

<p id="changeArea"> I <a href="http://www.chicken.com">love chicken but I hate</a> beef. </p>
<p id="changeArea2"> Chickenpie? pie-chicken. </p>

Я надеюсь на следующее:

<p id="changeArea"> I <a href="http://www.chicken.com">love chicken but I hate</a> beef. </p>
<p id="changeArea2"> Chickenpie? pie-<a class="tooltip" href="#">kip<span class="classic">chicken</span></a>. </p>

Как вы можете видеть в первой строке, HTML-код оставлен один, как текст для слова, потому что он находится внутри URL-адреса, и поэтому его сломали бы, если бы был вставлен якорь моей подсказки. Вторая строка игнорирует "куриный пирог", потому что Я хочу только обмен слова целиком, в соответствии с моим существующим регулярным выражением. "пирог с курицей" все же поменяется местами. Эта строка обрабатывается правильно с существующим кодом.

Я буквально просто хочу добавить дополнительные правила к моему существующему коду, которые говорят: "Не заменяйте код и не заменяйте, если в открытом теге якоря".

1 ответ

Решение

Поскольку вы в JavaScript, у вас уже есть доступ к DOM. Почему вы пытаетесь использовать регулярные выражения???

Просто перебирайте текстовые узлы, игнорируя существующие ссылки:

(function(elem) {
    var recurse = arguments.callee, nodes = elem.childNodes, l = nodes.length, i, t,
        getLink = function() {
            var a = document.createElement('a'), s = document.createElement('span');
            a.href = "#";
            a.className = "tooltip";
            a.appendChild(document.createTextNode(studyWord));
            s.className = "classic";
            s.appendChild(document.createTextNode(nativeWord));
            a.appendChild(s);
            return a;
        };
    for( i=0; i<l; i++) {
        switch(nodes[i].nodeType) {
        case 1:
            // element - recurse, but not if already a link
            if( nodes[i].nodeName != "A") recurse(nodes[i]);
            break;
        case 3:
            // text node, look for keyword
            t = nodes[i].nodeValue.search(new RegExp("\\b"+nativeWord+"\\b","i"));
            if( t > -1) {
                // found it! now to hack around...
                t = nodes[i].splitText(t);
                t.splitText(nativeWord.length);
                t.parentNode.replaceChild(t,getLink());
            }
            break;
        }
    }
})(document.body);

Обратите внимание: этот подход использует Vanilla JS. Это зависит от вас, чтобы убедиться, что он запускается после загрузки страницы. Это может быть сделано либо:

  • Добавление defer приписать скрипт, если он внешний
  • Поместить сценарий прямо перед </body> (или, по крайней мере, после всего контента, на который вы хотите повлиять)
  • Заворачивая это в window.onload обработчик или даже $(function() {...}) так как вы уже используете JQuery.
Другие вопросы по тегам