1 include(bbq.gui.error.NotLoggedIn); 2 include(bbq.gui.error.ServerError); 3 include(bbq.util.BBQUtil); 4 5 bbq.ajax.AJAXRequest = Class.create(/** @lends bbq.ajax.AJAXRequest.prototype */ { 6 /** 7 * Holds the options for this object. 8 * 9 * @type {Object} 10 */ 11 options: null, 12 _timeOut: null, 13 _interval: null, 14 15 /** 16 * <p>Wrapper for Prototype Ajax class which dds extras such as an independent server timeout and error handling.</p> 17 * 18 * <p>Typically you would use a subclass such as <code class="language-javascript">bbq.ajax.JSONRequest</code>.</p> 19 * 20 * @constructs 21 * @param {Object} options 22 * @param {String} options.url Where to send the request to. 23 * @param {String} [options.method="post"] "post" or "get". 24 * @param {Object} [options.args] key/value pairs. 25 * @param {Function} [options.onSuccess] Everything went as expected - eg. received HTTP 200. 26 * @param {Function} [options.onFailure] The call failed - eg. did not receive HTTP 200. 27 * @param {Function} [options.onException] An exception was thrown while attempting to make the call. 28 * @param {String} [options.postBody] A string to send as the body of the request. Subclasses will tend to use options.args over this value. 29 * @param {Object} [options.headers] A list of key/value pairs to send as request headers. 30 * @param {String} [options.contentType] The request content-type. 31 * @see bbq.ajax.JSONRequest 32 */ 33 initialize: function(options) { 34 this.options = options; 35 36 if(!this.options.method) { 37 this.options.method = "post"; 38 } 39 40 if(!this.options.args) { 41 this.options.args = {}; 42 } 43 44 if(!this.options.headers) { 45 this.options.headers = {}; 46 } 47 48 this._sendRequest(); 49 }, 50 51 _getPostBody: function() { 52 return this.options.postBody; 53 }, 54 55 /** 56 * Sends the request via the specified method 57 * 58 * @return void 59 */ 60 _sendRequest: function() { 61 try { 62 var requestHeaders = this._createRequestHeaders(); 63 64 for(var key in requestHeaders) { 65 this.options.headers[key] = requestHeaders[key]; 66 } 67 68 var request = new Ajax.Request(this.options.url, { 69 method: this.options.method, 70 postBody: this._getPostBody(), 71 onSuccess: this._onSuccess.bind(this), 72 onFailure: this._onFailure.bind(this), 73 onExcepton: this._onException.bind(this), 74 requestHeaders: this.options.headers, 75 contentType: this.options.contentType 76 }); 77 78 if(typeof(firebug) != "undefined" && firebug.watchXHR instanceof Function) { 79 // enable firebug lite to watch the ajax call status 80 request.transport._name = this.options.method.toUpperCase() + ' ' + this.options.url; 81 firebug.watchXHR(request.transport); 82 } 83 84 // get time out data from server configuration 85 if(typeof(ServerConfig) != "undefined" && ServerConfig["timeout"]) { 86 this._timeOut = ServerConfig["timeout"]; 87 } else { 88 this._timeOut = 30; 89 } 90 91 // check timeout every second 92 this._interval = setInterval(this._checkTimeOut.bind(this), 1000); 93 94 if(typeof(NotificationArea) != "undefined") { 95 NotificationArea.startLoad(); 96 } 97 } catch(e) { 98 Log.error("Could not send request", e); 99 } 100 }, 101 102 _createRequestHeaders: function() { 103 return { 104 105 }; 106 }, 107 108 /** 109 * @access protected 110 * @param {String} handlerName 111 * @param {Object} args 112 */ 113 _callHandler: function(handlerName, args) { 114 try { 115 if(typeof(NotificationArea) != "undefined") { 116 NotificationArea.stopLoad(); 117 } 118 119 clearInterval(this._interval); 120 121 if(this.options[handlerName] && this.options[handlerName] instanceof Function) { 122 this.options[handlerName].apply(this, args); 123 } 124 } catch(e) { 125 Log.error("Error encountered while invoking handler " + handlerName, e); 126 } 127 }, 128 129 /** 130 * @param {Object} serverResponse 131 */ 132 _onSuccess: function(serverResponse) { 133 try { 134 var responseType = serverResponse.getResponseHeader("X-BBQ-ResponseType"); 135 136 if(responseType < 0) { 137 if(this.options.onFailure) { 138 // have been passed a failure callback 139 this._onFailure(serverResponse); 140 } else { 141 // fall back to default behaviour 142 var code = "error" + responseType; 143 var handler = bbq.ajax.AJAXRequest.errorHandlers[code]; 144 145 if (handler && handler instanceof Function) { 146 handler.call(this, this, serverResponse); 147 } else { 148 Log.error("Received error code " + responseType + " but have no handler to handle it."); 149 Log.error("Either pass an onFaliure callback to this bbq.ajax.AJAXRequest or define bbq.ajax.AJAXRequest.errorHandlers['" + code + "'] = function(serverResponse) { ... };"); 150 } 151 } 152 153 return; 154 } 155 156 this._callHandler("onSuccess", $A(arguments)); 157 } catch(e) { 158 Log.error("Could not invoke onSuccess handler", e); 159 } 160 }, 161 162 _onFailure: function() { 163 try { 164 Log.error('Request to ' + this.options.method.toUpperCase() + ' ' + this.options.url + " failed"); 165 this._callHandler("onFailure", $A(arguments)); 166 } catch(e) { 167 Log.error("Could not invoke onFaliure handler", e); 168 } 169 }, 170 171 _onException: function() { 172 try { 173 Log.error('Request to ' + this.options.method.toUpperCase() + ' ' + this.options.url + " threw exception"); 174 this._callHandler("onException", $A(arguments)); 175 } catch(e) { 176 Log.error("Could not invoke onException handler", e); 177 } 178 }, 179 180 /** 181 * Checks to see if the timer has reached 0. If so the server request has timed out. 182 * 183 * @return void 184 */ 185 _checkTimeOut: function() { 186 if(this._timeOut == 0) { 187 this._timedOut(); 188 clearInterval(this._interval); 189 } else { 190 this._timeOut--; 191 } 192 }, 193 194 /** 195 * Shows the user a warning 196 * 197 * @return void 198 */ 199 _timedOut: function() { 200 Log.warn("Ajax call to " + this.options.url + " timed out"); 201 202 if(typeof(NotificationArea) != "undefined" && typeof(Language) != "undefined" && Language.get instanceof Function) { 203 NotificationArea.stopLoad(); 204 NotificationArea.setMessage( 205 Language.get("bbq.ajax.AJAXRequest.ajaxtimeoutheader"), 206 Language.get("bbq.ajax.AJAXRequest.ajaxtimeoutmessage"), 207 "error" 208 ); 209 NotificationArea.setMessage( 210 Language.get("bbq.ajax.AJAXRequest.reloadpageheader"), 211 Language.get("bbq.ajax.AJAXRequest.reloadpagemessage"), 212 "error" 213 ); 214 } 215 } 216 }); 217 218 /** 219 * Add custom error handlers to this map. Error handlers should 220 * be a function with the following signature: 221 * 222 * <pre><code class="language-javascript"> 223 * function(bbq.ajax.AJAXRequest, XMLHttpRequest); 224 * </code></pre> 225 * 226 * @see bbq.ajax.AJAXRequest 227 */ 228 bbq.ajax.AJAXRequest.errorHandlers = {}; 229 bbq.ajax.AJAXRequest.errorHandlers["error-100"] = function(request, response) { 230 var errorMessage = new bbq.gui.error.ServerError({ 231 url: request.options.url, 232 args: request.options.args, 233 serverResponse: BBQUtil.urlDecode(response.getResponseHeader("X-bbq-responseMessage")) 234 }); 235 errorMessage.appear(); 236 }; 237 bbq.ajax.AJAXRequest.errorHandlers["error-99"] = function(request, response) { 238 var errorMessage = new bbq.gui.error.NotLoggedIn(); 239 errorMessage.appear(); 240 }; 241