Adding support for etags in $.ajax() - and simplified the if-modified-since implement...
[jquery.git] / src / ajax.js
index 8262bc7..2365387 100644 (file)
@@ -71,7 +71,7 @@ jQuery.fn.extend({
                .filter(function(){
                        return this.name && !this.disabled &&
                                (this.checked || /select|textarea/i.test(this.nodeName) ||
-                                       /text|hidden|password/i.test(this.type));
+                                       /text|hidden|password|search/i.test(this.type));
                })
                .map(function(i, elem){
                        var val = jQuery(this).val();
@@ -95,7 +95,7 @@ jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".sp
 var jsc = now();
 
 jQuery.extend({
-  
+
        get: function( url, data, callback, type ) {
                // shift arguments if data argument was ommited
                if ( jQuery.isFunction( data ) ) {
@@ -170,6 +170,7 @@ jQuery.extend({
 
        // Last-Modified header cache for next request
        lastModified: {},
+       etag: {},
 
        ajax: function( s ) {
                // Extend the settings, but re-extend 's' so that it can be
@@ -233,9 +234,6 @@ jQuery.extend({
                // If data is available, append data to url for get requests
                if ( s.data && type == "GET" ) {
                        s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
-
-                       // IE likes to send both get and post data, prevent this
-                       s.data = null;
                }
 
                // Watch for a new set of requests
@@ -267,12 +265,17 @@ jQuery.extend({
                                                done = true;
                                                success();
                                                complete();
+
+                                               // Handle memory leak in IE
+                                               script.onload = script.onreadystatechange = null;
                                                head.removeChild( script );
                                        }
                                };
                        }
 
-                       head.appendChild(script);
+                       // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
+                       // This arises when a base node is used (#2709 and #4378).
+                       head.insertBefore( script, head.firstChild );
 
                        // We handle everything using the script element injection
                        return undefined;
@@ -296,10 +299,13 @@ jQuery.extend({
                        if ( s.data )
                                xhr.setRequestHeader("Content-Type", s.contentType);
 
-                       // Set the If-Modified-Since header, if ifModified mode.
-                       if ( s.ifModified )
-                               xhr.setRequestHeader("If-Modified-Since",
-                                       jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
+                               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+                               if ( s.ifModified ) {
+                                       if (jQuery.lastModified[s.url])
+                                               xhr.setRequestHeader("If-Modified-Since", jQuery.lastModified[s.url]);
+                                       if (jQuery.etag[s.url])
+                                               xhr.setRequestHeader("If-None-Match", jQuery.etag[s.url]);
+                               }
 
                        // Set header so the called script knows that it's an XMLHttpRequest
                        xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
@@ -361,16 +367,7 @@ jQuery.extend({
                                }
 
                                // Make sure that the request was successful or notmodified
-                               if ( status == "success" ) {
-                                       // Cache Last-Modified header, if ifModified mode.
-                                       var modRes;
-                                       try {
-                                               modRes = xhr.getResponseHeader("Last-Modified");
-                                       } catch(e) {} // swallow exception thrown by FF if header is not available
-
-                                       if ( s.ifModified && modRes )
-                                               jQuery.lastModified[s.url] = modRes;
-
+                               if ( status == "success" || status == "notmodified" ) {
                                        // JSONP handles its own success callback
                                        if ( !jsonp )
                                                success();
@@ -404,7 +401,7 @@ jQuery.extend({
 
                // Send the data
                try {
-                       xhr.send(s.data);
+                       xhr.send( type === "POST" ? s.data : null );
                } catch(e) {
                        jQuery.handleError(s, xhr, null, e);
                }
@@ -465,13 +462,16 @@ jQuery.extend({
 
        // Determines if an XMLHttpRequest returns NotModified
        httpNotModified: function( xhr, url ) {
-               try {
-                       var xhrRes = xhr.getResponseHeader("Last-Modified");
+               var last_modified = xhr.getResponseHeader("Last-Modified");
+               var etag = xhr.getResponseHeader("Etag");
 
-                       // Firefox always returns 200. check Last-Modified date
-                       return xhr.status == 304 || xhrRes == jQuery.lastModified[url];
-               } catch(e){}
-               return false;
+               if (last_modified) 
+                       jQuery.lastModified[url] = last_modified;
+
+               if (etag) 
+                       jQuery.etag[url] = etag;
+
+               return xhr.status == 304;
        },
 
        httpData: function( xhr, type, s ) {
@@ -479,26 +479,34 @@ jQuery.extend({
                        xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
                        data = xml ? xhr.responseXML : xhr.responseText;
 
-               if ( xml && data.documentElement.tagName == "parsererror" )
+               if ( xml && data.documentElement.tagName == "parsererror" ) {
                        throw "parsererror";
-                       
+               }
+
                // Allow a pre-filtering function to sanitize the response
                // s != null is checked to keep backwards compatibility
-               if( s && s.dataFilter )
+               if ( s && s.dataFilter ) {
                        data = s.dataFilter( data, type );
+               }
 
                // The filter can actually parse the response
-               if( typeof data === "string" ){
+               if ( typeof data === "string" ) {
 
                        // If the type is "script", eval it in global context
-                       if ( type == "script" )
+                       if ( type === "script" ) {
                                jQuery.globalEval( data );
+                       }
 
                        // Get the JavaScript object, if JSON is used.
-                       if ( type == "json" )
-                               data = window["eval"]("(" + data + ")");
+                       if ( type == "json" ) {
+                               if ( typeof JSON === "object" && JSON.parse ) {
+                                       data = JSON.parse( data );
+                               } else {
+                                       data = (new Function("return " + data))();
+                               }
+                       }
                }
-               
+
                return data;
        },