Blame | Last modification | View Log | RSS feed
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);}).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 key/value mapping object and returns a string representing// a URL-encoded version of that object.// example:// this object://// | {// | blah: "blah",// | multi: [// | "thud",// | "thonk"// | ]// | };//// yeilds the following query string://// | "blah=blah&multi=thud&multi=thonk"// FIXME: need to implement encodeAscii!!var ec = encodeURIComponent;var ret = "";var backstop = {};for(var x in map){if(map[x] != backstop[x]){if(_d.isArray(map[x])){for(var y=0; y<map[x].length; y++){ret += ec(x) + "=" + ec(map[x][y]) + "&";}}else{ret += ec(x) + "=" + ec(map[x]) + "&";}}}if(ret.length && ret.charAt(ret.length-1) == "&"){ret = ret.substr(0, ret.length-1);}return ret; // String}dojo.formToQuery = function(/*DOMNode||String*/ formNode){// summary:// return URL-encoded string representing the form passed as either a// node or string ID identifying the form to serializereturn _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 serializereturn _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&"//// returns 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 dc = decodeURIComponent;_d.forEach(qp, function(item){if(item.length){var parts = item.split("=");var name = dc(parts.shift());var val = dc(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 APItimeout: 1000, // millisecondshandleAs: "text", // replaces the always-wrong "mimetype"content: {key: "value"},// browser-specific, MAY be unsupportedsync: true, // defaults to falseform: 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(!djConfig.usePlainJson){console.debug("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 _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 _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){if(_d.isIE && !xhr.responseXML){_d.forEach(["MSXML2", "Microsoft", "MSXML", "MSXML3"], function(i){try{var doc = new ActiveXObject(prefixes[i]+".XMLDOM");doc.async = false;doc.loadXML(xhr.responseText);return doc; // DOMDocument}catch(e){ /* squelch */ };});}else{return xhr.responseXML;}}};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(kwArgs){// 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:}=====*//*=====dojo.__ioCallbackArgs = function(kwArgs){// 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.}=====*/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 #2844var actnNode = form.getAttributeNode("action");ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : null);formObject = _d.formToObject(form);}// set up the query paramsvar miArgs = [{}];if(formObject){// potentially over-ride url-provided params w/ form valuesmiArgs.push(formObject);}if(args.content){// stuff in content over-rides what's set by formmiArgs.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 Deferredreturn 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 hangsif(!_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 complainfor(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!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){if(_d._isDocumentOk(dfd.ioArgs.xhr)){dfd.callback(dfd);}else{dfd.errback(new Error("bad http response code:" + dfd.ioArgs.xhr.status));}}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;ioArgs.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{ioArgs.xhr.setRequestHeader(hdr, args.headers[hdr]);}}}// FIXME: is this appropriate for all content types?ioArgs.xhr.setRequestHeader("Content-Type", (args.contentType||_defaultContentType));// FIXME: set other headers here!try{ioArgs.xhr.send(ioArgs.query);}catch(e){dfd.cancel();}_d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);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.__xhrArgs = function(kwArgs){// 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.}=====*/dojo.xhrGet = function(/*dojo.__xhrArgs*/ args){// summary:// Sends an HTTP GET request to the server.var dfd = _makeXhrDeferred(args);_d._ioAddQueryToUrl(dfd.ioArgs);return _doIt("GET", dfd); // dojo.Deferred}dojo.xhrPost = function(/*dojo.__xhrArgs*/ args){//summary:// Sends an HTTP POST request to the server.return _doIt("POST", _makeXhrDeferred(args)); // 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 _doIt("PUT", _makeXhrDeferred(args)); // 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.var dfd = _makeXhrDeferred(args);_d._ioAddQueryToUrl(dfd.ioArgs);return _doIt("DELETE", dfd); // 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");}*/})();}