]> git.pond.sub.org Git - eow/blobdiff - static/dojo-release-1.1.1/dojo/_base/xhr.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dojo / _base / xhr.js
diff --git a/static/dojo-release-1.1.1/dojo/_base/xhr.js b/static/dojo-release-1.1.1/dojo/_base/xhr.js
new file mode 100644 (file)
index 0000000..f6e7f1a
--- /dev/null
@@ -0,0 +1,730 @@
+if(!dojo._hasResource["dojo._base.xhr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.xhr"] = true;
+dojo.provide("dojo._base.xhr");
+dojo.require("dojo._base.Deferred");
+dojo.require("dojo._base.json");
+dojo.require("dojo._base.lang");
+dojo.require("dojo._base.query");
+
+(function(){
+       var _d = dojo;
+       function setValue(/*Object*/obj, /*String*/name, /*String*/value){
+               //summary:
+               //              For the nameed property in object, set the value. If a value
+               //              already exists and it is a string, convert the value to be an
+               //              array of values.
+               var val = obj[name];
+               if(_d.isString(val)){
+                       obj[name] = [val, value];
+               }else if(_d.isArray(val)){
+                       val.push(value);
+               }else{
+                       obj[name] = value;
+               }
+       }
+
+       dojo.formToObject = function(/*DOMNode||String*/ formNode){
+               // summary:
+               //              dojo.formToObject returns the values encoded in an HTML form as
+               //              string properties in an object which it then returns. Disabled form
+               //              elements, buttons, and other non-value form elements are skipped.
+               //              Multi-select elements are returned as an array of string values.
+               // description:
+               //              This form:
+               //
+               //              |       <form id="test_form">
+               //              |               <input type="text" name="blah" value="blah">
+               //              |               <input type="text" name="no_value" value="blah" disabled>
+               //              |               <input type="button" name="no_value2" value="blah">
+               //              |               <select type="select" multiple name="multi" size="5">
+               //              |                       <option value="blah">blah</option>
+               //              |                       <option value="thud" selected>thud</option>
+               //              |                       <option value="thonk" selected>thonk</option>
+               //              |               </select>
+               //              |       </form>
+               //
+               //              yields this object structure as the result of a call to
+               //              formToObject():
+               //
+               //              |       { 
+               //              |               blah: "blah",
+               //              |               multi: [
+               //              |                       "thud",
+               //              |                       "thonk"
+               //              |               ]
+               //              |       };
+       
+               var ret = {};
+               var iq = "input:not([type=file]):not([type=submit]):not([type=image]):not([type=reset]):not([type=button]), select, textarea";
+               _d.query(iq, formNode).filter(function(node){
+                       return !node.disabled && node.name;
+               }).forEach(function(item){
+                       var _in = item.name;
+                       var type = (item.type||"").toLowerCase();
+                       if(type == "radio" || type == "checkbox"){
+                               if(item.checked){ setValue(ret, _in, item.value); }
+                       }else if(item.multiple){
+                               ret[_in] = [];
+                               _d.query("option", item).forEach(function(opt){
+                                       if(opt.selected){
+                                               setValue(ret, _in, opt.value);
+                                       }
+                               });
+                       }else{ 
+                               setValue(ret, _in, item.value);
+                               if(type == "image"){
+                                       ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0;
+                               }
+                       }
+               });
+               return ret; // Object
+       }
+
+       dojo.objectToQuery = function(/*Object*/ map){
+               //      summary:
+               //              takes a name/value mapping object and returns a string representing
+               //              a URL-encoded version of that object.
+               //      example:
+               //              this object:
+               //
+               //              |       { 
+               //              |               blah: "blah",
+               //              |               multi: [
+               //              |                       "thud",
+               //              |                       "thonk"
+               //              |               ]
+               //              |       };
+               //
+               //      yields the following query string:
+               //      
+               //      |       "blah=blah&multi=thud&multi=thonk"
+
+               // FIXME: need to implement encodeAscii!!
+               var enc = encodeURIComponent;
+               var pairs = [];
+               var backstop = {};
+               for(var name in map){
+                       var value = map[name];
+                       if(value != backstop[name]){
+                               var assign = enc(name) + "=";
+                               if(_d.isArray(value)){
+                                       for(var i=0; i < value.length; i++){
+                                               pairs.push(assign + enc(value[i]));
+                                       }
+                               }else{
+                                       pairs.push(assign + enc(value));
+                               }
+                       }
+               }
+               return pairs.join("&"); // String
+       }
+
+       dojo.formToQuery = function(/*DOMNode||String*/ formNode){
+               // summary:
+               //              Returns a URL-encoded string representing the form passed as either a
+               //              node or string ID identifying the form to serialize
+               return _d.objectToQuery(_d.formToObject(formNode)); // String
+       }
+
+       dojo.formToJson = function(/*DOMNode||String*/ formNode, /*Boolean?*/prettyPrint){
+               // summary:
+               //              return a serialized JSON string from a form node or string
+               //              ID identifying the form to serialize
+               return _d.toJson(_d.formToObject(formNode), prettyPrint); // String
+       }
+
+       dojo.queryToObject = function(/*String*/ str){
+               // summary:
+               //              returns an object representing a de-serialized query section of a
+               //              URL. Query keys with multiple values are returned in an array.
+               // description:
+               //              This string:
+               //
+               //      |               "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&"
+               //              
+               //              results in this object structure:
+               //
+               //      |               {
+               //      |                       foo: [ "bar", "baz" ],
+               //      |                       thinger: " spaces =blah",
+               //      |                       zonk: "blarg"
+               //      |               }
+               //      
+               //              Note that spaces and other urlencoded entities are correctly
+               //              handled.
+
+               // FIXME: should we grab the URL string if we're not passed one?
+               var ret = {};
+               var qp = str.split("&");
+               var dec = decodeURIComponent;
+               _d.forEach(qp, function(item){
+                       if(item.length){
+                               var parts = item.split("=");
+                               var name = dec(parts.shift());
+                               var val = dec(parts.join("="));
+                               if(_d.isString(ret[name])){
+                                       ret[name] = [ret[name]];
+                               }
+                               if(_d.isArray(ret[name])){
+                                       ret[name].push(val);
+                               }else{
+                                       ret[name] = val;
+                               }
+                       }
+               });
+               return ret; // Object
+       }
+
+       /*
+               from refactor.txt:
+
+               all bind() replacement APIs take the following argument structure:
+
+                       {
+                               url: "blah.html",
+
+                               // all below are optional, but must be supported in some form by
+                               // every IO API
+                               timeout: 1000, // milliseconds
+                               handleAs: "text", // replaces the always-wrong "mimetype"
+                               content: { 
+                                       key: "value"
+                               },
+
+                               // browser-specific, MAY be unsupported
+                               sync: true, // defaults to false
+                               form: dojo.byId("someForm") 
+                       }
+       */
+
+       // need to block async callbacks from snatching this thread as the result
+       // of an async callback might call another sync XHR, this hangs khtml forever
+       // must checked by watchInFlight()
+
+       dojo._blockAsync = false;
+
+       dojo._contentHandlers = {
+               "text": function(xhr){ return xhr.responseText; },
+               "json": function(xhr){
+                       if(!dojo.config.usePlainJson){
+                               console.warn("Consider using mimetype:text/json-comment-filtered"
+                                       + " to avoid potential security issues with JSON endpoints"
+                                       + " (use djConfig.usePlainJson=true to turn off this message)");
+                       }
+                       return (xhr.status == 204) ? undefined : _d.fromJson(xhr.responseText);
+               },
+               "json-comment-filtered": function(xhr){ 
+                       // NOTE: we provide the json-comment-filtered option as one solution to
+                       // the "JavaScript Hijacking" issue noted by Fortify and others. It is
+                       // not appropriate for all circumstances.
+
+                       var value = xhr.responseText;
+                       var cStartIdx = value.indexOf("\/*");
+                       var cEndIdx = value.lastIndexOf("*\/");
+                       if(cStartIdx == -1 || cEndIdx == -1){
+                               throw new Error("JSON was not comment filtered");
+                       }
+                       return (xhr.status == 204) ? undefined :
+                               _d.fromJson(value.substring(cStartIdx+2, cEndIdx));
+               },
+               "javascript": function(xhr){ 
+                       // FIXME: try Moz and IE specific eval variants?
+                       return _d.eval(xhr.responseText);
+               },
+               "xml": function(xhr){ 
+                       var result = xhr.responseXML;
+                       if(_d.isIE && (!result || window.location.protocol == "file:")){
+                               _d.forEach(["MSXML2", "Microsoft", "MSXML", "MSXML3"], function(prefix){
+                                       try{
+                                               var dom = new ActiveXObject(prefix + ".XMLDOM");
+                                               dom.async = false;
+                                               dom.loadXML(xhr.responseText);
+                                               result = dom;
+                                       }catch(e){ /* Not available. Squelch and try next one. */ }
+                               });
+                       }
+                       return result; // DOMDocument
+               }
+       };
+
+       dojo._contentHandlers["json-comment-optional"] = function(xhr){
+               var handlers = _d._contentHandlers;
+               try{
+                       return handlers["json-comment-filtered"](xhr);
+               }catch(e){
+                       return handlers["json"](xhr);
+               }
+       };
+
+       /*=====
+       dojo.__IoArgs = function(){
+               //      url: String
+               //              URL to server endpoint.
+               //      content: Object?
+               //              Contains properties with string values. These
+               //              properties will be serialized as name1=value2 and
+               //              passed in the request.
+               //      timeout: Integer?
+               //              Milliseconds to wait for the response. If this time
+               //              passes, the then error callbacks are called.
+               //      form: DOMNode?
+               //              DOM node for a form. Used to extract the form values
+               //              and send to the server.
+               //      preventCache: Boolean?
+               //              Default is false. If true, then a
+               //              "dojo.preventCache" parameter is sent in the request
+               //              with a value that changes with each request
+               //              (timestamp). Useful only with GET-type requests.
+               //      handleAs: String?
+               //              Acceptable values depend on the type of IO
+               //              transport (see specific IO calls for more information).
+               //      load: Function?
+               //              function(response, ioArgs){}. response is an Object, ioArgs
+               //              is of type dojo.__IoCallbackArgs. The load function will be
+               //              called on a successful response.
+               //      error: Function?
+               //              function(response, ioArgs){}. response is an Object, ioArgs
+               //              is of type dojo.__IoCallbackArgs. The error function will
+               //              be called in an error case. 
+               //      handle: Function?
+               //              function(response, ioArgs){}. response is an Object, ioArgs
+               //              is of type dojo.__IoCallbackArgs. The handle function will
+               //              be called in either the successful or error case.  For
+               //              the load, error and handle functions, the ioArgs object
+               //              will contain the following properties: 
+               this.url = url;
+               this.content = content;
+               this.timeout = timeout;
+               this.form = form;
+               this.preventCache = preventCache;
+               this.handleAs = handleAs;
+               this.load = load;
+               this.error = error;
+               this.handle = handle;
+       }
+       =====*/
+
+       /*=====
+       dojo.__IoCallbackArgs = function(args, xhr, url, query, handleAs, id, canDelete, json){
+               //      args: Object
+               //              the original object argument to the IO call.
+               //      xhr: XMLHttpRequest
+               //              For XMLHttpRequest calls only, the
+               //              XMLHttpRequest object that was used for the
+               //              request.
+               //      url: String
+               //              The final URL used for the call. Many times it
+               //              will be different than the original args.url
+               //              value.
+               //      query: String
+               //              For non-GET requests, the
+               //              name1=value1&name2=value2 parameters sent up in
+               //              the request.
+               //      handleAs: String
+               //              The final indicator on how the response will be
+               //              handled.
+               //      id: String
+               //              For dojo.io.script calls only, the internal
+               //              script ID used for the request.
+               //      canDelete: Boolean
+               //              For dojo.io.script calls only, indicates
+               //              whether the script tag that represents the
+               //              request can be deleted after callbacks have
+               //              been called. Used internally to know when
+               //              cleanup can happen on JSONP-type requests.
+               //      json: Object
+               //              For dojo.io.script calls only: holds the JSON
+               //              response for JSONP-type requests. Used
+               //              internally to hold on to the JSON responses.
+               //              You should not need to access it directly --
+               //              the same object should be passed to the success
+               //              callbacks directly.
+               this.args = args;
+               this.xhr = xhr;
+               this.url = url;
+               this.query = query;
+               this.handleAs = handleAs;
+               this.id = id;
+               this.canDelete = canDelete;
+               this.json = json;
+       }
+       =====*/
+
+
+
+       dojo._ioSetArgs = function(/*dojo.__IoArgs*/args,
+                       /*Function*/canceller,
+                       /*Function*/okHandler,
+                       /*Function*/errHandler){
+               //      summary: 
+               //              sets up the Deferred and ioArgs property on the Deferred so it
+               //              can be used in an io call.
+               //      args:
+               //              The args object passed into the public io call. Recognized properties on
+               //              the args object are:
+               //      canceller:
+               //              The canceller function used for the Deferred object. The function
+               //              will receive one argument, the Deferred object that is related to the
+               //              canceller.
+               //      okHandler:
+               //              The first OK callback to be registered with Deferred. It has the opportunity
+               //              to transform the OK response. It will receive one argument -- the Deferred
+               //              object returned from this function.
+               //      errHandler:
+               //              The first error callback to be registered with Deferred. It has the opportunity
+               //              to do cleanup on an error. It will receive two arguments: error (the 
+               //              Error object) and dfd, the Deferred object returned from this function.
+
+               var ioArgs = {args: args, url: args.url};
+
+               //Get values from form if requestd.
+               var formObject = null;
+               if(args.form){ 
+                       var form = _d.byId(args.form);
+                       //IE requires going through getAttributeNode instead of just getAttribute in some form cases, 
+                       //so use it for all.  See #2844
+                       var actnNode = form.getAttributeNode("action");
+                       ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : null); 
+                       formObject = _d.formToObject(form);
+               }
+
+               // set up the query params
+               var miArgs = [{}];
+       
+               if(formObject){
+                       // potentially over-ride url-provided params w/ form values
+                       miArgs.push(formObject);
+               }
+               if(args.content){
+                       // stuff in content over-rides what's set by form
+                       miArgs.push(args.content);
+               }
+               if(args.preventCache){
+                       miArgs.push({"dojo.preventCache": new Date().valueOf()});
+               }
+               ioArgs.query = _d.objectToQuery(_d.mixin.apply(null, miArgs));
+       
+               // .. and the real work of getting the deferred in order, etc.
+               ioArgs.handleAs = args.handleAs || "text";
+               var d = new _d.Deferred(canceller);
+               d.addCallbacks(okHandler, function(error){
+                       return errHandler(error, d);
+               });
+
+               //Support specifying load, error and handle callback functions from the args.
+               //For those callbacks, the "this" object will be the args object.
+               //The callbacks will get the deferred result value as the
+               //first argument and the ioArgs object as the second argument.
+               var ld = args.load;
+               if(ld && _d.isFunction(ld)){
+                       d.addCallback(function(value){
+                               return ld.call(args, value, ioArgs);
+                       });
+               }
+               var err = args.error;
+               if(err && _d.isFunction(err)){
+                       d.addErrback(function(value){
+                               return err.call(args, value, ioArgs);
+                       });
+               }
+               var handle = args.handle;
+               if(handle && _d.isFunction(handle)){
+                       d.addBoth(function(value){
+                               return handle.call(args, value, ioArgs);
+                       });
+               }
+               
+               d.ioArgs = ioArgs;
+       
+               // FIXME: need to wire up the xhr object's abort method to something
+               // analagous in the Deferred
+               return d;
+       }
+
+       var _deferredCancel = function(/*Deferred*/dfd){
+               //summary: canceller function for dojo._ioSetArgs call.
+               
+               dfd.canceled = true;
+               var xhr = dfd.ioArgs.xhr;
+               var _at = typeof xhr.abort;
+               if(_at == "function" || _at == "unknown"){
+                       xhr.abort();
+               }
+               var err = new Error("xhr cancelled");
+               err.dojoType = "cancel";
+               return err;
+       }
+       var _deferredOk = function(/*Deferred*/dfd){
+               //summary: okHandler function for dojo._ioSetArgs call.
+
+               return _d._contentHandlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
+       }
+       var _deferError = function(/*Error*/error, /*Deferred*/dfd){
+               //summary: errHandler function for dojo._ioSetArgs call.
+               
+               // console.debug("xhr error in:", dfd.ioArgs.xhr);
+               console.debug(error);
+               return error;
+       }
+
+       var _makeXhrDeferred = function(/*dojo.__XhrArgs*/args){
+               //summary: makes the Deferred object for this xhr request.
+               var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError);
+               //Pass the args to _xhrObj, to allow xhr iframe proxy interceptions.
+               dfd.ioArgs.xhr = _d._xhrObj(dfd.ioArgs.args);
+               return dfd;
+       }
+
+       // avoid setting a timer per request. It degrades performance on IE
+       // something fierece if we don't use unified loops.
+       var _inFlightIntvl = null;
+       var _inFlight = [];
+       var _watchInFlight = function(){
+               //summary: 
+               //              internal method that checks each inflight XMLHttpRequest to see
+               //              if it has completed or if the timeout situation applies.
+               
+               var now = (new Date()).getTime();
+               // make sure sync calls stay thread safe, if this callback is called
+               // during a sync call and this results in another sync call before the
+               // first sync call ends the browser hangs
+               if(!_d._blockAsync){
+                       // we need manual loop because we often modify _inFlight (and therefore 'i') while iterating
+                       // note: the second clause is an assigment on purpose, lint may complain
+                       for(var i = 0, tif; i < _inFlight.length && (tif = _inFlight[i]); i++){
+                               var dfd = tif.dfd;
+                               try{
+                                       if(!dfd || dfd.canceled || !tif.validCheck(dfd)){
+                                               _inFlight.splice(i--, 1); 
+                                       }else if(tif.ioCheck(dfd)){
+                                               _inFlight.splice(i--, 1);
+                                               tif.resHandle(dfd);
+                                       }else if(dfd.startTime){
+                                               //did we timeout?
+                                               if(dfd.startTime + (dfd.ioArgs.args.timeout || 0) < now){
+                                                       _inFlight.splice(i--, 1);
+                                                       var err = new Error("timeout exceeded");
+                                                       err.dojoType = "timeout";
+                                                       dfd.errback(err);
+                                                       //Cancel the request so the io module can do appropriate cleanup.
+                                                       dfd.cancel();
+                                               }
+                                       }
+                               }catch(e){
+                                       // FIXME: make sure we errback! (fixed?  remove console.debug?)
+                                       console.debug(e);
+                                       dfd.errback(new Error("_watchInFlightError!"));
+                               }
+                       }
+               }
+
+               if(!_inFlight.length){
+                       clearInterval(_inFlightIntvl);
+                       _inFlightIntvl = null;
+                       return;
+               }
+
+       }
+
+       dojo._ioCancelAll = function(){
+               //summary: Cancels all pending IO requests, regardless of IO type
+               //(xhr, script, iframe).
+               try{
+                       _d.forEach(_inFlight, function(i){
+                               i.dfd.cancel();
+                       });
+               }catch(e){/*squelch*/}
+       }
+
+       //Automatically call cancel all io calls on unload
+       //in IE for trac issue #2357.
+       if(_d.isIE){
+               _d.addOnUnload(_d._ioCancelAll);
+       }
+
+       _d._ioWatch = function(/*Deferred*/dfd,
+               /*Function*/validCheck,
+               /*Function*/ioCheck,
+               /*Function*/resHandle){
+               //summary: watches the io request represented by dfd to see if it completes.
+               //dfd:
+               //              The Deferred object to watch.
+               //validCheck:
+               //              Function used to check if the IO request is still valid. Gets the dfd
+               //              object as its only argument.
+               //ioCheck:
+               //              Function used to check if basic IO call worked. Gets the dfd
+               //              object as its only argument.
+               //resHandle:
+               //              Function used to process response. Gets the dfd
+               //              object as its only argument.
+               if(dfd.ioArgs.args.timeout){
+                       dfd.startTime = (new Date()).getTime();
+               }
+               _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle});
+               if(!_inFlightIntvl){
+                       _inFlightIntvl = setInterval(_watchInFlight, 50);
+               }
+               _watchInFlight(); // handle sync requests
+       }
+
+       var _defaultContentType = "application/x-www-form-urlencoded";
+
+       var _validCheck = function(/*Deferred*/dfd){
+               return dfd.ioArgs.xhr.readyState; //boolean
+       }
+       var _ioCheck = function(/*Deferred*/dfd){
+               return 4 == dfd.ioArgs.xhr.readyState; //boolean
+       }
+       var _resHandle = function(/*Deferred*/dfd){
+               var xhr = dfd.ioArgs.xhr;
+               if(_d._isDocumentOk(xhr)){
+                       dfd.callback(dfd);
+               }else{
+                       var err = new Error("Unable to load " + dfd.ioArgs.url + " status:" + xhr.status);
+                       err.status = xhr.status;
+                       err.responseText = xhr.responseText;
+                       dfd.errback(err);
+               }
+       }
+
+       var _doIt = function(/*String*/type, /*Deferred*/dfd){
+               // IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open).
+               // workaround for IE6's apply() "issues"
+               var ioArgs = dfd.ioArgs;
+               var args = ioArgs.args;
+               var xhr = ioArgs.xhr;
+               xhr.open(type, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined);
+               if(args.headers){
+                       for(var hdr in args.headers){
+                               if(hdr.toLowerCase() === "content-type" && !args.contentType){
+                                       args.contentType = args.headers[hdr];
+                               }else{
+                                       xhr.setRequestHeader(hdr, args.headers[hdr]);
+                               }
+                       }
+               }
+               // FIXME: is this appropriate for all content types?
+               xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType);
+               if(!args.headers || !args.headers["X-Requested-With"]){
+                       xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+               }
+               // FIXME: set other headers here!
+               try{
+                       xhr.send(ioArgs.query);
+               }catch(e){
+                       dfd.cancel();
+               }
+               _d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);
+               xhr = null;
+               return dfd; //Deferred
+       }
+
+       dojo._ioAddQueryToUrl = function(/*dojo.__IoCallbackArgs*/ioArgs){
+               //summary: Adds query params discovered by the io deferred construction to the URL.
+               //Only use this for operations which are fundamentally GET-type operations.
+               if(ioArgs.query.length){
+                       ioArgs.url += (ioArgs.url.indexOf("?") == -1 ? "?" : "&") + ioArgs.query;
+                       ioArgs.query = null;
+               }               
+       }
+
+       /*=====
+       dojo.declare("dojo.__XhrArgs", dojo.__IoArgs, {
+               constructor: function(){
+                       //      summary:
+                       //              In addition to the properties listed for the dojo._IoArgs type,
+                       //              the following properties are allowed for dojo.xhr* methods.
+                       //      handleAs: String?
+                       //              Acceptable values are: text (default), json, json-comment-optional,
+                       //              json-comment-filtered, javascript, xml
+                       //      sync: Boolean?
+                       //              false is default. Indicates whether the request should
+                       //              be a synchronous (blocking) request.
+                       //      headers: Object?
+                       //              Additional HTTP headers to send in the request.
+                       this.handleAs = handleAs;
+                       this.sync = sync;
+                       this.headers = headers;
+               }
+       });
+       =====*/
+
+       dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){
+               //      summary: 
+               //              Sends an HTTP request with the given method. If the request has an 
+               //              HTTP body, then pass true for hasBody. The method argument should be uppercase.
+               //              Also look at dojo.xhrGet(), xhrPost(), xhrPut() and dojo.xhrDelete() for shortcuts
+               //              for those HTTP methods. There are also methods for "raw" PUT and POST methods
+               //              via dojo.rawXhrPut() and dojo.rawXhrPost() respectively.
+               var dfd = _makeXhrDeferred(args);
+               if(!hasBody){
+                       _d._ioAddQueryToUrl(dfd.ioArgs);
+               }
+               return _doIt(method, dfd); // dojo.Deferred
+       }
+
+       dojo.xhrGet = function(/*dojo.__XhrArgs*/ args){
+               //      summary: 
+               //              Sends an HTTP GET request to the server.
+               return _d.xhr("GET", args); //dojo.Deferred
+       }
+
+       dojo.xhrPost = function(/*dojo.__XhrArgs*/ args){
+               //summary: 
+               //              Sends an HTTP POST request to the server.
+               return _d.xhr("POST", args, true); // dojo.Deferred
+       }
+
+       dojo.rawXhrPost = function(/*dojo.__XhrArgs*/ args){
+               //      summary:
+               //              Sends an HTTP POST request to the server. In addtion to the properties
+               //              listed for the dojo.__XhrArgs type, the following property is allowed:
+               //      postData:
+               //              String. The raw data to send in the body of the POST request.
+               var dfd = _makeXhrDeferred(args);
+               dfd.ioArgs.query = args.postData;
+               return _doIt("POST", dfd); // dojo.Deferred
+       }
+
+       dojo.xhrPut = function(/*dojo.__XhrArgs*/ args){
+               //      summary:
+               //              Sends an HTTP PUT request to the server.
+               return _d.xhr("PUT", args, true); // dojo.Deferred
+       }
+
+       dojo.rawXhrPut = function(/*dojo.__XhrArgs*/ args){
+               //      summary:
+               //              Sends an HTTP PUT request to the server. In addtion to the properties
+               //              listed for the dojo.__XhrArgs type, the following property is allowed:
+               //      putData:
+               //              String. The raw data to send in the body of the PUT request.
+               var dfd = _makeXhrDeferred(args);
+               var ioArgs = dfd.ioArgs;
+               if(args.putData){
+                       ioArgs.query = args.putData;
+                       args.putData = null;
+               }
+               return _doIt("PUT", dfd); // dojo.Deferred
+       }
+
+       dojo.xhrDelete = function(/*dojo.__XhrArgs*/ args){
+               //      summary:
+               //              Sends an HTTP DELETE request to the server.
+               return _d.xhr("DELETE", args); //dojo.Deferred
+       }
+
+       /*
+       dojo.wrapForm = function(formNode){
+               //summary:
+               //              A replacement for FormBind, but not implemented yet.
+
+               // FIXME: need to think harder about what extensions to this we might
+               // want. What should we allow folks to do w/ this? What events to
+               // set/send?
+               throw new Error("dojo.wrapForm not yet implemented");
+       }
+       */
+})();
+
+}