diff --git a/src/manipulation.js b/src/manipulation.js index 6f0b44803..70487c139 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -1,7 +1,7 @@ (function( jQuery ) { function createSafeFragment( document ) { - var list = nodeNames.split( " " ), + var list = nodeNames.split( "|" ), safeFrag = document.createDocumentFragment(); if ( safeFrag.createElement ) { @@ -14,8 +14,8 @@ function createSafeFragment( document ) { return safeFrag; } -var nodeNames = "abbr article aside audio canvas datalist details figcaption figure footer " + - "header hgroup mark meter nav output progress section summary time video", +var nodeNames = "abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, rleadingWhitespace = /^\s+/, rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, @@ -24,7 +24,7 @@ var nodeNames = "abbr article aside audio canvas datalist details figcaption fig rhtml = /<|&#?\w+;/, rnoInnerhtml = /<(?:script|style)/i, rnocache = /<(?:script|object|embed|option|style)/i, - rnoshimcache = new RegExp("<(?:" + nodeNames.replace(" ", "|") + ")", "i"), + rnoshimcache = new RegExp("<(?:" + nodeNames + ")", "i"), // checked="checked" or checked rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, rscriptType = /\/(java|ecma)script/i, @@ -468,7 +468,7 @@ jQuery.buildFragment = function( args, nodes, scripts ) { doc = nodes[0].ownerDocument || nodes[0]; } - // Ensure that an attr object doesn't incorrectly stand in as a document object + // Ensure that an attr object doesn't incorrectly stand in as a document object // Chrome and Firefox seem to allow this to occur and will throw exception // Fixes #8950 if ( !doc.createDocumentFragment ) { @@ -564,12 +564,21 @@ function findInputs( elem ) { } } +// Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js +function shimCloneNode( elem ) { + var div = document.createElement( "div" ); + safeFragment.appendChild( div ); + + div.innerHTML = elem.outerHTML; + return div.firstChild; +} + jQuery.extend({ clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var clone = elem.cloneNode(true), - srcElements, - destElements, - i; + var srcElements, + destElements, + i, + clone = elem.cloneNode( true ); if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { @@ -579,10 +588,14 @@ jQuery.extend({ // proprietary methods to clear the events. Thanks to MooTools // guys for this hotness. + // IE<=8 does not properly clone detached, unknown element nodes + if ( rnoshimcache.test( "<" + elem.nodeName ) ) { + clone = shimCloneNode( elem ); + } + cloneFixAttributes( elem, clone ); - // Using Sizzle here is crazy slow, so we use getElementsByTagName - // instead + // Using Sizzle here is crazy slow, so we use getElementsByTagName instead srcElements = getAll( elem ); destElements = getAll( clone ); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 560464224..1c2fc4f54 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -1558,3 +1558,87 @@ test("jQuery.clone - no exceptions for object elements #9587", function() { ok( false, e.message ); } }); + +test("jQuery() & wrap[Inner/All]() handle unknown elems (#10667)", function() { + expect(2); + + var $wraptarget = jQuery( "
Target
" ).appendTo( "#qunit-fixture" ), + $section = jQuery( "
" ).appendTo( "#qunit-fixture" ); + + $wraptarget.wrapAll(""); + + notEqual( $wraptarget.parent("aside").css("background-color"), "transparent", "HTML5 elements created with wrapAll inherit styles" ); + notEqual( $section.css("background-color"), "transparent", "HTML5 elements create with jQuery( string ) inherit styles" ); +}); + +test("Cloned, detached HTML5 elems (#10667,10670)", function() { + expect(7); + + var $section = jQuery( "
" ).appendTo( "#qunit-fixture" ), + $clone; + + // First clone + $clone = $section.clone(); + + // Infer that the test is being run in IE<=8 + if ( $clone[0].outerHTML && !jQuery.support.opacity ) { + // This branch tests cloning nodes by reading the outerHTML, used only in IE<=8 + equal( $clone[0].outerHTML, "
", "detached clone outerHTML matches '
'" ); + } else { + // This branch tests a known behaviour in modern browsers that should never fail. + // Included for expected test count symmetry (expecting 1) + equal( $clone[0].nodeName, "SECTION", "detached clone nodeName matches 'SECTION' in modern browsers" ); + } + + // Bind an event + $section.bind( "click", function( event ) { + ok( true, "clone fired event" ); + }); + + // Second clone (will have an event bound) + $clone = $section.clone( true ); + + // Trigger an event from the first clone + $clone.trigger( "click" ); + $clone.unbind( "click" ); + + // Add a child node with text to the original + $section.append( "

Hello

" ); + + // Third clone (will have child node and text) + $clone = $section.clone( true ); + + equal( $clone.find("p").text(), "Hello", "Assert text in child of clone" ); + + // Trigger an event from the third clone + $clone.trigger( "click" ); + $clone.unbind( "click" ); + + // Add attributes to copy + $section.attr({ + "class": "foo bar baz", + "title": "This is a title" + }); + + // Fourth clone (will have newly added attributes) + $clone = $section.clone( true ); + + equal( $clone.attr("class"), $section.attr("class"), "clone and element have same class attribute" ); + equal( $clone.attr("title"), $section.attr("title"), "clone and element have same title attribute" ); + + // Remove the original + $section.remove(); + + // Clone the clone + $section = $clone.clone( true ); + + // Remove the clone + $clone.remove(); + + // Trigger an event from the clone of the clone + $section.trigger( "click" ); + + // Unbind any remaining events + $section.unbind( "click" ); + $clone.unbind( "click" ); +});