[OpenLayers-Commits] r7335 - in trunk/openlayers: build lib lib/OpenLayers lib/OpenLayers/Format lib/OpenLayers/Layer lib/OpenLayers/Request lib/OpenLayers/Tile tests tests/Request tests/Tile tests/manual

commits at openlayers.org commits at openlayers.org
Mon Jun 9 15:51:38 EDT 2008


Author: tschaub
Date: 2008-06-09 15:51:38 -0400 (Mon, 09 Jun 2008)
New Revision: 7335

Added:
   trunk/openlayers/lib/OpenLayers/Request.js
   trunk/openlayers/lib/OpenLayers/Request/
   trunk/openlayers/lib/OpenLayers/Request/XMLHttpRequest.js
   trunk/openlayers/tests/Request.html
   trunk/openlayers/tests/Request/
   trunk/openlayers/tests/Request/XMLHttpRequest.html
Modified:
   trunk/openlayers/build/license.txt
   trunk/openlayers/lib/OpenLayers.js
   trunk/openlayers/lib/OpenLayers/Ajax.js
   trunk/openlayers/lib/OpenLayers/Format/KML.js
   trunk/openlayers/lib/OpenLayers/Layer/GML.js
   trunk/openlayers/lib/OpenLayers/Layer/GeoRSS.js
   trunk/openlayers/lib/OpenLayers/Layer/MapGuide.js
   trunk/openlayers/lib/OpenLayers/Layer/Text.js
   trunk/openlayers/lib/OpenLayers/Layer/WFS.js
   trunk/openlayers/lib/OpenLayers/Tile/WFS.js
   trunk/openlayers/tests/Ajax.html
   trunk/openlayers/tests/Tile/WFS.html
   trunk/openlayers/tests/list-tests.html
   trunk/openlayers/tests/manual/ajax.html
Log:
Adding cross-browser XMLHttpRequest functionality and convenience methods around it in the OpenLayers.Request namespace.  Deprecating OpenLayers.Ajax.Request.  Full support sync/async requests using all HTTP verbs now.  r=elemoine (closes #1565)

Modified: trunk/openlayers/build/license.txt
===================================================================
--- trunk/openlayers/build/license.txt	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/build/license.txt	2008-06-09 19:51:38 UTC (rev 7335)
@@ -43,3 +43,12 @@
 *
 **/
 
+/**
+ * Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
+ * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */

Modified: trunk/openlayers/lib/OpenLayers/Ajax.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Ajax.js	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/lib/OpenLayers/Ajax.js	2008-06-09 19:51:38 UTC (rev 7335)
@@ -30,16 +30,18 @@
  */
 
 
-/** 
-* @param {} request
-*/
+/**
+ * Function: OpenLayers.nullHandler
+ * @param {} request
+ */
 OpenLayers.nullHandler = function(request) {
     alert(OpenLayers.i18n("unhandledRequest", {'statusText':request.statusText}));
 };
 
 /** 
  * Function: loadURL
- * Background load a document.
+ * Background load a document.  For more flexibility in using XMLHttpRequest,
+ *     see the <OpenLayers.Request> methods.
  *
  * Parameters:
  * uri - {String} URI of source doc
@@ -49,35 +51,32 @@
  * caller - {Object} object which gets callbacks
  * onComplete - {Function} Optional callback for success.  The callback
  *     will be called with this set to caller and will receive the request
- *     object as an argument.
+ *     object as an argument.  Note that if you do not specify an onComplete
+ *     function, <OpenLayers.nullHandler> will be called (which pops up an
+ *     alert dialog).
  * onFailure - {Function} Optional callback for failure.  In the event of
  *     a failure, the callback will be called with this set to caller and will
- *     receive the request object as an argument.
+ *     receive the request object as an argument.  Note that if you do not
+ *     specify an onComplete function, <OpenLayers.nullHandler> will be called
+ *     (which pops up an alert dialog).
  *
  * Returns:
- * {XMLHttpRequest}  The request object.  To abort loading, call
- *     request.abort().
+ * {<OpenLayers.Request.XMLHttpRequest>}  The request object. To abort loading,
+ *     call request.abort().
  */
 OpenLayers.loadURL = function(uri, params, caller,
                                   onComplete, onFailure) {
-
-    var success = (onComplete) ? OpenLayers.Function.bind(onComplete, caller)
-                                : OpenLayers.nullHandler;
-
-    var failure = (onFailure) ? OpenLayers.Function.bind(onFailure, caller)
-                           : OpenLayers.nullHandler;
-
-    // from prototype.js
-    var request = new OpenLayers.Ajax.Request(
-        uri, 
-        {
-            method: 'get', 
-            parameters: params,
-            onComplete: success, 
-            onFailure: failure
-        }
-    );
-    return request.transport;
+    
+    if(typeof params == 'string') {
+        params = OpenLayers.Util.getParameters(params);
+    }
+    var success = (onComplete) ? onComplete : OpenLayers.nullHandler;
+    var failure = (onFailure) ? onFailure : OpenLayers.nullHandler;
+    
+    return OpenLayers.Request.GET({
+        url: uri, params: params,
+        success: success, failure: failure, scope: caller
+    });
 };
 
 /** 
@@ -263,6 +262,7 @@
 
 /**
  * Class: OpenLayers.Ajax.Request
+ * *Deprecated*.  Use <OpenLayers.Request> method instead.
  *
  * Inherit:
  *  - <OpenLayers.Ajax.Base>

Modified: trunk/openlayers/lib/OpenLayers/Format/KML.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Format/KML.js	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/lib/OpenLayers/Format/KML.js	2008-06-09 19:51:38 UTC (rev 7335)
@@ -249,11 +249,9 @@
      * 
      */
     fetchLink: function(href) {
-        var request = new OpenLayers.Ajax.Request(href, 
-                      {method: 'get', asynchronous: false });
-
-        if (request && request.transport) {
-            return request.transport.responseText;
+        var request = OpenLayers.Request.GET({url: href, async: false});
+        if (request) {
+            return request.responseText;
         }
     },
 

Modified: trunk/openlayers/lib/OpenLayers/Layer/GML.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer/GML.js	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/lib/OpenLayers/Layer/GML.js	2008-06-09 19:51:38 UTC (rev 7335)
@@ -100,7 +100,12 @@
      */
     loadGML: function() {
         if (!this.loaded) {
-            var results = OpenLayers.loadURL(this.url, null, this, this.requestSuccess, this.requestFailure);
+            OpenLayers.Request.GET({
+                url: this.url,
+                success: this.requestSuccess,
+                failure: this.requestFailure,
+                scope: this
+            });
             this.loaded = true;
         }    
     },    

Modified: trunk/openlayers/lib/OpenLayers/Layer/GeoRSS.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer/GeoRSS.js	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/lib/OpenLayers/Layer/GeoRSS.js	2008-06-09 19:51:38 UTC (rev 7335)
@@ -100,7 +100,11 @@
     loadRSS: function() {
         if (!this.loaded) {
             this.events.triggerEvent("loadstart");
-            OpenLayers.loadURL(this.location, null, this, this.parseData);
+            OpenLayers.Request.GET({
+                url: this.location,
+                success: this.parseData,
+                scope: this
+            });
             this.loaded = true;
         }    
     },    
@@ -127,7 +131,7 @@
      * Parse the data returned from the Events call.
      *
      * Parameters:
-     * ajaxRequest - {XMLHttpRequest} 
+     * ajaxRequest - {<OpenLayers.Request.XMLHttpRequest>} 
      */
     parseData: function(ajaxRequest) {
         var doc = ajaxRequest.responseXML;

Modified: trunk/openlayers/lib/OpenLayers/Layer/MapGuide.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer/MapGuide.js	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/lib/OpenLayers/Layer/MapGuide.js	2008-06-09 19:51:38 UTC (rev 7335)
@@ -202,12 +202,10 @@
             getVisParams.mapName = this.params.mapName;
             getVisParams.format = 'text/xml';
             getVisParams = OpenLayers.Util.extend(getVisParams, params);
-                
-            new OpenLayers.Ajax.Request(this.url, 
-                  { parameters: getVisParams,
-                    method: 'get',
-                    asynchronous: false   //must be synchronous call to return control here
-                  });
+            
+            OpenLayers.Request.GET({
+                url: this.url, params: getVisParams, async: false
+            });
           }
           
           //construct the full URL

Modified: trunk/openlayers/lib/OpenLayers/Layer/Text.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer/Text.js	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/lib/OpenLayers/Layer/Text.js	2008-06-09 19:51:38 UTC (rev 7335)
@@ -109,8 +109,12 @@
                 };
 
                 this.events.triggerEvent("loadstart");
-                OpenLayers.loadURL(this.location, null, 
-                                   this, this.parseData, onFail);
+                OpenLayers.Request.GET({
+                    url: this.location,
+                    success: this.parseData,
+                    failure: onFail,
+                    scope: this
+                });
                 this.loaded = true;
             }
         }    
@@ -137,7 +141,7 @@
      * Method: parseData
      *
      * Parameters:
-     * ajaxRequest - {XMLHttpRequest} 
+     * ajaxRequest - {<OpenLayers.Request.XMLHttpRequest>} 
      */
     parseData: function(ajaxRequest) {
         var text = ajaxRequest.responseText;

Modified: trunk/openlayers/lib/OpenLayers/Layer/WFS.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer/WFS.js	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/lib/OpenLayers/Layer/WFS.js	2008-06-09 19:51:38 UTC (rev 7335)
@@ -455,21 +455,14 @@
         }
 
         var data = this.writer.write(this.features);
-        
-        var url = this.url;
 
-        var success = OpenLayers.Function.bind(this.commitSuccess, this);
-
-        var failure = OpenLayers.Function.bind(this.commitFailure, this);
-        
-        // from prototype.js
-        new OpenLayers.Ajax.Request(url, 
-                         {   method: 'post', 
-                             postBody: data,
-                             onComplete: success, 
-                             onFailure: failure
-                          }
-                         );
+        OpenLayers.Request.POST({
+            url: this.url,
+            data: data,
+            success: this.commitSuccess,
+            failure: this.commitFailure,
+            scope: this
+        });
     },
 
     /**

Added: trunk/openlayers/lib/OpenLayers/Request/XMLHttpRequest.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Request/XMLHttpRequest.js	                        (rev 0)
+++ trunk/openlayers/lib/OpenLayers/Request/XMLHttpRequest.js	2008-06-09 19:51:38 UTC (rev 7335)
@@ -0,0 +1,313 @@
+// Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @requires OpenLayers/Request.js
+ */
+
+(function () {
+
+    // Save reference to earlier defined object implementation (if any)
+    var oXMLHttpRequest    = window.XMLHttpRequest;
+
+    // Define on browser type
+    var bGecko    = !!window.controllers,
+        bIE        = window.document.all && !window.opera;
+
+    // Constructor
+    function cXMLHttpRequest() {
+        this._object    = oXMLHttpRequest ? new oXMLHttpRequest : new window.ActiveXObject('Microsoft.XMLHTTP');
+    };
+
+    // BUGFIX: Firefox with Firebug installed would break pages if not executed
+    if (bGecko && oXMLHttpRequest.wrapped)
+        cXMLHttpRequest.wrapped    = oXMLHttpRequest.wrapped;
+
+    // Constants
+    cXMLHttpRequest.UNSENT                = 0;
+    cXMLHttpRequest.OPENED                = 1;
+    cXMLHttpRequest.HEADERS_RECEIVED    = 2;
+    cXMLHttpRequest.LOADING                = 3;
+    cXMLHttpRequest.DONE                = 4;
+
+    // Public Properties
+    cXMLHttpRequest.prototype.readyState    = cXMLHttpRequest.UNSENT;
+    cXMLHttpRequest.prototype.responseText    = "";
+    cXMLHttpRequest.prototype.responseXML    = null;
+    cXMLHttpRequest.prototype.status        = 0;
+    cXMLHttpRequest.prototype.statusText    = "";
+
+    // Instance-level Events Handlers
+    cXMLHttpRequest.prototype.onreadystatechange    = null;
+
+    // Class-level Events Handlers
+    cXMLHttpRequest.onreadystatechange    = null;
+    cXMLHttpRequest.onopen                = null;
+    cXMLHttpRequest.onsend                = null;
+    cXMLHttpRequest.onabort                = null;
+
+    // Public Methods
+    cXMLHttpRequest.prototype.open    = function(sMethod, sUrl, bAsync, sUser, sPassword) {
+
+        // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests
+        this._async        = bAsync;
+
+        // Set the onreadystatechange handler
+        var oRequest    = this,
+            nState        = this.readyState;
+
+        // BUGFIX: IE - memory leak on page unload (inter-page leak)
+        if (bIE) {
+            var fOnUnload    = function() {
+                if (oRequest._object.readyState != cXMLHttpRequest.DONE)
+                    fCleanTransport(oRequest);
+            };
+            if (bAsync)
+                window.attachEvent("onunload", fOnUnload);
+        }
+
+        this._object.onreadystatechange    = function() {
+            if (bGecko && !bAsync)
+                return;
+
+            // Synchronize state
+            oRequest.readyState        = oRequest._object.readyState;
+
+            //
+            fSynchronizeValues(oRequest);
+
+            // BUGFIX: Firefox fires unneccesary DONE when aborting
+            if (oRequest._aborted) {
+                // Reset readyState to UNSENT
+                oRequest.readyState    = cXMLHttpRequest.UNSENT;
+
+                // Return now
+                return;
+            }
+
+            if (oRequest.readyState == cXMLHttpRequest.DONE) {
+                //
+                fCleanTransport(oRequest);
+// Uncomment this block if you need a fix for IE cache
+/*
+                // BUGFIX: IE - cache issue
+                if (!oRequest._object.getResponseHeader("Date")) {
+                    // Save object to cache
+                    oRequest._cached    = oRequest._object;
+
+                    // Instantiate a new transport object
+                    cXMLHttpRequest.call(oRequest);
+
+                    // Re-send request
+                    oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
+                    oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0));
+                    // Copy headers set
+                    if (oRequest._headers)
+                        for (var sHeader in oRequest._headers)
+                            if (typeof oRequest._headers[sHeader] == "string")    // Some frameworks prototype objects with functions
+                                oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);
+
+                    oRequest._object.onreadystatechange    = function() {
+                        // Synchronize state
+                        oRequest.readyState        = oRequest._object.readyState;
+
+                        if (oRequest._aborted) {
+                            //
+                            oRequest.readyState    = cXMLHttpRequest.UNSENT;
+
+                            // Return
+                            return;
+                        }
+
+                        if (oRequest.readyState == cXMLHttpRequest.DONE) {
+                            // Clean Object
+                            fCleanTransport(oRequest);
+
+                            // get cached request
+                            if (oRequest.status == 304)
+                                oRequest._object    = oRequest._cached;
+
+                            //
+                            delete oRequest._cached;
+
+                            //
+                            fSynchronizeValues(oRequest);
+
+                            //
+                            fReadyStateChange(oRequest);
+
+                            // BUGFIX: IE - memory leak in interrupted
+                            if (bIE && bAsync)
+                                window.detachEvent("onunload", fOnUnload);
+                        }
+                    };
+                    oRequest._object.send(null);
+
+                    // Return now - wait untill re-sent request is finished
+                    return;
+                };
+*/
+                // BUGFIX: IE - memory leak in interrupted
+                if (bIE && bAsync)
+                    window.detachEvent("onunload", fOnUnload);
+            }
+
+            // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice
+            if (nState != oRequest.readyState)
+                fReadyStateChange(oRequest);
+
+            nState    = oRequest.readyState;
+        };
+
+        // Add method sniffer
+        if (cXMLHttpRequest.onopen)
+            cXMLHttpRequest.onopen.apply(this, arguments);
+
+        this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
+
+        // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
+        if (!bAsync && bGecko) {
+            this.readyState    = cXMLHttpRequest.OPENED;
+
+            fReadyStateChange(this);
+        }
+    };
+    cXMLHttpRequest.prototype.send    = function(vData) {
+        // Add method sniffer
+        if (cXMLHttpRequest.onsend)
+            cXMLHttpRequest.onsend.apply(this, arguments);
+
+        // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required
+        // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent
+        // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)
+        if (vData && vData.nodeType) {
+            vData    = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;
+            if (!this._headers["Content-Type"])
+                this._object.setRequestHeader("Content-Type", "application/xml");
+        }
+
+        this._object.send(vData);
+
+        // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
+        if (bGecko && !this._async) {
+            this.readyState    = cXMLHttpRequest.OPENED;
+
+            // Synchronize state
+            fSynchronizeValues(this);
+
+            // Simulate missing states
+            while (this.readyState < cXMLHttpRequest.DONE) {
+                this.readyState++;
+                fReadyStateChange(this);
+                // Check if we are aborted
+                if (this._aborted)
+                    return;
+            }
+        }
+    };
+    cXMLHttpRequest.prototype.abort    = function() {
+        // Add method sniffer
+        if (cXMLHttpRequest.onabort)
+            cXMLHttpRequest.onabort.apply(this, arguments);
+
+        // BUGFIX: Gecko - unneccesary DONE when aborting
+        if (this.readyState > cXMLHttpRequest.UNSENT)
+            this._aborted    = true;
+
+        this._object.abort();
+
+        // BUGFIX: IE - memory leak
+        fCleanTransport(this);
+    };
+    cXMLHttpRequest.prototype.getAllResponseHeaders    = function() {
+        return this._object.getAllResponseHeaders();
+    };
+    cXMLHttpRequest.prototype.getResponseHeader    = function(sName) {
+        return this._object.getResponseHeader(sName);
+    };
+    cXMLHttpRequest.prototype.setRequestHeader    = function(sName, sValue) {
+        // BUGFIX: IE - cache issue
+        if (!this._headers)
+            this._headers    = {};
+        this._headers[sName]    = sValue;
+
+        return this._object.setRequestHeader(sName, sValue);
+    };
+    cXMLHttpRequest.prototype.toString    = function() {
+        return '[' + "object" + ' ' + "XMLHttpRequest" + ']';
+    };
+    cXMLHttpRequest.toString    = function() {
+        return '[' + "XMLHttpRequest" + ']';
+    };
+
+    // Helper function
+    function fReadyStateChange(oRequest) {
+        // Execute onreadystatechange
+        if (oRequest.onreadystatechange)
+            oRequest.onreadystatechange.apply(oRequest);
+
+        // Sniffing code
+        if (cXMLHttpRequest.onreadystatechange)
+            cXMLHttpRequest.onreadystatechange.apply(oRequest);
+    };
+
+    function fGetDocument(oRequest) {
+        var oDocument    = oRequest.responseXML;
+        // Try parsing responseText
+        if (bIE && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) {
+            oDocument    = new ActiveXObject('Microsoft.XMLDOM');
+            oDocument.loadXML(oRequest.responseText);
+        }
+        // Check if there is no error in document
+        if (oDocument)
+            if ((bIE && oDocument.parseError != 0) || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror"))
+                return null;
+        return oDocument;
+    };
+
+    function fSynchronizeValues(oRequest) {
+        try {    oRequest.responseText    = oRequest._object.responseText;    } catch (e) {}
+        try {    oRequest.responseXML    = fGetDocument(oRequest._object);    } catch (e) {}
+        try {    oRequest.status            = oRequest._object.status;            } catch (e) {}
+        try {    oRequest.statusText        = oRequest._object.statusText;        } catch (e) {}
+    };
+
+    function fCleanTransport(oRequest) {
+        // BUGFIX: IE - memory leak (on-page leak)
+        oRequest._object.onreadystatechange    = new window.Function;
+
+        // Delete private properties
+        delete oRequest._headers;
+    };
+
+    // Internet Explorer 5.0 (missing apply)
+    if (!window.Function.prototype.apply) {
+        window.Function.prototype.apply    = function(oRequest, oArguments) {
+            if (!oArguments)
+                oArguments    = [];
+            oRequest.__func    = this;
+            oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
+            delete oRequest.__func;
+        };
+    };
+
+    // Register new object with window
+    /**
+     * Class: OpenLayers.Request.XMLHttpRequest
+     * Standard-compliant (W3C) cross-browser implementation of the
+     *     XMLHttpRequest object.  From
+     *     http://code.google.com/p/xmlhttprequest/.
+     */
+    OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;
+})();
\ No newline at end of file

Added: trunk/openlayers/lib/OpenLayers/Request.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Request.js	                        (rev 0)
+++ trunk/openlayers/lib/OpenLayers/Request.js	2008-06-09 19:51:38 UTC (rev 7335)
@@ -0,0 +1,266 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Namespace: OpenLayers.Request
+ * The OpenLayers.Request namespace contains convenience methods for working
+ *     with XMLHttpRequests.  These methods work with a cross-browser
+ *     W3C compliant <OpenLayers.Request.XMLHttpRequest> class.
+ */
+OpenLayers.Request = {
+    
+    /**
+     * Constant: DEFAULT_CONFIG
+     * {Object} Default configuration for all requests.
+     */
+    DEFAULT_CONFIG: {
+        method: "GET",
+        url: window.location.href,
+        async: true,
+        user: undefined,
+        password: undefined,
+        params: null,
+        proxy: OpenLayers.ProxyHost,
+        headers: {},
+        data: null,
+        callback: function() {},
+        success: null,
+        failure: null,
+        scope: null
+    },
+    
+    /**
+     * APIMethod: issue
+     * Create a new XMLHttpRequest object, open it, set any headers, bind
+     *     a callback to done state, and send any data.
+     *
+     * Parameters:
+     * config - {Object} Object containing properties for configuring the
+     *     request.  Allowed configuration properties are described below.
+     *     This object is modified and should not be reused.
+     *
+     * Allowed config properties:
+     * method - {String} One of GET, POST, PUT, DELETE, HEAD, or
+     *     OPTIONS.  Default is GET.
+     * url - {String} URL for the request.
+     * async - {Boolean} Open an asynchronous request.  Default is true.
+     * user - {String} User for relevant authentication scheme.  Set
+     *     to null to clear current user.
+     * password - {String} Password for relevant authentication scheme.
+     *     Set to null to clear current password.
+     * proxy - {String} Optional proxy.  Defaults to
+     *     <OpenLayers.ProxyHost>.
+     * params - {Object} Any key:value pairs to be appended to the
+     *     url as a query string.  Assumes url doesn't already include a query
+     *     string or hash.  Parameter values that are arrays will be
+     *     concatenated with a comma (note that this goes against form-encoding)
+     *     as is done with <OpenLayers.Util.getParameterString>.
+     * headers - {Object} Object with header:value pairs to be set on
+     *     the request.
+     * data - {Object} Any data to send with the request.
+     * callback - {Function} Function to call when request is done.
+     *     To determine if the request failed, check request.status (200
+     *     indicates success).
+     * success - {Function} Optional function to call if request status is in
+     *     the 200s.  This will be called in addition to callback above and
+     *     would typically only be used as an alternative.
+     * failure - {Function} Optional function to call if request status is not
+     *     in the 200s.  This will be called in addition to callback above and
+     *     would typically only be used as an alternative.
+     * scope - {Object} If callback is a public method on some object,
+     *     set the scope to that object.
+     *
+     * Returns:
+     * {XMLHttpRequest} Request object.  To abort the request before a response
+     *     is received, call abort() on the request object.
+     */
+    issue: function(config) {        
+        // apply default config - proxy host may have changed
+        var defaultConfig = OpenLayers.Util.extend(
+            this.DEFAULT_CONFIG,
+            {proxy: OpenLayers.ProxyHost}
+        );
+        config = OpenLayers.Util.applyDefaults(config, defaultConfig);
+
+        // create request, open, and set headers
+        var request = new OpenLayers.Request.XMLHttpRequest();
+        var url = config.url;
+        if(config.params) {
+            url += "?" + OpenLayers.Util.getParameterString(config.params);
+        }
+        if(config.proxy && (url.indexOf("http") == 0)) {
+            url = config.proxy + encodeURIComponent(url);
+        }
+        request.open(
+            config.method, url, config.async, config.user, config.password
+        );
+        for(var header in config.headers) {
+            request.setRequestHeader(header, config.headers[header]);
+        }
+
+        // bind callbacks to readyState 4 (done)
+        var complete = (config.scope) ?
+            OpenLayers.Function.bind(config.callback, config.scope) :
+            config.callback;
+        
+        // optional success callback
+        var success;
+        if(config.success) {
+            success = (config.scope) ?
+                OpenLayers.Function.bind(config.success, config.scope) :
+                config.success;
+        }
+
+        // optional failure callback
+        var failure;
+        if(config.failure) {
+            failure = (config.scope) ?
+                OpenLayers.Function.bind(config.failure, config.scope) :
+                config.failure;
+        }
+         
+        request.onreadystatechange = function() {
+            if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
+                complete(request);
+                if(success && request.status >= 200 && request.status < 300) {
+                    success(request);
+                }
+                if(failure && (request.status < 200 || request.status >= 300)) {
+                    failure(request);
+                }
+            }
+        }
+        
+        // send request (optionally with data) and return
+        request.send(config.data);
+        return request;
+    },
+    
+    /**
+     * APIMethod: GET
+     * Send an HTTP GET request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to GET.
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.
+     *     This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    GET: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "GET"});
+        return OpenLayers.Request.issue(config);
+    },
+    
+    /**
+     * APIMethod: POST
+     * Send a POST request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to POST and "Content-Type" header set to "application/xml".
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.  The
+     *     default "Content-Type" header will be set to "application-xml" if
+     *     none is provided.  This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    POST: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "POST"});
+        // set content type to application/xml if it isn't already set
+        config.headers = config.headers ? config.headers : {};
+        if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
+            config.headers["Content-Type"] = "application/xml";
+        }
+        return OpenLayers.Request.issue(config);
+    },
+    
+    /**
+     * APIMethod: PUT
+     * Send an HTTP PUT request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to PUT and "Content-Type" header set to "application/xml".
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.  The
+     *     default "Content-Type" header will be set to "application-xml" if
+     *     none is provided.  This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    PUT: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "PUT"});
+        // set content type to application/xml if it isn't already set
+        config.headers = config.headers ? config.headers : {};
+        if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
+            config.headers["Content-Type"] = "application/xml";
+        }
+        return OpenLayers.Request.issue(config);
+    },
+    
+    /**
+     * APIMethod: DELETE
+     * Send an HTTP DELETE request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to DELETE.
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.
+     *     This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    DELETE: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "DELETE"});
+        return OpenLayers.Request.issue(config);
+    },
+  
+    /**
+     * APIMethod: HEAD
+     * Send an HTTP HEAD request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to HEAD.
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.
+     *     This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    HEAD: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "HEAD"});
+        return OpenLayers.Request.issue(config);
+    },
+    
+    /**
+     * APIMethod: OPTIONS
+     * Send an HTTP OPTIONS request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to OPTIONS.
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.
+     *     This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    OPTIONS: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "OPTIONS"});
+        return OpenLayers.Request.issue(config);
+    }
+
+};
\ No newline at end of file

Modified: trunk/openlayers/lib/OpenLayers/Tile/WFS.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Tile/WFS.js	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/lib/OpenLayers/Tile/WFS.js	2008-06-09 19:51:38 UTC (rev 7335)
@@ -32,7 +32,7 @@
     
     /** 
      * Property: request 
-     * {OpenLayers.Ajax.Request} 
+     * {<OpenLayers.Request.XMLHttpRequest>} 
      */ 
     request: null,     
     
@@ -100,8 +100,7 @@
 
     /** 
     * Method: loadFeaturesForRegion
-    * get the full request string from the ds and the tile params 
-    *     and call the AJAX loadURL(). 
+    * Abort any pending requests and issue another request for data. 
     *
     * Input are function pointers for what to do on success and failure.
     *
@@ -113,7 +112,12 @@
         if(this.request) {
             this.request.abort();
         }
-        this.request = OpenLayers.loadURL(this.url, null, this, success);
+        this.request = OpenLayers.Request.GET({
+            url: this.url,
+            success: success,
+            failure: failure,
+            scope: this
+        });
     },
     
     /**
@@ -122,7 +126,7 @@
     * layer.addFeatures in vector mode, addResults otherwise. 
     *
     * Parameters:
-    * request - {XMLHttpRequest}
+    * request - {<OpenLayers.Request.XMLHttpRequest>}
     */
     requestSuccess:function(request) {
         if (this.features) {

Modified: trunk/openlayers/lib/OpenLayers.js
===================================================================
--- trunk/openlayers/lib/OpenLayers.js	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/lib/OpenLayers.js	2008-06-09 19:51:38 UTC (rev 7335)
@@ -84,6 +84,8 @@
             "Rico/Corner.js",
             "Rico/Color.js",
             "OpenLayers/Ajax.js",
+            "OpenLayers/Request.js",
+            "OpenLayers/Request/XMLHttpRequest.js",
             "OpenLayers/Events.js",
             "OpenLayers/Projection.js",
             "OpenLayers/Map.js",

Modified: trunk/openlayers/tests/Ajax.html
===================================================================
--- trunk/openlayers/tests/Ajax.html	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/tests/Ajax.html	2008-06-09 19:51:38 UTC (rev 7335)
@@ -4,13 +4,21 @@
   <script type="text/javascript">
 
     function test_Ajax_loadUrl(t) {
-        t.plan(1);
-        var req = OpenLayers.Ajax.Request;
-        OpenLayers.ProxyHost = "/?url=";
-        OpenLayers.Ajax.Request.prototype.request = function(uri) {
-            t.eq(uri, "/?url=http%3A%2F%2Fexample.com%2F%3Fformat%3Dimage%2Bkml", "URI matches what we expect from loadurl");
-        }
-        OpenLayers.loadURL("http://example.com/?format=image+kml");
+        t.plan(5);
+        var _get = OpenLayers.Request.GET;
+        var caller = {};
+        var onComplete = function() {};
+        var onFailure = function() {};
+        var params = {};
+        OpenLayers.Request.GET = function(config) {
+            t.eq(config.url, "http://example.com/?format=image+kml", "correct url")
+            t.eq(config.params, params, "correct params");
+            t.eq(config.scope, caller, "correct scope");
+            t.ok(config.success === onComplete, "correct success callback");
+            t.ok(config.failure === onFailure, "correct failure callback");
+        };
+        OpenLayers.loadURL("http://example.com/?format=image+kml", params, caller, onComplete, onFailure);
+        OpenLayers.Request.GET = _get;
     }
   </script>
 </head>

Added: trunk/openlayers/tests/Request/XMLHttpRequest.html
===================================================================
--- trunk/openlayers/tests/Request/XMLHttpRequest.html	                        (rev 0)
+++ trunk/openlayers/tests/Request/XMLHttpRequest.html	2008-06-09 19:51:38 UTC (rev 7335)
@@ -0,0 +1,14 @@
+<html>
+<head>
+    <script src="../../lib/OpenLayers.js"></script>
+    <script type="text/javascript">
+        function test_constructor(t) {
+            t.plan(1);
+            t.ok(new OpenLayers.Request.XMLHttpRequest(),
+                 "constructor didn't fail and we trust the code is well tested in OpenLayers.Request methods");
+        }
+    </script>
+</head>
+<body>
+</body>
+</html>

Added: trunk/openlayers/tests/Request.html
===================================================================
--- trunk/openlayers/tests/Request.html	                        (rev 0)
+++ trunk/openlayers/tests/Request.html	2008-06-09 19:51:38 UTC (rev 7335)
@@ -0,0 +1,205 @@
+<html>
+<head>
+    <script src="../lib/OpenLayers.js"></script>
+    <script type="text/javascript">
+    function setup() {
+        window._xhr = OpenLayers.Request.XMLHttpRequest;
+        var anon = new Function();
+        OpenLayers.Request.XMLHttpRequest = function() {};
+        OpenLayers.Request.XMLHttpRequest.prototype = {
+            open: anon,
+            setRequestHeader: anon,
+            send: anon
+        };
+        OpenLayers.Request.XMLHttpRequest.DONE = 4;
+    }
+    function teardown() {
+        OpenLayers.Request.XMLHttpRequest = window._xhr;
+        delete window._xhr;
+    }
+    
+    function test_issue(t) {
+        setup();
+
+        t.plan(18);
+        var request, config;
+        var proto = OpenLayers.Request.XMLHttpRequest.prototype;
+        var issue = OpenLayers.Function.bind(OpenLayers.Request.issue,
+                                             OpenLayers.Request);
+
+        // test that issue returns a new XMLHttpRequest - 1 test
+        request = issue();
+        t.ok(request instanceof OpenLayers.Request.XMLHttpRequest,
+             "returns an XMLHttpRequest instance");
+        
+        // test that issue calls xhr.open with correct args from config - 5 tests
+        var _open = proto.open;
+        config = {
+            method: "foo",
+            url: "http://nowhere",
+            async: "bar",
+            user: "uncle",
+            password: "sam"
+        };
+        proto.open = function(method, url, async, user, password) {
+            t.eq(method, config.method, "open called with correct method");
+            t.eq(url, config.url, "open called with correct url");
+            t.eq(async, config.async, "open called with correct async");
+            t.eq(user, config.user, "open called with correct user");
+            t.eq(password, config.password, "open called with correct password");
+        }
+        request = issue(config);
+        proto.open = _open;
+        
+        // test that headers are correctly set - 4 tests
+        var _setRequestHeader = proto.setRequestHeader;
+        config = {
+            headers: {
+                foo: "bar",
+                chicken: "soup"
+            }
+        };
+        proto.setRequestHeader = function(key, value) {
+            t.ok(key in config.headers, "setRequestHeader called with key: " + key);
+            t.eq(value, config.headers[key], "setRequestHeader called with correct value: " + value);
+        }
+        request = issue(config);
+        proto.setRequestHeader = _setRequestHeader;
+        
+        // test that callback is called (no scope) - 1 test
+        var unbound = function(request) {
+            t.ok(request instanceof OpenLayers.Request.XMLHttpRequest,
+                 "unbound callback called with xhr instance");
+        }
+        config = {
+            callback: unbound
+        };
+        request = issue(config);
+        request.readyState = OpenLayers.Request.XMLHttpRequest.DONE;
+        request.onreadystatechange();
+
+        // test that callback is called (with scope) - 2 tests
+        var obj = {};
+        var bound = function(request) {
+            t.ok(this === obj, "bound callback has correct scope");
+            t.ok(request instanceof OpenLayers.Request.XMLHttpRequest,
+                 "bound callback called with xhr instance");
+        }
+        config = {
+            callback: bound,
+            scope: obj
+        };
+        request = issue(config);
+        request.readyState = 4;
+        request.onreadystatechange();
+
+        // test that send is called with data - 1 test
+        var _send = proto.send;
+        config = {
+            method: "PUT",
+            data: "bling"
+        };
+        proto.send = function(data) {
+            t.eq(data, config.data, "send called with correct data");
+        }
+        request = issue(config);
+        proto.send = _send;
+        
+        // test that optional success callback is only called with 200s and
+        // failure is only called with non-200s
+        var _send = proto.send;
+        proto.send = function() {};
+        
+        config = {
+            success: function(req) {
+                t.ok(req.status >= 200 && req.status < 300,
+                     "success callback called with " + req.status + " status");
+            },
+            failure: function(req) {
+                t.ok(req.status < 200 || req.status >= 300,
+                     "failure callback called with " + req.status + " status");
+            }
+        };
+        request = issue(config);
+        request.readyState = 4;
+        
+        // mock up status 200 (1 test)
+        request.status = 200;
+        request.onreadystatechange();
+        
+        // mock up status 299 (1 test)
+        request.status = 299;
+        request.onreadystatechange();
+        
+        // mock up status 100 (1 test)
+        request.status = 100;
+        request.onreadystatechange();
+
+        // mock up status 300 (1 test)
+        request.status = 300;
+        request.onreadystatechange();
+
+        proto.send = _send;
+
+        teardown();
+    }
+    
+    function test_GET(t) {
+        t.plan(1);
+        var _issue = OpenLayers.Request.issue;
+        OpenLayers.Request.issue = function(config) {
+            t.eq(config.method, "GET", "calls issue with correct method");
+        }
+        OpenLayers.Request.GET();
+        OpenLayers.Request.issue = _issue;
+    }
+    function test_POST(t) {
+        t.plan(1);
+        var _issue = OpenLayers.Request.issue;
+        OpenLayers.Request.issue = function(config) {
+            t.eq(config.method, "POST", "calls issue with correct method");
+        }
+        OpenLayers.Request.POST();
+        OpenLayers.Request.issue = _issue;
+    }
+    function test_PUT(t) {
+        t.plan(1);
+        var _issue = OpenLayers.Request.issue;
+        OpenLayers.Request.issue = function(config) {
+            t.eq(config.method, "PUT", "calls issue with correct method");
+        }
+        OpenLayers.Request.PUT();
+        OpenLayers.Request.issue = _issue;
+    }
+    function test_DELETE(t) {
+        t.plan(1);
+        var _issue = OpenLayers.Request.issue;
+        OpenLayers.Request.issue = function(config) {
+            t.eq(config.method, "DELETE", "calls issue with correct method");
+        }
+        OpenLayers.Request.DELETE();
+        OpenLayers.Request.issue = _issue;
+    }
+    function test_HEAD(t) {
+        t.plan(1);
+        var _issue = OpenLayers.Request.issue;
+        OpenLayers.Request.issue = function(config) {
+            t.eq(config.method, "HEAD", "calls issue with correct method");
+        }
+        OpenLayers.Request.HEAD();
+        OpenLayers.Request.issue = _issue;
+    }
+    function test_OPTIONS(t) {
+        t.plan(1);
+        var _issue = OpenLayers.Request.issue;
+        OpenLayers.Request.issue = function(config) {
+            t.eq(config.method, "OPTIONS", "calls issue with correct method");
+        }
+        OpenLayers.Request.OPTIONS();
+        OpenLayers.Request.issue = _issue;
+    }
+    </script>
+</head>
+<body>
+</body>
+</html>

Modified: trunk/openlayers/tests/Tile/WFS.html
===================================================================
--- trunk/openlayers/tests/Tile/WFS.html	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/tests/Tile/WFS.html	2008-06-09 19:51:38 UTC (rev 7335)
@@ -64,12 +64,12 @@
 
         var g_Success = {};        
 
-        var tLoadURL = OpenLayers.loadURL;
-        OpenLayers.loadURL = function(url, params, caller, onComplete) {
-            t.ok(url == tile.url, "tile's url correctly passed as 1st param to loadURL");
-            t.ok(params == null, "null passed as 2nd param to loadURL");
-            t.ok(caller == tile, "tile passed as 3rd param to loadURL");
-            t.ok(onComplete == g_Success, "success param from loadFeaturesForRegion() passed as 4th param to loadURL");
+        var _get = OpenLayers.Request.GET;
+        OpenLayers.Request.GET = function(config) {
+            t.ok(config.url == tile.url, "tile's url correctly passed");
+            t.ok(config.params == null, "null params");
+            t.ok(config.scope == tile, "tile passed as scope");
+            t.ok(config.success == g_Success, "success passed");
         };
         
       //no running request -- 4 tests
@@ -82,8 +82,8 @@
             }
         };
         OpenLayers.Tile.WFS.prototype.loadFeaturesForRegion.apply(tile, [g_Success]);
-                
-        OpenLayers.loadURL = tLoadURL;
+
+        OpenLayers.Request.GET = _get;
     }
     
     function test_Tile_WFS_destroy(t) {

Modified: trunk/openlayers/tests/list-tests.html
===================================================================
--- trunk/openlayers/tests/list-tests.html	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/tests/list-tests.html	2008-06-09 19:51:38 UTC (rev 7335)
@@ -57,6 +57,8 @@
     <li>Lang.html</li>
     <li>Layer.html</li>
     <li>Renderer.html</li>
+    <li>Request.html</li>
+    <li>Request/XMLHttpRequest.html</li>
     <li>Layer/EventPane.html</li>
     <li>Layer/FixedZoomLevels.html</li>
     <li>Layer/GeoRSS.html</li>

Modified: trunk/openlayers/tests/manual/ajax.html
===================================================================
--- trunk/openlayers/tests/manual/ajax.html	2008-06-09 19:11:03 UTC (rev 7334)
+++ trunk/openlayers/tests/manual/ajax.html	2008-06-09 19:51:38 UTC (rev 7335)
@@ -1,70 +1,49 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
-    <title>Ajax Acceptance Test</title>
-    <style type="text/css">
-    
-        body {
-            font-size: 0.8em;
-        }
-        p {
-            padding-top: 1em;
-        }
-        
-        .buttons {
-            margin: 1em;
-            float: left;
-        }
-
-    </style>
-
+    <title>XHR Acceptance Test</title>
     <script src="../../lib/OpenLayers.js"></script>
     <script type="text/javascript">
         var url = "ajax.txt";
         function sendSynchronous(){
-            var request = new OpenLayers.Ajax.Request(url, {
-               'asynchronous': false,
-                onComplete: function() {
+            var request = OpenLayers.Request.GET({
+                url: url,
+                async: false,
+                callback: function() {
                     document.getElementById('send_sync').value += 'request completed\n';
                 }
             });
             document.getElementById('send_sync').value += 'other processing\n';
         }
         function sendAsynchronous(){
-            var request = new OpenLayers.Ajax.Request(url, {
-                onComplete: function() {
+            var request = OpenLayers.Request.GET({
+                url: url,
+                callback: function() {
                     document.getElementById('send_sync').value += 'request completed\n';
                 }
             });
             document.getElementById('send_sync').value += 'other processing\n';
         }
         function sendAndAbort(){
-            var request = new OpenLayers.Ajax.Request(url, {
-                onComplete: function(request) {
-                    if (request.responseText == '') {
-                        document.getElementById('send_sync').value += 'request aborted\n';
-                    }
+            var request = OpenLayers.Request.GET({
+                url: url,
+                callback: function() {
+                    document.getElementById('send_sync').value += 'never called\n';
                 }
             });
-            request.transport.abort();
+            request.abort();
             document.getElementById('send_sync').value += 'other processing\n';
         }
 
-    </script>
-  </head>
-  <body >
-    <div class="buttons">
-        <button onclick="sendSynchronous()">Send an synchronous Ajax request</button><br />
-        <button onclick="sendAsynchronous()">Send an asynchronous Ajax request</button><br />
-        <button onclick="sendAndAbort()">Send a request and abort it</button><br />
+        </script>
+    </head>
+    <body >
+        <button onclick="sendSynchronous()">synchronous</button>
+        expected output: "request completed" then "other processing"<br />
+        <button onclick="sendAsynchronous()">asynchronous</button>
+        expected output: "other processing" then "request completed"<br />
+        <button onclick="sendAndAbort()">send and abort</button>
+        expected output: "other processing" (and not "never called")<br />
         <textarea id="send_sync" rows="6"></textarea><br />
         <button onclick="document.getElementById('send_sync').value = ''">Clear</button>
-    </div>
-    <p><b></b></p>
-    <p>Clicking on the different buttons should give the following results in the textarea below :</p>
-    <ul>
-      <li>synchronous: "request completed" then "other processing"</li>
-      <li>asynchronous: "other processing" then "request completed"</li>
-      <li>abort: "request aborted" then "other processing" (note that real XHR behavior would not call onComplete with abort - meaning "request aborted" would not be displayed here)</li>
-    </ul>
   </body>
 </html>



More information about the Commits mailing list