aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorscottjehl <scott@scottjehl.com>2011-01-19 12:32:57 -0500
committerscottjehl <scott@scottjehl.com>2011-01-19 12:32:57 -0500
commitcb1f7eeac5073748ae6200f2f960fb330ec966a8 (patch)
treee952c698d6b8105340e78e694b2d0a6b4b125e28 /src
parent73d060b522ccf72847e67f56fea0e9b129ff273e (diff)
parent265cf0efa7ab3296b3fc4917b863d7b09e3d8bb4 (diff)
downloadjquery-cb1f7eeac5073748ae6200f2f960fb330ec966a8.tar.gz
jquery-cb1f7eeac5073748ae6200f2f960fb330ec966a8.zip
Merge remote branch 'upstream/master'
Diffstat (limited to 'src')
-rw-r--r--src/ajax.js159
-rw-r--r--src/ajax/jsonp.js105
-rw-r--r--src/ajax/script.js17
-rw-r--r--src/attributes.js4
-rw-r--r--src/core.js100
-rw-r--r--src/css.js29
-rw-r--r--src/data.js169
-rw-r--r--src/effects.js10
-rw-r--r--src/event.js48
-rw-r--r--src/manipulation.js33
-rw-r--r--src/offset.js2
-rw-r--r--src/queue.js8
-rw-r--r--src/support.js63
-rw-r--r--src/traversing.js20
14 files changed, 477 insertions, 290 deletions
diff --git a/src/ajax.js b/src/ajax.js
index 645163ad2..871481d01 100644
--- a/src/ajax.js
+++ b/src/ajax.js
@@ -175,11 +175,12 @@ jQuery.extend({
timeout: 0,
data: null,
dataType: null,
- dataTypes: null,
username: null,
password: null,
cache: null,
traditional: false,
+ headers: {},
+ crossDomain: null,
*/
xhr: function() {
return new window.XMLHttpRequest();
@@ -306,30 +307,35 @@ jQuery.extend({
// (match is used internally)
getResponseHeader: function( key , match ) {
- if ( state !== 2 ) {
- return null;
- }
+ if ( state === 2 ) {
- if ( responseHeaders === undefined ) {
+ if ( responseHeaders === undefined ) {
- responseHeaders = {};
+ responseHeaders = {};
- if ( typeof responseHeadersString === "string" ) {
+ if ( typeof responseHeadersString === "string" ) {
- while( ( match = rheaders.exec( responseHeadersString ) ) ) {
- responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
+ while( ( match = rheaders.exec( responseHeadersString ) ) ) {
+ responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
+ }
}
}
+ match = responseHeaders[ key.toLowerCase() ];
+
+ } else {
+
+ match = null;
}
- return responseHeaders[ key.toLowerCase() ];
+
+ return match;
},
// Cancel the request
abort: function( statusText ) {
- if ( transport && state !== 2 ) {
+ if ( transport ) {
transport.abort( statusText || "abort" );
- done( 0 , statusText );
}
+ done( 0 , statusText );
return this;
}
};
@@ -347,6 +353,10 @@ jQuery.extend({
// State is "done" now
state = 2;
+ // Dereference transport for early garbage collection
+ // (no matter how long the jXHR transport will be used
+ transport = 0;
+
// Set readyState
jXHR.readyState = status ? 4 : 0;
@@ -574,12 +584,6 @@ jQuery.extend({
// Remove hash character (#7531: and string promotion)
s.url = ( "" + s.url ).replace( rhash , "" );
- // Uppercase the type
- s.type = s.type.toUpperCase();
-
- // Determine if request has content
- s.hasContent = ! rnoContent.test( s.type );
-
// Extract dataTypes list
s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( /\s+/ );
@@ -595,88 +599,97 @@ jQuery.extend({
}
// Convert data if not already a string
- if ( s.data && s.processData && typeof s.data != "string" ) {
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
s.data = jQuery.param( s.data , s.traditional );
}
- // Get transport
- transport = jQuery.ajaxPrefilter( s , options ).ajaxTransport( s );
+ // Apply prefilters
+ jQuery.ajaxPrefilter( s , options );
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = ! rnoContent.test( s.type );
// Watch for a new set of requests
if ( s.global && jQuery.active++ === 0 ) {
jQuery.event.trigger( "ajaxStart" );
}
- // If no transport, we auto-abort
- if ( ! transport ) {
+ // More options handling for requests with no content
+ if ( ! s.hasContent ) {
- done( 0 , "transport not found" );
- jXHR = false;
-
- } else {
+ // If data is available, append data to url
+ if ( s.data ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
+ }
- // More options handling for requests with no content
- if ( ! s.hasContent ) {
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
- // If data is available, append data to url
- if ( s.data ) {
- s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
- }
+ var ts = jQuery.now(),
+ // try replacing _= if it is there
+ ret = s.url.replace( rts , "$1_=" + ts );
- // Add anti-cache in url if needed
- if ( s.cache === false ) {
+ // if nothing was replaced, add timestamp to the end
+ s.url = ret + ( (ret == s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "");
+ }
+ }
- var ts = jQuery.now(),
- // try replacing _= if it is there
- ret = s.url.replace( rts , "$1_=" + ts );
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ requestHeaders[ "content-type" ] = s.contentType;
+ }
- // if nothing was replaced, add timestamp to the end
- s.url = ret + ( (ret == s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "");
- }
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery_lastModified[ s.url ] ) {
+ requestHeaders[ "if-modified-since" ] = jQuery_lastModified[ s.url ];
}
-
- // Set the correct header, if data is being sent
- if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
- requestHeaders[ "content-type" ] = s.contentType;
+ if ( jQuery_etag[ s.url ] ) {
+ requestHeaders[ "if-none-match" ] = jQuery_etag[ s.url ];
}
+ }
- // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
- if ( s.ifModified ) {
- if ( jQuery_lastModified[ s.url ] ) {
- requestHeaders[ "if-modified-since" ] = jQuery_lastModified[ s.url ];
- }
- if ( jQuery_etag[ s.url ] ) {
- requestHeaders[ "if-none-match" ] = jQuery_etag[ s.url ];
- }
- }
+ // Set the Accepts header for the server, depending on the dataType
+ requestHeaders.accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
+ s.accepts[ s.dataTypes[ 0 ] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
+ s.accepts[ "*" ];
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ requestHeaders[ i.toLowerCase() ] = s.headers[ i ];
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext , jXHR , s ) === false || state === 2 ) ) {
+
+ // Abort if not done already
+ done( 0 , "abort" );
- // Set the Accepts header for the server, depending on the dataType
- requestHeaders.accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
- s.accepts[ s.dataTypes[ 0 ] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
- s.accepts[ "*" ];
+ // Return false
+ jXHR = false;
- // Check for headers option
- for ( i in s.headers ) {
- requestHeaders[ i.toLowerCase() ] = s.headers[ i ];
+ } else {
+
+ // Install callbacks on deferreds
+ for ( i in { success:1, error:1, complete:1 } ) {
+ jXHR[ i ]( s[ i ] );
}
- // Allow custom headers/mimetypes and early abort
- if ( s.beforeSend && ( s.beforeSend.call( callbackContext , jXHR , s ) === false || state === 2 ) ) {
+ // Get transport
+ transport = jQuery.ajaxTransport( s );
+
+ // If no transport, we auto-abort
+ if ( ! transport ) {
- // Abort if not done already
- done( 0 , "abort" );
- jXHR = false;
+ done( 0 , "notransport" );
} else {
// Set state as sending
- state = 1;
- jXHR.readyState = 1;
-
- // Install callbacks on deferreds
- for ( i in { success:1, error:1, complete:1 } ) {
- jXHR[ i ]( s[ i ] );
- }
+ state = jXHR.readyState = 1;
// Send global event
if ( s.global ) {
diff --git a/src/ajax/jsonp.js b/src/ajax/jsonp.js
index 1df5dd427..883876fc0 100644
--- a/src/ajax/jsonp.js
+++ b/src/ajax/jsonp.js
@@ -1,8 +1,7 @@
(function( jQuery ) {
var jsc = jQuery.now(),
- jsre = /(\=)(?:\?|%3F)(&|$)|()(?:\?\?|%3F%3F)()/i,
- rquery_jsonp = /\?/;
+ jsre = /(\=)(?:\?|%3F)(&|$)|()(?:\?\?|%3F%3F)()/i;
// Default jsonp settings
jQuery.ajaxSetup({
@@ -11,73 +10,77 @@ jQuery.ajaxSetup({
return "jsonp" + jsc++;
}
-// Normalize jsonp queries
-// 1) put callback parameter in url or data
-// 2) sneakily ensure transportDataType is always jsonp for jsonp requests
-}).ajaxPrefilter("json jsonp", function(s, originalSettings) {
+// Detect, normalize options and install callbacks for jsonp requests
+// (dataIsString is used internally)
+}).ajaxPrefilter("json jsonp", function(s, originalSettings, dataIsString) {
+
+ dataIsString = ( typeof(s.data) === "string" );
if ( s.dataTypes[ 0 ] === "jsonp" ||
- originalSettings.jsonp ||
originalSettings.jsonpCallback ||
- jsre.test(s.url) ||
- typeof(s.data) === "string" && jsre.test(s.data) ) {
+ originalSettings.jsonp != null ||
+ s.jsonp !== false && ( jsre.test( s.url ) ||
+ dataIsString && jsre.test( s.data ) ) ) {
- var jsonpCallback = s.jsonpCallback =
+ var responseContainer,
+ jsonpCallback = s.jsonpCallback =
jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
- url = s.url.replace(jsre, "$1" + jsonpCallback + "$2"),
- data = s.url === url && typeof(s.data) === "string" ? s.data.replace(jsre, "$1" + jsonpCallback + "$2") : s.data;
-
- if ( url === s.url && data === s.data ) {
- url += (rquery_jsonp.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
+ previous = window[ jsonpCallback ],
+ url = s.url,
+ data = s.data,
+ replace = "$1" + jsonpCallback + "$2";
+
+ if ( s.jsonp !== false ) {
+ url = url.replace( jsre, replace );
+ if ( s.url === url ) {
+ if ( dataIsString ) {
+ data = data.replace( jsre, replace );
+ }
+ if ( s.data === data ) {
+ // Add callback manually
+ url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
+ }
+ }
}
s.url = url;
s.data = data;
- s.dataTypes[ 0 ] = "jsonp";
- }
-
-// Bind transport to jsonp dataType
-}).ajaxTransport("jsonp", function(s) {
- // Put callback in place
- var responseContainer,
- jsonpCallback = s.jsonpCallback,
- previous = window[ jsonpCallback ];
+ window [ jsonpCallback ] = function( response ) {
+ responseContainer = [response];
+ };
- window [ jsonpCallback ] = function( response ) {
- responseContainer = [response];
- };
+ s.complete = [function() {
- s.complete = [function() {
+ // Set callback back to previous value
+ window[ jsonpCallback ] = previous;
- // Set callback back to previous value
- window[ jsonpCallback ] = previous;
-
- // Call if it was a function and we have a response
- if ( previous) {
- if ( responseContainer && jQuery.isFunction ( previous ) ) {
- window[ jsonpCallback ] ( responseContainer[0] );
+ // Call if it was a function and we have a response
+ if ( previous) {
+ if ( responseContainer && jQuery.isFunction ( previous ) ) {
+ window[ jsonpCallback ] ( responseContainer[0] );
+ }
+ } else {
+ // else, more memory leak avoidance
+ try{ delete window[ jsonpCallback ]; } catch(e){}
}
- } else {
- // else, more memory leak avoidance
- try{ delete window[ jsonpCallback ]; } catch(e){}
- }
- }, s.complete ];
+ }, s.complete ];
- // Sneakily ensure this will be handled as json
- s.dataTypes[ 0 ] = "json";
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( ! responseContainer ) {
+ jQuery.error( jsonpCallback + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
- // Use data converter to retrieve json after script execution
- s.converters["script json"] = function() {
- if ( ! responseContainer ) {
- jQuery.error( jsonpCallback + " was not called" );
- }
- return responseContainer[ 0 ];
- };
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
- // Delegate to script transport
- return "script";
+ // Delegate to script
+ return "script";
+ }
});
})( jQuery );
diff --git a/src/ajax/script.js b/src/ajax/script.js
index 8e2e89ac5..b0e576f27 100644
--- a/src/ajax/script.js
+++ b/src/ajax/script.js
@@ -15,18 +15,23 @@ jQuery.ajaxSetup({
"text script": jQuery.globalEval
}
-// Bind script tag hack transport
-}).ajaxTransport("script", function(s) {
+// Handle cache's special case and global
+}).ajaxPrefilter("script", function(s) {
- // Handle cache special case
if ( s.cache === undefined ) {
s.cache = false;
}
- // This transport only deals with cross domain get requests
- if ( s.crossDomain && s.async && ( s.type === "GET" || ! s.data ) ) {
-
+ if ( s.crossDomain ) {
+ s.type = "GET";
s.global = false;
+ }
+
+// Bind script tag hack transport
+}).ajaxTransport("script", function(s) {
+
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
var script,
head = document.getElementsByTagName("head")[0] || document.documentElement;
diff --git a/src/attributes.js b/src/attributes.js
index fec132340..d37400a68 100644
--- a/src/attributes.js
+++ b/src/attributes.js
@@ -133,11 +133,11 @@ jQuery.fn.extend({
} else if ( type === "undefined" || type === "boolean" ) {
if ( this.className ) {
// store className if set
- jQuery.data( this, "__className__", this.className );
+ jQuery._data( this, "__className__", this.className );
}
// toggle whole className
- this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || "";
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
}
});
},
diff --git a/src/core.js b/src/core.js
index 4361577e2..f116ef4d1 100644
--- a/src/core.js
+++ b/src/core.js
@@ -3,7 +3,7 @@ var jQuery = (function() {
// Define a local copy of jQuery
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
- return new jQuery.fn.init( selector, context );
+ return new jQuery.fn.init( selector, context, rootjQuery );
},
// Map over jQuery in case of overwrite
@@ -19,12 +19,8 @@ var jQuery = function( selector, context ) {
// (both of which we optimize for)
quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,
- // Is it a simple selector
- isSimple = /^.[^:#\[\.,]*$/,
-
// Check if a string has a non-whitespace character in it
rnotwhite = /\S/,
- rwhite = /\s/,
// Used for trimming whitespace
trimLeft = /^\s+/,
@@ -63,6 +59,9 @@ var jQuery = function( selector, context ) {
// The deferred used on DOM ready
readyList,
+ // Promise methods
+ promiseMethods = "then done fail isResolved isRejected promise".split( " " ),
+
// The ready event handler
DOMContentLoaded,
@@ -78,7 +77,8 @@ var jQuery = function( selector, context ) {
class2type = {};
jQuery.fn = jQuery.prototype = {
- init: function( selector, context ) {
+ constructor: jQuery,
+ init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc;
// Handle $(""), $(null), or $(undefined)
@@ -112,6 +112,7 @@ jQuery.fn = jQuery.prototype = {
// HANDLE: $(html) -> $(array)
if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
doc = (context ? context.ownerDocument || context : document);
// If a single string is passed in and it's a single tag
@@ -171,7 +172,7 @@ jQuery.fn = jQuery.prototype = {
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
- return jQuery( context ).find( selector );
+ return this.constructor( context ).find( selector );
}
// HANDLE: $(function)
@@ -222,7 +223,7 @@ jQuery.fn = jQuery.prototype = {
// (returning the new matched element set)
pushStack: function( elems, name, selector ) {
// Build a new jQuery matched element set
- var ret = jQuery();
+ var ret = this.constructor();
if ( jQuery.isArray( elems ) ) {
push.apply( ret, elems );
@@ -287,7 +288,7 @@ jQuery.fn = jQuery.prototype = {
},
end: function() {
- return this.prevObject || jQuery(null);
+ return this.prevObject || this.constructor(null);
},
// For internal use only.
@@ -578,7 +579,7 @@ jQuery.extend({
script.type = "text/javascript";
- if ( jQuery.support.scriptEval ) {
+ if ( jQuery.support.scriptEval() ) {
script.appendChild( document.createTextNode( data ) );
} else {
script.text = data;
@@ -896,9 +897,10 @@ jQuery.extend({
Deferred: function( func ) {
var deferred = jQuery._Deferred(),
- failDeferred = jQuery._Deferred();
+ failDeferred = jQuery._Deferred(),
+ promise;
- // Add errorDeferred methods and redefine cancel
+ // Add errorDeferred methods, then and promise
jQuery.extend( deferred , {
then: function( doneCallbacks , failCallbacks ) {
@@ -911,14 +913,18 @@ jQuery.extend({
isRejected: failDeferred.isResolved,
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
- promise: function( obj ) {
- obj = obj || {};
- jQuery.each( "then done fail isResolved isRejected".split( " " ) , function( _ , method ) {
- obj[ method ] = deferred[ method ];
- });
- obj.promise = function() {
- return obj;
- };
+ // (i is used internally)
+ promise: function( obj , i ) {
+ if ( obj == null ) {
+ if ( promise ) {
+ return promise;
+ }
+ promise = obj = {};
+ }
+ i = promiseMethods.length;
+ while( i-- ) {
+ obj[ promiseMethods[ i ] ] = deferred[ promiseMethods[ i ] ];
+ }
return obj;
}
@@ -940,10 +946,32 @@ jQuery.extend({
// Deferred helper
when: function( object ) {
- object = object && jQuery.isFunction( object.promise ) ?
- object :
- jQuery.Deferred().resolve( object );
- return object.promise();
+ var args = arguments,
+ length = args.length,
+ deferred = length <= 1 && object && jQuery.isFunction( object.promise ) ?
+ object :
+ jQuery.Deferred(),
+ promise = deferred.promise(),
+ resolveArray;
+
+ if ( length > 1 ) {
+ resolveArray = new Array( length );
+ jQuery.each( args, function( index, element, args ) {
+ jQuery.when( element ).done( function( value ) {
+ args = arguments;
+ resolveArray[ index ] = args.length > 1 ? slice.call( args , 0 ) : value;
+ if( ! --length ) {
+ deferred.fire( promise, resolveArray );
+ }
+ }).fail( function() {
+ deferred.fireReject( promise, arguments );
+ });
+ return !deferred.isRejected();
+ });
+ } else if ( deferred !== object ) {
+ deferred.resolve( object );
+ }
+ return promise;
},
// Use of jQuery.browser is frowned upon.
@@ -960,6 +988,25 @@ jQuery.extend({
return { browser: match[1] || "", version: match[2] || "0" };
},
+ subclass: function(){
+ function jQuerySubclass( selector, context ) {
+ return new jQuerySubclass.fn.init( selector, context );
+ }
+ jQuerySubclass.superclass = this;
+ jQuerySubclass.fn = jQuerySubclass.prototype = this();
+ jQuerySubclass.fn.constructor = jQuerySubclass;
+ jQuerySubclass.subclass = this.subclass;
+ jQuerySubclass.fn.init = function init( selector, context ) {
+ if (context && context instanceof jQuery && !(context instanceof jQuerySubclass)){
+ context = jQuerySubclass(context);
+ }
+ return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass );
+ };
+ jQuerySubclass.fn.init.prototype = jQuerySubclass.fn;
+ var rootjQuerySubclass = jQuerySubclass(document);
+ return jQuerySubclass;
+ },
+
browser: {}
});
@@ -988,9 +1035,8 @@ if ( indexOf ) {
};
}
-// Verify that \s matches non-breaking spaces
-// (IE fails on this test)
-if ( !rwhite.test( "\xA0" ) ) {
+// IE doesn't match non-breaking spaces with \s
+if ( rnotwhite.test( "\xA0" ) ) {
trimLeft = /^[\s\xA0]+/;
trimRight = /[\s\xA0]+$/;
}
diff --git a/src/css.js b/src/css.js
index a6e2bb614..19c6342d2 100644
--- a/src/css.js
+++ b/src/css.js
@@ -12,6 +12,9 @@ var ralpha = /alpha\([^)]*\)/i,
cssHeight = [ "Top", "Bottom" ],
curCSS,
+ getComputedStyle,
+ currentStyle,
+
fcamelCase = function( all, letter ) {
return letter.toUpperCase();
};
@@ -169,6 +172,10 @@ jQuery.each(["height", "width"], function( i, name ) {
if ( val <= 0 ) {
val = curCSS( elem, name, name );
+ if ( val === "0px" && currentStyle ) {
+ val = currentStyle( elem, name, name );
+ }
+
if ( val != null ) {
// Should return "auto" instead of 0, use 0 for
// temporary backwards-compat
@@ -234,7 +241,7 @@ if ( !jQuery.support.opacity ) {
}
if ( document.defaultView && document.defaultView.getComputedStyle ) {
- curCSS = function( elem, newName, name ) {
+ getComputedStyle = function( elem, newName, name ) {
var ret, defaultView, computedStyle;
name = name.replace( rupper, "-$1" ).toLowerCase();
@@ -252,10 +259,13 @@ if ( document.defaultView && document.defaultView.getComputedStyle ) {
return ret;
};
-} else if ( document.documentElement.currentStyle ) {
- curCSS = function( elem, name ) {
- var left, rsLeft,
+}
+
+if ( document.documentElement.currentStyle ) {
+ currentStyle = function( elem, name ) {
+ var left,
ret = elem.currentStyle && elem.currentStyle[ name ],
+ rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],
style = elem.style;
// From the awesome hack by Dean Edwards
@@ -266,22 +276,27 @@ if ( document.defaultView && document.defaultView.getComputedStyle ) {
if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
// Remember the original values
left = style.left;
- rsLeft = elem.runtimeStyle.left;
// Put in the new values to get a computed value out
- elem.runtimeStyle.left = elem.currentStyle.left;
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ }
style.left = name === "fontSize" ? "1em" : (ret || 0);
ret = style.pixelLeft + "px";
// Revert the changed values
style.left = left;
- elem.runtimeStyle.left = rsLeft;
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = rsLeft;
+ }
}
return ret === "" ? "auto" : ret;
};
}
+curCSS = getComputedStyle || currentStyle;
+
function getWH( elem, name, extra ) {
var which = name === "width" ? cssWidth : cssHeight,
val = name === "width" ? elem.offsetWidth : elem.offsetHeight;
diff --git a/src/data.js b/src/data.js
index 4d1d1bd55..21f0e3a55 100644
--- a/src/data.js
+++ b/src/data.js
@@ -1,7 +1,6 @@
(function( jQuery ) {
-var windowData = {},
- rbrace = /^(?:\{.*\}|\[.*\])$/;
+var rbrace = /^(?:\{.*\}|\[.*\])$/;
jQuery.extend({
cache: {},
@@ -23,110 +22,170 @@ jQuery.extend({
},
hasData: function( elem ) {
- if ( elem.nodeType ) {
- elem = jQuery.cache[ elem[jQuery.expando] ];
- }
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
return !!elem && !jQuery.isEmptyObject(elem);
},
- data: function( elem, name, data ) {
+ data: function( elem, name, data, pvt /* Internal Use Only */ ) {
if ( !jQuery.acceptData( elem ) ) {
return;
}
- elem = elem == window ?
- windowData :
- elem;
+ var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache,
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
- var isNode = elem.nodeType,
- id = isNode ? elem[ jQuery.expando ] : null,
- cache = jQuery.cache, thisCache;
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;
- if ( isNode && !id && typeof name === "string" && data === undefined ) {
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {
return;
}
- // Get the data from the object directly
- if ( !isNode ) {
- cache = elem;
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ elem[ jQuery.expando ] = id = ++jQuery.uuid;
+ } else {
+ id = jQuery.expando;
+ }
+ }
- // Compute a unique ID for the element
- } else if ( !id ) {
- elem[ jQuery.expando ] = id = ++jQuery.uuid;
+ if ( !cache[ id ] ) {
+ cache[ id ] = {};
}
- // Avoid generating a new cache unless none exists and we
- // want to manipulate it.
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
if ( typeof name === "object" ) {
- if ( isNode ) {
+ if ( pvt ) {
+ cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
+ } else {
cache[ id ] = jQuery.extend(cache[ id ], name);
+ }
+ }
- } else {
- jQuery.extend( cache, name );
+ thisCache = cache[ id ];
+
+ // Internal jQuery data is stored in a separate object inside the object's data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data
+ if ( pvt ) {
+ if ( !thisCache[ internalKey ] ) {
+ thisCache[ internalKey ] = {};
}
- } else if ( isNode && !cache[ id ] ) {
- cache[ id ] = {};
+ thisCache = thisCache[ internalKey ];
}
- thisCache = isNode ? cache[ id ] : cache;
-
- // Prevent overriding the named cache with undefined values
if ( data !== undefined ) {
thisCache[ name ] = data;
}
- return typeof name === "string" ? thisCache[ name ] : thisCache;
+ // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
+ // not attempt to inspect the internal events object using jQuery.data, as this
+ // internal data object is undocumented and subject to change.
+ if ( name === "events" && !thisCache[name] ) {
+ return thisCache[ internalKey ] && thisCache[ internalKey ].events;
+ }
+
+ return getByName ? thisCache[ name ] : thisCache;
},
- removeData: function( elem, name ) {
+ removeData: function( elem, name, pvt /* Internal Use Only */ ) {
if ( !jQuery.acceptData( elem ) ) {
return;
}
- elem = elem == window ?
- windowData :
- elem;
+ var internalKey = jQuery.expando, isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
- var isNode = elem.nodeType,
- id = isNode ? elem[ jQuery.expando ] : elem,
- cache = jQuery.cache,
- thisCache = isNode ? cache[ id ] : id;
+ // See jQuery.data for more information
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
- // If we want to remove a specific section of the element's data
if ( name ) {
+ var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];
+
if ( thisCache ) {
- // Remove the section of cache data
delete thisCache[ name ];
- // If we've removed all the data, remove the element's cache
- if ( isNode && jQuery.isEmptyObject(thisCache) ) {
- jQuery.removeData( elem );
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( !jQuery.isEmptyObject(thisCache) ) {
+ return;
}
}
+ }
+
+ // See jQuery.data for more information
+ if ( pvt ) {
+ delete cache[ id ][ internalKey ];
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !jQuery.isEmptyObject(cache[ id ]) ) {
+ return;
+ }
+ }
+
+ var internalCache = cache[ id ][ internalKey ];
- // Otherwise, we want to remove all of the element's data
+ // Browsers that fail expando deletion also refuse to delete expandos on
+ // the window, but it will allow it on all other JS objects; other browsers
+ // don't care
+ if ( jQuery.support.deleteExpando || cache != window ) {
+ delete cache[ id ];
} else {
- if ( isNode && jQuery.support.deleteExpando ) {
- delete elem[ jQuery.expando ];
+ cache[ id ] = null;
+ }
+ // We destroyed the entire user cache at once because it's faster than
+ // iterating through each key, but we need to continue to persist internal
+ // data if it existed
+ if ( internalCache ) {
+ cache[ id ] = {};
+ cache[ id ][ internalKey ] = internalCache;
+
+ // Otherwise, we need to eliminate the expando on the node to avoid
+ // false lookups in the cache for entries that no longer exist
+ } else if ( isNode ) {
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( jQuery.support.deleteExpando ) {
+ delete elem[ jQuery.expando ];
} else if ( elem.removeAttribute ) {
elem.removeAttribute( jQuery.expando );
-
- // Completely remove the data cache
- } else if ( isNode ) {
- delete cache[ id ];
-
- // Remove all fields from the object
} else {
- for ( var n in elem ) {
- delete elem[ n ];
- }
+ elem[ jQuery.expando ] = null;
}
}
},
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return jQuery.data( elem, name, data, true );
+ },
+
// A method for determining if a DOM node can handle the data expando
acceptData: function( elem ) {
if ( elem.nodeName ) {
diff --git a/src/effects.js b/src/effects.js
index bd57ffc3d..b0675395f 100644
--- a/src/effects.js
+++ b/src/effects.js
@@ -27,7 +27,7 @@ jQuery.fn.extend({
// Reset the inline display of this element to learn if it is
// being hidden by cascaded rules or not
- if ( !jQuery.data(elem, "olddisplay") && display === "none" ) {
+ if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
display = elem.style.display = "";
}
@@ -35,7 +35,7 @@ jQuery.fn.extend({
// in a stylesheet to whatever the default browser style is
// for such an element
if ( display === "" && jQuery.css( elem, "display" ) === "none" ) {
- jQuery.data(elem, "olddisplay", defaultDisplay(elem.nodeName));
+ jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName));
}
}
@@ -46,7 +46,7 @@ jQuery.fn.extend({
display = elem.style.display;
if ( display === "" || display === "none" ) {
- elem.style.display = jQuery.data(elem, "olddisplay") || "";
+ elem.style.display = jQuery._data(elem, "olddisplay") || "";
}
}
@@ -62,8 +62,8 @@ jQuery.fn.extend({
for ( var i = 0, j = this.length; i < j; i++ ) {
var display = jQuery.css( this[i], "display" );
- if ( display !== "none" && !jQuery.data( this[i], "olddisplay" ) ) {
- jQuery.data( this[i], "olddisplay", display );
+ if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) {
+ jQuery._data( this[i], "olddisplay", display );
}
}
diff --git a/src/event.js b/src/event.js
index 675e5fff3..2ddf28812 100644
--- a/src/event.js
+++ b/src/event.js
@@ -8,7 +8,8 @@ var rnamespaces = /\.(.*)$/,
fcleanup = function( nm ) {
return nm.replace(rescape, "\\$&");
},
- focusCounts = { focusin: 0, focusout: 0 };
+ focusCounts = { focusin: 0, focusout: 0 },
+ eventKey = "events";
/*
* A number of helper functions used for managing events.
@@ -50,7 +51,7 @@ jQuery.event = {
}
// Init the element's event structure
- var elemData = jQuery.data( elem );
+ var elemData = jQuery._data( elem );
// If no elemData is found then we must be trying to bind to one of the
// banned noData elements
@@ -58,10 +59,7 @@ jQuery.event = {
return;
}
- // Use a key less likely to result in collisions for plain JS objects.
- // Fixes bug #7150.
- var eventKey = elem.nodeType ? "events" : "__events__",
- events = elemData[ eventKey ],
+ var events = elemData[ eventKey ],
eventHandle = elemData.handle;
if ( typeof events === "function" ) {
@@ -177,8 +175,7 @@ jQuery.event = {
}
var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
- eventKey = elem.nodeType ? "events" : "__events__",
- elemData = jQuery.data( elem ),
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
events = elemData && elemData[ eventKey ];
if ( !elemData || !events ) {
@@ -290,10 +287,10 @@ jQuery.event = {
delete elemData.handle;
if ( typeof elemData === "function" ) {
- jQuery.removeData( elem, eventKey );
+ jQuery.removeData( elem, eventKey, true );
} else if ( jQuery.isEmptyObject( elemData ) ) {
- jQuery.removeData( elem );
+ jQuery.removeData( elem, undefined, true );
}
}
},
@@ -325,9 +322,16 @@ jQuery.event = {
// Only trigger if we've ever bound an event for it
if ( jQuery.event.global[ type ] ) {
+ // XXX This code smells terrible. event.js should not be directly
+ // inspecting the data cache
jQuery.each( jQuery.cache, function() {
- if ( this.events && this.events[type] ) {
- jQuery.event.trigger( event, data, this.handle.elem );
+ // internalKey variable is just used to make it easier to find
+ // and potentially change this stuff later; currently it just
+ // points to jQuery.expando
+ var internalKey = jQuery.expando,
+ internalCache = this[ internalKey ];
+ if ( internalCache && internalCache.events && internalCache.events[type] ) {
+ jQuery.event.trigger( event, data, internalCache.handle.elem );
}
});
}
@@ -353,8 +357,8 @@ jQuery.event = {
// Trigger the event, it is assumed that "handle" is a function
var handle = elem.nodeType ?
- jQuery.data( elem, "handle" ) :
- (jQuery.data( elem, "__events__" ) || {}).handle;
+ jQuery._data( elem, "handle" ) :
+ (jQuery._data( elem, eventKey ) || {}).handle;
if ( handle ) {
handle.apply( elem, data );
@@ -432,7 +436,7 @@ jQuery.event = {
event.namespace = event.namespace || namespace_sort.join(".");
- events = jQuery.data(this, this.nodeType ? "events" : "__events__");
+ events = jQuery._data(this, eventKey);
if ( typeof events === "function" ) {
events = events.events;
@@ -603,7 +607,7 @@ jQuery.Event = function( src ) {
// Events bubbling up the document may have been marked as prevented
// by a handler lower down the tree; reflect the correct value.
- this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
+ this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
// Event type
@@ -787,12 +791,12 @@ if ( !jQuery.support.changeBubbles ) {
return;
}
- data = jQuery.data( elem, "_change_data" );
+ data = jQuery._data( elem, "_change_data" );
val = getVal(elem);
// the current data will be also retrieved by beforeactivate
if ( e.type !== "focusout" || elem.type !== "radio" ) {
- jQuery.data( elem, "_change_data", val );
+ jQuery._data( elem, "_change_data", val );
}
if ( data === undefined || val === data ) {
@@ -837,7 +841,7 @@ if ( !jQuery.support.changeBubbles ) {
// information
beforeactivate: function( e ) {
var elem = e.target;
- jQuery.data( elem, "_change_data", getVal(elem) );
+ jQuery._data( elem, "_change_data", getVal(elem) );
}
},
@@ -986,8 +990,8 @@ jQuery.fn.extend({
return this.click( jQuery.proxy( fn, function( event ) {
// Figure out which function to execute
- var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
- jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
// Make sure that clicks stop
event.preventDefault();
@@ -1075,7 +1079,7 @@ function liveHandler( event ) {
var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
elems = [],
selectors = [],
- events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
+ events = jQuery._data( this, eventKey );
if ( typeof events === "function" ) {
events = events.events;
diff --git a/src/manipulation.js b/src/manipulation.js
index cf533c818..596a45736 100644
--- a/src/manipulation.js
+++ b/src/manipulation.js
@@ -346,7 +346,7 @@ jQuery.fn.extend({
table ?
root(this[i], first) :
this[i],
- i > 0 || results.cacheable || this.length > 1 ?
+ i > 0 || results.cacheable || (this.length > 1 && i > 0) ?
jQuery(fragment).clone(true)[0] :
fragment
);
@@ -381,17 +381,24 @@ function cloneCopyEvent(orig, ret) {
throw "Cloned data mismatch";
}
- var oldData = jQuery.data( orig[nodeIndex] ),
- curData = jQuery.data( this, oldData ),
- events = oldData && oldData.events;
+ var internalKey = jQuery.expando,
+ oldData = jQuery.data( orig[nodeIndex] ),
+ curData = jQuery.data( this, oldData );
- if ( events ) {
- delete curData.handle;
- curData.events = {};
+ // Switch to use the internal data object, if it exists, for the next
+ // stage of data copying
+ if ( (oldData = oldData[ internalKey ]) ) {
+ var events = oldData.events;
+ curData = curData[ internalKey ] = jQuery.extend({}, oldData);
- for ( var type in events ) {
- for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
- jQuery.event.add( this, type, events[ type ][ i ], events[ type ][ i ].data );
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( var type in events ) {
+ for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( this, type, events[ type ][ i ], events[ type ][ i ].data );
+ }
}
}
}
@@ -608,8 +615,7 @@ jQuery.extend({
},
cleanData: function( elems ) {
- var data, id, cache = jQuery.cache,
- special = jQuery.event.special,
+ var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,
deleteExpando = jQuery.support.deleteExpando;
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
@@ -620,13 +626,14 @@ jQuery.extend({
id = elem[ jQuery.expando ];
if ( id ) {
- data = cache[ id ];
+ data = cache[ id ] && cache[ id ][ internalKey ];
if ( data && data.events ) {
for ( var type in data.events ) {
if ( special[ type ] ) {
jQuery.event.remove( elem, type );
+ // This is a shortcut to avoid jQuery.event.remove's overhead
} else {
jQuery.removeEvent( elem, type, data.handle );
}
diff --git a/src/offset.js b/src/offset.js
index 2040c9d83..a10d30a0f 100644
--- a/src/offset.js
+++ b/src/offset.js
@@ -30,7 +30,7 @@ if ( "getBoundingClientRect" in document.documentElement ) {
// Make sure we're not dealing with a disconnected DOM node
if ( !box || !jQuery.contains( docElem, elem ) ) {
- return box || { top: 0, left: 0 };
+ return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
}
var body = doc.body,
diff --git a/src/queue.js b/src/queue.js
index 735b0e189..9e3e2fb52 100644
--- a/src/queue.js
+++ b/src/queue.js
@@ -7,7 +7,7 @@ jQuery.extend({
}
type = (type || "fx") + "queue";
- var q = jQuery.data( elem, type );
+ var q = jQuery._data( elem, type );
// Speed up dequeue by getting out quickly if this is just a lookup
if ( !data ) {
@@ -15,7 +15,7 @@ jQuery.extend({
}
if ( !q || jQuery.isArray(data) ) {
- q = jQuery.data( elem, type, jQuery.makeArray(data) );
+ q = jQuery._data( elem, type, jQuery.makeArray(data) );
} else {
q.push( data );
@@ -46,6 +46,10 @@ jQuery.extend({
jQuery.dequeue(elem, type);
});
}
+
+ if ( !queue.length ) {
+ jQuery.removeData( elem, type + "queue", true );
+ }
}
});
diff --git a/src/support.js b/src/support.js
index e4c3ea916..7be28fdaf 100644
--- a/src/support.js
+++ b/src/support.js
@@ -4,10 +4,7 @@
jQuery.support = {};
- var root = document.documentElement,
- script = document.createElement("script"),
- div = document.createElement("div"),
- id = "script" + jQuery.now();
+ var div = document.createElement("div");
div.style.display = "none";
div.innerHTML = " <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
@@ -64,7 +61,7 @@
deleteExpando: true,
optDisabled: false,
checkClone: false,
- scriptEval: false,
+ _scriptEval: null,
noCloneEvent: true,
boxModel: null,
inlineBlockNeedsLayout: false,
@@ -77,32 +74,46 @@
select.disabled = true;
jQuery.support.optDisabled = !opt.disabled;
- script.type = "text/javascript";
- try {
- script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
- } catch(e) {}
-
- root.insertBefore( script, root.firstChild );
+ jQuery.support.scriptEval = function() {
+ if ( jQuery.support._scriptEval === null ) {
+ var root = document.documentElement,
+ script = document.createElement("script"),
+ id = "script" + jQuery.now();
+
+ script.type = "text/javascript";
+ try {
+ script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
+ } catch(e) {}
+
+ root.insertBefore( script, root.firstChild );
+
+ // Make sure that the execution of code works by injecting a script
+ // tag with appendChild/createTextNode
+ // (IE doesn't support this, fails, and uses .text instead)
+ if ( window[ id ] ) {
+ jQuery.support._scriptEval = true;
+ delete window[ id ];
+ } else {
+ jQuery.support._scriptEval = false;
+ }
+
+ root.removeChild( script );
+ // release memory in IE
+ root = script = id = null;
+ }
- // Make sure that the execution of code works by injecting a script
- // tag with appendChild/createTextNode
- // (IE doesn't support this, fails, and uses .text instead)
- if ( window[ id ] ) {
- jQuery.support.scriptEval = true;
- delete window[ id ];
- }
+ return jQuery.support._scriptEval;
+ };
// Test to see if it's possible to delete an expando from an element
// Fails in Internet Explorer
try {
- delete script.test;
+ delete div.test;
} catch(e) {
jQuery.support.deleteExpando = false;
}
- root.removeChild( script );
-
if ( div.attachEvent && div.fireEvent ) {
div.attachEvent("onclick", function click() {
// Cloning a node shouldn't copy over any
@@ -177,6 +188,14 @@
var el = document.createElement("div");
eventName = "on" + eventName;
+ // We only care about the case where non-standard event systems
+ // are used, namely in IE. Short-circuiting here helps us to
+ // avoid an eval call (in setAttribute) which can cause CSP
+ // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+ if ( !el.attachEvent ) {
+ return true;
+ }
+
var isSupported = (eventName in el);
if ( !isSupported ) {
el.setAttribute(eventName, "return;");
@@ -191,6 +210,6 @@
jQuery.support.changeBubbles = eventSupported("change");
// release memory in IE
- root = script = div = all = a = null;
+ div = all = a = null;
})();
})( jQuery );
diff --git a/src/traversing.js b/src/traversing.js
index 689e90196..929547c11 100644
--- a/src/traversing.js
+++ b/src/traversing.js
@@ -6,7 +6,14 @@ var runtil = /Until$/,
rmultiselector = /,/,
isSimple = /^.[^:#\[\.,]*$/,
slice = Array.prototype.slice,
- POS = jQuery.expr.match.POS;
+ POS = jQuery.expr.match.POS,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
jQuery.fn.extend({
find: function( selector ) {
@@ -196,7 +203,12 @@ jQuery.each({
}
}, function( name, fn ) {
jQuery.fn[ name ] = function( until, selector ) {
- var ret = jQuery.map( this, fn, until );
+ var ret = jQuery.map( this, fn, until ),
+ // The variable 'args' was introduced in
+ // https://github.com/jquery/jquery/commit/52a0238
+ // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
+ // http://code.google.com/p/v8/issues/detail?id=1050
+ args = slice.call(arguments);
if ( !runtil.test( name ) ) {
selector = until;
@@ -206,13 +218,13 @@ jQuery.each({
ret = jQuery.filter( selector, ret );
}
- ret = this.length > 1 ? jQuery.unique( ret ) : ret;
+ ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
ret = ret.reverse();
}
- return this.pushStack( ret, name, slice.call(arguments).join(",") );
+ return this.pushStack( ret, name, args.join(",") );
};
});