added abortAllRequests which does just that.
[Evergreen.git] / Open-ILS / web / opac / common / js / RemoteRequest.js
1 var XML_HTTP_GATEWAY = "gateway";
2 var XML_HTTP_SERVER = "dev.gapines.org";
3 var XML_HTTP_MAX_TRIES = 3;
4
5 //var IAMXUL = false;
6 function isXUL() { try { if(IAMXUL) return true;}catch(e){return false;}; }
7
8 /* some communication exceptions */
9 function EX(message) { this.init(message); }
10 EX.prototype.init = function(message) { this.message = message; }
11 EX.prototype.toString = function() { return "\n *** Exception Occured \n" + this.message; }  
12 EXCommunication.prototype              = new EX();
13 EXCommunication.prototype.constructor  = EXCommunication;
14 EXCommunication.baseClass              = EX.prototype.constructor;
15 function EXCommunication(message) { this.classname="EXCommunication"; this.init("EXCommunication: " + message); }                          
16 /* ------------------------------------------------ */
17
18
19 var _allrequests = {};
20
21 function cleanRemoteRequests() {
22         for( var i in _allrequests ) 
23                 destroyRequest(_allrequests[i]);
24 }
25
26 function abortAllRequests() {
27         for( var i in _allrequests ) {
28                 var r = _allrequests[i];
29                 if(r) { 
30                         /* this has to come before abort() or IE will puke on you */
31                         r.xmlhttp.onreadystatechange = function(){};
32                         r.abort();
33                         destroyRequest(r);
34                 }
35         }
36 }
37
38 function destroyRequest(r) {
39         if(r == null) return;
40
41         if( r.xmlhttp ) {
42                 r.xmlhttp.onreadystatechange = function(){};
43                 //r.abort();
44                 r.xmlhttp = null;
45         }
46
47         r.callback                              = null;
48         r.userdata                              = null;
49         _allrequests[r.id]      = null;
50 }
51
52 /* ----------------------------------------------------------------------- */
53 /* Request object */
54 function RemoteRequest( service, method ) {
55
56
57         this.service    = service;
58         this.method             = method;
59         this.xmlhttp    = false;
60         this.name               = null;
61         this.sendCount = 0;
62
63         this.type               = "POST"; /* default */
64         this.id                 = service + method + Math.random();
65         this.cancelled = false;
66
67         _allrequests[this.id] = this;
68
69         var i = 2;
70         this.params = ""; 
71
72         while(i < arguments.length) {
73                 var object = js2JSON(arguments[i++]);
74                 this.params += "&param=" + encodeURIComponent(object);
75         }
76
77         if(!this.params) { this.params = ""; }
78         this.param_string = "service=" + service + "&method=" + method + this.params;
79         if( this.buildXMLRequest() == null ) alert("Browser is not supported!");
80 }
81
82 RemoteRequest.prototype.abort = function() {
83         if( this.xmlhttp ) this.xmlhttp.abort();
84 }
85
86 /* constructs our XMLHTTPRequest object */
87 RemoteRequest.prototype.buildXMLRequest = function() {
88
89         var x;
90         try { 
91                 x = new ActiveXObject("Msxml2.XMLHTTP"); 
92         } catch (e) {
93                 try { 
94                         x = new ActiveXObject("Microsoft.XMLHTTP"); 
95                 } catch (E) {
96                         x = false;
97                 }
98         }
99
100         if (!x && typeof XMLHttpRequest!='undefined') x = new XMLHttpRequest();
101
102         if(!x) {
103                 alert("NEEDS NEWER JAVASCRIPT for XMLHTTPRequest()");
104                 return null;
105         }
106
107         this.xmlhttp = x;
108         return true;
109 }
110
111
112 function _remoteRequestCallback(id) {
113
114         var object = _allrequests[id];
115         if(object.cancelled) return;
116
117         if( object.xmlhttp.readyState == 4 ) {
118                 try {
119                         object.callback(object);
120                 } catch(E) {
121
122                         /* if we receive a communication error, retry the request up
123                                 to XML_HTTP_MAX_TRIES attempts */
124                         if( E && E.classname == "EXCommunication" ) {
125
126                                 //try { dump('Communication Error: ' + E ); } catch(e){}
127                                 alert('Debug:  Communication Error: ' + E );
128
129                                 if(object.sendCount >= XML_HTTP_MAX_TRIES ) {
130                                         if(isXUL()) throw object;
131                                          else alert("Arrrgghh, Matey! Error communicating:\n" + E  + "\n" + object.param_string);
132                                 } else {
133                                         object.buildXMLRequest();
134                                         object.send();
135                                         return;
136                                 }
137                         } else { throw E; }
138
139                 } finally { 
140                         destroyRequest(object); 
141                         object = null; 
142                 }  
143         }
144 }
145
146
147 /* define the callback we use when this request has received
148         all of its data */
149 RemoteRequest.prototype.setCompleteCallback = function(callback) {
150         if(this.cancelled) return;
151         this.callback = callback;
152         var id = this.id;
153         this.xmlhttp.onreadystatechange = function() { _remoteRequestCallback(id); }
154 }
155
156
157 /* http by default.  This makes it https. *ONLY works when
158         embedded in a XUL app. */
159 RemoteRequest.prototype.setSecure = function(bool) {
160         this.secure = bool; 
161 }
162
163 RemoteRequest.prototype.send = function(blocking) {
164
165         if(this.cancelled) return;
166
167         /* determine the xmlhttp server dynamically */
168         var url = location.protocol + "//" + location.host + "/" + XML_HTTP_GATEWAY;
169
170         if(isXUL()) {
171                 if(this.secure || url.match(/^https:/) )
172                         url =   "https://" + XML_HTTP_SERVER + "/" + XML_HTTP_GATEWAY;
173                 else
174                         url =   "http://" + XML_HTTP_SERVER + "/" + XML_HTTP_GATEWAY;
175         }
176
177         var data = null;
178         if( this.type == 'GET' ) url +=  "?" + this.param_string; 
179
180         try {
181
182                 if(blocking) this.xmlhttp.open(this.type, url, false);
183                 else this.xmlhttp.open(this.type, url, true);
184                 
185         } catch(E) {
186                 alert("Fatal error opening XMLHTTPRequest for URL:\n" + url + '\n');
187                 return;
188         }
189
190
191         if( this.type == 'POST' ) {
192                 data = this.param_string;
193                 this.xmlhttp.setRequestHeader('Content-Type',
194                                 'application/x-www-form-urlencoded');
195         }
196
197         try{ this.xmlhttp.send( data ); } catch(e){}
198
199         this.sendCount += 1;
200         return this;
201 }
202
203 /* returns the actual response text from the request */
204 RemoteRequest.prototype.getText = function() {
205         return this.xmlhttp.responseText;
206 }
207
208 RemoteRequest.prototype.isReady = function() {
209         return this.xmlhttp.readyState == 4;
210 }
211
212
213 /* returns the JSON->js result object  */
214 RemoteRequest.prototype.getResultObject = function() {
215
216         if(this.cancelled) return null;
217         if(!this.xmlhttp) return null;
218
219         var text = this.xmlhttp.responseText;
220         if(text == "" || text == " " || text == null) null;
221
222         var obj = JSON2js(text);
223         if(!obj) return null;
224
225         if( obj.status != 200 ) {
226                 if(!isXUL()) {
227                         alert("A Server Error Occured.  Debug information follows:\n" +
228                                 "Status: " + obj.status + '\n' + obj.debug + '\n' 
229                                 + 'Payload: ' + js2JSON(obj.payload) + '\n');
230                 } else { 
231                         dump('Remote Request Error:' +
232                                         '\ncode = '             + obj.status + 
233                                         '\ndebug: '             + obj.debug + 
234                                         '\npayload: '   + js2JSON(obj.payload)); 
235                         throw obj;
236                 }
237         }
238
239         var payload = obj.payload;
240         if(!payload || payload.length == 0) return null;
241         payload = (payload.length == 1) ? payload[0] : payload;
242
243         if(payload.__isfieldmapper && payload.classname == "perm_ex") {
244                 if(!isXUL()) alert(payload.err_msg());
245                 throw payload;
246         }
247
248         return payload;
249 }
250
251 /* adds a new parameter to the request */
252 RemoteRequest.prototype.addParam = function(param) {
253         var string = encodeURIComponent(js2JSON(param));
254         this.param_string += "&param=" + string;
255 }
256