views:

276

answers:

1

I am trying dynamically to append an <svg> element to an existing SVG island on an XHTML page (Firefox 3.6.3). And it is crashing the browser.

Done manually, this works as expected:

<svg xmlns="http://www.w3.org/2000/svg"&gt;
    <svg xmlns="http://www.w3.org/2000/svg"&gt;
        ...         
    </svg>
</svg>

However, if you dynamically add this element using JavaScript, the browser crashes. Simple example:

<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
    <title>SVG island example</title>
    <script type="text/javascript"><![CDATA[
        function crash( )
        {
            svgs = document.getElementsByTagNameNS( "http://www.w3.org/2000/svg", "svg" );

            for ( var i = 0; i < svgs.length; i++ )
            {
                var e = document.createElementNS( "http://www.w3.org/2000/svg", "svg" );
                svgs[i].appendChild( e );
            }
        }
    ]]></script>
</head>
<body>
    <svg id="mySVG" xmlns="http://www.w3.org/2000/svg"&gt;
    </svg>
    <button onclick="crash()">Crash Firefox</button>
</body>
</html>

Interestingly, if I do a getElementById, it works fine. Interesting, but not particularly helpful in my situation since I'm storing pointers to SVGDocuments. Example:

function doesntCrash( )
{
    var svg = document.getElementById( "mySVG" );
    var e = document.createElementNS( "http://www.w3.org/2000/svg", "svg" );
    svg.appendChild( e );
}

As far as I can tell, this is a Firefox bug. Does anyone have any insight into this matter?

UPDATED (solution): As stated below, the issue was the "liveness" of the HTMLCollection returned by the getElementsByTagNameNS call which I mistook for a native array (tsk, tsk!) A quick hackaround would be to either store the array length in a variable, if you're only appending. A better solution might be to copy the array contents to a native array, as described here. Here's an updated using that method:

function doesntCrash( )
{
    var svgs = document.getElementsByTagNameNS( "http://www.w3.org/2000/svg", "svg" );

    // copy contents to native a static, array
    svgs = Array.prototype.slice.call( svgs );

    for ( var i = 0; i < svgs.length; i++ )
    {
        var e = document.createElementNS( "http://www.w3.org/2000/svg", "svg" );
        svgs[i].appendChild( e );
    }
}

Thank you Sergey Ilinsky for your quick response!

+1  A: 

The cause to your problem is likely hidden in liveness of the NodeSet returned by the getElementByTagName(NS) method call (which is not the case for querySelectorAll method, for example). So in your code you find all elements with name "svg" from SVG namespace, then start walking through this list and add new "svg" elements to the document that end up added to the collection you are walking too. Teoretically script simply should never exit, but in practice as you see browser crashes.

Sergey Ilinsky
You're absolutely right. Shame on me for mistaking the returned `HTMLCollection` with a native JavaScript array... Thank you for your quick response!
zourtney