2.0: Refactor jQuery.clean #1117

Closed
wants to merge 4 commits into
from
View
@@ -470,11 +470,12 @@ jQuery.extend({
return [ context.createElement( parsed[1] ) ];
}
- parsed = context.createDocumentFragment();
- jQuery.clean( [ data ], context, parsed, scripts );
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
+
if ( scripts ) {
jQuery( scripts ).remove();
}
+
return jQuery.merge( [], parsed.childNodes );
},
View
@@ -265,7 +265,7 @@ jQuery.fn.extend({
l = this.length,
set = this,
iNoClone = l - 1,
- value = args[0],
+ value = args[ 0 ],
isFunction = jQuery.isFunction( value );
// We can't cloneNode fragments that contain checked, in WebKit
@@ -280,9 +280,7 @@ jQuery.fn.extend({
}
if ( l ) {
- doc = this[ 0 ].ownerDocument;
- fragment = doc.createDocumentFragment();
- jQuery.clean( args, doc, fragment, undefined, this );
+ fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
first = fragment.firstChild;
if ( fragment.childNodes.length === 1 ) {
@@ -420,97 +418,82 @@ jQuery.extend({
return clone;
},
- clean: function( elems, context, fragment, scripts, selection ) {
- var elem, tmp, tag, wrap, j, ll,
+ buildFragment: function( elems, context, scripts, selection ) {
+ var elem, tmp, tag, wrap, contains, j,
i = 0,
- l = elems.length,
- ret = [],
- container = context === document && fragment;
-
- // Ensure that context is a document
- if ( !context || typeof context.createDocumentFragment === "undefined" ) {
- context = document;
- }
-
- for ( ; i < l; i++ ) {
- elem = elems[ i ];
+ fragment = context.createDocumentFragment(),
+ nodes = [];
- if ( elem || elem === 0 ) {
+ while ( ( elem = elems[ i++ ] ) || elem === 0 ) {
// Add nodes directly
if ( jQuery.type( elem ) === "object" ) {
- core_push.apply( ret, elem.nodeType ? [ elem ] : elem );
+ core_push.apply( nodes, elem.nodeType ? [ elem ] : elem );
// Convert non-html into a text node
} else if ( !rhtml.test( elem ) ) {
- ret.push( context.createTextNode( elem ) );
+ core_push.call( nodes, context.createTextNode( elem ) );
// Convert html into DOM nodes
} else {
-
- // Ensure a safe container
- container = container || context.createDocumentFragment();
- tmp = tmp || container.appendChild( context.createElement("div") );
+ tmp = tmp || fragment.appendChild( context.createElement("div") );
// Deserialize a standard representation
tag = ( rtagName.exec( elem ) || ["", ""] )[ 1 ].toLowerCase();
wrap = wrapMap[ tag ] || wrapMap._default;
tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" );
// Descend through wrappers to the right content
- j = wrap[0];
+ j = wrap[ 0 ];
while ( j-- ) {
- tmp = tmp.lastChild;
+ tmp = tmp.firstChild;
}
- core_push.apply( ret, tmp.childNodes );
+ core_push.apply( nodes, tmp.childNodes );
- // Fix #12392 - remove childNodes parent
- tmp.textContent = "";
+ // Remember the top-level container
+ tmp = fragment.firstChild;
- // Remember the top-level container for proper cleanup
- tmp = container.lastChild;
+ // Fixes #12346
+ // Support: Webkit, IE
+ tmp.textContent = "";
}
- }
}
- // Fix #11356: Clear elements from fragment
- if ( tmp ) {
- container.removeChild( tmp );
- }
+ // Remove wrapper from fragment
+ fragment.textContent = "";
- if ( fragment ) {
- for ( i = 0, l = ret.length; i < l; i++ ) {
- elem = ret[ i ];
- container = jQuery.contains( elem.ownerDocument, elem );
+ i = 0;
+ while ( (elem = nodes[ i++ ]) ) {
+ contains = jQuery.contains( elem.ownerDocument, elem );
- // Append to fragment
- // #4087 - If origin and destination elements are the same, and this is
- // that element, do not append to fragment
- if ( !selection || jQuery.inArray( elem, selection ) === -1 ) {
- fragment.appendChild( elem );
- }
- tmp = getAll( elem, "script" );
+ // #4087 - If origin and destination elements are the same, and this is
+ // that element, do not do anything
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+ continue;
+ }
- // Preserve script evaluation history
- if ( container ) {
- setGlobalEval( tmp );
- }
+ // Append to fragment
+ tmp = getAll( fragment.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
- // Capture executables
- if ( scripts ) {
- for ( j = 0, ll = tmp.length; j < ll; j++ ) {
- elem = tmp[ j ];
+ // Capture executables
+ if ( scripts ) {
- if ( rscriptType.test( elem.type || "" ) ) {
- scripts.push( elem );
- }
+ j = 0;
+ while ( (elem = tmp[ j++ ]) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ core_push.call( scripts, elem );
}
}
}
}
- return ret;
+ return fragment;
},
cleanData: function( elems, /* internal */ acceptData ) {
View
@@ -1210,7 +1210,7 @@ test("jQuery.proxy", function(){
});
test("jQuery.parseHTML", function() {
- expect( 13 );
+ expect( 17 );
var html, nodes;
@@ -1237,6 +1237,15 @@ test("jQuery.parseHTML", function() {
equal( jQuery.parseHTML( "\t<div></div>" )[0].nodeValue, "\t", "Preserve leading whitespace" );
equal( jQuery.parseHTML(" <div/> ")[0].nodeType, 3, "Leading spaces are treated as text nodes (#11290)" );
+
+ html = jQuery.parseHTML( "<div>test div</div>" );
+
+ equal( html[ 0 ].parentNode.nodeType, 11, "parentNode should be documentFragment" );
+ equal( html[ 0 ].innerHTML, "test div", "Content should be preserved" );
+
+ equal( jQuery.parseHTML("<span><span>").length, 1, "Incorrect html-strings should not break anything" );
+ equal( jQuery.parseHTML("<td><td>")[ 1 ].parentNode.nodeType, 11,
+ "parentNode should be documentFragment for wrapMap (variable in manipulation module) elements too" );
});
test("jQuery.parseJSON", function(){
@@ -463,12 +463,13 @@ var testAppend = function( valueObj ) {
jQuery.each( "thead tbody tfoot colgroup caption tr th td".split(" "), function( i, name ) {
$table.append( valueObj( "<" + name + "/>" ) );
equal( $table.find( name ).length, 1, "Append " + name );
- ok( jQuery.clean( ["<" + name + "/>"] ).length, name + " wrapped correctly" );
+ ok( jQuery.parseHTML( "<" + name + "/>" ).length, name + " wrapped correctly" );
});
jQuery("#table colgroup").append( valueObj("<col/>") );
equal( jQuery("#table colgroup col").length, 1, "Append col" );
+
jQuery("#form")
.append( valueObj("<select id='appendSelect1'></select>") )
.append( valueObj("<select id='appendSelect2'><option>Test</option></select>") );
@@ -641,24 +642,6 @@ test( "append HTML5 sectioning elements (Bug #6485)", function() {
equal( aside.length, 1, "HTML5 elements do not collapse their children" );
});
-test( "jQuery.clean, #12392", function() {
-
- expect( 6 );
-
- var elems = jQuery.clean( [ "<div>test div</div>", "<p>test p</p>" ] );
-
- ok( elems[ 0 ].parentNode == null || elems[ 0 ].parentNode.nodeType === 11, "parentNode should be documentFragment or null" );
- ok( elems[ 1 ].parentNode == null || elems[ 1 ].parentNode.nodeType === 11, "parentNode should be documentFragment or null" );
-
- equal( elems[ 0 ].innerHTML, "test div", "Content should be preserved" );
- equal( elems[ 1 ].innerHTML, "test p", "Content should be preserved" );
-
- equal( jQuery.clean([ "<span><span>" ]).length, 1, "Incorrect html-strings should not break anything" );
-
- elems = jQuery.clean([ "<td><td>" ]);
- ok( elems[ 1 ].parentNode == null || elems[ 1 ].parentNode.nodeType === 11, "parentNode should be documentFragment or null" );
-});
-
if ( jQuery.css ) {
test( "HTML5 Elements inherit styles from style rules (Bug #10501)", function() {