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