]> dev.renevier.net Git - syp.git/blob - openlayers/lib/OpenLayers/Ajax.js
initial commit
[syp.git] / openlayers / lib / OpenLayers / Ajax.js
1 /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2  * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3  * full text of the license. */
4
5 /**
6  * @requires OpenLayers/Request/XMLHttpRequest.js
7  * @requires OpenLayers/Console.js
8  */
9
10 OpenLayers.ProxyHost = "";
11 //OpenLayers.ProxyHost = "examples/proxy.cgi?url=";
12
13 /**
14  * Ajax reader for OpenLayers
15  *
16  *  @uri url to do remote XML http get
17  *  @param {String} 'get' format params (x=y&a=b...)
18  *  @who object to handle callbacks for this request
19  *  @complete  the function to be called on success 
20  *  @failure  the function to be called on failure
21  *  
22  *   example usage from a caller:
23  *  
24  *     caps: function(request) {
25  *      -blah-  
26  *     },
27  *  
28  *     OpenLayers.loadURL(url,params,this,caps);
29  *
30  * Notice the above example does not provide an error handler; a default empty
31  * handler is provided which merely logs the error if a failure handler is not 
32  * supplied
33  *
34  */
35
36
37 /**
38  * Function: OpenLayers.nullHandler
39  * @param {} request
40  */
41 OpenLayers.nullHandler = function(request) {
42     OpenLayers.Console.userError(OpenLayers.i18n("unhandledRequest", {'statusText':request.statusText}));
43 };
44
45 /** 
46  * APIFunction: loadURL
47  * Background load a document.  For more flexibility in using XMLHttpRequest,
48  *     see the <OpenLayers.Request> methods.
49  *
50  * Parameters:
51  * uri - {String} URI of source doc
52  * params - {String} or {Object} GET params. Either a string in the form
53  *     "?hello=world&foo=bar" (do not forget the leading question mark)
54  *     or an object in the form {'hello': 'world', 'foo': 'bar}
55  * caller - {Object} object which gets callbacks
56  * onComplete - {Function} Optional callback for success.  The callback
57  *     will be called with this set to caller and will receive the request
58  *     object as an argument.  Note that if you do not specify an onComplete
59  *     function, <OpenLayers.nullHandler> will be called (which pops up a 
60  *     user friendly error message dialog).
61  * onFailure - {Function} Optional callback for failure.  In the event of
62  *     a failure, the callback will be called with this set to caller and will
63  *     receive the request object as an argument.  Note that if you do not
64  *     specify an onComplete function, <OpenLayers.nullHandler> will be called
65  *     (which pops up a user friendly error message dialog).
66  *
67  * Returns:
68  * {<OpenLayers.Request.XMLHttpRequest>}  The request object. To abort loading,
69  *     call request.abort().
70  */
71 OpenLayers.loadURL = function(uri, params, caller,
72                                   onComplete, onFailure) {
73     
74     if(typeof params == 'string') {
75         params = OpenLayers.Util.getParameters(params);
76     }
77     var success = (onComplete) ? onComplete : OpenLayers.nullHandler;
78     var failure = (onFailure) ? onFailure : OpenLayers.nullHandler;
79     
80     return OpenLayers.Request.GET({
81         url: uri, params: params,
82         success: success, failure: failure, scope: caller
83     });
84 };
85
86 /** 
87  * Function: parseXMLString
88  * Parse XML into a doc structure
89  * 
90  * Parameters:
91  * text - {String} 
92  * 
93  * Returns:
94  * {?} Parsed AJAX Responsev
95  */
96 OpenLayers.parseXMLString = function(text) {
97
98     //MS sucks, if the server is bad it dies
99     var index = text.indexOf('<');
100     if (index > 0) {
101         text = text.substring(index);
102     }
103
104     var ajaxResponse = OpenLayers.Util.Try(
105         function() {
106             var xmldom = new ActiveXObject('Microsoft.XMLDOM');
107             xmldom.loadXML(text);
108             return xmldom;
109         },
110         function() {
111             return new DOMParser().parseFromString(text, 'text/xml');
112         },
113         function() {
114             var req = new XMLHttpRequest();
115             req.open("GET", "data:" + "text/xml" +
116                      ";charset=utf-8," + encodeURIComponent(text), false);
117             if (req.overrideMimeType) {
118                 req.overrideMimeType("text/xml");
119             }
120             req.send(null);
121             return req.responseXML;
122         }
123     );
124
125     return ajaxResponse;
126 };
127
128
129 /**
130  * Namespace: OpenLayers.Ajax
131  */
132 OpenLayers.Ajax = {
133
134     /**
135      * Method: emptyFunction
136      */
137     emptyFunction: function () {},
138
139     /**
140      * Method: getTransport
141      * 
142      * Returns: 
143      * {Object} Transport mechanism for whichever browser we're in, or false if
144      *          none available.
145      */
146     getTransport: function() {
147         return OpenLayers.Util.Try(
148             function() {return new XMLHttpRequest();},
149             function() {return new ActiveXObject('Msxml2.XMLHTTP');},
150             function() {return new ActiveXObject('Microsoft.XMLHTTP');}
151         ) || false;
152     },
153
154     /**
155      * Property: activeRequestCount
156      * {Integer}
157      */
158     activeRequestCount: 0
159 };
160
161 /**
162  * Namespace: OpenLayers.Ajax.Responders
163  * {Object}
164  */
165 OpenLayers.Ajax.Responders = {
166   
167     /**
168      * Property: responders
169      * {Array}
170      */
171     responders: [],
172
173     /**
174      * Method: register
175      *  
176      * Parameters:
177      * responderToAdd - {?}
178      */
179     register: function(responderToAdd) {
180         for (var i = 0; i < this.responders.length; i++){
181             if (responderToAdd == this.responders[i]){
182                 return;
183             }
184         }
185         this.responders.push(responderToAdd);
186     },
187
188     /**
189      * Method: unregister
190      *  
191      * Parameters:
192      * responderToRemove - {?}
193      */
194     unregister: function(responderToRemove) {
195         OpenLayers.Util.removeItem(this.reponders, responderToRemove);
196     },
197
198     /**
199      * Method: dispatch
200      * 
201      * Parameters:
202      * callback - {?}
203      * request - {?}
204      * transport - {?}
205      */
206     dispatch: function(callback, request, transport) {
207         var responder;
208         for (var i = 0; i < this.responders.length; i++) {
209             responder = this.responders[i];
210      
211             if (responder[callback] && 
212                 typeof responder[callback] == 'function') {
213                 try {
214                     responder[callback].apply(responder, 
215                                               [request, transport]);
216                 } catch (e) {}
217             }
218         }
219     }
220 };
221
222 OpenLayers.Ajax.Responders.register({
223     /** 
224      * Function: onCreate
225      */
226     onCreate: function() {
227         OpenLayers.Ajax.activeRequestCount++;
228     },
229
230     /**
231      * Function: onComplete
232      */
233      onComplete: function() {
234          OpenLayers.Ajax.activeRequestCount--;
235      }
236 });
237
238 /**
239  * Class: OpenLayers.Ajax.Base
240  */
241 OpenLayers.Ajax.Base = OpenLayers.Class({
242       
243     /**
244      * Constructor: OpenLayers.Ajax.Base
245      * 
246      * Parameters: 
247      * options - {Object}
248      */
249     initialize: function(options) {
250         this.options = {
251             method:       'post',
252             asynchronous: true,
253             contentType:  'application/xml',
254             parameters:   ''
255         };
256         OpenLayers.Util.extend(this.options, options || {});
257         
258         this.options.method = this.options.method.toLowerCase();
259         
260         if (typeof this.options.parameters == 'string') {
261             this.options.parameters = 
262                 OpenLayers.Util.getParameters(this.options.parameters);
263         }
264     }
265 });
266
267 /**
268  * Class: OpenLayers.Ajax.Request
269  * *Deprecated*.  Use <OpenLayers.Request> method instead.
270  *
271  * Inherit:
272  *  - <OpenLayers.Ajax.Base>
273  */
274 OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {
275
276     /**
277      * Property: _complete
278      *
279      * {Boolean}
280      */
281     _complete: false,
282       
283     /**
284      * Constructor: OpenLayers.Ajax.Request
285      * 
286      * Parameters: 
287      * url - {String}
288      * options - {Object}
289      */
290     initialize: function(url, options) {
291         OpenLayers.Ajax.Base.prototype.initialize.apply(this, [options]);
292         
293         if (OpenLayers.ProxyHost && OpenLayers.String.startsWith(url, "http")) {
294             url = OpenLayers.ProxyHost + encodeURIComponent(url);
295         }
296         
297         this.transport = OpenLayers.Ajax.getTransport();
298         this.request(url);
299     },
300
301     /**
302      * Method: request
303      * 
304      * Parameters:
305      * url - {String}
306      */
307     request: function(url) {
308         this.url = url;
309         this.method = this.options.method;
310         var params = OpenLayers.Util.extend({}, this.options.parameters);
311         
312         if (this.method != 'get' && this.method != 'post') {
313             // simulate other verbs over post
314             params['_method'] = this.method;
315             this.method = 'post';
316         }
317
318         this.parameters = params;        
319         
320         if (params = OpenLayers.Util.getParameterString(params)) {
321             // when GET, append parameters to URL
322             if (this.method == 'get') {
323                 this.url += ((this.url.indexOf('?') > -1) ? '&' : '?') + params;
324             } else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
325                 params += '&_=';
326             }
327         }
328         try {
329             var response = new OpenLayers.Ajax.Response(this);
330             if (this.options.onCreate) {
331                 this.options.onCreate(response);
332             }
333             
334             OpenLayers.Ajax.Responders.dispatch('onCreate', 
335                                                 this, 
336                                                 response);
337     
338             this.transport.open(this.method.toUpperCase(), 
339                                 this.url,
340                                 this.options.asynchronous);
341     
342             if (this.options.asynchronous) {
343                 window.setTimeout(
344                     OpenLayers.Function.bind(this.respondToReadyState, this, 1),
345                     10);
346             }
347             
348             this.transport.onreadystatechange = 
349                 OpenLayers.Function.bind(this.onStateChange, this);    
350             this.setRequestHeaders();
351     
352             this.body =  this.method == 'post' ?
353                 (this.options.postBody || params) : null;
354             this.transport.send(this.body);
355     
356             // Force Firefox to handle ready state 4 for synchronous requests
357             if (!this.options.asynchronous && 
358                 this.transport.overrideMimeType) {
359                 this.onStateChange();
360             }
361         } catch (e) {
362             this.dispatchException(e);
363         }
364     },
365
366     /**
367      * Method: onStateChange
368      */
369     onStateChange: function() {
370         var readyState = this.transport.readyState;
371         if (readyState > 1 && !((readyState == 4) && this._complete)) {
372             this.respondToReadyState(this.transport.readyState);
373         }
374     },
375      
376     /**
377      * Method: setRequestHeaders
378      */
379     setRequestHeaders: function() {
380         var headers = {
381             'X-Requested-With': 'XMLHttpRequest',
382             'Accept': 'text/javascript, text/html, application/xml, text/xml, */*',
383             'OpenLayers': true
384         };
385
386         if (this.method == 'post') {
387             headers['Content-type'] = this.options.contentType +
388                 (this.options.encoding ? '; charset=' + this.options.encoding : '');
389     
390             /* Force "Connection: close" for older Mozilla browsers to work
391              * around a bug where XMLHttpRequest sends an incorrect
392              * Content-length header. See Mozilla Bugzilla #246651.
393              */
394             if (this.transport.overrideMimeType &&
395                 (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) {
396                 headers['Connection'] = 'close';
397             }
398         }
399         // user-defined headers
400         if (typeof this.options.requestHeaders == 'object') {    
401             var extras = this.options.requestHeaders;
402             
403             if (typeof extras.push == 'function') {
404                 for (var i = 0, length = extras.length; i < length; i += 2) {
405                     headers[extras[i]] = extras[i+1];
406                 }
407             } else {
408                 for (var i in extras) {
409                     headers[i] = extras[i];
410                 }
411             }
412         }
413         
414         for (var name in headers) {
415             this.transport.setRequestHeader(name, headers[name]);
416         }
417     },
418     
419     /**
420      * Method: success
421      *
422      * Returns:
423      * {Boolean} - 
424      */
425     success: function() {
426         var status = this.getStatus();
427         return !status || (status >=200 && status < 300);
428     },
429     
430     /**
431      * Method: getStatus
432      *
433      * Returns:
434      * {Integer} - Status
435      */
436     getStatus: function() {
437         try {
438             return this.transport.status || 0;
439         } catch (e) {
440             return 0;
441         }
442     },
443
444     /**
445      * Method: respondToReadyState
446      *
447      * Parameters:
448      * readyState - {?}
449      */
450     respondToReadyState: function(readyState) {
451         var state = OpenLayers.Ajax.Request.Events[readyState];
452         var response = new OpenLayers.Ajax.Response(this);
453     
454         if (state == 'Complete') {
455             try {
456                 this._complete = true;
457                 (this.options['on' + response.status] ||
458                     this.options['on' + (this.success() ? 'Success' : 'Failure')] ||
459                     OpenLayers.Ajax.emptyFunction)(response);
460             } catch (e) {
461                 this.dispatchException(e);
462             }
463     
464             var contentType = response.getHeader('Content-type');
465         }
466     
467         try {
468             (this.options['on' + state] || 
469              OpenLayers.Ajax.emptyFunction)(response);
470              OpenLayers.Ajax.Responders.dispatch('on' + state, 
471                                                  this, 
472                                                  response);
473         } catch (e) {
474             this.dispatchException(e);
475         }
476     
477         if (state == 'Complete') {
478             // avoid memory leak in MSIE: clean up
479             this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
480         }
481     },
482     
483     /**
484      * Method: getHeader
485      * 
486      * Parameters:
487      * name - {String} Header name
488      *
489      * Returns:
490      * {?} - response header for the given name
491      */
492     getHeader: function(name) {
493         try {
494             return this.transport.getResponseHeader(name);
495         } catch (e) {
496             return null;
497         }
498     },
499
500     /**
501      * Method: dispatchException
502      * If the optional onException function is set, execute it
503      * and then dispatch the call to any other listener registered
504      * for onException.
505      * 
506      * If no optional onException function is set, we suspect that
507      * the user may have also not used
508      * OpenLayers.Ajax.Responders.register to register a listener
509      * for the onException call.  To make sure that something
510      * gets done with this exception, only dispatch the call if there
511      * are listeners.
512      *
513      * If you explicitly want to swallow exceptions, set
514      * request.options.onException to an empty function (function(){})
515      * or register an empty function with <OpenLayers.Ajax.Responders>
516      * for onException.
517      * 
518      * Parameters:
519      * exception - {?}
520      */
521     dispatchException: function(exception) {
522         var handler = this.options.onException;
523         if(handler) {
524             // call options.onException and alert any other listeners
525             handler(this, exception);
526             OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
527         } else {
528             // check if there are any other listeners
529             var listener = false;
530             var responders = OpenLayers.Ajax.Responders.responders;
531             for (var i = 0; i < responders.length; i++) {
532                 if(responders[i].onException) {
533                     listener = true;
534                     break;
535                 }
536             }
537             if(listener) {
538                 // call all listeners
539                 OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
540             } else {
541                 // let the exception through
542                 throw exception;
543             }
544         }
545     }
546 });
547
548 /** 
549  * Property: Events
550  * {Array(String)}
551  */
552 OpenLayers.Ajax.Request.Events =
553   ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
554
555 /**
556  * Class: OpenLayers.Ajax.Response
557  */
558 OpenLayers.Ajax.Response = OpenLayers.Class({
559
560     /**
561      * Property: status
562      *
563      * {Integer}
564      */
565     status: 0,
566     
567
568     /**
569      * Property: statusText
570      *
571      * {String}
572      */
573     statusText: '',
574       
575     /**
576      * Constructor: OpenLayers.Ajax.Response
577      * 
578      * Parameters: 
579      * request - {Object}
580      */
581     initialize: function(request) {
582         this.request = request;
583         var transport = this.transport = request.transport,
584             readyState = this.readyState = transport.readyState;
585         
586         if ((readyState > 2 &&
587             !(!!(window.attachEvent && !window.opera))) ||
588             readyState == 4) {
589             this.status       = this.getStatus();
590             this.statusText   = this.getStatusText();
591             this.responseText = transport.responseText == null ?
592                 '' : String(transport.responseText);
593         }
594         
595         if(readyState == 4) {
596             var xml = transport.responseXML;
597             this.responseXML  = xml === undefined ? null : xml;
598         }
599     },
600     
601     /**
602      * Method: getStatus
603      */
604     getStatus: OpenLayers.Ajax.Request.prototype.getStatus,
605     
606     /**
607      * Method: getStatustext
608      *
609      * Returns:
610      * {String} - statusText
611      */
612     getStatusText: function() {
613         try {
614             return this.transport.statusText || '';
615         } catch (e) {
616             return '';
617         }
618     },
619     
620     /**
621      * Method: getHeader
622      */
623     getHeader: OpenLayers.Ajax.Request.prototype.getHeader,
624     
625     /** 
626      * Method: getResponseHeader
627      *
628      * Returns:
629      * {?} - response header for given name
630      */
631     getResponseHeader: function(name) {
632         return this.transport.getResponseHeader(name);
633     }
634 });
635
636
637 /**
638  * Function: getElementsByTagNameNS
639  * 
640  * Parameters:
641  * parentnode - {?}
642  * nsuri - {?}
643  * nsprefix - {?}
644  * tagname - {?}
645  * 
646  * Returns:
647  * {?}
648  */
649 OpenLayers.Ajax.getElementsByTagNameNS  = function(parentnode, nsuri, 
650                                                    nsprefix, tagname) {
651     var elem = null;
652     if (parentnode.getElementsByTagNameNS) {
653         elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
654     } else {
655         elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
656     }
657     return elem;
658 };
659
660
661 /**
662  * Function: serializeXMLToString
663  * Wrapper function around XMLSerializer, which doesn't exist/work in
664  *     IE/Safari. We need to come up with a way to serialize in those browser:
665  *     for now, these browsers will just fail. #535, #536
666  *
667  * Parameters: 
668  * xmldom {XMLNode} xml dom to serialize
669  * 
670  * Returns:
671  * {?}
672  */
673 OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
674     var serializer = new XMLSerializer();
675     var data = serializer.serializeToString(xmldom);
676     return data;
677 };