Skip to content
Permalink
Browse files

Speed up & compatibility improvements for new clone mechanism in IE.

  • Loading branch information...
csnover committed Dec 13, 2010
1 parent 8b33e23 commit 1a3fd3329dde3c61dc4b2b14792fb9a61b637893
Showing with 62 additions and 22 deletions.
  1. +52 −20 src/manipulation.js
  2. +1 −1 test/index.html
  3. +9 −1 test/unit/manipulation.js
@@ -193,28 +193,20 @@ jQuery.fn.extend({
// 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.
var srcElements = jQuery(this).find('*').andSelf();
jQuery(clone).find('*').andSelf().each(function (i, clone) {
// We do not need to do anything for non-Elements
if (this.nodeType !== 1) {
return;
}

// clearAttributes removes the attributes, but also
// removes the attachEvent events
clone.clearAttributes();
// Using Sizzle here is crazy slow, so we use getElementsByTagName
// instead
var srcElements = this.getElementsByTagName("*"),
destElements = clone.getElementsByTagName("*");

// mergeAttributes only merges back on the original attributes,
// not the events
clone.mergeAttributes(srcElements[i]);
// 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"
for ( var i = 0; srcElements[i]; ++i ) {
cloneFixAttributes( srcElements[i], destElements[i] );
}

// IE6-8 fail to clone children inside object elements that use
// the proprietary classid attribute value (rather than the type
// attribute) to identify the type of content to display
if (clone.nodeName.toLowerCase() === 'object') {
clone.outerHTML = srcElements[i].outerHTML;
}
});
cloneFixAttributes( this, clone );
}

return clone;
@@ -355,7 +347,7 @@ jQuery.fn.extend({
root(this[i], first) :
this[i],
i > 0 || results.cacheable || this.length > 1 ?
fragment.cloneNode(true) :
jQuery(fragment).clone(true)[0] :
fragment
);
}
@@ -402,6 +394,46 @@ function cloneCopyEvent(orig, ret) {
});
}

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

var nodeName = dest.nodeName.toLowerCase();

// clearAttributes removes the attributes, which we don't want,
// but also removes the attachEvent events, which we *do* want
dest.clearAttributes();

// mergeAttributes, in contrast, only merges back on the
// original attributes, not the events
dest.mergeAttributes(src);

// IE6-8 fail to clone children inside object elements that use
// the proprietary classid attribute value (rather than the type
// attribute) to identify the type of content to display
if ( nodeName === "object" ) {
dest.outerHTML = src.outerHTML;
}

This comment has been minimized.

Copy link
@jeresig

jeresig Dec 15, 2010

Member

These else if statements aren't matching the core style guideline - the } should be on the same line as the else if.

This comment has been minimized.

Copy link
@csnover

csnover Dec 15, 2010

Author Member

Put the comment inside them then, or…?

This comment has been minimized.

Copy link
@jaubourg

jaubourg Dec 15, 2010

Member

Yep, that's what is done in this case.


// IE6-? fails to persist the checked state of a cloned checkbox
// or radio button
else if ( nodeName === "input" && src.checked ) {
dest.defaultChecked = dest.checked = src.checked;
}

// IE6-? fails to return the selected option to the default selected
// state when cloning options
else if ( nodeName === "option" ) {
dest.selected = src.defaultSelected;
}

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

jQuery.buildFragment = function( args, nodes, scripts ) {
var fragment, cacheable, cacheresults,
doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
@@ -263,7 +263,7 @@ <h2 id="qunit-userAgent"></h2>

<div id="slidetogglein" class='chain test'>slideToggleIn<div>slideToggleIn</div></div>
<div id="slidetoggleout" class='chain test out'>slideToggleOut<div>slideToggleOut</div></div>

<div id="fadetogglein" class='chain test'>fadeToggleIn<div>fadeToggleIn</div></div>
<div id="fadetoggleout" class='chain test out'>fadeToggleOut<div>fadeToggleOut</div></div>

@@ -382,7 +382,7 @@ test("append(Function) with incoming value", function() {
});

test("append the same fragment with events (Bug #6997, 5566)", function () {
expect(2 + (document.fireEvent ? 1 : 0));
expect(4 + (document.fireEvent ? 1 : 0));
stop(1000);

var element;
@@ -413,6 +413,14 @@ test("append the same fragment with events (Bug #6997, 5566)", function () {

jQuery("#listWithTabIndex li").before(element);
jQuery("#listWithTabIndex li.test6997").eq(1).click();

element = jQuery("<select><option>Foo</option><option selected>Bar</option></select>");

equals( element.clone().find("option:selected").val(), element.find("option:selected").val(), "Selected option cloned correctly" );

element = jQuery("<input type='checkbox'>").attr('checked', 'checked');

equals( element.clone().is(":checked"), element.is(":checked"), "Checked input cloned correctly" );
});

test("appendTo(String|Element|Array&lt;Element&gt;|jQuery)", function() {

0 comments on commit 1a3fd33

Please sign in to comment.
You can’t perform that action at this time.