]> dev.renevier.net Git - syp.git/blob - openlayers/lib/OpenLayers/Request/XMLHttpRequest.js
initial commit
[syp.git] / openlayers / lib / OpenLayers / Request / XMLHttpRequest.js
1 // Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //   http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 /**
16  * @requires OpenLayers/Request.js
17  */
18
19 (function () {
20
21     // Save reference to earlier defined object implementation (if any)
22     var oXMLHttpRequest    = window.XMLHttpRequest;
23
24     // Define on browser type
25     var bGecko    = !!window.controllers,
26         bIE        = window.document.all && !window.opera;
27
28     // Constructor
29     function cXMLHttpRequest() {
30         this._object    = oXMLHttpRequest ? new oXMLHttpRequest : new window.ActiveXObject('Microsoft.XMLHTTP');
31     };
32
33     // BUGFIX: Firefox with Firebug installed would break pages if not executed
34     if (bGecko && oXMLHttpRequest.wrapped)
35         cXMLHttpRequest.wrapped    = oXMLHttpRequest.wrapped;
36
37     // Constants
38     cXMLHttpRequest.UNSENT                = 0;
39     cXMLHttpRequest.OPENED                = 1;
40     cXMLHttpRequest.HEADERS_RECEIVED    = 2;
41     cXMLHttpRequest.LOADING                = 3;
42     cXMLHttpRequest.DONE                = 4;
43
44     // Public Properties
45     cXMLHttpRequest.prototype.readyState    = cXMLHttpRequest.UNSENT;
46     cXMLHttpRequest.prototype.responseText    = "";
47     cXMLHttpRequest.prototype.responseXML    = null;
48     cXMLHttpRequest.prototype.status        = 0;
49     cXMLHttpRequest.prototype.statusText    = "";
50
51     // Instance-level Events Handlers
52     cXMLHttpRequest.prototype.onreadystatechange    = null;
53
54     // Class-level Events Handlers
55     cXMLHttpRequest.onreadystatechange    = null;
56     cXMLHttpRequest.onopen                = null;
57     cXMLHttpRequest.onsend                = null;
58     cXMLHttpRequest.onabort                = null;
59
60     // Public Methods
61     cXMLHttpRequest.prototype.open    = function(sMethod, sUrl, bAsync, sUser, sPassword) {
62
63         // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests
64         this._async        = bAsync;
65
66         // Set the onreadystatechange handler
67         var oRequest    = this,
68             nState        = this.readyState;
69
70         // BUGFIX: IE - memory leak on page unload (inter-page leak)
71         if (bIE) {
72             var fOnUnload    = function() {
73                 if (oRequest._object.readyState != cXMLHttpRequest.DONE)
74                     fCleanTransport(oRequest);
75             };
76             if (bAsync)
77                 window.attachEvent("onunload", fOnUnload);
78         }
79
80         this._object.onreadystatechange    = function() {
81             if (bGecko && !bAsync)
82                 return;
83
84             // Synchronize state
85             oRequest.readyState        = oRequest._object.readyState;
86
87             //
88             fSynchronizeValues(oRequest);
89
90             // BUGFIX: Firefox fires unneccesary DONE when aborting
91             if (oRequest._aborted) {
92                 // Reset readyState to UNSENT
93                 oRequest.readyState    = cXMLHttpRequest.UNSENT;
94
95                 // Return now
96                 return;
97             }
98
99             if (oRequest.readyState == cXMLHttpRequest.DONE) {
100                 //
101                 fCleanTransport(oRequest);
102 // Uncomment this block if you need a fix for IE cache
103 /*
104                 // BUGFIX: IE - cache issue
105                 if (!oRequest._object.getResponseHeader("Date")) {
106                     // Save object to cache
107                     oRequest._cached    = oRequest._object;
108
109                     // Instantiate a new transport object
110                     cXMLHttpRequest.call(oRequest);
111
112                     // Re-send request
113                     oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
114                     oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0));
115                     // Copy headers set
116                     if (oRequest._headers)
117                         for (var sHeader in oRequest._headers)
118                             if (typeof oRequest._headers[sHeader] == "string")    // Some frameworks prototype objects with functions
119                                 oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);
120
121                     oRequest._object.onreadystatechange    = function() {
122                         // Synchronize state
123                         oRequest.readyState        = oRequest._object.readyState;
124
125                         if (oRequest._aborted) {
126                             //
127                             oRequest.readyState    = cXMLHttpRequest.UNSENT;
128
129                             // Return
130                             return;
131                         }
132
133                         if (oRequest.readyState == cXMLHttpRequest.DONE) {
134                             // Clean Object
135                             fCleanTransport(oRequest);
136
137                             // get cached request
138                             if (oRequest.status == 304)
139                                 oRequest._object    = oRequest._cached;
140
141                             //
142                             delete oRequest._cached;
143
144                             //
145                             fSynchronizeValues(oRequest);
146
147                             //
148                             fReadyStateChange(oRequest);
149
150                             // BUGFIX: IE - memory leak in interrupted
151                             if (bIE && bAsync)
152                                 window.detachEvent("onunload", fOnUnload);
153                         }
154                     };
155                     oRequest._object.send(null);
156
157                     // Return now - wait untill re-sent request is finished
158                     return;
159                 };
160 */
161                 // BUGFIX: IE - memory leak in interrupted
162                 if (bIE && bAsync)
163                     window.detachEvent("onunload", fOnUnload);
164             }
165
166             // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice
167             if (nState != oRequest.readyState)
168                 fReadyStateChange(oRequest);
169
170             nState    = oRequest.readyState;
171         };
172
173         // Add method sniffer
174         if (cXMLHttpRequest.onopen)
175             cXMLHttpRequest.onopen.apply(this, arguments);
176
177         this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
178
179         // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
180         if (!bAsync && bGecko) {
181             this.readyState    = cXMLHttpRequest.OPENED;
182
183             fReadyStateChange(this);
184         }
185     };
186     cXMLHttpRequest.prototype.send    = function(vData) {
187         // Add method sniffer
188         if (cXMLHttpRequest.onsend)
189             cXMLHttpRequest.onsend.apply(this, arguments);
190
191         // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required
192         // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent
193         // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)
194         if (vData && vData.nodeType) {
195             vData    = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;
196             if (!this._headers["Content-Type"])
197                 this._object.setRequestHeader("Content-Type", "application/xml");
198         }
199
200         this._object.send(vData);
201
202         // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
203         if (bGecko && !this._async) {
204             this.readyState    = cXMLHttpRequest.OPENED;
205
206             // Synchronize state
207             fSynchronizeValues(this);
208
209             // Simulate missing states
210             while (this.readyState < cXMLHttpRequest.DONE) {
211                 this.readyState++;
212                 fReadyStateChange(this);
213                 // Check if we are aborted
214                 if (this._aborted)
215                     return;
216             }
217         }
218     };
219     cXMLHttpRequest.prototype.abort    = function() {
220         // Add method sniffer
221         if (cXMLHttpRequest.onabort)
222             cXMLHttpRequest.onabort.apply(this, arguments);
223
224         // BUGFIX: Gecko - unneccesary DONE when aborting
225         if (this.readyState > cXMLHttpRequest.UNSENT)
226             this._aborted    = true;
227
228         this._object.abort();
229
230         // BUGFIX: IE - memory leak
231         fCleanTransport(this);
232     };
233     cXMLHttpRequest.prototype.getAllResponseHeaders    = function() {
234         return this._object.getAllResponseHeaders();
235     };
236     cXMLHttpRequest.prototype.getResponseHeader    = function(sName) {
237         return this._object.getResponseHeader(sName);
238     };
239     cXMLHttpRequest.prototype.setRequestHeader    = function(sName, sValue) {
240         // BUGFIX: IE - cache issue
241         if (!this._headers)
242             this._headers    = {};
243         this._headers[sName]    = sValue;
244
245         return this._object.setRequestHeader(sName, sValue);
246     };
247     cXMLHttpRequest.prototype.toString    = function() {
248         return '[' + "object" + ' ' + "XMLHttpRequest" + ']';
249     };
250     cXMLHttpRequest.toString    = function() {
251         return '[' + "XMLHttpRequest" + ']';
252     };
253
254     // Helper function
255     function fReadyStateChange(oRequest) {
256         // Execute onreadystatechange
257         if (oRequest.onreadystatechange)
258             oRequest.onreadystatechange.apply(oRequest);
259
260         // Sniffing code
261         if (cXMLHttpRequest.onreadystatechange)
262             cXMLHttpRequest.onreadystatechange.apply(oRequest);
263     };
264
265     function fGetDocument(oRequest) {
266         var oDocument    = oRequest.responseXML;
267         // Try parsing responseText
268         if (bIE && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) {
269             oDocument    = new ActiveXObject('Microsoft.XMLDOM');
270             oDocument.loadXML(oRequest.responseText);
271         }
272         // Check if there is no error in document
273         if (oDocument)
274             if ((bIE && oDocument.parseError != 0) || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror"))
275                 return null;
276         return oDocument;
277     };
278
279     function fSynchronizeValues(oRequest) {
280         try {    oRequest.responseText    = oRequest._object.responseText;    } catch (e) {}
281         try {    oRequest.responseXML    = fGetDocument(oRequest._object);    } catch (e) {}
282         try {    oRequest.status            = oRequest._object.status;            } catch (e) {}
283         try {    oRequest.statusText        = oRequest._object.statusText;        } catch (e) {}
284     };
285
286     function fCleanTransport(oRequest) {
287         // BUGFIX: IE - memory leak (on-page leak)
288         oRequest._object.onreadystatechange    = new window.Function;
289
290         // Delete private properties
291         delete oRequest._headers;
292     };
293
294     // Internet Explorer 5.0 (missing apply)
295     if (!window.Function.prototype.apply) {
296         window.Function.prototype.apply    = function(oRequest, oArguments) {
297             if (!oArguments)
298                 oArguments    = [];
299             oRequest.__func    = this;
300             oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
301             delete oRequest.__func;
302         };
303     };
304
305     // Register new object with window
306     /**
307      * Class: OpenLayers.Request.XMLHttpRequest
308      * Standard-compliant (W3C) cross-browser implementation of the
309      *     XMLHttpRequest object.  From
310      *     http://code.google.com/p/xmlhttprequest/.
311      */
312     OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;
313 })();