/* Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ 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, cfg = _d.config; function setValue(/*Object*/obj, /*String*/name, /*String*/value){ //summary: // For the named 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. //Skip it if there is no value if(value === null){ return; } var val = obj[name]; if(typeof val == "string"){ // inline'd type check obj[name] = [val, value]; }else if(_d.isArray(val)){ val.push(value); }else{ obj[name] = value; } } dojo.fieldToObject = function(/*DOMNode||String*/ inputNode){ // summary: // Serialize a form field to a JavaScript object. // // description: // Returns the value encoded in a form field as // as a string or an array of strings. Disabled form elements // and unchecked radio and checkboxes are skipped. Multi-select // elements are returned as an array of string values. var ret = null; var item = _d.byId(inputNode); if(item){ var _in = item.name; var type = (item.type||"").toLowerCase(); if(_in && type && !item.disabled){ if(type == "radio" || type == "checkbox"){ if(item.checked){ ret = item.value; } }else if(item.multiple){ ret = []; _d.query("option", item).forEach(function(opt){ if(opt.selected){ ret.push(opt.value); } }); }else{ ret = item.value; } } } return ret; // Object }; dojo.formToObject = function(/*DOMNode||String*/ formNode){ // summary: // Serialize a form node to a JavaScript object. // description: // 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. // // example: // This form: // |
// // yields this object structure as the result of a call to // formToObject(): // // | { // | blah: "blah", // | multi: [ // | "thud", // | "thonk" // | ] // | }; var ret = {}; var exclude = "file|submit|image|reset|button|"; _d.forEach(dojo.byId(formNode).elements, function(item){ var _in = item.name; var type = (item.type||"").toLowerCase(); if(_in && type && exclude.indexOf(type) == -1 && !item.disabled){ setValue(ret, _in, _d.fieldToObject(item)); 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: // Create 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: // Create an object representing a de-serialized query section of a // URL. Query keys with multiple values are returned in an array. // // example: // 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(typeof ret[name] == "string"){ // inline'd type check ret[name] = [ret[name]]; } if(_d.isArray(ret[name])){ ret[name].push(val); }else{ ret[name] = val; } } }); return ret; // Object }; // 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; // MOW: remove dojo._contentHandlers alias in 2.0 var handlers = _d._contentHandlers = dojo.contentHandlers = { // summary: // A map of availble XHR transport handle types. Name matches the // `handleAs` attribute passed to XHR calls. // // description: // A map of availble XHR transport handle types. Name matches the // `handleAs` attribute passed to XHR calls. Each contentHandler is // called, passing the xhr object for manipulation. The return value // from the contentHandler will be passed to the `load` or `handle` // functions defined in the original xhr call. // // example: // Creating a custom content-handler: // | dojo.contentHandlers.makeCaps = function(xhr){ // | return xhr.responseText.toUpperCase(); // | } // | // and later: // | dojo.xhrGet({ // | url:"foo.txt", // | handleAs:"makeCaps", // | load: function(data){ /* data is a toUpper version of foo.txt */ } // | }); text: function(xhr){ // summary: A contentHandler which simply returns the plaintext response data return xhr.responseText; }, json: function(xhr){ // summary: A contentHandler which returns a JavaScript object created from the response data return _d.fromJson(xhr.responseText || null); }, "json-comment-filtered": function(xhr){ // summary: A contentHandler which expects comment-filtered JSON. // description: // A contentHandler which expects comment-filtered JSON. // the json-comment-filtered option was implemented to prevent // "JavaScript Hijacking", but it is less secure than standard JSON. Use // standard JSON instead. JSON prefixing can be used to subvert hijacking. // // Will throw a notice suggesting to use application/json mimetype, as // json-commenting can introduce security issues. To decrease the chances of hijacking, // use the standard `json` contentHandler, and prefix your "JSON" with: {}&& // // use djConfig.useCommentedJson = true to turn off the notice if(!dojo.config.useCommentedJson){ console.warn("Consider using the standard mimetype:application/json." + " json-commenting can introduce security issues. To" + " decrease the chances of hijacking, use the standard the 'json' handler and" + " prefix your json with: {}&&\n" + "Use djConfig.useCommentedJson=true to turn off this message."); } 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 _d.fromJson(value.substring(cStartIdx+2, cEndIdx)); }, javascript: function(xhr){ // summary: A contentHandler which evaluates the response data, expecting it to be valid JavaScript // FIXME: try Moz and IE specific eval variants? return _d.eval(xhr.responseText); }, xml: function(xhr){ // summary: A contentHandler returning an XML Document parsed from the response data var result = xhr.responseXML; if(_d.isIE && (!result || !result.documentElement)){ //WARNING: this branch used by the xml handling in dojo.io.iframe, //so be sure to test dojo.io.iframe if making changes below. var ms = function(n){ return "MSXML" + n + ".DOMDocument"; }; var dp = ["Microsoft.XMLDOM", ms(6), ms(4), ms(3), ms(2)]; _d.some(dp, function(p){ try{ var dom = new ActiveXObject(p); dom.async = false; dom.loadXML(xhr.responseText); result = dom; }catch(e){ return false; } return true; }); } return result; // DOMDocument }, "json-comment-optional": function(xhr){ // summary: A contentHandler which checks the presence of comment-filtered JSON and // alternates between the `json` and `json-comment-filtered` contentHandlers. if(xhr.responseText && /^[^{\[]*\/\*/.test(xhr.responseText)){ return handlers["json-comment-filtered"](xhr); }else{ 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). // rawBody: String? // Sets the raw body for an HTTP request. If this is used, then the content // property is ignored. This is mostly useful for HTTP methods that have // a body to their requests, like PUT or POST. This property can be used instead // of postData and putData for dojo.rawXhrPost and dojo.rawXhrPut respectively. // ioPublish: Boolean? // Set this explicitly to false to prevent publishing of topics related to // IO operations. Otherwise, if djConfig.ioPublish is set to true, topics // will be published via dojo.publish for different phases of an IO operation. // See dojo.__IoPublish for a list of topics that are published. // load: Function? // This function will be // called on a successful HTTP response code. // error: Function? // This function will // be called when the request fails due to a network or server error, the url // is invalid, etc. It will also be called if the load or handle callback throws an // exception, unless djConfig.debugAtAllCosts is true. This allows deployed applications // to continue to run even when a logic error happens in the callback, while making // it easier to troubleshoot while in debug mode. // handle: Function? // This function will // be called at the end of every request, whether or not an error occurs. this.url = url; this.content = content; this.timeout = timeout; this.form = form; this.preventCache = preventCache; this.handleAs = handleAs; this.ioPublish = ioPublish; this.load = function(response, ioArgs){ // ioArgs: dojo.__IoCallbackArgs // Provides additional information about the request. // response: Object // The response in the format as defined with handleAs. } this.error = function(response, ioArgs){ // ioArgs: dojo.__IoCallbackArgs // Provides additional information about the request. // response: Object // The response in the format as defined with handleAs. } this.handle = function(loadOrError, response, ioArgs){ // loadOrError: String // Provides a string that tells you whether this function // was called because of success (load) or failure (error). // response: Object // The response in the format as defined with handleAs. // ioArgs: dojo.__IoCallbackArgs // Provides additional information about the request. } } =====*/ /*===== 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.__IoPublish = function(){ // summary: // This is a list of IO topics that can be published // if djConfig.ioPublish is set to true. IO topics can be // published for any Input/Output, network operation. So, // dojo.xhr, dojo.io.script and dojo.io.iframe can all // trigger these topics to be published. // start: String // "/dojo/io/start" is sent when there are no outstanding IO // requests, and a new IO request is started. No arguments // are passed with this topic. // send: String // "/dojo/io/send" is sent whenever a new IO request is started. // It passes the dojo.Deferred for the request with the topic. // load: String // "/dojo/io/load" is sent whenever an IO request has loaded // successfully. It passes the response and the dojo.Deferred // for the request with the topic. // error: String // "/dojo/io/error" is sent whenever an IO request has errored. // It passes the error and the dojo.Deferred // for the request with the topic. // done: String // "/dojo/io/done" is sent whenever an IO request has completed, // either by loading or by erroring. It passes the error and // the dojo.Deferred for the request with the topic. // stop: String // "/dojo/io/stop" is sent when all outstanding IO requests have // finished. No arguments are passed with this topic. this.start = "/dojo/io/start"; this.send = "/dojo/io/send"; this.load = "/dojo/io/load"; this.error = "/dojo/io/error"; this.done = "/dojo/io/done"; this.stop = "/dojo/io/stop"; } =====*/ 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); }); } //Plug in topic publishing, if dojo.publish is loaded. if(cfg.ioPublish && _d.publish && ioArgs.args.ioPublish !== false){ d.addCallbacks( function(res){ _d.publish("/dojo/io/load", [d, res]); return res; }, function(res){ _d.publish("/dojo/io/error", [d, res]); return res; } ); d.addBoth(function(res){ _d.publish("/dojo/io/done", [d, res]); return res; }); } 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 == "object" || _at == "unknown"){ xhr.abort(); } var err = dfd.ioArgs.error; if(!err){ err = new Error("xhr cancelled"); err.dojoType="cancel"; } return err; }; var _deferredOk = function(/*Deferred*/dfd){ // summary: okHandler function for dojo._ioSetArgs call. var ret = handlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr); return ret === undefined ? null : ret; }; var _deferError = function(/*Error*/error, /*Deferred*/dfd){ // summary: errHandler function for dojo._ioSetArgs call. if(!dfd.ioArgs.args.failOk){ console.error(error); } return error; }; // 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 = []; //Use a separate count for knowing if we are starting/stopping io calls. //Cannot use _inFlight.length since it can change at a different time than //when we want to do this kind of test. We only want to decrement the count //after a callback/errback has finished, since the callback/errback should be //considered as part of finishing a request. var _pubCount = 0; var _checkPubCount = function(dfd){ if(_pubCount <= 0){ _pubCount = 0; if(cfg.ioPublish && _d.publish && (!dfd || dfd && dfd.ioArgs.args.ioPublish !== false)){ _d.publish("/dojo/io/stop"); } } }; 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; var func = function(){ if(!dfd || dfd.canceled || !tif.validCheck(dfd)){ _inFlight.splice(i--, 1); _pubCount -= 1; }else if(tif.ioCheck(dfd)){ _inFlight.splice(i--, 1); tif.resHandle(dfd); _pubCount -= 1; }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(); _pubCount -= 1; } } }; if(dojo.config.debugAtAllCosts){ func.call(this); }else{ try{ func.call(this); }catch(e){ dfd.errback(e); } } } } _checkPubCount(dfd); 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){ try{ i.dfd.cancel(); }catch(e){/*squelch*/} }); }catch(e){/*squelch*/} }; //Automatically call cancel all io calls on unload //in IE for trac issue #2357. if(_d.isIE){ _d.addOnWindowUnload(_d._ioCancelAll); } _d._ioNotifyStart = function(/*Deferred*/dfd){ // summary: // If dojo.publish is available, publish topics // about the start of a request queue and/or the // the beginning of request. // description: // Used by IO transports. An IO transport should // call this method before making the network connection. if(cfg.ioPublish && _d.publish && dfd.ioArgs.args.ioPublish !== false){ if(!_pubCount){ _d.publish("/dojo/io/start"); } _pubCount += 1; _d.publish("/dojo/io/send", [dfd]); } }; _d._ioWatch = function(dfd, validCheck, ioCheck, resHandle){ // summary: // Watches the io request represented by dfd to see if it completes. // dfd: Deferred // The Deferred object to watch. // validCheck: Function // Function used to check if the IO request is still valid. Gets the dfd // object as its only argument. // ioCheck: Function // Function used to check if basic IO call worked. Gets the dfd // object as its only argument. // resHandle: Function // Function used to process response. Gets the dfd // object as its only argument. var args = dfd.ioArgs.args; if(args.timeout){ dfd.startTime = (new Date()).getTime(); } _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle}); if(!_inFlightIntvl){ _inFlightIntvl = setInterval(_watchInFlight, 50); } // handle sync requests //A weakness: async calls in flight //could have their handlers called as part of the //_watchInFlight call, before the sync's callbacks // are called. if(args.sync){ _watchInFlight(); } }; 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); } }; 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. See `dojo.contentHandlers` // 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. // failOk: Boolean? // false is default. Indicates whether a request should be // allowed to fail (and therefore no console error message in // the event of a failure) this.handleAs = handleAs; this.sync = sync; this.headers = headers; this.failOk = failOk; } }); =====*/ dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){ // summary: // Sends an HTTP request with the given method. // description: // Sends an HTTP request with the given method. // See also 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. // method: // HTTP method to be used, such as GET, POST, PUT, DELETE. Should be uppercase. // hasBody: // If the request has an HTTP body, then pass true for hasBody. //Make the Deferred object for this xhr request. var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError); var ioArgs = dfd.ioArgs; //Pass the args to _xhrObj, to allow alternate XHR calls based specific calls, like //the one used for iframe proxies. var xhr = ioArgs.xhr = _d._xhrObj(ioArgs.args); //If XHR factory fails, cancel the deferred. if(!xhr){ dfd.cancel(); return dfd; } //Allow for specifying the HTTP body completely. if("postData" in args){ ioArgs.query = args.postData; }else if("putData" in args){ ioArgs.query = args.putData; }else if("rawBody" in args){ ioArgs.query = args.rawBody; }else if((arguments.length > 2 && !hasBody) || "POST|PUT".indexOf(method.toUpperCase()) == -1){ //Check for hasBody being passed. If no hasBody, //then only append query string if not a POST or PUT request. _d._ioAddQueryToUrl(ioArgs); } // 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" xhr.open(method, 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 if(args.headers[hdr]){ //Only add header if it has a value. This allows for instnace, skipping //insertion of X-Requested-With by specifying empty value. xhr.setRequestHeader(hdr, args.headers[hdr]); } } } // FIXME: is this appropriate for all content types? xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType); if(!args.headers || !("X-Requested-With" in args.headers)){ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); } // FIXME: set other headers here! _d._ioNotifyStart(dfd); if(dojo.config.debugAtAllCosts){ xhr.send(ioArgs.query); }else{ try{ xhr.send(ioArgs.query); }catch(e){ ioArgs.error = e; dfd.cancel(); } } _d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle); xhr = null; return 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.rawXhrPost = dojo.xhrPost = 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. Send raw data in the body of the POST request. return _d.xhr("POST", args, true); // dojo.Deferred }; dojo.rawXhrPut = dojo.xhrPut = 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. Send raw data in the body of the PUT request. return _d.xhr("PUT", args, true); // 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"); } */ })(); }