Index: src/ajax/ajax.js =================================================================== --- src/ajax/ajax.js (revision 208) +++ src/ajax/ajax.js (working copy) @@ -5,7 +5,10 @@ /** * Load HTML from a remote file and inject it into the DOM */ -jQuery.fn.load = function( url, params, callback ) { +jQuery.fn.loadIfModified = function( url, params, callback ) { + jQuery.fn.load.apply(this, [url, params, callback, 1] ); +} +jQuery.fn.load = function( url, params, callback, ifModified ) { // I overwrote the event plugin's .load // this won't happen again, I hope -John if ( url && url.constructor == Function ) @@ -32,22 +35,30 @@ var self = this; // Request the remote document - jQuery.ajax( type, url, params,function(res){ + jQuery.ajax( type, url, params,function(res, status){ + + if( status == "notmodified" ) { + if( callback && callback.constructor == Function ) { + callback.apply( self, [res.responseText, status] ); + } + } else if( status == "failure" && callback && callback.constructor == Function ) { + // callback only. + callback.apply( self, [res.responseText, status] ); + } else { + // Inject the HTML into all the matched elements + self.html(res.responseText).each(function(){ + // If a callback function was provided + if ( callback && callback.constructor == Function ) + // Execute it within the context of the element + callback.apply( self, [res.responseText, status] ); + }); - // Inject the HTML into all the matched elements - self.html(res.responseText).each(function(){ - // If a callback function was provided - if ( callback && callback.constructor == Function ) - // Execute it within the context of the element - callback.apply( self, [res.responseText] ); - }); - - // Execute all the scripts inside of the newly-injected HTML - $("script", self).each(function(){ - eval( this.text || this.textContent || this.innerHTML || ""); - }); - - }); + // Execute all the scripts inside of the newly-injected HTML + $("script", self).each(function(){ + eval( this.text || this.textContent || this.innerHTML || ""); + }); + } + }, ifModified); return this; }; @@ -78,8 +89,9 @@ /** * Load a remote page using a GET request */ - get: function( url, data, callback, type ) { + get: function( url, data, callback, type, ifModified ) { if ( data.constructor == Function ) { + type = callback; callback = data; data = null; } @@ -88,25 +100,36 @@ url += "?" + jQuery.param(data); // Build and start the HTTP Request - jQuery.ajax( "GET", url, null, function(r) { - if ( callback ) callback( jQuery.httpData(r,type) ); - }); + jQuery.ajax( "GET", url, null, function(r, status) { + if ( callback ) callback( jQuery.httpData(r,type), status ); + }, ifModified); }, + getIfModified: function( url, data, callback, type ) { + jQuery.get(url, data, callback, type, 1); + }, /** * Load a remote page using a POST request. */ post: function( url, data, callback, type ) { // Build and start the HTTP Request - jQuery.ajax( "POST", url, jQuery.param(data), function(r) { - if ( callback ) callback( jQuery.httpData(r,type) ); + jQuery.ajax( "POST", url, jQuery.param(data), function(r, status) { + if ( callback ) callback( jQuery.httpData(r,type), status ); }); }, + // timeout (ms) + timeout: 0, + ajaxTimeout: function(timeout) { + jQuery.timeout = timeout; + }, + // Last-Modified header cache for next request + lastModified: {}, + /** * A common wrapper for making XMLHttpRequests */ - ajax: function( type, url, data, ret ) { + ajax: function( type, url, data, ret, ifModified ) { // If only a single argument was passed in, // assume that it is a object of key/value pairs if ( !url ) { @@ -131,23 +154,46 @@ // Set the correct header, if data is being sent if ( data ) xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); - + + // Set the If-Modified-Since header, if ifModified mode. + if ( ifModified ) { + if ( jQuery.lastModified[url] ) { + xml.setRequestHeader("If-Modified-Since", jQuery.lastModified[url] ); + } else { + xml.setRequestHeader("If-Modified-Since", "Thu, 01 Jan 1970 00:00:00 GMT" ); + } + } + // Set header so calling script knows that it's an XMLHttpRequest xml.setRequestHeader("X-Requested-With", "XMLHttpRequest"); // Make sure the browser sends the right content length if ( xml.overrideMimeType ) xml.setRequestHeader("Connection", "close"); - + // Wait for a response to come back - xml.onreadystatechange = function(){ + var onreadystatechange = function(istimeout){ // The transfer is complete and the data is available - if ( xml.readyState == 4 ) { - // Make sure that the request was successful - if ( jQuery.httpSuccess( xml ) ) { + if ( xml && (xml.readyState == 4 || istimeout) ) { + var statusstr; + if( jQuery.httpSuccess( xml ) ) { + statusstr = "success"; + if ( ifModified && jQuery.httpNotModified( xml, url ) ) { + statusstr = "notmodified"; + } + } else { + statusstr = "failure"; + } + // Make sure that the request was successful or notmodified + if ( statusstr != "failure" ) { + // Cache Last-Modified header, if ifModified mode. + if ( ifModified && xml.getResponseHeader("Last-Modified") ) { + jQuery.lastModified[url] = xml.getResponseHeader("Last-Modified"); + } + // If a local callback was specified, fire it - if ( success ) success( xml ); + if ( success ) success( xml, statusstr ); // Fire the global callback jQuery.event.trigger( "ajaxSuccess" ); @@ -155,7 +201,7 @@ // Otherwise, the request was not successful } else { // If a local callback was specified, fire it - if ( error ) error( xml ); + if ( error ) error( xml, statusstr ); // Fire the global callback jQuery.event.trigger( "ajaxError" ); @@ -169,14 +215,31 @@ jQuery.event.trigger( "ajaxStop" ); // Process result - if ( ret ) ret(xml); - + if ( ret ) ret(xml, statusstr); + // Stop memory leaks xml.onreadystatechange = function(){}; xml = null; + } }; - + xml.onreadystatechange = onreadystatechange; + + // Timeout checker + if(jQuery.timeout > 0) { + setTimeout(function(){ + if(xml) { + xml.abort(); + // for Opera. Opera isn't call onreadystatechange when abort. + if(xml) { + onreadystatechange(1); + } + xml = null; + } + }, jQuery.timeout); + } + + // Send the data xml.send(data); }, @@ -193,6 +256,22 @@ } catch(e){} return false; }, + // Determines if an XMLHttpRequest returns NotModified + httpNotModified: function(xml, url) { + try { + + if( xml.status && ( xml.status == 304 ) ) { + return true; + } + // Firefox always returns 200. check Last-Modified date + if ( xml.getResponseHeader("Last-Modified") ) { + if( xml.getResponseHeader("Last-Modified") == jQuery.lastModified[url] ) { + return true; + } + } + } catch(e){} + return false; + }, // Get the data out of an XMLHttpRequest. // Return parsed XML if content-type header is "xml" and type is "xml" or omitted,