tags:

views:

84

answers:

1

While reading the book jQuery in Action and playing with the first events handling example, I discovered that jQuery doesn't consistently clone DOM Level 0 events. It clones the inline events, but not those defined as a property. It could be a good thing to discourage the use of inline event handlers, but is is by design? What is one wants to clone something from a legacy page ?

Here is an alteration of the example given in the book, to demonstrate the behavior.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"&gt;
<html>
  <head>
    <title>DOM Level 0 Events Example</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"&gt;
    </script>
<script type="text/javascript">
  $(function(){
    $('#testElement')[0].onclick = function(event) {
      say(this.id + ' Click ASSIGN [DOM 0]');
    }
            $('#testElement').click(function() { say(this.id + ' Click JQUERY [DOM 2]');});
            $('#testElement').clone(true).attr('id',"clonedElement").insertAfter($('#testElement'));
  });

  function say(text) {
    $('#console').append('<div>'+text+'</div>');
  }
  </script>
  </head>

  <body>
    <div id="testElement" style="border: solid brown 1px; margin: 10px; width : 100px; height: 100px;" onclick="say(this.id + ' Click INLINE [DOM 0]')">&nbsp;</div>
<div id="console"></div>
 </body>
</html>
+1  A: 

Line 305 to 312 in "jQuery-1.3.2.js

"IE" copies events bound via "attachEvent" when using "cloneNode". Calling "detachEvent" on the clone will also remove the events from the orignal. In order to get around this, we use "innerHTML". Unfortunately, this means some modifications to attributes in "IE" that are actually only stored as properties will not be copied (such as the the name attribute on an input).

The example to pasate not work in IE for the reason explained. We should make a modification to the method "clone" of jQuery to have this functionality in IE

EDIT:

ok, I'm sorry, now I understand the problem, but from what I see and what you can view in "clonedElement_2" is a limitation of "cloneNode". The only thing I can think of is to change the method "clone" of "jQuery"

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"&gt;
<html>
<head>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"&gt;&lt;/script&gt;
    <script language="JavaScript">

        (function($){

            $.fn.__extendClone = $.fn.clone;
            $.fn.clone = function(events){

                var ret = $(this).__extendClone(events);

                if (events){

                    var listEvents = ["onabort", "onblur", "onchange", "onclick", "ondblclick", "onerror", "onfocus", 
                        "onkeydown", "onkeypress", "onkeyup", "onload",  "onmousedown", "onmousemove", "onmouseout", 
                        "onmouseover", "onmouseup", "onreset", "onresize", "onselect", "onsubmit", "onunload"];

                    for (var inde in listEvents){
                        if ($.isFunction($(this)[0][listEvents[inde]])){
                            $(ret)[0][listEvents[inde]] = $(this)[0][listEvents[inde]];
                        }
                    }
                }

                return ret;

            };

        })(jQuery);     

        $(function()
        {
            //work
            var mytestElement = document.getElementById("testElement")
            mytestElement.setAttribute("style", "border: solid green 2px; margin: 10px; width : 100px; height: 100px;");

            //don't twork
            $('#testElement')[0].onclick = function(event) {
                say(this.id + ' Click ASSIGN [DOM 0]');
            }

            $('#testElement').click(function() { say(this.id + ' Click JQUERY [DOM 2]');});

            //clone jquery
            $('#testElement').clone(true).attr('id',"clonedElement").insertAfter($('#testElement'));

            //clone js
            var myNode = document.getElementById("testElement").cloneNode(true);
            myNode.setAttribute("id", "clonedElement_2");
            myNode.setAttribute("style", "border: solid blue 2px; margin: 10px; width : 100px; height: 100px;");
            document.getElementById("container").appendChild(myNode);

        });

        function say(text) {
            $('#console').append('<div>'+text+'</div>');
        }

    </script>
</head>
<body>
    <div id="testElement" style="border: solid brown 2px; margin: 10px; width : 100px; height: 100px;" onclick="say(this.id + ' Click INLINE [DOM 0]')">&nbsp;</div>
    <div id="container"></div>
    <div id="console"></div>
</body>
</html>
andres descalzo
Neither does it really work in non IE browsers too. The inline event handler is overwritten by the assignment onclick= .... But the inline event handler, rather than the property assignment gets copied to the clone in FF and chrome.
Dave.Sol
I edit the answer
andres descalzo
Thanks for the work around. I am wondering if I should submit this as a bug to the good jQuery people.
Dave.Sol
I honestly do not know, because rather than overwrite the method "clone" of "jQuery", this code is a fix for "cloneNode"
andres descalzo
"@ Dave.Sol" I was thinking about the method "cloneNode" and knowing that is called "Node", it is normal that only clone the HTML tag, to clone all the DOM included, should be called "cloneDomNode" (or something similar). Now, considering that "jQuery.clone" events also cloned "jQuery", should also cloned DOM events. ok?
andres descalzo