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