]> git.wh0rd.org - tt-rss.git/blob - lib/dojo/_base/xhr.js.uncompressed.js
update dojo to 1.7.3
[tt-rss.git] / lib / dojo / _base / xhr.js.uncompressed.js
1 define("dojo/_base/xhr", [
2 "./kernel", "./sniff", "require", "../io-query", "../dom", "../dom-form", "./Deferred", "./json", "./lang", "./array", "../on"
3 ], function(dojo, has, require, ioq, dom, domForm, deferred, json, lang, array, on){
4 // module:
5 // dojo/_base.xhr
6 // summary:
7 // This modules defines the dojo.xhr* API.
8
9 has.add("native-xhr", function() {
10 // if true, the environment has a native XHR implementation
11 return typeof XMLHttpRequest !== 'undefined';
12 });
13
14 if(1 && require.getXhr){
15 dojo._xhrObj = require.getXhr;
16 }else if (has("native-xhr")){
17 dojo._xhrObj = function(){
18 // summary:
19 // does the work of portably generating a new XMLHTTPRequest object.
20 try{
21 return new XMLHttpRequest();
22 }catch(e){
23 throw new Error("XMLHTTP not available: "+e);
24 }
25 };
26 }else{
27 // PROGIDs are in order of decreasing likelihood; this will change in time.
28 for(var XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], progid, i = 0; i < 3;){
29 try{
30 progid = XMLHTTP_PROGIDS[i++];
31 if (new ActiveXObject(progid)) {
32 // this progid works; therefore, use it from now on
33 break;
34 }
35 }catch(e){
36 // squelch; we're just trying to find a good ActiveX PROGID
37 // if they all fail, then progid ends up as the last attempt and that will signal the error
38 // the first time the client actually tries to exec an xhr
39 }
40 }
41 dojo._xhrObj= function() {
42 return new ActiveXObject(progid);
43 };
44 }
45
46 var cfg = dojo.config;
47
48 // mix in io-query and dom-form
49 dojo.objectToQuery = ioq.objectToQuery;
50 dojo.queryToObject = ioq.queryToObject;
51 dojo.fieldToObject = domForm.fieldToObject;
52 dojo.formToObject = domForm.toObject;
53 dojo.formToQuery = domForm.toQuery;
54 dojo.formToJson = domForm.toJson;
55
56 // need to block async callbacks from snatching this thread as the result
57 // of an async callback might call another sync XHR, this hangs khtml forever
58 // must checked by watchInFlight()
59
60 dojo._blockAsync = false;
61
62 // MOW: remove dojo._contentHandlers alias in 2.0
63 var handlers = dojo._contentHandlers = dojo.contentHandlers = {
64 // summary:
65 // A map of availble XHR transport handle types. Name matches the
66 // `handleAs` attribute passed to XHR calls.
67 //
68 // description:
69 // A map of availble XHR transport handle types. Name matches the
70 // `handleAs` attribute passed to XHR calls. Each contentHandler is
71 // called, passing the xhr object for manipulation. The return value
72 // from the contentHandler will be passed to the `load` or `handle`
73 // functions defined in the original xhr call.
74 //
75 // example:
76 // Creating a custom content-handler:
77 // | dojo.contentHandlers.makeCaps = function(xhr){
78 // | return xhr.responseText.toUpperCase();
79 // | }
80 // | // and later:
81 // | dojo.xhrGet({
82 // | url:"foo.txt",
83 // | handleAs:"makeCaps",
84 // | load: function(data){ /* data is a toUpper version of foo.txt */ }
85 // | });
86
87 "text": function(xhr){
88 // summary: A contentHandler which simply returns the plaintext response data
89 return xhr.responseText;
90 },
91 "json": function(xhr){
92 // summary: A contentHandler which returns a JavaScript object created from the response data
93 return json.fromJson(xhr.responseText || null);
94 },
95 "json-comment-filtered": function(xhr){
96 // summary: A contentHandler which expects comment-filtered JSON.
97 // description:
98 // A contentHandler which expects comment-filtered JSON.
99 // the json-comment-filtered option was implemented to prevent
100 // "JavaScript Hijacking", but it is less secure than standard JSON. Use
101 // standard JSON instead. JSON prefixing can be used to subvert hijacking.
102 //
103 // Will throw a notice suggesting to use application/json mimetype, as
104 // json-commenting can introduce security issues. To decrease the chances of hijacking,
105 // use the standard `json` contentHandler, and prefix your "JSON" with: {}&&
106 //
107 // use djConfig.useCommentedJson = true to turn off the notice
108 if(!dojo.config.useCommentedJson){
109 console.warn("Consider using the standard mimetype:application/json."
110 + " json-commenting can introduce security issues. To"
111 + " decrease the chances of hijacking, use the standard the 'json' handler and"
112 + " prefix your json with: {}&&\n"
113 + "Use djConfig.useCommentedJson=true to turn off this message.");
114 }
115
116 var value = xhr.responseText;
117 var cStartIdx = value.indexOf("\/*");
118 var cEndIdx = value.lastIndexOf("*\/");
119 if(cStartIdx == -1 || cEndIdx == -1){
120 throw new Error("JSON was not comment filtered");
121 }
122 return json.fromJson(value.substring(cStartIdx+2, cEndIdx));
123 },
124 "javascript": function(xhr){
125 // summary: A contentHandler which evaluates the response data, expecting it to be valid JavaScript
126
127 // FIXME: try Moz and IE specific eval variants?
128 return dojo.eval(xhr.responseText);
129 },
130 "xml": function(xhr){
131 // summary: A contentHandler returning an XML Document parsed from the response data
132 var result = xhr.responseXML;
133
134 if(has("ie")){
135 if((!result || !result.documentElement)){
136 //WARNING: this branch used by the xml handling in dojo.io.iframe,
137 //so be sure to test dojo.io.iframe if making changes below.
138 var ms = function(n){ return "MSXML" + n + ".DOMDocument"; };
139 var dp = ["Microsoft.XMLDOM", ms(6), ms(4), ms(3), ms(2)];
140 array.some(dp, function(p){
141 try{
142 var dom = new ActiveXObject(p);
143 dom.async = false;
144 dom.loadXML(xhr.responseText);
145 result = dom;
146 }catch(e){ return false; }
147 return true;
148 });
149 }
150 }
151 return result; // DOMDocument
152 },
153 "json-comment-optional": function(xhr){
154 // summary: A contentHandler which checks the presence of comment-filtered JSON and
155 // alternates between the `json` and `json-comment-filtered` contentHandlers.
156 if(xhr.responseText && /^[^{\[]*\/\*/.test(xhr.responseText)){
157 return handlers["json-comment-filtered"](xhr);
158 }else{
159 return handlers["json"](xhr);
160 }
161 }
162 };
163
164 /*=====
165 dojo.__IoArgs = function(){
166 // url: String
167 // URL to server endpoint.
168 // content: Object?
169 // Contains properties with string values. These
170 // properties will be serialized as name1=value2 and
171 // passed in the request.
172 // timeout: Integer?
173 // Milliseconds to wait for the response. If this time
174 // passes, the then error callbacks are called.
175 // form: DOMNode?
176 // DOM node for a form. Used to extract the form values
177 // and send to the server.
178 // preventCache: Boolean?
179 // Default is false. If true, then a
180 // "dojo.preventCache" parameter is sent in the request
181 // with a value that changes with each request
182 // (timestamp). Useful only with GET-type requests.
183 // handleAs: String?
184 // Acceptable values depend on the type of IO
185 // transport (see specific IO calls for more information).
186 // rawBody: String?
187 // Sets the raw body for an HTTP request. If this is used, then the content
188 // property is ignored. This is mostly useful for HTTP methods that have
189 // a body to their requests, like PUT or POST. This property can be used instead
190 // of postData and putData for dojo.rawXhrPost and dojo.rawXhrPut respectively.
191 // ioPublish: Boolean?
192 // Set this explicitly to false to prevent publishing of topics related to
193 // IO operations. Otherwise, if djConfig.ioPublish is set to true, topics
194 // will be published via dojo.publish for different phases of an IO operation.
195 // See dojo.__IoPublish for a list of topics that are published.
196 // load: Function?
197 // This function will be
198 // called on a successful HTTP response code.
199 // error: Function?
200 // This function will
201 // be called when the request fails due to a network or server error, the url
202 // is invalid, etc. It will also be called if the load or handle callback throws an
203 // exception, unless djConfig.debugAtAllCosts is true. This allows deployed applications
204 // to continue to run even when a logic error happens in the callback, while making
205 // it easier to troubleshoot while in debug mode.
206 // handle: Function?
207 // This function will
208 // be called at the end of every request, whether or not an error occurs.
209 this.url = url;
210 this.content = content;
211 this.timeout = timeout;
212 this.form = form;
213 this.preventCache = preventCache;
214 this.handleAs = handleAs;
215 this.ioPublish = ioPublish;
216 this.load = function(response, ioArgs){
217 // ioArgs: dojo.__IoCallbackArgs
218 // Provides additional information about the request.
219 // response: Object
220 // The response in the format as defined with handleAs.
221 }
222 this.error = function(response, ioArgs){
223 // ioArgs: dojo.__IoCallbackArgs
224 // Provides additional information about the request.
225 // response: Object
226 // The response in the format as defined with handleAs.
227 }
228 this.handle = function(loadOrError, response, ioArgs){
229 // loadOrError: String
230 // Provides a string that tells you whether this function
231 // was called because of success (load) or failure (error).
232 // response: Object
233 // The response in the format as defined with handleAs.
234 // ioArgs: dojo.__IoCallbackArgs
235 // Provides additional information about the request.
236 }
237 }
238 =====*/
239
240 /*=====
241 dojo.__IoCallbackArgs = function(args, xhr, url, query, handleAs, id, canDelete, json){
242 // args: Object
243 // the original object argument to the IO call.
244 // xhr: XMLHttpRequest
245 // For XMLHttpRequest calls only, the
246 // XMLHttpRequest object that was used for the
247 // request.
248 // url: String
249 // The final URL used for the call. Many times it
250 // will be different than the original args.url
251 // value.
252 // query: String
253 // For non-GET requests, the
254 // name1=value1&name2=value2 parameters sent up in
255 // the request.
256 // handleAs: String
257 // The final indicator on how the response will be
258 // handled.
259 // id: String
260 // For dojo.io.script calls only, the internal
261 // script ID used for the request.
262 // canDelete: Boolean
263 // For dojo.io.script calls only, indicates
264 // whether the script tag that represents the
265 // request can be deleted after callbacks have
266 // been called. Used internally to know when
267 // cleanup can happen on JSONP-type requests.
268 // json: Object
269 // For dojo.io.script calls only: holds the JSON
270 // response for JSONP-type requests. Used
271 // internally to hold on to the JSON responses.
272 // You should not need to access it directly --
273 // the same object should be passed to the success
274 // callbacks directly.
275 this.args = args;
276 this.xhr = xhr;
277 this.url = url;
278 this.query = query;
279 this.handleAs = handleAs;
280 this.id = id;
281 this.canDelete = canDelete;
282 this.json = json;
283 }
284 =====*/
285
286
287 /*=====
288 dojo.__IoPublish = function(){
289 // summary:
290 // This is a list of IO topics that can be published
291 // if djConfig.ioPublish is set to true. IO topics can be
292 // published for any Input/Output, network operation. So,
293 // dojo.xhr, dojo.io.script and dojo.io.iframe can all
294 // trigger these topics to be published.
295 // start: String
296 // "/dojo/io/start" is sent when there are no outstanding IO
297 // requests, and a new IO request is started. No arguments
298 // are passed with this topic.
299 // send: String
300 // "/dojo/io/send" is sent whenever a new IO request is started.
301 // It passes the dojo.Deferred for the request with the topic.
302 // load: String
303 // "/dojo/io/load" is sent whenever an IO request has loaded
304 // successfully. It passes the response and the dojo.Deferred
305 // for the request with the topic.
306 // error: String
307 // "/dojo/io/error" is sent whenever an IO request has errored.
308 // It passes the error and the dojo.Deferred
309 // for the request with the topic.
310 // done: String
311 // "/dojo/io/done" is sent whenever an IO request has completed,
312 // either by loading or by erroring. It passes the error and
313 // the dojo.Deferred for the request with the topic.
314 // stop: String
315 // "/dojo/io/stop" is sent when all outstanding IO requests have
316 // finished. No arguments are passed with this topic.
317 this.start = "/dojo/io/start";
318 this.send = "/dojo/io/send";
319 this.load = "/dojo/io/load";
320 this.error = "/dojo/io/error";
321 this.done = "/dojo/io/done";
322 this.stop = "/dojo/io/stop";
323 }
324 =====*/
325
326
327 dojo._ioSetArgs = function(/*dojo.__IoArgs*/args,
328 /*Function*/canceller,
329 /*Function*/okHandler,
330 /*Function*/errHandler){
331 // summary:
332 // sets up the Deferred and ioArgs property on the Deferred so it
333 // can be used in an io call.
334 // args:
335 // The args object passed into the public io call. Recognized properties on
336 // the args object are:
337 // canceller:
338 // The canceller function used for the Deferred object. The function
339 // will receive one argument, the Deferred object that is related to the
340 // canceller.
341 // okHandler:
342 // The first OK callback to be registered with Deferred. It has the opportunity
343 // to transform the OK response. It will receive one argument -- the Deferred
344 // object returned from this function.
345 // errHandler:
346 // The first error callback to be registered with Deferred. It has the opportunity
347 // to do cleanup on an error. It will receive two arguments: error (the
348 // Error object) and dfd, the Deferred object returned from this function.
349
350 var ioArgs = {args: args, url: args.url};
351
352 //Get values from form if requestd.
353 var formObject = null;
354 if(args.form){
355 var form = dom.byId(args.form);
356 //IE requires going through getAttributeNode instead of just getAttribute in some form cases,
357 //so use it for all. See #2844
358 var actnNode = form.getAttributeNode("action");
359 ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : null);
360 formObject = domForm.toObject(form);
361 }
362
363 // set up the query params
364 var miArgs = [{}];
365
366 if(formObject){
367 // potentially over-ride url-provided params w/ form values
368 miArgs.push(formObject);
369 }
370 if(args.content){
371 // stuff in content over-rides what's set by form
372 miArgs.push(args.content);
373 }
374 if(args.preventCache){
375 miArgs.push({"dojo.preventCache": new Date().valueOf()});
376 }
377 ioArgs.query = ioq.objectToQuery(lang.mixin.apply(null, miArgs));
378
379 // .. and the real work of getting the deferred in order, etc.
380 ioArgs.handleAs = args.handleAs || "text";
381 var d = new deferred(canceller);
382 d.addCallbacks(okHandler, function(error){
383 return errHandler(error, d);
384 });
385
386 //Support specifying load, error and handle callback functions from the args.
387 //For those callbacks, the "this" object will be the args object.
388 //The callbacks will get the deferred result value as the
389 //first argument and the ioArgs object as the second argument.
390 var ld = args.load;
391 if(ld && lang.isFunction(ld)){
392 d.addCallback(function(value){
393 return ld.call(args, value, ioArgs);
394 });
395 }
396 var err = args.error;
397 if(err && lang.isFunction(err)){
398 d.addErrback(function(value){
399 return err.call(args, value, ioArgs);
400 });
401 }
402 var handle = args.handle;
403 if(handle && lang.isFunction(handle)){
404 d.addBoth(function(value){
405 return handle.call(args, value, ioArgs);
406 });
407 }
408
409 //Plug in topic publishing, if dojo.publish is loaded.
410 if(cfg.ioPublish && dojo.publish && ioArgs.args.ioPublish !== false){
411 d.addCallbacks(
412 function(res){
413 dojo.publish("/dojo/io/load", [d, res]);
414 return res;
415 },
416 function(res){
417 dojo.publish("/dojo/io/error", [d, res]);
418 return res;
419 }
420 );
421 d.addBoth(function(res){
422 dojo.publish("/dojo/io/done", [d, res]);
423 return res;
424 });
425 }
426
427 d.ioArgs = ioArgs;
428
429 // FIXME: need to wire up the xhr object's abort method to something
430 // analagous in the Deferred
431 return d;
432 };
433
434 var _deferredCancel = function(/*Deferred*/dfd){
435 // summary: canceller function for dojo._ioSetArgs call.
436
437 dfd.canceled = true;
438 var xhr = dfd.ioArgs.xhr;
439 var _at = typeof xhr.abort;
440 if(_at == "function" || _at == "object" || _at == "unknown"){
441 xhr.abort();
442 }
443 var err = dfd.ioArgs.error;
444 if(!err){
445 err = new Error("xhr cancelled");
446 err.dojoType="cancel";
447 }
448 return err;
449 };
450 var _deferredOk = function(/*Deferred*/dfd){
451 // summary: okHandler function for dojo._ioSetArgs call.
452
453 var ret = handlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
454 return ret === undefined ? null : ret;
455 };
456 var _deferError = function(/*Error*/error, /*Deferred*/dfd){
457 // summary: errHandler function for dojo._ioSetArgs call.
458
459 if(!dfd.ioArgs.args.failOk){
460 console.error(error);
461 }
462 return error;
463 };
464
465 // avoid setting a timer per request. It degrades performance on IE
466 // something fierece if we don't use unified loops.
467 var _inFlightIntvl = null;
468 var _inFlight = [];
469
470
471 //Use a separate count for knowing if we are starting/stopping io calls.
472 //Cannot use _inFlight.length since it can change at a different time than
473 //when we want to do this kind of test. We only want to decrement the count
474 //after a callback/errback has finished, since the callback/errback should be
475 //considered as part of finishing a request.
476 var _pubCount = 0;
477 var _checkPubCount = function(dfd){
478 if(_pubCount <= 0){
479 _pubCount = 0;
480 if(cfg.ioPublish && dojo.publish && (!dfd || dfd && dfd.ioArgs.args.ioPublish !== false)){
481 dojo.publish("/dojo/io/stop");
482 }
483 }
484 };
485
486 var _watchInFlight = function(){
487 //summary:
488 // internal method that checks each inflight XMLHttpRequest to see
489 // if it has completed or if the timeout situation applies.
490
491 var now = (new Date()).getTime();
492 // make sure sync calls stay thread safe, if this callback is called
493 // during a sync call and this results in another sync call before the
494 // first sync call ends the browser hangs
495 if(!dojo._blockAsync){
496 // we need manual loop because we often modify _inFlight (and therefore 'i') while iterating
497 // note: the second clause is an assigment on purpose, lint may complain
498 for(var i = 0, tif; i < _inFlight.length && (tif = _inFlight[i]); i++){
499 var dfd = tif.dfd;
500 var func = function(){
501 if(!dfd || dfd.canceled || !tif.validCheck(dfd)){
502 _inFlight.splice(i--, 1);
503 _pubCount -= 1;
504 }else if(tif.ioCheck(dfd)){
505 _inFlight.splice(i--, 1);
506 tif.resHandle(dfd);
507 _pubCount -= 1;
508 }else if(dfd.startTime){
509 //did we timeout?
510 if(dfd.startTime + (dfd.ioArgs.args.timeout || 0) < now){
511 _inFlight.splice(i--, 1);
512 var err = new Error("timeout exceeded");
513 err.dojoType = "timeout";
514 dfd.errback(err);
515 //Cancel the request so the io module can do appropriate cleanup.
516 dfd.cancel();
517 _pubCount -= 1;
518 }
519 }
520 };
521 if(dojo.config.debugAtAllCosts){
522 func.call(this);
523 }else{
524 try{
525 func.call(this);
526 }catch(e){
527 dfd.errback(e);
528 }
529 }
530 }
531 }
532
533 _checkPubCount(dfd);
534
535 if(!_inFlight.length){
536 clearInterval(_inFlightIntvl);
537 _inFlightIntvl = null;
538 }
539 };
540
541 dojo._ioCancelAll = function(){
542 //summary: Cancels all pending IO requests, regardless of IO type
543 //(xhr, script, iframe).
544 try{
545 array.forEach(_inFlight, function(i){
546 try{
547 i.dfd.cancel();
548 }catch(e){/*squelch*/}
549 });
550 }catch(e){/*squelch*/}
551 };
552
553 //Automatically call cancel all io calls on unload
554 //in IE for trac issue #2357.
555 if(has("ie")){
556 on(window, "unload", dojo._ioCancelAll);
557 }
558
559 dojo._ioNotifyStart = function(/*Deferred*/dfd){
560 // summary:
561 // If dojo.publish is available, publish topics
562 // about the start of a request queue and/or the
563 // the beginning of request.
564 // description:
565 // Used by IO transports. An IO transport should
566 // call this method before making the network connection.
567 if(cfg.ioPublish && dojo.publish && dfd.ioArgs.args.ioPublish !== false){
568 if(!_pubCount){
569 dojo.publish("/dojo/io/start");
570 }
571 _pubCount += 1;
572 dojo.publish("/dojo/io/send", [dfd]);
573 }
574 };
575
576 dojo._ioWatch = function(dfd, validCheck, ioCheck, resHandle){
577 // summary:
578 // Watches the io request represented by dfd to see if it completes.
579 // dfd: Deferred
580 // The Deferred object to watch.
581 // validCheck: Function
582 // Function used to check if the IO request is still valid. Gets the dfd
583 // object as its only argument.
584 // ioCheck: Function
585 // Function used to check if basic IO call worked. Gets the dfd
586 // object as its only argument.
587 // resHandle: Function
588 // Function used to process response. Gets the dfd
589 // object as its only argument.
590 var args = dfd.ioArgs.args;
591 if(args.timeout){
592 dfd.startTime = (new Date()).getTime();
593 }
594
595 _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle});
596 if(!_inFlightIntvl){
597 _inFlightIntvl = setInterval(_watchInFlight, 50);
598 }
599 // handle sync requests
600 //A weakness: async calls in flight
601 //could have their handlers called as part of the
602 //_watchInFlight call, before the sync's callbacks
603 // are called.
604 if(args.sync){
605 _watchInFlight();
606 }
607 };
608
609 var _defaultContentType = "application/x-www-form-urlencoded";
610
611 var _validCheck = function(/*Deferred*/dfd){
612 return dfd.ioArgs.xhr.readyState; //boolean
613 };
614 var _ioCheck = function(/*Deferred*/dfd){
615 return 4 == dfd.ioArgs.xhr.readyState; //boolean
616 };
617 var _resHandle = function(/*Deferred*/dfd){
618 var xhr = dfd.ioArgs.xhr;
619 if(dojo._isDocumentOk(xhr)){
620 dfd.callback(dfd);
621 }else{
622 var err = new Error("Unable to load " + dfd.ioArgs.url + " status:" + xhr.status);
623 err.status = xhr.status;
624 err.responseText = xhr.responseText;
625 err.xhr = xhr;
626 dfd.errback(err);
627 }
628 };
629
630 dojo._ioAddQueryToUrl = function(/*dojo.__IoCallbackArgs*/ioArgs){
631 //summary: Adds query params discovered by the io deferred construction to the URL.
632 //Only use this for operations which are fundamentally GET-type operations.
633 if(ioArgs.query.length){
634 ioArgs.url += (ioArgs.url.indexOf("?") == -1 ? "?" : "&") + ioArgs.query;
635 ioArgs.query = null;
636 }
637 };
638
639 /*=====
640 dojo.declare("dojo.__XhrArgs", dojo.__IoArgs, {
641 constructor: function(){
642 // summary:
643 // In addition to the properties listed for the dojo._IoArgs type,
644 // the following properties are allowed for dojo.xhr* methods.
645 // handleAs: String?
646 // Acceptable values are: text (default), json, json-comment-optional,
647 // json-comment-filtered, javascript, xml. See `dojo.contentHandlers`
648 // sync: Boolean?
649 // false is default. Indicates whether the request should
650 // be a synchronous (blocking) request.
651 // headers: Object?
652 // Additional HTTP headers to send in the request.
653 // failOk: Boolean?
654 // false is default. Indicates whether a request should be
655 // allowed to fail (and therefore no console error message in
656 // the event of a failure)
657 // contentType: String|Boolean
658 // "application/x-www-form-urlencoded" is default. Set to false to
659 // prevent a Content-Type header from being sent, or to a string
660 // to send a different Content-Type.
661 this.handleAs = handleAs;
662 this.sync = sync;
663 this.headers = headers;
664 this.failOk = failOk;
665 }
666 });
667 =====*/
668
669 dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){
670 // summary:
671 // Sends an HTTP request with the given method.
672 // description:
673 // Sends an HTTP request with the given method.
674 // See also dojo.xhrGet(), xhrPost(), xhrPut() and dojo.xhrDelete() for shortcuts
675 // for those HTTP methods. There are also methods for "raw" PUT and POST methods
676 // via dojo.rawXhrPut() and dojo.rawXhrPost() respectively.
677 // method:
678 // HTTP method to be used, such as GET, POST, PUT, DELETE. Should be uppercase.
679 // hasBody:
680 // If the request has an HTTP body, then pass true for hasBody.
681
682 //Make the Deferred object for this xhr request.
683 var dfd = dojo._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError);
684 var ioArgs = dfd.ioArgs;
685
686 //Pass the args to _xhrObj, to allow alternate XHR calls based specific calls, like
687 //the one used for iframe proxies.
688 var xhr = ioArgs.xhr = dojo._xhrObj(ioArgs.args);
689 //If XHR factory fails, cancel the deferred.
690 if(!xhr){
691 dfd.cancel();
692 return dfd;
693 }
694
695 //Allow for specifying the HTTP body completely.
696 if("postData" in args){
697 ioArgs.query = args.postData;
698 }else if("putData" in args){
699 ioArgs.query = args.putData;
700 }else if("rawBody" in args){
701 ioArgs.query = args.rawBody;
702 }else if((arguments.length > 2 && !hasBody) || "POST|PUT".indexOf(method.toUpperCase()) == -1){
703 //Check for hasBody being passed. If no hasBody,
704 //then only append query string if not a POST or PUT request.
705 dojo._ioAddQueryToUrl(ioArgs);
706 }
707
708 // IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open).
709 // workaround for IE6's apply() "issues"
710 xhr.open(method, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined);
711 if(args.headers){
712 for(var hdr in args.headers){
713 if(hdr.toLowerCase() === "content-type" && !args.contentType){
714 args.contentType = args.headers[hdr];
715 }else if(args.headers[hdr]){
716 //Only add header if it has a value. This allows for instnace, skipping
717 //insertion of X-Requested-With by specifying empty value.
718 xhr.setRequestHeader(hdr, args.headers[hdr]);
719 }
720 }
721 }
722 // FIXME: is this appropriate for all content types?
723 if(args.contentType !== false){
724 xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType);
725 }
726 if(!args.headers || !("X-Requested-With" in args.headers)){
727 xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
728 }
729 // FIXME: set other headers here!
730 dojo._ioNotifyStart(dfd);
731 if(dojo.config.debugAtAllCosts){
732 xhr.send(ioArgs.query);
733 }else{
734 try{
735 xhr.send(ioArgs.query);
736 }catch(e){
737 ioArgs.error = e;
738 dfd.cancel();
739 }
740 }
741 dojo._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);
742 xhr = null;
743 return dfd; // dojo.Deferred
744 };
745
746 dojo.xhrGet = function(/*dojo.__XhrArgs*/ args){
747 // summary:
748 // Sends an HTTP GET request to the server.
749 return dojo.xhr("GET", args); // dojo.Deferred
750 };
751
752 dojo.rawXhrPost = dojo.xhrPost = function(/*dojo.__XhrArgs*/ args){
753 // summary:
754 // Sends an HTTP POST request to the server. In addtion to the properties
755 // listed for the dojo.__XhrArgs type, the following property is allowed:
756 // postData:
757 // String. Send raw data in the body of the POST request.
758 return dojo.xhr("POST", args, true); // dojo.Deferred
759 };
760
761 dojo.rawXhrPut = dojo.xhrPut = function(/*dojo.__XhrArgs*/ args){
762 // summary:
763 // Sends an HTTP PUT request to the server. In addtion to the properties
764 // listed for the dojo.__XhrArgs type, the following property is allowed:
765 // putData:
766 // String. Send raw data in the body of the PUT request.
767 return dojo.xhr("PUT", args, true); // dojo.Deferred
768 };
769
770 dojo.xhrDelete = function(/*dojo.__XhrArgs*/ args){
771 // summary:
772 // Sends an HTTP DELETE request to the server.
773 return dojo.xhr("DELETE", args); //dojo.Deferred
774 };
775
776 /*
777 dojo.wrapForm = function(formNode){
778 //summary:
779 // A replacement for FormBind, but not implemented yet.
780
781 // FIXME: need to think harder about what extensions to this we might
782 // want. What should we allow folks to do w/ this? What events to
783 // set/send?
784 throw new Error("dojo.wrapForm not yet implemented");
785 }
786 */
787
788 dojo._isDocumentOk = function(http){
789 var stat = http.status || 0;
790 stat =
791 (stat >= 200 && stat < 300) || // allow any 2XX response code
792 stat == 304 || // or, get it out of the cache
793 stat == 1223 || // or, Internet Explorer mangled the status code
794 !stat; // or, we're Titanium/browser chrome/chrome extension requesting a local file
795 return stat; // Boolean
796 };
797
798 dojo._getText = function(url){
799 var result;
800 dojo.xhrGet({url:url, sync:true, load:function(text){
801 result = text;
802 }});
803 return result;
804 };
805
806 // Add aliases for static functions to dojo.xhr since dojo.xhr is what's returned from this module
807 lang.mixin(dojo.xhr, {
808 _xhrObj: dojo._xhrObj,
809 fieldToObject: domForm.fieldToObject,
810 formToObject: domForm.toObject,
811 objectToQuery: ioq.objectToQuery,
812 formToQuery: domForm.toQuery,
813 formToJson: domForm.toJson,
814 queryToObject: ioq.queryToObject,
815 contentHandlers: handlers,
816 _ioSetArgs: dojo._ioSetArgs,
817 _ioCancelAll: dojo._ioCancelAll,
818 _ioNotifyStart: dojo._ioNotifyStart,
819 _ioWatch: dojo._ioWatch,
820 _ioAddQueryToUrl: dojo._ioAddQueryToUrl,
821 _isDocumentOk: dojo._isDocumentOk,
822 _getText: dojo._getText,
823 get: dojo.xhrGet,
824 post: dojo.xhrPost,
825 put: dojo.xhrPut,
826 del: dojo.xhrDelete // because "delete" is a reserved word
827 });
828
829 return dojo.xhr;
830 });