From: John Resig Date: Mon, 9 Feb 2009 14:48:15 +0000 (+0000) Subject: Reworked the .clone() function in IE. Fixes jQuery bugs #3500 (jQuery expandos were... X-Git-Url: http://git.asbjorn.it/?a=commitdiff_plain;h=ce90accc58d213fcf567ab2ca464ee9164601dc4;p=jquery.git Reworked the .clone() function in IE. Fixes jQuery bugs #3500 (jQuery expandos were causing extra elements to appear from using .html() cloning), #3254 (Mis-match in clone result length causes problem), and #2845 (Cloning an causes exceptions to be thrown). --- diff --git a/src/core.js b/src/core.js index 5c37858..ebad0c1 100644 --- a/src/core.js +++ b/src/core.js @@ -297,33 +297,37 @@ jQuery.fn = jQuery.prototype = { // attributes in IE that are actually only stored // as properties will not be copied (such as the // the name attribute on an input). - var clone = this.cloneNode(true), - container = document.createElement("div"); - container.appendChild(clone); - return jQuery.clean([container.innerHTML])[0]; + var html = this.outerHTML; + if ( !html ) { + var div = this.ownerDocument.createElement("div"); + div.appendChild( this.cloneNode(true) ); + html = div.innerHTML; + } + + return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0]; } else return this.cloneNode(true); }); - // Need to set the expando to null on the cloned set if it exists - // removeData doesn't work here, IE removes it from the original as well - // this is primarily for IE but the data expando shouldn't be copied over in any browser - var clone = ret.find("*").andSelf().each(function(){ - if ( this[ expando ] !== undefined ) - this[ expando ] = null; - }); - // Copy the events from the original to the clone - if ( events === true ) - this.find("*").andSelf().each(function(i){ - if (this.nodeType == 3) + if ( events === true ) { + var orig = this.find("*").andSelf(), i = 0; + + ret.find("*").andSelf().each(function(){ + if ( this.nodeName !== orig[i].nodeName ) return; - var events = jQuery.data( this, "events" ); - for ( var type in events ) - for ( var handler in events[ type ] ) - jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data ); + var events = jQuery.data( orig[i], "events" ); + + for ( var type in events ) { + for ( var handler in events[ type ] ) { + jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data ); + } + } + + i++; }); + } // Return the cloned set return ret; @@ -462,7 +466,7 @@ jQuery.fn = jQuery.prototype = { html: function( value ) { return value === undefined ? (this[0] ? - this[0].innerHTML : + this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") : null) : this.empty().append( value ); }, diff --git a/test/unit/core.js b/test/unit/core.js index 316d9e4..6da62be 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -1156,7 +1156,7 @@ test("find(String)", function() { }); test("clone()", function() { - expect(20); + expect(28); equals( 'This is a normal link: Yahoo', jQuery('#en').text(), 'Assert text for #en' ); var clone = jQuery('#yahoo').clone(); equals( 'Try them out:Yahoo', jQuery('#first').append(clone).text(), 'Check for clone' ); @@ -1176,6 +1176,31 @@ test("clone()", function() { // using contents will get comments regular, text, and comment nodes var cl = jQuery("#nonnodes").contents().clone(); ok( cl.length >= 2, "Check node,textnode,comment clone works (some browsers delete comments on clone)" ); + + var div = jQuery("
  • test
").click(function(){ + ok( true, "Bound event still exists." ); + }); + + div = div.clone(true).clone(true); + equals( div.length, 1, "One element cloned" ); + equals( div[0].nodeName.toUpperCase(), "DIV", "DIV element cloned" ); + div.trigger("click"); + + div = jQuery("
").append([ document.createElement("table"), document.createElement("table") ]); + div.find("table").click(function(){ + ok( true, "Bound event still exists." ); + }); + + div = div.clone(true); + equals( div.length, 1, "One element cloned" ); + equals( div[0].nodeName.toUpperCase(), "DIV", "DIV element cloned" ); + div.find("table:last").trigger("click"); + + div = jQuery("
").html(' '); + + div = div.clone(true); + equals( div.length, 1, "One element cloned" ); + equals( div[0].nodeName.toUpperCase(), "DIV", "DIV element cloned" ); }); if (!isLocal) {