]> source.dussan.org Git - jquery.git/commitdiff
Fix #12956. Improve cloneFixAttributes for IE9/10 case. Close gh-1034.
authorOleg <markelog@gmail.com>
Sun, 18 Nov 2012 18:53:24 +0000 (22:53 +0400)
committerDave Methvin <dave.methvin@gmail.com>
Wed, 12 Dec 2012 03:06:26 +0000 (22:06 -0500)
Remove clear(merge)Attributes hack

src/manipulation.js
test/unit/event.js

index 992696a0b983175f0d28ea91f991a314eb18a68a..bfecbf305ff893f7298958b77842d8ebc47cb425 100644 (file)
@@ -434,26 +434,26 @@ function cloneCopyEvent( src, dest ) {
 }
 
 function cloneFixAttributes( src, dest ) {
-       var nodeName;
+       var nodeName, data, e;
 
        // We do not need to do anything for non-Elements
        if ( dest.nodeType !== 1 ) {
                return;
        }
 
-       // clearAttributes removes the attributes, which we don't want,
-       // but also removes the attachEvent events, which we *do* want
-       if ( dest.clearAttributes ) {
-               dest.clearAttributes();
-       }
+       nodeName = dest.nodeName.toLowerCase();
 
-       // mergeAttributes, in contrast, only merges back on the
-       // original attributes, not the events
-       if ( dest.mergeAttributes ) {
-               dest.mergeAttributes( src );
-       }
+       // IE6-8 copies events bound via attachEvent when using cloneNode.
+       if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
+               data = jQuery._data( dest );
 
-       nodeName = dest.nodeName.toLowerCase();
+               for ( e in data.events ) {
+                       jQuery.removeEvent( dest, e, data.handle );
+               }
+
+               // Event data gets referenced instead of copied if the expando gets copied too
+               dest.removeAttribute( jQuery.expando );
+       }
 
        // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
        if ( nodeName === "script" && dest.text !== src.text ) {
@@ -498,10 +498,6 @@ function cloneFixAttributes( src, dest ) {
        } else if ( nodeName === "input" || nodeName === "textarea" ) {
                dest.defaultValue = src.defaultValue;
        }
-
-       // Event data gets referenced instead of copied if the expando
-       // gets copied too
-       dest.removeAttribute( jQuery.expando );
 }
 
 jQuery.each({
@@ -583,19 +579,12 @@ jQuery.extend({
 
                if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
                                (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
-                       // IE copies events bound via attachEvent when using cloneNode.
-                       // Calling detachEvent on the clone will also remove the events
-                       // from the original. In order to get around this, we use some
-                       // proprietary methods to clear the events. Thanks to MooTools
-                       // guys for this hotness.
 
                        // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
                        destElements = getAll( clone );
                        srcElements = getAll( elem );
 
-                       // Weird iteration because IE will replace the length property
-                       // with an element if you are cloning the body and one of the
-                       // elements on the page has a name or id of "length"
+                       // Fix all IE cloning issues
                        for ( i = 0; (node = srcElements[i]) != null; ++i ) {
                                // Ensure that the destination node is not null; Fixes #9587
                                if ( destElements[i] ) {
@@ -607,8 +596,8 @@ jQuery.extend({
                // Copy the events from the original to the clone
                if ( dataAndEvents ) {
                        if ( deepDataAndEvents ) {
-                               destElements = getAll( clone );
-                               srcElements = getAll( elem );
+                               srcElements = srcElements || getAll( elem );
+                               destElements = destElements || getAll( clone );
 
                                for ( i = 0; (node = srcElements[i]) != null; i++ ) {
                                        cloneCopyEvent( node, destElements[i] );
index 211d2d852abeb79508e36aa92c3d8d9aa6f08a7c..b5ad26d859dfd9445e87c0d882374757fcd41973 100644 (file)
@@ -3104,4 +3104,53 @@ test( "Namespace preserved when passed an Event (#12739)", function() {
        equal( triggered, 3, "foo.bar triggered" );
 });
 
+test( "make sure events cloned correctly", 18, function() {
+       var clone,
+               fixture = jQuery("#qunit-fixture"),
+               checkbox = jQuery("#check1"),
+               p = jQuery("#firstp");
 
+       fixture.on( "click change", function( event, result ) {
+               ok( result,  event.type + " on original element is fired" );
+
+       }).on( "click", "#firstp", function( event, result ) {
+               ok( result, "Click on original child element though delegation is fired" );
+
+       }).on( "change", "#check1", function( event, result ) {
+               ok( result, "Change on original child element though delegation is fired" );
+       });
+
+       p.on("click", function( event, result ) {
+               ok( true, "Click on original child element is fired" );
+       });
+
+       checkbox.on("change", function( event, result ) {
+               ok( true, "Change on original child element is fired" );
+       });
+
+       fixture.clone().click().change(); // 0 events should be fired
+
+       clone = fixture.clone( true );
+
+       clone.find("p:first").trigger( "click", true ); // 3 events should fire
+       clone.find("#check1").trigger( "change", true ); // 3 events should fire
+       clone.remove();
+
+       clone = fixture.clone( true, true );
+       clone.find("p:first").trigger( "click", true ); // 3 events should fire
+       clone.find("#check1").trigger( "change", true ); // 3 events should fire
+
+       fixture.off();
+       p.off();
+       checkbox.off();
+
+       p.click(); // 0 should be fired
+       checkbox.change(); // 0 should be fired
+
+       clone.find("p:first").trigger( "click", true ); // 3 events should fire
+       clone.find("#check1").trigger( "change", true ); // 3 events should fire
+       clone.remove();
+
+       clone.find("p:first").click(); // 0 should be fired
+       clone.find("#check1").change(); // 0 events should fire
+});