Split out the fragment-building code from domManip. Switched core.js to using that instead. Also moved the standalone tag detection to $(...) for performance.
This commit is contained in:
parent
b7d4e0e46c
commit
9d8d74569c
19
src/core.js
19
src/core.js
|
@ -31,6 +31,9 @@ var jQuery = function( selector, context ) {
|
||||||
// Used for trimming whitespace
|
// Used for trimming whitespace
|
||||||
rtrim = /^\s+|\s+$/g,
|
rtrim = /^\s+|\s+$/g,
|
||||||
|
|
||||||
|
// Match a standalone tag
|
||||||
|
rsingleTag = /^<(\w+)\s*\/?>$/,
|
||||||
|
|
||||||
// Keep a UserAgent string for use with jQuery.browser
|
// Keep a UserAgent string for use with jQuery.browser
|
||||||
userAgent = navigator.userAgent.toLowerCase(),
|
userAgent = navigator.userAgent.toLowerCase(),
|
||||||
|
|
||||||
|
@ -41,7 +44,7 @@ var jQuery = function( selector, context ) {
|
||||||
|
|
||||||
jQuery.fn = jQuery.prototype = {
|
jQuery.fn = jQuery.prototype = {
|
||||||
init: function( selector, context ) {
|
init: function( selector, context ) {
|
||||||
var match, elem, ret;
|
var match, elem, ret, doc;
|
||||||
|
|
||||||
// Handle $(""), $(null), or $(undefined)
|
// Handle $(""), $(null), or $(undefined)
|
||||||
if ( !selector ) {
|
if ( !selector ) {
|
||||||
|
@ -70,7 +73,19 @@ jQuery.fn = jQuery.prototype = {
|
||||||
|
|
||||||
// HANDLE: $(html) -> $(array)
|
// HANDLE: $(html) -> $(array)
|
||||||
if ( match[1] ) {
|
if ( match[1] ) {
|
||||||
selector = jQuery.clean( [ match[1] ], context );
|
doc = (context ? context.ownerDocument || context : document);
|
||||||
|
|
||||||
|
// If a single string is passed in and it's a single tag
|
||||||
|
// just do a createElement and skip the rest
|
||||||
|
ret = rsingleTag.exec( selector );
|
||||||
|
|
||||||
|
if ( ret ) {
|
||||||
|
selector = [ doc.createElement( ret[1] ) ];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ret = buildFragment( [ match[1] ], [ doc ] );
|
||||||
|
selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
|
||||||
|
}
|
||||||
|
|
||||||
// HANDLE: $("#id")
|
// HANDLE: $("#id")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
|
var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
|
||||||
rleadingWhitespace = /^\s+/,
|
rleadingWhitespace = /^\s+/,
|
||||||
rsingleTag = /^<(\w+)\s*\/?>$/,
|
|
||||||
rxhtmlTag = /(<(\w+)[^>]*?)\/>/g,
|
rxhtmlTag = /(<(\w+)[^>]*?)\/>/g,
|
||||||
rselfClosing = /^(?:abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i,
|
rselfClosing = /^(?:abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i,
|
||||||
rinsideTable = /^<(thead|tbody|tfoot|colg|cap)/,
|
rinsideTable = /^<(thead|tbody|tfoot|colg|cap)/,
|
||||||
|
@ -166,8 +165,7 @@ jQuery.fn.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
domManip: function( args, table, callback ) {
|
domManip: function( args, table, callback ) {
|
||||||
var fragment, scripts, cacheable, cached, cacheresults, first,
|
var results, first, value = args[0], scripts = [];
|
||||||
value = args[0];
|
|
||||||
|
|
||||||
if ( jQuery.isFunction(value) ) {
|
if ( jQuery.isFunction(value) ) {
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
|
@ -177,23 +175,14 @@ jQuery.fn.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( this[0] ) {
|
if ( this[0] ) {
|
||||||
if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && args[0].indexOf("<option") < 0 ) {
|
// If we're in a fragment, just use that instead of building a new one
|
||||||
cacheable = true;
|
if ( args[0] && args[0].parentNode && args[0].parentNode.nodeType === 11 ) {
|
||||||
cacheresults = jQuery.fragments[ args[0] ];
|
results = { fragment: args[0].parentNode };
|
||||||
if ( cacheresults ) {
|
} else {
|
||||||
if ( cacheresults !== 1 ) {
|
results = buildFragment( args, this[0], scripts );
|
||||||
fragment = cacheresults;
|
|
||||||
}
|
|
||||||
cached = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !fragment ) {
|
first = results.fragment.firstChild;
|
||||||
fragment = (this[0].ownerDocument || this[0]).createDocumentFragment();
|
|
||||||
scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment );
|
|
||||||
}
|
|
||||||
|
|
||||||
first = fragment.firstChild;
|
|
||||||
|
|
||||||
if ( first ) {
|
if ( first ) {
|
||||||
table = table && jQuery.nodeName( first, "tr" );
|
table = table && jQuery.nodeName( first, "tr" );
|
||||||
|
@ -203,9 +192,9 @@ jQuery.fn.extend({
|
||||||
table ?
|
table ?
|
||||||
root(this[i], first) :
|
root(this[i], first) :
|
||||||
this[i],
|
this[i],
|
||||||
cacheable || this.length > 1 || i > 0 ?
|
results.cacheable || this.length > 1 || i > 0 ?
|
||||||
fragment.cloneNode(true) :
|
results.fragment.cloneNode(true) :
|
||||||
fragment
|
results.fragment
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,10 +202,6 @@ jQuery.fn.extend({
|
||||||
if ( scripts ) {
|
if ( scripts ) {
|
||||||
jQuery.each( scripts, evalScript );
|
jQuery.each( scripts, evalScript );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( cacheable ) {
|
|
||||||
jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -230,6 +215,33 @@ jQuery.fn.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function buildFragment(args, nodes, scripts){
|
||||||
|
var fragment, cacheable, cached, cacheresults, doc;
|
||||||
|
|
||||||
|
if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && args[0].indexOf("<option") < 0 ) {
|
||||||
|
cacheable = true;
|
||||||
|
cacheresults = jQuery.fragments[ args[0] ];
|
||||||
|
if ( cacheresults ) {
|
||||||
|
if ( cacheresults !== 1 ) {
|
||||||
|
fragment = cacheresults;
|
||||||
|
}
|
||||||
|
cached = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !fragment ) {
|
||||||
|
doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
|
||||||
|
fragment = doc.createDocumentFragment();
|
||||||
|
jQuery.clean( args, doc, fragment, scripts );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( cacheable ) {
|
||||||
|
jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { fragment: fragment, cacheable: cacheable };
|
||||||
|
}
|
||||||
|
|
||||||
jQuery.fragments = {};
|
jQuery.fragments = {};
|
||||||
|
|
||||||
jQuery.each({
|
jQuery.each({
|
||||||
|
@ -284,7 +296,7 @@ jQuery.each({
|
||||||
});
|
});
|
||||||
|
|
||||||
jQuery.extend({
|
jQuery.extend({
|
||||||
clean: function( elems, context, fragment ) {
|
clean: function( elems, context, fragment, scripts ) {
|
||||||
context = context || document;
|
context = context || document;
|
||||||
|
|
||||||
// !context.createElement fails in IE with an error but returns typeof 'object'
|
// !context.createElement fails in IE with an error but returns typeof 'object'
|
||||||
|
@ -292,16 +304,7 @@ jQuery.extend({
|
||||||
context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
|
context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a single string is passed in and it's a single tag
|
var ret = [], div = context.createElement("div");
|
||||||
// just do a createElement and skip the rest
|
|
||||||
if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
|
|
||||||
var match = rsingleTag.exec(elems[0]);
|
|
||||||
if ( match ) {
|
|
||||||
return [ context.createElement( match[1] ) ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var ret = [], scripts = [], div = context.createElement("div");
|
|
||||||
|
|
||||||
jQuery.each(elems, function(i, elem){
|
jQuery.each(elems, function(i, elem){
|
||||||
if ( typeof elem === "number" ) {
|
if ( typeof elem === "number" ) {
|
||||||
|
@ -393,7 +396,7 @@ jQuery.extend({
|
||||||
|
|
||||||
if ( fragment ) {
|
if ( fragment ) {
|
||||||
for ( var i = 0; ret[i]; i++ ) {
|
for ( var i = 0; ret[i]; i++ ) {
|
||||||
if ( jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
|
if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
|
||||||
scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
|
scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
|
||||||
} else {
|
} else {
|
||||||
if ( ret[i].nodeType === 1 ) {
|
if ( ret[i].nodeType === 1 ) {
|
||||||
|
@ -402,8 +405,6 @@ jQuery.extend({
|
||||||
fragment.appendChild( ret[i] );
|
fragment.appendChild( ret[i] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return scripts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -337,7 +337,7 @@ test("jQuery('html')", function() {
|
||||||
test("jQuery('html', context)", function() {
|
test("jQuery('html', context)", function() {
|
||||||
expect(1);
|
expect(1);
|
||||||
|
|
||||||
var $div = jQuery("<div/>");
|
var $div = jQuery("<div/>")[0];
|
||||||
var $span = jQuery("<span/>", $div);
|
var $span = jQuery("<span/>", $div);
|
||||||
equals($span.length, 1, "Verify a span created with a div context works, #1763");
|
equals($span.length, 1, "Verify a span created with a div context works, #1763");
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue