Fix #6913 - add more documentation to code
[roojs1] / Roo / lib / Ajax.js
1  
2
3 (function() {
4     /**
5      * @class Roo.lib.Ajax
6      *
7      * provide a simple Ajax request utility functions
8      * 
9      * Portions of this file are based on pieces of Yahoo User Interface Library
10     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
11     * YUI licensed under the BSD License:
12     * http://developer.yahoo.net/yui/license.txt
13     * <script type="text/javascript">
14     *
15      *
16      */
17     Roo.lib.Ajax = {
18         /**
19          * @static 
20          */
21         request : function(method, uri, cb, data, options) {
22             if(options){
23                 var hs = options.headers;
24                 if(hs){
25                     for(var h in hs){
26                         if(hs.hasOwnProperty(h)){
27                             this.initHeader(h, hs[h], false);
28                         }
29                     }
30                 }
31                 if(options.xmlData){
32                     this.initHeader('Content-Type', 'text/xml', false);
33                     method = 'POST';
34                     data = options.xmlData;
35                 }
36             }
37
38             return this.asyncRequest(method, uri, cb, data);
39         },
40         /**
41          * serialize a form
42          *
43          * @static
44          * @param {DomForm} form element
45          * @return {String} urlencode form output.
46          */
47         serializeForm : function(form) {
48             if(typeof form == 'string') {
49                 form = (document.getElementById(form) || document.forms[form]);
50             }
51
52             var el, name, val, disabled, data = '', hasSubmit = false;
53             for (var i = 0; i < form.elements.length; i++) {
54                 el = form.elements[i];
55                 disabled = form.elements[i].disabled;
56                 name = form.elements[i].name;
57                 val = form.elements[i].value;
58
59                 if (!disabled && name){
60                     switch (el.type)
61                             {
62                         case 'select-one':
63                         case 'select-multiple':
64                             for (var j = 0; j < el.options.length; j++) {
65                                 if (el.options[j].selected) {
66                                     if (Roo.isIE) {
67                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
68                                     }
69                                     else {
70                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
71                                     }
72                                 }
73                             }
74                             break;
75                         case 'radio':
76                         case 'checkbox':
77                             if (el.checked) {
78                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
79                             }
80                             break;
81                         case 'file':
82
83                         case undefined:
84
85                         case 'reset':
86
87                         case 'button':
88
89                             break;
90                         case 'submit':
91                             if(hasSubmit == false) {
92                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
93                                 hasSubmit = true;
94                             }
95                             break;
96                         default:
97                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
98                             break;
99                     }
100                 }
101             }
102             data = data.substr(0, data.length - 1);
103             return data;
104         },
105
106         headers:{},
107
108         hasHeaders:false,
109
110         useDefaultHeader:true,
111
112         defaultPostHeader:'application/x-www-form-urlencoded',
113
114         useDefaultXhrHeader:true,
115
116         defaultXhrHeader:'XMLHttpRequest',
117
118         hasDefaultHeaders:true,
119
120         defaultHeaders:{},
121
122         poll:{},
123
124         timeout:{},
125
126         pollInterval:50,
127
128         transactionId:0,
129
130         setProgId:function(id)
131         {
132             this.activeX.unshift(id);
133         },
134
135         setDefaultPostHeader:function(b)
136         {
137             this.useDefaultHeader = b;
138         },
139
140         setDefaultXhrHeader:function(b)
141         {
142             this.useDefaultXhrHeader = b;
143         },
144
145         setPollingInterval:function(i)
146         {
147             if (typeof i == 'number' && isFinite(i)) {
148                 this.pollInterval = i;
149             }
150         },
151
152         createXhrObject:function(transactionId)
153         {
154             var obj,http;
155             try
156             {
157
158                 http = new XMLHttpRequest();
159
160                 obj = { conn:http, tId:transactionId };
161             }
162             catch(e)
163             {
164                 for (var i = 0; i < this.activeX.length; ++i) {
165                     try
166                     {
167
168                         http = new ActiveXObject(this.activeX[i]);
169
170                         obj = { conn:http, tId:transactionId };
171                         break;
172                     }
173                     catch(e) {
174                     }
175                 }
176             }
177             finally
178             {
179                 return obj;
180             }
181         },
182
183         getConnectionObject:function()
184         {
185             var o;
186             var tId = this.transactionId;
187
188             try
189             {
190                 o = this.createXhrObject(tId);
191                 if (o) {
192                     this.transactionId++;
193                 }
194             }
195             catch(e) {
196             }
197             finally
198             {
199                 return o;
200             }
201         },
202
203         asyncRequest:function(method, uri, callback, postData)
204         {
205             var o = this.getConnectionObject();
206
207             if (!o) {
208                 return null;
209             }
210             else {
211                 o.conn.open(method, uri, true);
212
213                 if (this.useDefaultXhrHeader) {
214                     if (!this.defaultHeaders['X-Requested-With']) {
215                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
216                     }
217                 }
218
219                 if(postData && this.useDefaultHeader){
220                     this.initHeader('Content-Type', this.defaultPostHeader);
221                 }
222
223                  if (this.hasDefaultHeaders || this.hasHeaders) {
224                     this.setHeader(o);
225                 }
226
227                 this.handleReadyState(o, callback);
228                 o.conn.send(postData || null);
229
230                 return o;
231             }
232         },
233
234         handleReadyState:function(o, callback)
235         {
236             var oConn = this;
237
238             if (callback && callback.timeout) {
239                 
240                 this.timeout[o.tId] = window.setTimeout(function() {
241                     oConn.abort(o, callback, true);
242                 }, callback.timeout);
243             }
244
245             this.poll[o.tId] = window.setInterval(
246                     function() {
247                         if (o.conn && o.conn.readyState == 4) {
248                             window.clearInterval(oConn.poll[o.tId]);
249                             delete oConn.poll[o.tId];
250
251                             if(callback && callback.timeout) {
252                                 window.clearTimeout(oConn.timeout[o.tId]);
253                                 delete oConn.timeout[o.tId];
254                             }
255
256                             oConn.handleTransactionResponse(o, callback);
257                         }
258                     }
259                     , this.pollInterval);
260         },
261
262         handleTransactionResponse:function(o, callback, isAbort)
263         {
264
265             if (!callback) {
266                 this.releaseObject(o);
267                 return;
268             }
269
270             var httpStatus, responseObject;
271
272             try
273             {
274                 if (o.conn.status !== undefined && o.conn.status != 0) {
275                     httpStatus = o.conn.status;
276                 }
277                 else {
278                     httpStatus = 13030;
279                 }
280             }
281             catch(e) {
282
283
284                 httpStatus = 13030;
285             }
286
287             if (httpStatus >= 200 && httpStatus < 300) {
288                 responseObject = this.createResponseObject(o, callback.argument);
289                 if (callback.success) {
290                     if (!callback.scope) {
291                         callback.success(responseObject);
292                     }
293                     else {
294
295
296                         callback.success.apply(callback.scope, [responseObject]);
297                     }
298                 }
299             }
300             else {
301                 switch (httpStatus) {
302
303                     case 12002:
304                     case 12029:
305                     case 12030:
306                     case 12031:
307                     case 12152:
308                     case 13030:
309                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
310                         if (callback.failure) {
311                             if (!callback.scope) {
312                                 callback.failure(responseObject);
313                             }
314                             else {
315                                 callback.failure.apply(callback.scope, [responseObject]);
316                             }
317                         }
318                         break;
319                     default:
320                         responseObject = this.createResponseObject(o, callback.argument);
321                         if (callback.failure) {
322                             if (!callback.scope) {
323                                 callback.failure(responseObject);
324                             }
325                             else {
326                                 callback.failure.apply(callback.scope, [responseObject]);
327                             }
328                         }
329                 }
330             }
331
332             this.releaseObject(o);
333             responseObject = null;
334         },
335
336         createResponseObject:function(o, callbackArg)
337         {
338             var obj = {};
339             var headerObj = {};
340
341             try
342             {
343                 var headerStr = o.conn.getAllResponseHeaders();
344                 var header = headerStr.split('\n');
345                 for (var i = 0; i < header.length; i++) {
346                     var delimitPos = header[i].indexOf(':');
347                     if (delimitPos != -1) {
348                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
349                     }
350                 }
351             }
352             catch(e) {
353             }
354
355             obj.tId = o.tId;
356             obj.status = o.conn.status;
357             obj.statusText = o.conn.statusText;
358             obj.getResponseHeader = headerObj;
359             obj.getAllResponseHeaders = headerStr;
360             obj.responseText = o.conn.responseText;
361             obj.responseXML = o.conn.responseXML;
362
363             if (typeof callbackArg !== undefined) {
364                 obj.argument = callbackArg;
365             }
366
367             return obj;
368         },
369
370         createExceptionObject:function(tId, callbackArg, isAbort)
371         {
372             var COMM_CODE = 0;
373             var COMM_ERROR = 'communication failure';
374             var ABORT_CODE = -1;
375             var ABORT_ERROR = 'transaction aborted';
376
377             var obj = {};
378
379             obj.tId = tId;
380             if (isAbort) {
381                 obj.status = ABORT_CODE;
382                 obj.statusText = ABORT_ERROR;
383             }
384             else {
385                 obj.status = COMM_CODE;
386                 obj.statusText = COMM_ERROR;
387             }
388
389             if (callbackArg) {
390                 obj.argument = callbackArg;
391             }
392
393             return obj;
394         },
395
396         initHeader:function(label, value, isDefault)
397         {
398             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
399
400             if (headerObj[label] === undefined) {
401                 headerObj[label] = value;
402             }
403             else {
404
405
406                 headerObj[label] = value + "," + headerObj[label];
407             }
408
409             if (isDefault) {
410                 this.hasDefaultHeaders = true;
411             }
412             else {
413                 this.hasHeaders = true;
414             }
415         },
416
417
418         setHeader:function(o)
419         {
420             if (this.hasDefaultHeaders) {
421                 for (var prop in this.defaultHeaders) {
422                     if (this.defaultHeaders.hasOwnProperty(prop)) {
423                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
424                     }
425                 }
426             }
427
428             if (this.hasHeaders) {
429                 for (var prop in this.headers) {
430                     if (this.headers.hasOwnProperty(prop)) {
431                         o.conn.setRequestHeader(prop, this.headers[prop]);
432                     }
433                 }
434                 this.headers = {};
435                 this.hasHeaders = false;
436             }
437         },
438
439         resetDefaultHeaders:function() {
440             delete this.defaultHeaders;
441             this.defaultHeaders = {};
442             this.hasDefaultHeaders = false;
443         },
444
445         abort:function(o, callback, isTimeout)
446         {
447             if(this.isCallInProgress(o)) {
448                 o.conn.abort();
449                 window.clearInterval(this.poll[o.tId]);
450                 delete this.poll[o.tId];
451                 if (isTimeout) {
452                     delete this.timeout[o.tId];
453                 }
454
455                 this.handleTransactionResponse(o, callback, true);
456
457                 return true;
458             }
459             else {
460                 return false;
461             }
462         },
463
464
465         isCallInProgress:function(o)
466         {
467             if (o && o.conn) {
468                 return o.conn.readyState != 4 && o.conn.readyState != 0;
469             }
470             else {
471
472                 return false;
473             }
474         },
475
476
477         releaseObject:function(o)
478         {
479
480             o.conn = null;
481
482             o = null;
483         },
484
485         activeX:[
486         'MSXML2.XMLHTTP.3.0',
487         'MSXML2.XMLHTTP',
488         'Microsoft.XMLHTTP'
489         ]
490
491
492     };
493 })();