Upgrade to ExtJS 3.0.3 - Released 10/11/2009
[extjs.git] / src / adapter / core / ext-base-ajax.js
1 /*!
2  * Ext JS Library 3.0.3
3  * Copyright(c) 2006-2009 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /*\r
8  * Portions of this file are based on pieces of Yahoo User Interface Library\r
9  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.\r
10  * YUI licensed under the BSD License:\r
11  * http://developer.yahoo.net/yui/license.txt\r
12  */\r
13     Ext.lib.Ajax = function() {     \r
14             var activeX = ['MSXML2.XMLHTTP.3.0',\r
15                                    'MSXML2.XMLHTTP',\r
16                                    'Microsoft.XMLHTTP'],\r
17             CONTENTTYPE = 'Content-Type';\r
18                                    \r
19                 // private\r
20                 function setHeader(o) {\r
21                 var conn = o.conn,\r
22                         prop;\r
23                 \r
24                 function setTheHeaders(conn, headers){\r
25                         for (prop in headers) {\r
26                     if (headers.hasOwnProperty(prop)) {\r
27                         conn.setRequestHeader(prop, headers[prop]);\r
28                     }\r
29                 }   \r
30                 }               \r
31                 \r
32             if (pub.defaultHeaders) {\r
33                     setTheHeaders(conn, pub.defaultHeaders);\r
34             }\r
35 \r
36             if (pub.headers) {\r
37                                 setTheHeaders(conn, pub.headers);\r
38                 delete pub.headers;                \r
39             }\r
40         }    \r
41         \r
42         // private\r
43         function createExceptionObject(tId, callbackArg, isAbort, isTimeout) {          \r
44             return {\r
45                     tId : tId,\r
46                     status : isAbort ? -1 : 0,\r
47                     statusText : isAbort ? 'transaction aborted' : 'communication failure',\r
48                 isAbort: isAbort,\r
49                 isTimeout: isTimeout,\r
50                     argument : callbackArg\r
51             };\r
52         }  \r
53         \r
54         // private \r
55         function initHeader(label, value) {         \r
56                         (pub.headers = pub.headers || {})[label] = value;                                   \r
57         }\r
58             \r
59         // private\r
60         function createResponseObject(o, callbackArg) {\r
61             var headerObj = {},\r
62                 headerStr,              \r
63                 conn = o.conn,\r
64                 t,\r
65                 s;\r
66 \r
67             try {\r
68                 headerStr = o.conn.getAllResponseHeaders();   \r
69                 Ext.each(headerStr.replace(/\r\n/g, '\n').split('\n'), function(v){\r
70                     t = v.indexOf(':');\r
71                     if(t >= 0){\r
72                         s = v.substr(0, t).toLowerCase();\r
73                         if(v.charAt(t + 1) == ' '){\r
74                             ++t;\r
75                         }\r
76                         headerObj[s] = v.substr(t + 1);\r
77                     }\r
78                 });\r
79             } catch(e) {}\r
80                         \r
81             return {\r
82                 tId : o.tId,\r
83                 status : conn.status,\r
84                 statusText : conn.statusText,\r
85                 getResponseHeader : function(header){return headerObj[header.toLowerCase()];},\r
86                 getAllResponseHeaders : function(){return headerStr},\r
87                 responseText : conn.responseText,\r
88                 responseXML : conn.responseXML,\r
89                 argument : callbackArg\r
90             };\r
91         }\r
92         \r
93         // private\r
94         function releaseObject(o) {\r
95             o.conn = null;\r
96             o = null;\r
97         }        \r
98             \r
99         // private\r
100         function handleTransactionResponse(o, callback, isAbort, isTimeout) {\r
101             if (!callback) {\r
102                 releaseObject(o);\r
103                 return;\r
104             }\r
105 \r
106             var httpStatus, responseObject;\r
107 \r
108             try {\r
109                 if (o.conn.status !== undefined && o.conn.status != 0) {\r
110                     httpStatus = o.conn.status;\r
111                 }\r
112                 else {\r
113                     httpStatus = 13030;\r
114                 }\r
115             }\r
116             catch(e) {\r
117                 httpStatus = 13030;\r
118             }\r
119 \r
120             if ((httpStatus >= 200 && httpStatus < 300) || (Ext.isIE && httpStatus == 1223)) {\r
121                 responseObject = createResponseObject(o, callback.argument);\r
122                 if (callback.success) {\r
123                     if (!callback.scope) {\r
124                         callback.success(responseObject);\r
125                     }\r
126                     else {\r
127                         callback.success.apply(callback.scope, [responseObject]);\r
128                     }\r
129                 }\r
130             }\r
131             else {\r
132                 switch (httpStatus) {\r
133                     case 12002:\r
134                     case 12029:\r
135                     case 12030:\r
136                     case 12031:\r
137                     case 12152:\r
138                     case 13030:\r
139                         responseObject = createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false), isTimeout);\r
140                         if (callback.failure) {\r
141                             if (!callback.scope) {\r
142                                 callback.failure(responseObject);\r
143                             }\r
144                             else {\r
145                                 callback.failure.apply(callback.scope, [responseObject]);\r
146                             }\r
147                         }\r
148                         break;\r
149                     default:\r
150                         responseObject = createResponseObject(o, callback.argument);\r
151                         if (callback.failure) {\r
152                             if (!callback.scope) {\r
153                                 callback.failure(responseObject);\r
154                             }\r
155                             else {\r
156                                 callback.failure.apply(callback.scope, [responseObject]);\r
157                             }\r
158                         }\r
159                 }\r
160             }\r
161 \r
162             releaseObject(o);\r
163             responseObject = null;\r
164         }  \r
165         \r
166         // private\r
167         function handleReadyState(o, callback){\r
168             callback = callback || {};\r
169             var conn = o.conn,\r
170                 tId = o.tId,\r
171                 poll = pub.poll,\r
172                 cbTimeout = callback.timeout || null;\r
173 \r
174             if (cbTimeout) {\r
175                 pub.timeout[tId] = setTimeout(function() {\r
176                     pub.abort(o, callback, true);\r
177                 }, cbTimeout);\r
178             }\r
179 \r
180             poll[tId] = setInterval(\r
181                 function() {\r
182                     if (conn && conn.readyState == 4) {\r
183                         clearInterval(poll[tId]);\r
184                         poll[tId] = null;\r
185 \r
186                         if (cbTimeout) {\r
187                             clearTimeout(pub.timeout[tId]);\r
188                             pub.timeout[tId] = null;\r
189                         }\r
190 \r
191                         handleTransactionResponse(o, callback);\r
192                     }\r
193                 },\r
194                 pub.pollInterval);\r
195         }\r
196         \r
197         // private\r
198         function asyncRequest(method, uri, callback, postData) {\r
199             var o = getConnectionObject() || null;\r
200 \r
201             if (o) {\r
202                 o.conn.open(method, uri, true);\r
203 \r
204                 if (pub.useDefaultXhrHeader) {                    \r
205                         initHeader('X-Requested-With', pub.defaultXhrHeader);\r
206                 }\r
207 \r
208                 if(postData && pub.useDefaultHeader && (!pub.headers || !pub.headers[CONTENTTYPE])){\r
209                     initHeader(CONTENTTYPE, pub.defaultPostHeader);\r
210                 }\r
211 \r
212                 if (pub.defaultHeaders || pub.headers) {\r
213                     setHeader(o);\r
214                 }\r
215 \r
216                 handleReadyState(o, callback);\r
217                 o.conn.send(postData || null);\r
218             }\r
219             return o;\r
220         }\r
221         \r
222         // private\r
223         function getConnectionObject() {\r
224             var o;              \r
225 \r
226             try {\r
227                 if (o = createXhrObject(pub.transactionId)) {\r
228                     pub.transactionId++;\r
229                 }\r
230             } catch(e) {\r
231             } finally {\r
232                 return o;\r
233             }\r
234         }\r
235                \r
236         // private\r
237         function createXhrObject(transactionId) {\r
238             var http;\r
239                 \r
240             try {\r
241                 http = new XMLHttpRequest();                \r
242             } catch(e) {\r
243                 for (var i = 0; i < activeX.length; ++i) {                  \r
244                     try {\r
245                         http = new ActiveXObject(activeX[i]);                        \r
246                         break;\r
247                     } catch(e) {}\r
248                 }\r
249             } finally {\r
250                 return {conn : http, tId : transactionId};\r
251             }\r
252         }\r
253                  \r
254             var pub = {\r
255                 request : function(method, uri, cb, data, options) {\r
256                             if(options){\r
257                                 var me = this,                  \r
258                                         xmlData = options.xmlData,\r
259                                         jsonData = options.jsonData,\r
260                         hs;\r
261                                         \r
262                                 Ext.applyIf(me, options);               \r
263                             \r
264                             if(xmlData || jsonData){\r
265                         hs = me.headers;\r
266                         if(!hs || !hs[CONTENTTYPE]){\r
267                                         initHeader(CONTENTTYPE, xmlData ? 'text/xml' : 'application/json');\r
268                         }\r
269                                     data = xmlData || (Ext.isObject(jsonData) ? Ext.encode(jsonData) : jsonData);\r
270                                 }\r
271                             }                               \r
272                             return asyncRequest(method || options.method || "POST", uri, cb, data);\r
273                 },\r
274         \r
275                 serializeForm : function(form) {\r
276                         var fElements = form.elements || (document.forms[form] || Ext.getDom(form)).elements,\r
277                         hasSubmit = false,\r
278                         encoder = encodeURIComponent,\r
279                                 element,\r
280                         options, \r
281                         name, \r
282                         val,                    \r
283                         data = '',\r
284                         type;\r
285                         \r
286                         Ext.each(fElements, function(element) {                     \r
287                         name = element.name;                 \r
288                                         type = element.type;\r
289                                         \r
290                         if (!element.disabled && name){\r
291                                 if(/select-(one|multiple)/i.test(type)){                                        \r
292                                             Ext.each(element.options, function(opt) {\r
293                                                     if (opt.selected) {\r
294                                                             data += String.format("{0}={1}&",                                                                                             \r
295                                                                                                  encoder(name),\r
296                                                          encoder((opt.hasAttribute ? opt.hasAttribute('value') : opt.getAttribute('value') !== null) ? opt.value : opt.text));\r
297                                 }                                                               \r
298                             });\r
299                                 } else if(!/file|undefined|reset|button/i.test(type)) {\r
300                                         if(!(/radio|checkbox/i.test(type) && !element.checked) && !(type == 'submit' && hasSubmit)){\r
301                                     \r
302                                 data += encoder(name) + '=' + encoder(element.value) + '&';                     \r
303                                 hasSubmit = /submit/i.test(type);    \r
304                             }                           \r
305                                 } \r
306                         }\r
307                     });            \r
308                     return data.substr(0, data.length - 1);\r
309                 },\r
310                 \r
311                 useDefaultHeader : true,\r
312                 defaultPostHeader : 'application/x-www-form-urlencoded; charset=UTF-8',\r
313                 useDefaultXhrHeader : true,\r
314                 defaultXhrHeader : 'XMLHttpRequest',        \r
315                 poll : {},\r
316                 timeout : {},\r
317                 pollInterval : 50,\r
318                 transactionId : 0,\r
319                 \r
320 //      This is never called - Is it worth exposing this?                       \r
321 //              setProgId : function(id) {\r
322 //                  activeX.unshift(id);\r
323 //              },\r
324 \r
325 //      This is never called - Is it worth exposing this?       \r
326 //              setDefaultPostHeader : function(b) {\r
327 //                  this.useDefaultHeader = b;\r
328 //              },\r
329                 \r
330 //      This is never called - Is it worth exposing this?       \r
331 //              setDefaultXhrHeader : function(b) {\r
332 //                  this.useDefaultXhrHeader = b;\r
333 //              },\r
334 \r
335 //      This is never called - Is it worth exposing this?               \r
336 //              setPollingInterval : function(i) {\r
337 //                  if (typeof i == 'number' && isFinite(i)) {\r
338 //                      this.pollInterval = i;\r
339 //                  }\r
340 //              },\r
341                 \r
342 //      This is never called - Is it worth exposing this?\r
343 //              resetDefaultHeaders : function() {\r
344 //                  this.defaultHeaders = null;\r
345 //              },\r
346         \r
347                 abort : function(o, callback, isTimeout) {\r
348                         var me = this,\r
349                                 tId = o.tId,\r
350                                 isAbort = false;\r
351                         \r
352                     if (me.isCallInProgress(o)) {\r
353                         o.conn.abort();\r
354                         clearInterval(me.poll[tId]);\r
355                         me.poll[tId] = null;\r
356                         if (isTimeout) {\r
357                             me.timeout[tId] = null;\r
358                         }\r
359                                         \r
360                         handleTransactionResponse(o, callback, (isAbort = true), isTimeout);                \r
361                     }\r
362                     return isAbort;\r
363                 },\r
364         \r
365                 isCallInProgress : function(o) {\r
366                     // if there is a connection and readyState is not 0 or 4\r
367                     return o.conn && !{0:true,4:true}[o.conn.readyState];               \r
368                 }\r
369             };\r
370             return pub;\r
371     }();