aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorXavi <xavi.rmz@gmail.com>2011-01-18 12:06:05 -0500
committerXavi <xavi.rmz@gmail.com>2011-01-18 12:06:05 -0500
commit0942b3b3f55c77664f3a72b1e2ae0b58cf108d4c (patch)
tree7159dfa9716438b77280de2c23e92991acfddea6 /src
parentb78e3fc39f96d63a60ea66e3d066815626e633d8 (diff)
parent3d0aa196c5420e7f68b32cee38f0cc740d4959c6 (diff)
downloadjquery-0942b3b3f55c77664f3a72b1e2ae0b58cf108d4c.tar.gz
jquery-0942b3b3f55c77664f3a72b1e2ae0b58cf108d4c.zip
Merge branch 'master' of git://github.com/jquery/jquery into bug_7931
Diffstat (limited to 'src')
-rw-r--r--src/ajax.js290
-rw-r--r--src/ajax/jsonp.js106
-rw-r--r--src/ajax/script.js35
-rw-r--r--src/ajax/xhr.js88
-rw-r--r--src/attributes.js4
-rw-r--r--src/core.js93
-rw-r--r--src/css.js12
-rw-r--r--src/data.js169
-rw-r--r--src/effects.js10
-rw-r--r--src/event.js48
-rw-r--r--src/manipulation.js55
-rw-r--r--src/queue.js8
-rw-r--r--src/support.js56
-rw-r--r--src/traversing.js16
14 files changed, 609 insertions, 381 deletions
diff --git a/src/ajax.js b/src/ajax.js
index d570fcccb..871481d01 100644
--- a/src/ajax.js
+++ b/src/ajax.js
@@ -61,26 +61,34 @@ jQuery.fn.extend({
type: type,
dataType: "html",
data: params,
- complete: function( res, status ) {
+ // Complete callback (responseText is used internally)
+ complete: function( jXHR, status, responseText ) {
+ // Store the response as specified by the jXHR object
+ responseText = jXHR.responseText;
// If successful, inject the HTML into all the matched elements
- if ( status === "success" || status === "notmodified" ) {
+ if ( jXHR.isResolved() ) {
+ // #4825: Get the actual response in case
+ // a dataFilter is present in ajaxSettings
+ jXHR.done(function( r ) {
+ responseText = r;
+ });
// See if a selector was specified
self.html( selector ?
// Create a dummy div to hold the results
jQuery("<div>")
// inject the contents of the document in, removing the scripts
// to avoid any 'Permission Denied' errors in IE
- .append(res.responseText.replace(rscript, ""))
+ .append(responseText.replace(rscript, ""))
// Locate the specified elements
.find(selector) :
// If not, just inject the full result
- res.responseText );
+ responseText );
}
if ( callback ) {
- self.each( callback, [res.responseText, status, res] );
+ self.each( callback, [responseText, status, jXHR] );
}
}
});
@@ -152,7 +160,8 @@ jQuery.extend({
},
ajaxSetup: function( settings ) {
- jQuery.extend( jQuery.ajaxSettings, settings );
+ jQuery.extend( true, jQuery.ajaxSettings, settings );
+ return this;
},
ajaxSettings: {
@@ -166,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();
@@ -257,6 +267,8 @@ jQuery.extend({
// Deferreds
deferred = jQuery.Deferred(),
completeDeferred = jQuery._Deferred(),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
// Headers (they are sent all at once)
requestHeaders = {},
// Response headers
@@ -266,6 +278,9 @@ jQuery.extend({
transport,
// timeout handle
timeoutTimer,
+ // Cross-domain detection vars
+ loc = document.location,
+ parts,
// The jXHR state
state = 0,
// Loop variable
@@ -292,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;
}
};
@@ -333,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;
@@ -354,17 +378,10 @@ jQuery.extend({
// Stored success
success,
// Stored error
- error = statusText;
-
- // If not timeout, force a jQuery-compliant status text
- if ( statusText != "timeout" ) {
- statusText = ( status >= 200 && status < 300 ) ?
- "success" :
- ( status === 304 ? "notmodified" : "error" );
- }
+ error;
// If successful, handle type chaining
- if ( statusText === "success" || statusText === "notmodified" ) {
+ if ( status >= 200 && status < 300 || status === 304 ) {
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
@@ -380,91 +397,124 @@ jQuery.extend({
}
}
- if ( s.ifModified && statusText === "notmodified" ) {
+ // If not modified
+ if ( status === 304 ) {
- success = null;
+ // Set the statusText accordingly
+ statusText = "notmodified";
+ // Mark as a success
isSuccess = 1;
+ // If we have data
} else {
+
+ // Set the statusText accordingly
+ statusText = "success";
+
// Chain data conversions and determine the final value
// (if an exception is thrown in the process, it'll be notified as an error)
try {
var i,
+ // Current dataType
current,
+ // Previous dataType
prev,
- checker,
+ // Conversion function
conv,
+ // Conversion functions (when text is used in-between)
conv1,
conv2,
- convertion,
+ // Local references to dataTypes & converters
dataTypes = s.dataTypes,
converters = s.converters,
+ // DataType to responseXXX field mapping
responses = {
"xml": "XML",
"text": "Text"
};
+ // For each dataType in the chain
for( i = 0 ; i < dataTypes.length ; i++ ) {
current = dataTypes[ i ];
+ // If a responseXXX field for this dataType exists
+ // and if it hasn't been set yet
if ( responses[ current ] ) {
+ // Set it
jXHR[ "response" + responses[ current ] ] = response;
+ // Mark it as set
responses[ current ] = 0;
}
+ // If this is not the first element
if ( i ) {
+ // Get the dataType to convert from
prev = dataTypes[ i - 1 ];
+ // If no catch-all and dataTypes are actually different
if ( prev !== "*" && current !== "*" && prev !== current ) {
- conv = converters[ ( conversion = prev + " " + current ) ] ||
+ // Get the converter
+ conv = converters[ prev + " " + current ] ||
converters[ "* " + current ];
conv1 = conv2 = 0;
+ // If there is no direct converter and none of the dataTypes is text
if ( ! conv && prev !== "text" && current !== "text" ) {
+ // Try with text in-between
conv1 = converters[ prev + " text" ] || converters[ "* text" ];
conv2 = converters[ "text " + current ];
+ // Revert back to a single converter
+ // if one of the converter is an equivalence
if ( conv1 === true ) {
conv = conv2;
} else if ( conv2 === true ) {
conv = conv1;
}
}
-
+ // If we found no converter, dispatch an error
if ( ! ( conv || conv1 && conv2 ) ) {
throw conversion;
}
-
+ // If found converter is not an equivalence
if ( conv !== true ) {
+ // Convert with 1 or 2 converters accordingly
response = conv ? conv( response ) : conv2( conv1( response ) );
}
}
+ // If it is the first element of the chain
+ // and we have a dataFilter
} else if ( s.dataFilter ) {
-
- response = s.dataFilter( response );
+ // Apply the dataFilter
+ response = s.dataFilter( response , current );
+ // Get dataTypes again in case the filter changed them
dataTypes = s.dataTypes;
}
}
+ // End of loop
// We have a real success
success = response;
isSuccess = 1;
+ // If an exception was thrown
} catch(e) {
+ // We have a parsererror
statusText = "parsererror";
error = "" + e;
}
}
- } else { // if not success, mark it as an error
+ // if not success, mark it as an error
+ } else {
- error = error || statusText;
+ error = statusText = statusText || "error";
// Set responseText if needed
if ( response ) {
@@ -483,6 +533,9 @@ jQuery.extend({
deferred.fireReject( callbackContext , [ jXHR , statusText , error ] );
}
+ // Status-dependent callbacks
+ jXHR.statusCode( statusCode );
+
if ( s.global ) {
globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ) ,
[ jXHR , s , isSuccess ? success : error ] );
@@ -506,23 +559,37 @@ jQuery.extend({
jXHR.error = jXHR.fail;
jXHR.complete = completeDeferred.done;
+ // Status-dependent callbacks
+ jXHR.statusCode = function( map ) {
+ if ( map ) {
+ var resolved = jXHR.isResolved(),
+ tmp;
+ if ( resolved || jXHR.isRejected() ) {
+ tmp = map[ jXHR.status ];
+ if ( tmp ) {
+ if ( map === statusCode ) {
+ delete statusCode[ jXHR.status ];
+ }
+ jXHR[ resolved ? "done" : "fail" ]( tmp );
+ }
+ } else {
+ for( tmp in map ) {
+ statusCode[ tmp ] = [ statusCode[ tmp ] , map[ tmp ] ];
+ }
+ }
+ }
+ return this;
+ };
+
// 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+/ );
// Determine if a cross-domain request is in order
- var parts = rurl.exec( s.url.toLowerCase() ),
- loc = location;
-
if ( ! s.crossDomain ) {
+ parts = rurl.exec( s.url.toLowerCase() );
s.crossDomain = !!(
parts &&
( parts[ 1 ] && parts[ 1 ] != loc.protocol ||
@@ -532,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.ajax.prefilter( s , options ).transport( 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 ];
+ }
- // 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[ "*" ];
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext , jXHR , s ) === false || state === 2 ) ) {
- // Check for headers option
- for ( i in s.headers ) {
- requestHeaders[ i.toLowerCase() ] = s.headers[ i ];
+ // Abort if not done already
+ done( 0 , "abort" );
+
+ // Return false
+ jXHR = false;
+
+ } 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 );
- // Abort if not done already
- done( 0 , "abort" );
- jXHR = false;
+ // If no transport, we auto-abort
+ if ( ! transport ) {
+
+ 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 ) {
@@ -787,7 +863,7 @@ function ajax_selectOrExecute( structure , s ) {
}
}
- return noSelect ? jQuery.ajax : selected;
+ return noSelect ? jQuery : selected;
}
// Add an element to one of the structures in ajaxSettings
@@ -846,13 +922,13 @@ function ajax_addElement( structure , args ) {
}
}
- return jQuery.ajax;
+ return jQuery;
}
// Install prefilter & transport methods
-jQuery.each( [ "prefilter" , "transport" ] , function( _ , name ) {
- _ = name + "s";
- jQuery.ajax[ name ] = function() {
+jQuery.each( [ "Prefilter" , "Transport" ] , function( _ , name ) {
+ _ = name.toLowerCase() + "s";
+ jQuery[ "ajax" + name ] = function() {
return ajax_addElement( _ , arguments );
};
} );
diff --git a/src/ajax/jsonp.js b/src/ajax/jsonp.js
index f4b324e17..883876fc0 100644
--- a/src/ajax/jsonp.js
+++ b/src/ajax/jsonp.js
@@ -1,8 +1,7 @@
(function( jQuery ) {
var jsc = jQuery.now(),
- jsre = /\=(?:\?|%3F)(&|$)/i,
- rquery_jsonp = /\?/;
+ jsre = /(\=)(?:\?|%3F)(&|$)|()(?:\?\?|%3F%3F)()/i;
// Default jsonp settings
jQuery.ajaxSetup({
@@ -10,75 +9,78 @@ jQuery.ajaxSetup({
jsonpCallback: function() {
return "jsonp" + jsc++;
}
-});
-// Normalize jsonp queries
-// 1) put callback parameter in url or data
-// 2) sneakily ensure transportDataType is always jsonp for jsonp requests
-jQuery.ajax.prefilter("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, "=" + jsonpCallback + "$1"),
- data = s.url === url && typeof(s.data) === "string" ? s.data.replace(jsre, "=" + jsonpCallback + "$1") : 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
-}).transport("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 0db0de6c7..b0e576f27 100644
--- a/src/ajax/script.js
+++ b/src/ajax/script.js
@@ -1,7 +1,7 @@
(function( jQuery ) {
-// Install text to script executor
-jQuery.extend( true, jQuery.ajaxSettings , {
+// Install script dataType
+jQuery.ajaxSetup({
accepts: {
script: "text/javascript, application/javascript"
@@ -14,20 +14,24 @@ jQuery.extend( true, jQuery.ajaxSettings , {
converters: {
"text script": jQuery.globalEval
}
-} );
-// Bind script tag hack transport
-jQuery.ajax.transport("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;
@@ -47,7 +51,7 @@ jQuery.ajax.transport("script", function(s) {
script.src = s.url;
// Attach handlers for all browsers
- script.onload = script.onreadystatechange = function( _ , statusText) {
+ script.onload = script.onreadystatechange = function( _ , isAbort ) {
if ( ! script.readyState || /loaded|complete/.test( script.readyState ) ) {
@@ -59,10 +63,13 @@ jQuery.ajax.transport("script", function(s) {
head.removeChild( script );
}
+ // Dereference the script
script = 0;
- // Callback
- callback( statusText ? 0 : 200, statusText || "success" );
+ // Callback if not abort
+ if ( ! isAbort ) {
+ callback( 200, "success" );
+ }
}
};
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
@@ -70,9 +77,9 @@ jQuery.ajax.transport("script", function(s) {
head.insertBefore( script, head.firstChild );
},
- abort: function(statusText) {
+ abort: function() {
if ( script ) {
- script.onload( 0 , statusText );
+ script.onload(0,1);
}
}
};
diff --git a/src/ajax/xhr.js b/src/ajax/xhr.js
index 26e91ce79..34aa832fe 100644
--- a/src/ajax/xhr.js
+++ b/src/ajax/xhr.js
@@ -1,19 +1,16 @@
(function( jQuery ) {
-var // Next fake timer id
- xhrPollingId = jQuery.now(),
+var // Next active xhr id
+ xhrId = jQuery.now(),
- // Callbacks hashtable
+ // active xhrs
xhrs = {},
- // XHR pool
- xhrPool = [],
+ // #5280: see below
+ xhrUnloadAbortInstalled;
- // #5280: see end of file
- xhrUnloadAbortMarker;
-
-jQuery.ajax.transport( function( s , determineDataType ) {
+jQuery.ajaxTransport( function( s , determineDataType ) {
// Cross domain only allowed if supported through XMLHttpRequest
if ( ! s.crossDomain || jQuery.support.cors ) {
@@ -25,26 +22,24 @@ jQuery.ajax.transport( function( s , determineDataType ) {
send: function(headers, complete) {
// #5280: we need to abort on unload or IE will keep connections alive
- if ( ! xhrUnloadAbortMarker ) {
+ if ( ! xhrUnloadAbortInstalled ) {
- xhrUnloadAbortMarker = [];
+ xhrUnloadAbortInstalled = 1;
jQuery(window).bind( "unload" , function() {
// Abort all pending requests
jQuery.each(xhrs, function(_, xhr) {
if ( xhr.onreadystatechange ) {
- xhr.onreadystatechange( xhrUnloadAbortMarker );
+ xhr.onreadystatechange( 1 );
}
});
- // Reset polling structure to be safe
- xhrs = {};
-
});
}
- var xhr = xhrPool.pop() || s.xhr(),
+ // Get a new xhr
+ var xhr = s.xhr(),
handle;
// Open the socket
@@ -58,7 +53,7 @@ jQuery.ajax.transport( function( s , determineDataType ) {
// Requested-With header
// Not set for crossDomain requests with no content
// (see why at http://trac.dojotoolkit.org/ticket/9486)
- // Won't change header if already provided in beforeSend
+ // Won't change header if already provided
if ( ! ( s.crossDomain && ! s.hasContent ) && ! headers["x-requested-with"] ) {
headers["x-requested-with"] = "XMLHttpRequest";
}
@@ -76,49 +71,40 @@ jQuery.ajax.transport( function( s , determineDataType ) {
try {
xhr.send( ( s.hasContent && s.data ) || null );
} catch(e) {
- // Store back in pool
- xhrPool.push( xhr );
complete(0, "error", "" + e);
return;
}
// Listener
- callback = function ( abortStatusText ) {
+ callback = function( _ , isAbort ) {
// Was never called and is aborted or complete
- if ( callback && ( abortStatusText || xhr.readyState === 4 ) ) {
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+ // Only called once
+ callback = 0;
- // Do not listen anymore
- // and Store back in pool
+ // Do not keep as active anymore
+ // and store back into pool
if (handle) {
xhr.onreadystatechange = jQuery.noop;
delete xhrs[ handle ];
- handle = undefined;
- xhrPool.push( xhr );
}
- callback = 0;
-
- // Get info
- var status, statusText, response, responseHeaders;
-
- if ( abortStatusText ) {
+ // If it's an abort
+ if ( isAbort ) {
+ // Abort it manually if needed
if ( xhr.readyState !== 4 ) {
xhr.abort();
}
-
- // Stop here if unloadAbort
- if ( abortStatusText === xhrUnloadAbortMarker ) {
- return;
- }
-
- status = 0;
- statusText = abortStatusText;
-
} else {
- status = xhr.status;
+ // Get info
+ var status = xhr.status,
+ statusText,
+ response,
+ responseHeaders = xhr.getAllResponseHeaders();
try { // Firefox throws an exception when accessing statusText for faulty cross-domain requests
@@ -130,8 +116,6 @@ jQuery.ajax.transport( function( s , determineDataType ) {
}
- responseHeaders = xhr.getAllResponseHeaders();
-
// Filter status for non standard behaviours
// (so many they seem to be the actual "standard")
status =
@@ -164,10 +148,10 @@ jQuery.ajax.transport( function( s , determineDataType ) {
xhr.getResponseHeader("content-type"),
xhr.responseText,
xhr.responseXML );
- }
- // Call complete
- complete(status,statusText,response,responseHeaders);
+ // Call complete
+ complete(status,statusText,response,responseHeaders);
+ }
}
};
@@ -180,18 +164,16 @@ jQuery.ajax.transport( function( s , determineDataType ) {
} else {
- // Listener is externalized to handle abort on unload
- handle = xhrPollingId++;
+ // Add to list of active xhrs
+ handle = xhrId++;
xhrs[ handle ] = xhr;
- xhr.onreadystatechange = function() {
- callback();
- };
+ xhr.onreadystatechange = callback;
}
},
- abort: function(statusText) {
+ abort: function() {
if ( callback ) {
- callback(statusText);
+ callback(0,1);
}
}
};
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 b9e6d816f..4311e3103 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
@@ -63,6 +63,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 +81,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 +116,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
@@ -129,7 +134,7 @@ jQuery.fn = jQuery.prototype = {
} else {
ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
- selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
+ selector = (ret.cacheable ? jQuery(ret.fragment).clone()[0] : ret.fragment).childNodes;
}
return jQuery.merge( this, selector );
@@ -171,7 +176,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 +227,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 +292,7 @@ jQuery.fn = jQuery.prototype = {
},
end: function() {
- return this.prevObject || jQuery(null);
+ return this.prevObject || this.constructor(null);
},
// For internal use only.
@@ -578,7 +583,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 +901,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 +917,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 +950,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 +992,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: {}
});
diff --git a/src/css.js b/src/css.js
index 8a83c6072..19c6342d2 100644
--- a/src/css.js
+++ b/src/css.js
@@ -263,8 +263,9 @@ if ( document.defaultView && document.defaultView.getComputedStyle ) {
if ( document.documentElement.currentStyle ) {
currentStyle = function( elem, name ) {
- var left, rsLeft,
+ var left,
ret = elem.currentStyle && elem.currentStyle[ name ],
+ rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],
style = elem.style;
// From the awesome hack by Dean Edwards
@@ -275,16 +276,19 @@ if ( document.documentElement.currentStyle ) {
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;
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 493082212..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 );
+ }
}
}
}
@@ -420,15 +427,29 @@ function cloneFixAttributes(src, dest) {
if ( nodeName === "object" ) {
dest.outerHTML = src.outerHTML;
- // IE6-8 fails to persist the checked state of a cloned checkbox
- // or radio button
- } else if ( nodeName === "input" && src.checked ) {
- dest.defaultChecked = dest.checked = src.checked;
+ } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+ if ( src.checked ) {
+ dest.defaultChecked = dest.checked = src.checked;
+ }
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
// IE6-8 fails to return the selected option to the default selected
// state when cloning options
} else if ( nodeName === "option" ) {
dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
}
// Event data gets referenced instead of copied if the expando
@@ -594,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++ ) {
@@ -606,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/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..f502811ae 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,45 @@
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 );
-
- // 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 ];
- }
+ 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;
+ }
+ 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
@@ -191,6 +201,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..b36ce3db8 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,8 @@ 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 ),
+ args = slice.call(arguments);
if ( !runtil.test( name ) ) {
selector = until;
@@ -206,13 +214,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(",") );
};
});