JavaScript Node.replaceChild () не учитывает innerHtml нового ребенка - PullRequest
0 голосов
/ 24 декабря 2010

При создании аддона Firefox я столкнулся со странной проблемой.
У меня есть массив узлов, возвращаемый каким-то итератором.Итератор возвращает только узлы, содержащие Node.TEXT_NODE в качестве одного или нескольких дочерних элементов.Скрипт запускается при загрузке страницы.
Мне нужно найти текст в этих узлах с помощью регулярного выражения и окружить его тегом SPAN.

//beginning skipped  
var node = nodeList[i];    
var node_html = node.innerHTML;  
var node_content = node.textContent;  
if(node_content.length > 1){  
    var new_str = "<SPAN class='bar'>" + foo + "</SPAN>";  
    var regexp = new RegExp( foo , 'g' );  
    node_html = node_html.replace(regexp, new_str);  
    node.innerHTML = node_html;  
}

Базовая версия выглядела так и работала, за исключением одной проблемы - node.innerHTML может содержать атрибуты, обработчики событий, которые также могут содержать foo, которые не должны быть окружены тегами <span>.
Поэтому я решил делать замены только в текстовых узлах.Но текстовые узлы не могут содержать HTML-тег, поэтому мне пришлось обернуть их <div>.Например:

var node = nodeList[i];
for(var j=0; j<node.childNodes.length; j++){
    var child = node.childNodes[j];
    var child_content = child.textContent;
    if(child.nodeType == Node.TEXT_NODE && child_content.length >1){
        var newChild = document.createElement('div');
//          var newTextNode = document.createTextNode(child_content);
//          newChild.appendChild(newTextNode);
        var new_html = child_content;            
        var new_str = "<SPAN class='bar'>" + foo + "</SPAN>";
        var regexp = new RegExp( foo , 'g' );
        new_html = new_html.replace(regexp, new_str);
        newChild.innerHTML = new_html;
        alert(newChild.innerHTML);
        node.replaceChild(newChild, child);
    }
}

В этом случае alert(newChild.innerHTML); показывает правильный HTML.Но после визуализации страницы все созданные <div> пусты!Я озадачен.
Если я раскомментирую этот код:

//          var newTextNode = document.createTextNode(child_content);  
//          newChild.appendChild(newTextNode);  

alert также показывает все правильно, а <div> s заполнены текстом (добавление textNode работает нормально), но снова без<span> s.И еще одна забавная вещь - я не могу выделить этот новый контент <div> s с помощью мыши в браузере.
Похоже, он не учитывает новый innerHTML, и я не могу понять, почему.
Я что-то не так делаю?(Конечно, но что? Или это ошибка / функция FF?)

Ответы [ 2 ]

1 голос
/ 24 декабря 2010

Поскольку вы находитесь в Firefox, вы можете использовать забавные вещи, такие как TreeWalker и Range. Вы можете даже быть в состоянии избавиться от кода, который дает вам начальный массив узлов.

var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
var range = document.createRange();
var wrapper = document.createElement('span');
wrapper.className = "wrapper";
var node;
var re = /^wrap me$/;
while (node = walker.nextNode()) {
  if (re.test(node.textContent)) {
    range.selectNode(node);
    range.surroundContents(wrapper.cloneNode(true));
  }
}

JSBin

Вы можете настроить это таким образом, чтобы обернуть только часть текстового узла, установив диапазон по-разному, и TreeWalker можно отфильтровать больше.

Диапазон / TreeWalker

0 голосов
/ 24 декабря 2010

Этот код действительно странный; почему эти три строки находятся вне оператора if?

Я думаю, это должно выглядеть примерно так:

var node = nodeList[i];
for(var j=0; j<node.childNodes.length; j++){
  var child = node.childNodes[j];
  var child_content = child.textContent;
  if(child.nodeType == Node.TEXT_NODE && child_content.length >1){
    var newChild = document.createElement('div');
    newChild.innerHTML = '<span class="bar">' + child_content + '</span>';
    node.replaceChild(newChild, child);
}

Теперь я не могу понять, что происходит с этим регулярным выражением и заменой; для меня нет смысла в коде, который вы разместили.

...