Skip to content

Commit 93e1892

Browse files
markelogdmethvin
authored andcommitted
Fix #12956. Improve cloneFixAttributes for IE9/10 case. Close jquerygh-1034.
Remove clear(merge)Attributes hack
1 parent f42e1e6 commit 93e1892

File tree

2 files changed

+64
-26
lines changed

2 files changed

+64
-26
lines changed

src/manipulation.js

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -434,26 +434,26 @@ function cloneCopyEvent( src, dest ) {
434434
}
435435

436436
function cloneFixAttributes( src, dest ) {
437-
var nodeName;
437+
var nodeName, data, e;
438438

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

444-
// clearAttributes removes the attributes, which we don't want,
445-
// but also removes the attachEvent events, which we *do* want
446-
if ( dest.clearAttributes ) {
447-
dest.clearAttributes();
448-
}
444+
nodeName = dest.nodeName.toLowerCase();
449445

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

456-
nodeName = dest.nodeName.toLowerCase();
450+
for ( e in data.events ) {
451+
jQuery.removeEvent( dest, e, data.handle );
452+
}
453+
454+
// Event data gets referenced instead of copied if the expando gets copied too
455+
dest.removeAttribute( jQuery.expando );
456+
}
457457

458458
// IE blanks contents when cloning scripts, and tries to evaluate newly-set text
459459
if ( nodeName === "script" && dest.text !== src.text ) {
@@ -498,10 +498,6 @@ function cloneFixAttributes( src, dest ) {
498498
} else if ( nodeName === "input" || nodeName === "textarea" ) {
499499
dest.defaultValue = src.defaultValue;
500500
}
501-
502-
// Event data gets referenced instead of copied if the expando
503-
// gets copied too
504-
dest.removeAttribute( jQuery.expando );
505501
}
506502

507503
jQuery.each({
@@ -583,19 +579,12 @@ jQuery.extend({
583579

584580
if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
585581
(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
586-
// IE copies events bound via attachEvent when using cloneNode.
587-
// Calling detachEvent on the clone will also remove the events
588-
// from the original. In order to get around this, we use some
589-
// proprietary methods to clear the events. Thanks to MooTools
590-
// guys for this hotness.
591582

592583
// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
593584
destElements = getAll( clone );
594585
srcElements = getAll( elem );
595586

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

613602
for ( i = 0; (node = srcElements[i]) != null; i++ ) {
614603
cloneCopyEvent( node, destElements[i] );

test/unit/event.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3104,4 +3104,53 @@ test( "Namespace preserved when passed an Event (#12739)", function() {
31043104
equal( triggered, 3, "foo.bar triggered" );
31053105
});
31063106

3107+
test( "make sure events cloned correctly", 18, function() {
3108+
var clone,
3109+
fixture = jQuery("#qunit-fixture"),
3110+
checkbox = jQuery("#check1"),
3111+
p = jQuery("#firstp");
31073112

3113+
fixture.on( "click change", function( event, result ) {
3114+
ok( result, event.type + " on original element is fired" );
3115+
3116+
}).on( "click", "#firstp", function( event, result ) {
3117+
ok( result, "Click on original child element though delegation is fired" );
3118+
3119+
}).on( "change", "#check1", function( event, result ) {
3120+
ok( result, "Change on original child element though delegation is fired" );
3121+
});
3122+
3123+
p.on("click", function( event, result ) {
3124+
ok( true, "Click on original child element is fired" );
3125+
});
3126+
3127+
checkbox.on("change", function( event, result ) {
3128+
ok( true, "Change on original child element is fired" );
3129+
});
3130+
3131+
fixture.clone().click().change(); // 0 events should be fired
3132+
3133+
clone = fixture.clone( true );
3134+
3135+
clone.find("p:first").trigger( "click", true ); // 3 events should fire
3136+
clone.find("#check1").trigger( "change", true ); // 3 events should fire
3137+
clone.remove();
3138+
3139+
clone = fixture.clone( true, true );
3140+
clone.find("p:first").trigger( "click", true ); // 3 events should fire
3141+
clone.find("#check1").trigger( "change", true ); // 3 events should fire
3142+
3143+
fixture.off();
3144+
p.off();
3145+
checkbox.off();
3146+
3147+
p.click(); // 0 should be fired
3148+
checkbox.change(); // 0 should be fired
3149+
3150+
clone.find("p:first").trigger( "click", true ); // 3 events should fire
3151+
clone.find("#check1").trigger( "change", true ); // 3 events should fire
3152+
clone.remove();
3153+
3154+
clone.find("p:first").click(); // 0 should be fired
3155+
clone.find("#check1").change(); // 0 events should fire
3156+
});

0 commit comments

Comments
 (0)