Skip to content

Commit

Permalink
Fix #12956. Improve cloneFixAttributes for IE9/10 case. Close gh-1034.
Browse files Browse the repository at this point in the history
Remove clear(merge)Attributes hack
  • Loading branch information
markelog authored and dmethvin committed Dec 12, 2012
1 parent f42e1e6 commit 93e1892
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 26 deletions.
41 changes: 15 additions & 26 deletions src/manipulation.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -434,26 +434,26 @@ function cloneCopyEvent( src, dest ) {
} }


function cloneFixAttributes( src, dest ) { function cloneFixAttributes( src, dest ) {
var nodeName; var nodeName, data, e;


// We do not need to do anything for non-Elements // We do not need to do anything for non-Elements
if ( dest.nodeType !== 1 ) { if ( dest.nodeType !== 1 ) {
return; return;
} }


// clearAttributes removes the attributes, which we don't want, nodeName = dest.nodeName.toLowerCase();
// but also removes the attachEvent events, which we *do* want
if ( dest.clearAttributes ) {
dest.clearAttributes();
}


// mergeAttributes, in contrast, only merges back on the // IE6-8 copies events bound via attachEvent when using cloneNode.
// original attributes, not the events if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
if ( dest.mergeAttributes ) { data = jQuery._data( dest );
dest.mergeAttributes( src );
}


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 // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
if ( nodeName === "script" && dest.text !== src.text ) { if ( nodeName === "script" && dest.text !== src.text ) {
Expand Down Expand Up @@ -498,10 +498,6 @@ function cloneFixAttributes( src, dest ) {
} else if ( nodeName === "input" || nodeName === "textarea" ) { } else if ( nodeName === "input" || nodeName === "textarea" ) {
dest.defaultValue = src.defaultValue; dest.defaultValue = src.defaultValue;
} }

// Event data gets referenced instead of copied if the expando
// gets copied too
dest.removeAttribute( jQuery.expando );
} }


jQuery.each({ jQuery.each({
Expand Down Expand Up @@ -583,19 +579,12 @@ jQuery.extend({


if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { (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 // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
destElements = getAll( clone ); destElements = getAll( clone );
srcElements = getAll( elem ); srcElements = getAll( elem );


// Weird iteration because IE will replace the length property // Fix all IE cloning issues
// with an element if you are cloning the body and one of the
// elements on the page has a name or id of "length"
for ( i = 0; (node = srcElements[i]) != null; ++i ) { for ( i = 0; (node = srcElements[i]) != null; ++i ) {
// Ensure that the destination node is not null; Fixes #9587 // Ensure that the destination node is not null; Fixes #9587
if ( destElements[i] ) { if ( destElements[i] ) {
Expand All @@ -607,8 +596,8 @@ jQuery.extend({
// Copy the events from the original to the clone // Copy the events from the original to the clone
if ( dataAndEvents ) { if ( dataAndEvents ) {
if ( deepDataAndEvents ) { if ( deepDataAndEvents ) {
destElements = getAll( clone ); srcElements = srcElements || getAll( elem );
srcElements = getAll( elem ); destElements = destElements || getAll( clone );


for ( i = 0; (node = srcElements[i]) != null; i++ ) { for ( i = 0; (node = srcElements[i]) != null; i++ ) {
cloneCopyEvent( node, destElements[i] ); cloneCopyEvent( node, destElements[i] );
Expand Down
49 changes: 49 additions & 0 deletions test/unit/event.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -3104,4 +3104,53 @@ test( "Namespace preserved when passed an Event (#12739)", function() {
equal( triggered, 3, "foo.bar triggered" ); 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
});

0 comments on commit 93e1892

Please sign in to comment.