Ian Y.
Ian Y.

Reputation: 2457

DOMNodeInserted behaves weird when performing DOM manipulation on body

The following code uses DOMNodeInserted to perform DOM manipulation on the body element once it is inserted into the DOM. I know $(document).ready(function { }); is enough to do the job, but I want to test the DOMNodeInserted event.

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>
        function DOMmanipulation() {
            if (document.body) {
                document.removeEventListener('DOMNodeInserted', DOMmanipulation);
                // DOM manipulation start
                document.body.innerHTML = '<div class="wrapper">' + document.body.innerHTML + '</div>';
                // DOM manipulation end
            }
        }
        if (document.addEventListener) {
            document.addEventListener('DOMNodeInserted', DOMmanipulation);
        }
    </script>
</head>
<body>
    <p>Lorem ipsum dolor sit amet.</p>
</body>
</html>


As you can see, the DOM manipulation is to wrap all innerHTML of body into <div class="wrapper"></div>.

It does work. However, a weird thing happened. If you use Firebug or Chrome Developer Tool to inspect the manipulated body, you can find that there was a mysterious element being added. It is:

<div style="padding: 0px; margin: 1px 0px 0px; border: 0px none; visibility: hidden; width: 0px; height: 0px; position: static; top: 0px;"></div>

And despite the success of the manipulation, Firebug shows this error:

And Chrome Developer Tool shows this error:

But if the manipulation is just adding className, there is no error:

document.body.className += ' js';


The most weird thing is, if you remove the jQuery reference, the event won't work. Does that mean the native DOMNodeInserted event sometimes needs jQuery to work?


By the way, if the DOM manipulation is using jQuery syntax:

$('body').wrapInner('<div class="wrapper"></div>');

Then the mysterious element becomes more weird:

<div style="padding: 0px; margin: 1px 0px 0px; border: 0px; visibility: hidden; width: 0px; height: 0px; position: static; top: 0px; zoom: 1; ">
    <div style="position: absolute; top: 0px; left: 0px; width: 1px; height: 1px; padding: 0px; margin: 1% 0px 0px; border: 0px; visibility: hidden; ">
        <div style="position: relative; top: 0px; left: 0px; width: 1px; height: 1px; padding: 0px; margin: 0px; border: 5px solid rgb(0, 0, 0); display: block; overflow: hidden; ">
            <div style="padding: 0px; margin: 0px; border: 0px; display: block; overflow: hidden; "></div>
        </div>
        <table style="position:absolute;top:0;left:0;width:1px;height:1px;padding:0;margin:0;border:5px solid #000;" cellpadding="0" cellspacing="0"><tbody><tr><td></td></tr></tbody></table>
    </div>
</div>



To sum up, we can see three issues from the above experiment:

Any explanation would be appreciated. Thanks.

Upvotes: 0

Views: 1338

Answers (1)

Andreas
Andreas

Reputation: 21881

jQuery starts some tests when it has been loaded (line 1537 in the un-minified version)

// Run tests that need a body at doc ready
jQuery(function() {
var container, outer, inner, table, td, offsetSupport,
...

For this it adds a div element with some stylings. That is your mysterious element you've found.

Because of your event handler, this element gets wrapped within another div. At line 1654 jQuery wants to remove their test element with

body.removeChild( container );

which failes because the container isn't a child element of body anymore.

Edit
In your example you're not adding an element to the DOM so the event can't fire ;)

window.onload = function() {
    document.body.appendChild(document.createElement("div"));  // will fire DOMNodeInserted
}

Why it "works" with jQuery? Because jQuery adds an element to the DOM (the mysterious test element) :)

Upvotes: 2

Related Questions