1 // ========================================================================== 2 // Project: The M-Project - Mobile HTML5 Application Framework 3 // Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved. 4 // (c) 2011 panacoda GmbH. All rights reserved. 5 // Creator: Sebastian 6 // Date: 28.10.2010 7 // License: Dual licensed under the MIT or GPL Version 2 licenses. 8 // http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE 9 // http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE 10 // ========================================================================== 11 12 m_require('core/foundation/object.js'); 13 14 /** 15 * @class 16 * 17 * The root class for every request. Makes ajax requests. Is used e.g. for querying REST web services. 18 * First M.Request.init needs to be called, then send. 19 * 20 * @extends M.Object 21 */ 22 M.Request = M.Object.extend( 23 /** @scope M.Request.prototype */ { 24 25 /** 26 * The type of this object. 27 * 28 * @type String 29 */ 30 type: 'M.Request', 31 32 /** 33 * The HTTP method to use. 34 * 35 * Defaults to GET. 36 * 37 * @type String 38 */ 39 method: 'GET', 40 41 /** 42 * The URL this request is sent to. 43 * 44 * @type String 45 */ 46 url: null, 47 48 /** 49 * Sends the request asynchronously instead of blocking the browser. 50 * You should almost always make requests asynchronous. You can change this 51 * options with the async() helper option (or simply set it directly). 52 * 53 * Defaults to YES. 54 * 55 * @type Boolean 56 */ 57 isAsync: YES, 58 59 60 /** 61 * Processes the request and response as JSON if possible. 62 * 63 * Defaults to NO. 64 * 65 * @type Boolean 66 */ 67 isJSON: NO, 68 69 /** 70 * Optional timeout value of the request in milliseconds. 71 * 72 * @type Number 73 */ 74 timeout: null, 75 76 /** 77 * If set, contains the request's callbacks in sub objects. There are three 78 * possible callbacks that can be used: 79 * 80 * - beforeSend 81 * - success 82 * - error 83 * 84 * A callback object consists of at least an action but can also specify a 85 * target object that determines the scope for that action. If a target is 86 * specified, the action can either be a string (the name if a method within 87 * the specified scope) or a function. If there is no target specified, the 88 * action must be a function. So a success callback could e.g. look like: 89 * 90 * callbacks: { 91 * success: { 92 * target: MyApp.MyController, 93 * action: 'successCallback' 94 * } 95 * } 96 * 97 * Or it could look like: 98 * 99 * callbacks: { 100 * success: { 101 * target: MyApp.MyController, 102 * action: function() { 103 * // do something... 104 * } 105 * } 106 * } 107 * 108 * Depending on the type of callback, there are different parameters, that 109 * are automatically passed to the callback: 110 * 111 * - beforeSend(request) 112 * - success(data, msg, request) 113 * - error(request, msg) 114 * 115 * For further information about that, take a look at the internal callbacks 116 * of M.Request: 117 * 118 * - internalBeforeSend 119 * - internalOnSuccess 120 * - internalOnError 121 * 122 * @type Object 123 */ 124 callbacks: null, 125 126 /** 127 * This property can be used to specify whether or not to cache the request. 128 * Setting this to YES will set the 'Cache-Control' property of the request 129 * header to 'no-cache'. 130 * 131 * @Boolean 132 */ 133 sendNoCacheHeader: YES, 134 135 /** 136 * This property can be used to specify whether or not to send a timestamp 137 * along with the request in order to make every request unique. Since some 138 * browsers (e.g. Android) automatically cache identical requests, setting 139 * this property to YES will add an additional parameter to the request, 140 * containing the current timestamp. 141 * 142 * So if you have any trouble with caching of requests, try setting this to 143 * YES. But note, that it might also cause trouble on the server-side if they 144 * do not expect this additional parameter. 145 * 146 * @Boolean 147 */ 148 sendTimestamp: NO, 149 150 /** 151 * The data body of the request. 152 * 153 * @type String, Object 154 */ 155 data: null, 156 157 /** 158 * Holds the jQuery request object 159 * 160 * @type Object 161 */ 162 request: null, 163 164 /** 165 * Initializes a request. Sets the parameter of this request object with the passed values. 166 * 167 * @param {Object} obj The parameter object. Includes: 168 * * method: the http method to use, e.g. 'POST' 169 * * url: the request url, e.g. 'twitter.com/search.json' (needs a proxy to be set because of Same-Origin-Policy) 170 * * isAsync: defines whether request should be made async or not. defaults to YES. Should be YES. 171 * * isJSON: defines whether to process request and response as JSON 172 * * timout: defines timeout in milliseconds 173 * * data: the data to be transmitted 174 * * beforeSend: callback that is called before request is sent 175 * * onError: callback that is called when an error occured 176 * * onSuccess: callback that is called when request was successful 177 */ 178 init: function(obj){ 179 obj = obj ? obj : {}; 180 return this.extend({ 181 method: obj['method'] ? obj['method'] : this.method, 182 url: obj['url'] ? obj['url'] : this.url, 183 isAsync: obj['isAsync'] ? obj['isAsync'] : this.isAsync, 184 isJSON: obj['isJSON'] ? obj['isJSON'] : this.isJSON, 185 timeout: obj['timeout'] ? obj['timeout'] : this.timeout, 186 data: obj['data'] ? obj['data'] : this.data, 187 callbacks: obj['callbacks'], 188 sendNoCacheHeader: obj['sendNoCacheHeader'], 189 sendTimestamp: obj['sendTimestamp'], 190 beforeSend: obj['beforeSend'] ? obj['beforeSend'] : this.beforeSend, 191 onError: obj['onError'] ? obj['onError'] : this.onError, 192 onSuccess: obj['onSuccess'] ? obj['onSuccess'] : this.onSuccess 193 }); 194 }, 195 196 /** 197 * A pre-callback that is called right before the request is sent. 198 * 199 * Note: This method will be removed with v1.0! Use the callbacks 200 * property instead. 201 * 202 * @deprecated 203 * @param {Object} request The XMLHttpRequest object. 204 */ 205 beforeSend: function(request){}, 206 207 /** 208 * The callback to be called if the request failed. 209 * 210 * Note: This method will be removed with v1.0! Use the callbacks 211 * property instead. 212 * 213 * @deprecated 214 * @param {Object} request The XMLHttpRequest object. 215 * @param {String} msg The error message. 216 */ 217 onError: function(request, msg){}, 218 219 /** 220 * The callback to be called if the request succeeded. 221 * 222 * Note: This method will be removed with v1.0! Use the callbacks 223 * property instead. 224 * 225 * @deprecated 226 * @param {String|Object} data The data returned from the server. 227 * @param {String} msg A String describing the status. 228 * @param {Object} request The XMLHttpRequest object. 229 */ 230 onSuccess: function(data, msg, request){}, 231 232 /** 233 * This method is an internal callback that is called right before a 234 * request is send. 235 * 236 * @param {Object} request The XMLHttpRequest object. 237 */ 238 internalBeforeSend: function(request){ 239 if(this.sendNoCacheHeader) { 240 request.setRequestHeader('Cache-Control', 'no-cache'); 241 } 242 243 if(!this.callbacks && this.beforeSend) { 244 this.beforeSend(request); 245 } 246 247 if(this.callbacks && this.callbacks['beforeSend'] && M.EventDispatcher.checkHandler(this.callbacks['beforeSend'])) { 248 M.EventDispatcher.callHandler(this.callbacks['beforeSend'], null, NO, [request]); 249 } 250 }, 251 252 /** 253 * This method is an internal callback that is called if a request 254 * failed. 255 * 256 * @param {Object} request The XMLHttpRequest object. 257 * @param {String} msg The error message. 258 */ 259 internalOnError: function(request, msg){ 260 if(!this.callbacks && this.onError) { 261 this.onError(request, msg); 262 } 263 264 if(this.callbacks && this.callbacks['error'] && M.EventDispatcher.checkHandler(this.callbacks['error'])) { 265 M.EventDispatcher.callHandler(this.callbacks['error'], null, NO, [request, msg]); 266 } 267 }, 268 269 /** 270 * This method is an internal callback that is called if the request 271 * succeeded. 272 * 273 * @param {String|Object} data The data returned from the server. 274 * @param {String} msg A String describing the status. 275 * @param {Object} request The XMLHttpRequest object. 276 */ 277 internalOnSuccess: function(data, msg, request){ 278 if(!this.callbacks && this.onSuccess) { 279 this.onSuccess(data, msg, request); 280 } 281 282 if(this.callbacks && this.callbacks['success'] && M.EventDispatcher.checkHandler(this.callbacks['success'])) { 283 M.EventDispatcher.callHandler(this.callbacks['success'], null, NO, [data, msg, request]); 284 } 285 }, 286 287 /** 288 * Sends an Ajax request by using jQuery's $.ajax(). 289 * Needs init first! 290 */ 291 send: function(){ 292 this.request = $.ajax({ 293 type: this.method, 294 url: this.url, 295 async: this.isAsync, 296 dataType: this.isJSON ? 'json' : 'text', 297 contentType: this.isJSON ? 'application/json' : 'application/x-www-form-urlencoded', 298 timeout: this.timeout, 299 data: this.data ? this.data : '', 300 context: this, 301 beforeSend: this.internalBeforeSend, 302 success: this.internalOnSuccess, 303 error: this.internalOnError, 304 cache: !this.sendTimestamp 305 }); 306 }, 307 308 /** 309 * Aborts this request. Delegate to jQuery 310 * 311 * @return Boolean Indicating whether request exists and is aborted or not 312 */ 313 abort: function() { 314 if(this.request) { 315 this.request.abort(); 316 return YES; 317 } 318 return NO; 319 } 320 321 });