Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / data / Connection.js
index a1c2217..1e27240 100644 (file)
@@ -13,7 +13,6 @@ If you are unsure which license is appropriate for your use, please contact the
 
 */
 /**
- * @class Ext.data.Connection
  * The Connection class encapsulates a connection to the page's originating domain, allowing requests to be made either
  * to a configured URL, or to a URL specified at request time.
  *
@@ -21,7 +20,7 @@ If you are unsure which license is appropriate for your use, please contact the
  * to the statement immediately following the {@link #request} call. To process returned data, use a success callback
  * in the request options object, or an {@link #requestcomplete event listener}.
  *
- * <p><u>File Uploads</u></p>
+ * # File Uploads
  *
  * File uploads are not performed using normal "Ajax" techniques, that is they are not performed using XMLHttpRequests.
  * Instead the form is submitted in the standard manner with the DOM &lt;form&gt; element temporarily modified to have its
@@ -32,8 +31,8 @@ If you are unsure which license is appropriate for your use, please contact the
  * send the return object, then the Content-Type header must be set to "text/html" in order to tell the browser to
  * insert the text unchanged into the document body.
  *
- * Characters which are significant to an HTML parser must be sent as HTML entities, so encode "&lt;" as "&amp;lt;", "&amp;" as
- * "&amp;amp;" etc.
+ * Characters which are significant to an HTML parser must be sent as HTML entities, so encode `<` as `&lt;`, `&` as
+ * `&amp;` etc.
  *
  * The response text is retrieved from the document, and a fake XMLHttpRequest object is created containing a
  * responseText property in order to conform to the requirements of event handlers and callbacks.
@@ -60,23 +59,39 @@ Ext.define('Ext.data.Connection', {
     password: '',
 
     /**
-     * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
+     * @cfg {Boolean} disableCaching
+     * True to add a unique cache-buster param to GET requests.
      */
     disableCaching: true,
 
     /**
-     * @cfg {String} disableCachingParam (Optional) Change the parameter which is sent went disabling caching
-     * through a cache buster. Defaults to '_dc'
+     * @cfg {Boolean} withCredentials
+     * True to set `withCredentials = true` on the XHR object
+     */
+    withCredentials: false,
+
+    /**
+     * @cfg {Boolean} cors
+     * True to enable CORS support on the XHR object. Currently the only effect of this option
+     * is to use the XDomainRequest object instead of XMLHttpRequest if the browser is IE8 or above.
+     */
+    cors: false,
+
+    /**
+     * @cfg {String} disableCachingParam
+     * Change the parameter which is sent went disabling caching through a cache buster.
      */
     disableCachingParam: '_dc',
 
     /**
-     * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
+     * @cfg {Number} timeout
+     * The timeout in milliseconds to be used for requests.
      */
     timeout : 30000,
 
     /**
-     * @cfg {Object} extraParams (Optional) Any parameters to be appended to the request.
+     * @cfg {Object} extraParams
+     * Any parameters to be appended to the request.
      */
 
     useDefaultHeader : true,
@@ -92,29 +107,27 @@ Ext.define('Ext.data.Connection', {
             /**
              * @event beforerequest
              * Fires before a network request is made to retrieve a data object.
-             * @param {Connection} conn This Connection object.
+             * @param {Ext.data.Connection} conn This Connection object.
              * @param {Object} options The options config object passed to the {@link #request} method.
              */
             'beforerequest',
             /**
              * @event requestcomplete
              * Fires if the request was successfully completed.
-             * @param {Connection} conn This Connection object.
+             * @param {Ext.data.Connection} conn This Connection object.
              * @param {Object} response The XHR object containing the response data.
-             * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
-             * for details.
+             * See [The XMLHttpRequest Object](http://www.w3.org/TR/XMLHttpRequest/) for details.
              * @param {Object} options The options config object passed to the {@link #request} method.
              */
             'requestcomplete',
             /**
              * @event requestexception
              * Fires if an error HTTP status was returned from the server.
-             * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP Status Code Definitions</a>
+             * See [HTTP Status Code Definitions](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
              * for details of HTTP status codes.
-             * @param {Connection} conn This Connection object.
+             * @param {Ext.data.Connection} conn This Connection object.
              * @param {Object} response The XHR object containing the response data.
-             * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
-             * for details.
+             * See [The XMLHttpRequest Object](http://www.w3.org/TR/XMLHttpRequest/) for details.
              * @param {Object} options The options config object passed to the {@link #request} method.
              */
             'requestexception'
@@ -124,101 +137,112 @@ Ext.define('Ext.data.Connection', {
     },
 
     /**
-     * <p>Sends an HTTP request to a remote server.</p>
-     * <p><b>Important:</b> Ajax server requests are asynchronous, and this call will
+     * Sends an HTTP request to a remote server.
+     *
+     * **Important:** Ajax server requests are asynchronous, and this call will
      * return before the response has been received. Process any returned data
-     * in a callback function.</p>
-     * <pre><code>
-Ext.Ajax.request({
-url: 'ajax_demo/sample.json',
-success: function(response, opts) {
-  var obj = Ext.decode(response.responseText);
-  console.dir(obj);
-},
-failure: function(response, opts) {
-  console.log('server-side failure with status code ' + response.status);
-}
-});
-     * </code></pre>
-     * <p>To execute a callback function in the correct scope, use the <tt>scope</tt> option.</p>
-     * @param {Object} options An object which may contain the following properties:<ul>
-     * <li><b>url</b> : String/Function (Optional)<div class="sub-desc">The URL to
-     * which to send the request, or a function to call which returns a URL string. The scope of the
-     * function is specified by the <tt>scope</tt> option. Defaults to the configured
-     * <tt>{@link #url}</tt>.</div></li>
-     * <li><b>params</b> : Object/String/Function (Optional)<div class="sub-desc">
-     * An object containing properties which are used as parameters to the
-     * request, a url encoded string or a function to call to get either. The scope of the function
-     * is specified by the <tt>scope</tt> option.</div></li>
-     * <li><b>method</b> : String (Optional)<div class="sub-desc">The HTTP method to use
+     * in a callback function.
+     *
+     *     Ext.Ajax.request({
+     *         url: 'ajax_demo/sample.json',
+     *         success: function(response, opts) {
+     *             var obj = Ext.decode(response.responseText);
+     *             console.dir(obj);
+     *         },
+     *         failure: function(response, opts) {
+     *             console.log('server-side failure with status code ' + response.status);
+     *         }
+     *     });
+     *
+     * To execute a callback function in the correct scope, use the `scope` option.
+     *
+     * @param {Object} options An object which may contain the following properties:
+     *
+     * (The options object may also contain any other property which might be needed to perform
+     * postprocessing in a callback because it is passed to callback functions.)
+     *
+     * @param {String/Function} options.url The URL to which to send the request, or a function
+     * to call which returns a URL string. The scope of the function is specified by the `scope` option.
+     * Defaults to the configured `url`.
+     *
+     * @param {Object/String/Function} options.params An object containing properties which are
+     * used as parameters to the request, a url encoded string or a function to call to get either. The scope
+     * of the function is specified by the `scope` option.
+     *
+     * @param {String} options.method The HTTP method to use
      * for the request. Defaults to the configured method, or if no method was configured,
      * "GET" if no parameters are being sent, and "POST" if parameters are being sent.  Note that
-     * the method name is case-sensitive and should be all caps.</div></li>
-     * <li><b>callback</b> : Function (Optional)<div class="sub-desc">The
-     * function to be called upon receipt of the HTTP response. The callback is
-     * called regardless of success or failure and is passed the following
-     * parameters:<ul>
-     * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
-     * <li><b>success</b> : Boolean<div class="sub-desc">True if the request succeeded.</div></li>
-     * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.
-     * See <a href="http://www.w3.org/TR/XMLHttpRequest/">http://www.w3.org/TR/XMLHttpRequest/</a> for details about
-     * accessing elements of the response.</div></li>
-     * </ul></div></li>
-     * <li><a id="request-option-success"></a><b>success</b> : Function (Optional)<div class="sub-desc">The function
-     * to be called upon success of the request. The callback is passed the following
-     * parameters:<ul>
-     * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
-     * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
-     * </ul></div></li>
-     * <li><b>failure</b> : Function (Optional)<div class="sub-desc">The function
-     * to be called upon failure of the request. The callback is passed the
-     * following parameters:<ul>
-     * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
-     * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
-     * </ul></div></li>
-     * <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in
-     * which to execute the callbacks: The "this" object for the callback function. If the <tt>url</tt>, or <tt>params</tt> options were
-     * specified as functions from which to draw values, then this also serves as the scope for those function calls.
-     * Defaults to the browser window.</div></li>
-     * <li><b>timeout</b> : Number (Optional)<div class="sub-desc">The timeout in milliseconds to be used for this request. Defaults to 30 seconds.</div></li>
-     * <li><b>form</b> : Element/HTMLElement/String (Optional)<div class="sub-desc">The <tt>&lt;form&gt;</tt>
-     * Element or the id of the <tt>&lt;form&gt;</tt> to pull parameters from.</div></li>
-     * <li><a id="request-option-isUpload"></a><b>isUpload</b> : Boolean (Optional)<div class="sub-desc"><b>Only meaningful when used
-     * with the <tt>form</tt> option</b>.
-     * <p>True if the form object is a file upload (will be set automatically if the form was
-     * configured with <b><tt>enctype</tt></b> "multipart/form-data").</p>
-     * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
+     * the method name is case-sensitive and should be all caps.
+     *
+     * @param {Function} options.callback The function to be called upon receipt of the HTTP response.
+     * The callback is called regardless of success or failure and is passed the following parameters:
+     * @param {Object} options.callback.options The parameter to the request call.
+     * @param {Boolean} options.callback.success True if the request succeeded.
+     * @param {Object} options.callback.response The XMLHttpRequest object containing the response data.
+     * See [www.w3.org/TR/XMLHttpRequest/](http://www.w3.org/TR/XMLHttpRequest/) for details about
+     * accessing elements of the response.
+     *
+     * @param {Function} options.success The function to be called upon success of the request.
+     * The callback is passed the following parameters:
+     * @param {Object} options.success.response The XMLHttpRequest object containing the response data.
+     * @param {Object} options.success.options The parameter to the request call.
+     *
+     * @param {Function} options.failure The function to be called upon success of the request.
+     * The callback is passed the following parameters:
+     * @param {Object} options.failure.response The XMLHttpRequest object containing the response data.
+     * @param {Object} options.failure.options The parameter to the request call.
+     *
+     * @param {Object} options.scope The scope in which to execute the callbacks: The "this" object for
+     * the callback function. If the `url`, or `params` options were specified as functions from which to
+     * draw values, then this also serves as the scope for those function calls. Defaults to the browser
+     * window.
+     *
+     * @param {Number} options.timeout The timeout in milliseconds to be used for this request.
+     * Defaults to 30 seconds.
+     *
+     * @param {Ext.Element/HTMLElement/String} options.form The `<form>` Element or the id of the `<form>`
+     * to pull parameters from.
+     *
+     * @param {Boolean} options.isUpload **Only meaningful when used with the `form` option.**
+     *
+     * True if the form object is a file upload (will be set automatically if the form was configured
+     * with **`enctype`** `"multipart/form-data"`).
+     *
+     * File uploads are not performed using normal "Ajax" techniques, that is they are **not**
      * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
-     * DOM <tt>&lt;form></tt> element temporarily modified to have its
-     * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
-     * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
-     * but removed after the return data has been gathered.</p>
-     * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
-     * server is using JSON to send the return object, then the
-     * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
-     * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
-     * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
-     * is created containing a <tt>responseText</tt> property in order to conform to the
-     * requirements of event handlers and callbacks.</p>
-     * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
-     * and some server technologies (notably JEE) may require some custom processing in order to
-     * retrieve parameter names and parameter values from the packet content.</p>
-     * </div></li>
-     * <li><b>headers</b> : Object (Optional)<div class="sub-desc">Request
-     * headers to set for the request.</div></li>
-     * <li><b>xmlData</b> : Object (Optional)<div class="sub-desc">XML document
-     * to use for the post. Note: This will be used instead of params for the post
-     * data. Any params will be appended to the URL.</div></li>
-     * <li><b>jsonData</b> : Object/String (Optional)<div class="sub-desc">JSON
-     * data to use as the post. Note: This will be used instead of params for the post
-     * data. Any params will be appended to the URL.</div></li>
-     * <li><b>disableCaching</b> : Boolean (Optional)<div class="sub-desc">True
-     * to add a unique cache-buster param to GET requests.</div></li>
-     * </ul></p>
-     * <p>The options object may also contain any other property which might be needed to perform
-     * postprocessing in a callback because it is passed to callback functions.</p>
-     * @return {Object} request The request object. This may be used
-     * to cancel the request.
+     * DOM `<form>` element temporarily modified to have its [target][] set to refer to a dynamically
+     * generated, hidden `<iframe>` which is inserted into the document but removed after the return data
+     * has been gathered.
+     *
+     * The server response is parsed by the browser to create the document for the IFRAME. If the
+     * server is using JSON to send the return object, then the [Content-Type][] header must be set to
+     * "text/html" in order to tell the browser to insert the text unchanged into the document body.
+     *
+     * The response text is retrieved from the document, and a fake XMLHttpRequest object is created
+     * containing a `responseText` property in order to conform to the requirements of event handlers
+     * and callbacks.
+     *
+     * Be aware that file upload packets are sent with the content type [multipart/form][] and some server
+     * technologies (notably JEE) may require some custom processing in order to retrieve parameter names
+     * and parameter values from the packet content.
+     *
+     * [target]: http://www.w3.org/TR/REC-html40/present/frames.html#adef-target
+     * [Content-Type]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17
+     * [multipart/form]: http://www.faqs.org/rfcs/rfc2388.html
+     *
+     * @param {Object} options.headers Request headers to set for the request.
+     *
+     * @param {Object} options.xmlData XML document to use for the post. Note: This will be used instead
+     * of params for the post data. Any params will be appended to the URL.
+     *
+     * @param {Object/String} options.jsonData JSON data to use as the post. Note: This will be used
+     * instead of params for the post data. Any params will be appended to the URL.
+     *
+     * @param {Boolean} options.disableCaching True to add a unique cache-buster param to GET requests.
+     *
+     * @param {Boolean} options.withCredentials True to add the withCredentials property to the XHR object
+     *
+     * @return {Object} The request object. This may be used to cancel the request.
      */
     request : function(options) {
         options = options || {};
@@ -247,7 +271,12 @@ failure: function(response, opts) {
             }
 
             // create a connection object
-            xhr = this.getXhrInstance();
+
+            if ((options.cors === true || me.cors === true) && Ext.isIe && Ext.ieVersion >= 8) {
+                xhr = new XDomainRequest();
+            } else {
+                xhr = this.getXhrInstance();
+            }
 
             async = options.async !== false ? (options.async || me.async) : false;
 
@@ -258,6 +287,10 @@ failure: function(response, opts) {
                 xhr.open(requestOptions.method, requestOptions.url, async);
             }
 
+            if (options.withCredentials === true || me.withCredentials === true) {
+                xhr.withCredentials = true;
+            }
+
             headers = me.setupHeaders(xhr, options, requestOptions.data, requestOptions.params);
 
             // create the transaction object
@@ -273,7 +306,7 @@ failure: function(response, opts) {
                 }, options.timeout || me.timeout)
             };
             me.requests[request.id] = request;
-
+            me.latestId = request.id;
             // bind our statechange listener
             if (async) {
                 xhr.onreadystatechange = Ext.Function.bind(me.onStateChange, me, [request]);
@@ -292,13 +325,13 @@ failure: function(response, opts) {
     },
 
     /**
-     * Upload a form using a hidden iframe.
-     * @param {Mixed} form The form to upload
+     * Uploads a form using a hidden iframe.
+     * @param {String/HTMLElement/Ext.Element} form The form to upload
      * @param {String} url The url to post to
      * @param {String} params Any extra parameters to pass
      * @param {Object} options The initial options
      */
-    upload: function(form, url, params, options){
+    upload: function(form, url, params, options) {
         form = Ext.getDom(form);
         options = options || {};
 
@@ -364,7 +397,13 @@ failure: function(response, opts) {
         });
     },
 
-    onUploadComplete: function(frame, options){
+    /**
+     * @private
+     * Callback handler for the upload function. After we've submitted the form via the iframe this creates a bogus
+     * response object to simulate an XHR and populates its responseText from the now-loaded iframe's document body
+     * (or a textarea inside the body). We then clean up by removing the iframe
+     */
+    onUploadComplete: function(frame, options) {
         var me = this,
             // bogus response object
             response = {
@@ -373,7 +412,7 @@ failure: function(response, opts) {
             }, doc, firstChild;
 
         try {
-            doc = frame.contentWindow.document || frame.contentDocument || window.frames[id].document;
+            doc = frame.contentWindow.document || frame.contentDocument || window.frames[frame.id].document;
             if (doc) {
                 if (doc.body) {
                     if (/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)) { // json response wrapped in textarea
@@ -399,7 +438,7 @@ failure: function(response, opts) {
     },
 
     /**
-     * Detect whether the form is intended to be used for an upload.
+     * Detects whether the form is intended to be used for an upload.
      * @private
      */
     isFormUpload: function(options){
@@ -411,7 +450,7 @@ failure: function(response, opts) {
     },
 
     /**
-     * Get the form object from options.
+     * Gets the form object from options.
      * @private
      * @param {Object} options The request options
      * @return {HTMLElement} The form, null if not passed
@@ -421,7 +460,7 @@ failure: function(response, opts) {
     },
 
     /**
-     * Set various options such as the url, params for the request
+     * Sets various options such as the url, params for the request
      * @param {Object} options The initial options
      * @param {Object} scope The scope to execute in
      * @return {Object} The params for the request
@@ -511,6 +550,7 @@ failure: function(response, opts) {
 
     /**
      * Template method for overriding url
+     * @template
      * @private
      * @param {Object} options
      * @param {String} url
@@ -527,6 +567,7 @@ failure: function(response, opts) {
 
     /**
      * Template method for overriding params
+     * @template
      * @private
      * @param {Object} options
      * @param {String} params
@@ -536,7 +577,7 @@ failure: function(response, opts) {
         var form = this.getForm(options),
             serializedForm;
         if (form && !this.isFormUpload(options)) {
-            serializedForm = Ext.core.Element.serializeForm(form);
+            serializedForm = Ext.Element.serializeForm(form);
             params = params ? (params + '&' + serializedForm) : serializedForm;
         }
         return params;
@@ -544,6 +585,7 @@ failure: function(response, opts) {
 
     /**
      * Template method for overriding method
+     * @template
      * @private
      * @param {Object} options
      * @param {String} method
@@ -634,11 +676,14 @@ failure: function(response, opts) {
     })(),
 
     /**
-     * Determine whether this object has a request outstanding.
-     * @param {Object} request (Optional) defaults to the last transaction
+     * Determines whether this object has a request outstanding.
+     * @param {Object} [request] Defaults to the last transaction
      * @return {Boolean} True if there is an outstanding request.
      */
     isLoading : function(request) {
+        if (!request) {
+            request = this.getLatest();
+        }
         if (!(request && request.xhr)) {
             return false;
         }
@@ -648,13 +693,15 @@ failure: function(response, opts) {
     },
 
     /**
-     * Aborts any outstanding request.
-     * @param {Object} request (Optional) defaults to the last request
+     * Aborts an active request.
+     * @param {Object} [request] Defaults to the last request
      */
     abort : function(request) {
-        var me = this,
-            requests = me.requests,
-            id;
+        var me = this;
+        
+        if (!request) {
+            request = me.getLatest();
+        }
 
         if (request && me.isLoading(request)) {
             /*
@@ -670,14 +717,37 @@ failure: function(response, opts) {
             }
             me.onComplete(request);
             me.cleanup(request);
-        } else if (!request) {
-            for(id in requests) {
-                if (requests.hasOwnProperty(id)) {
-                    me.abort(requests[id]);
-                }
+        }
+    },
+    
+    /**
+     * Aborts all active requests
+     */
+    abortAll: function(){
+        var requests = this.requests,
+            id;
+        
+        for (id in requests) {
+            if (requests.hasOwnProperty(id)) {
+                this.abort(requests[id]);
             }
         }
     },
+    
+    /**
+     * Gets the most recent request
+     * @private
+     * @return {Object} The request. Null if there is no recent request
+     */
+    getLatest: function(){
+        var id = this.latestId,
+            request;
+            
+        if (id) {
+            request = this.requests[id];
+        }
+        return request || null;
+    },
 
     /**
      * Fires when the state of the xhr changes
@@ -693,7 +763,7 @@ failure: function(response, opts) {
     },
 
     /**
-     * Clear the timeout on the request
+     * Clears the timeout on the request
      * @private
      * @param {Object} The request
      */
@@ -703,7 +773,7 @@ failure: function(response, opts) {
     },
 
     /**
-     * Clean up any left over information from the request
+     * Cleans up any left over information from the request
      * @private
      * @param {Object} The request
      */
@@ -724,14 +794,14 @@ failure: function(response, opts) {
             result,
             success,
             response;
-            
+
         try {
             result = me.parseStatus(request.xhr.status);
         } catch (e) {
             // in some browsers we can't access the status if the readyState is not 4, so the request has failed
             result = {
-                success : false, 
-                isException : false 
+                success : false,
+                isException : false
             };
         }
         success = result.success;
@@ -755,7 +825,7 @@ failure: function(response, opts) {
     },
 
     /**
-     * Check if the response status was successful
+     * Checks if the response status was successful
      * @param {Number} status The status code
      * @return {Object} An object containing success/status state
      */
@@ -785,7 +855,7 @@ failure: function(response, opts) {
     },
 
     /**
-     * Create the response object
+     * Creates the response object
      * @private
      * @param {Object} request
      */
@@ -829,7 +899,7 @@ failure: function(response, opts) {
     },
 
     /**
-     * Create the exception object
+     * Creates the exception object
      * @private
      * @param {Object} request
      */