Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.normalize() crashes in IE6

I am doing some manipulation of TextNodes in javascript, and I (unfortunately) need to support IE6. Node.normalize() is crashing, and I need to work around this. My first inclination is to just re-implement it using other DOM methods. How would I implement this?

like image 644
Christian Oudard Avatar asked Jan 07 '10 20:01

Christian Oudard


3 Answers

The following version is shorter and more efficient than others posted here. The improvements are:

  • No repeated calls to node.childNodes and node.childNodes.length
  • No creation of extra text nodes; instead, for each merge, keep the first existing text node and use its appendData() method
  • Shorter

The code:

function normalize(node) {
    var child = node.firstChild, nextChild;
    while (child) {
        if (child.nodeType == 3) {
            while ((nextChild = child.nextSibling) && nextChild.nodeType == 3) {
                child.appendData(nextChild.data);
                node.removeChild(nextChild);
            }
        } else {
            normalize(child);
        }
        child = child.nextSibling;
    }
}
like image 157
Tim Down Avatar answered Nov 03 '22 03:11

Tim Down


The solution above was running very slow and crashing Firefox for me. So I optimized it a bit and it's working great now (the main issue was with repeatedly referencing the HTML collection object node.childNodes).

Thanks for the great starting point, but I figured this was worth posting:


function myNormalize(node) {
    for (var i=0, children = node.childNodes, nodeCount = children.length; i<nodeCount; i++) {
        var child = children[i];
        if (child.nodeType == 1) {
            myNormalize(child);
            continue;
        }
        if (child.nodeType != 3) { continue; }
        var next = child.nextSibling;
        if (next == null || next.nodeType != 3) { continue; }
        var combined_text = child.nodeValue + next.nodeValue;
        new_node = node.ownerDocument.createTextNode(combined_text);
        node.insertBefore(new_node, child);
        node.removeChild(child);
        node.removeChild(next);
        i--;
        nodeCount--;
    }
}
like image 42
Jon Raasch Avatar answered Nov 03 '22 03:11

Jon Raasch


You'd need to recursively look through all of the child nodes of the current node. When considering a node, you'd delete any empty text nodes and combine any adjacent text nodes.

 function myNormalize( node )
     for each child node of node do
         if child is not text
            normalize(child)
         else
            if child node is empty
               delete
               continue
            else 
                sibling = next node
                while sibling exists and sibling is a text node
                    if sibling is empty
                       delete sibling
                    else
                       combine sibling with child
                    get next sibling
                end
            end
        end
    end
end
like image 31
tvanfosson Avatar answered Nov 03 '22 01:11

tvanfosson