// vim: et:ts=4:sw=4:sts=4:ft=javascript 'use strict'; /*@ Ox.Request Basic request handler object FIXME: options is not a property, just documenting defaults options Options object timeout request timeout type request type, possible values POST, GET, PUT, DELETE url request url @*/ Ox.Request = (function() { var cache = {}, //dfd = $.Deferred(), $element = Ox.Element(), pending = {}, requests = {}, self = { options: { timeout: 60000, type: 'POST', url: '/api/' } }; return { /*@ cancel cancel pending requests () -> cancel all requests (fn) -> cancel all requests where function returns true (id) -> cancel request by id @*/ cancel: function() { if (arguments.length == 0) { // cancel all requests requests = {}; } else if (Ox.isFunction(arguments[0])) { // cancel with function Ox.forEach(requests, function(req, id) { if (arguments[0](req)) { delete requests[id]; } }); } else { // cancel by id delete requests[arguments[0]]; } }, /*@ clearCache clear cached results () -> ... @*/ clearCache: function(query) { if (!query) { cache = {}; } else { cache = Ox.filter(cache, function(val, key) { return key.indexOf(query) == -1; }); } }, /*@ bindEvent bindEvent to error/authrize requests @*/ bindEvent: $element.bindEvent, // fixme: remove _leakCache: function() { return cache; }, /*@ options get/set options () -> get options (options) -> set options options Options Object @*/ options: function() { return Ox.getset(self.options, arguments, function() {}, this); }, /*@ requests pending requests () -> returns number of requests @*/ requests: function() { return Ox.len(requests); }, /*@ send send request (options) -> returns request id options Options Object age cache age id request id timeout overwrite default timeout type overwrite default type url overwrite default url @*/ send: function(options) { var options = Ox.extend({ age: -1, callback: null, id: Ox.uid(), timeout: self.options.timeout, type: self.options.type, url: self.options.url }, options), req = JSON.stringify({ url: options.url, data: options.data }); if (pending[options.id]) { setTimeout(function() { Ox.Request.send(options); }, 0); } else { requests[options.id] = { url: options.url, data: options.data }; if (cache[req] && ( options.age == -1 || options.age > +new Date() - cache[req].time )) { var data = cache[req].data; setTimeout(function() { callback && callback(data); }, 0); } else { pending[options.id] = true; $.ajax({ complete: complete, data: options.data, //dataType: 'json', timeout: options.timeout, type: options.type, url: options.url }); } } function callback(data) { if (requests[options.id]) { delete requests[options.id]; options.callback && options.callback(data); } } function complete(request) { var $dialog, data; try { data = JSON.parse(request.responseText); } catch (err) { try { data = { status: { code: request.status, text: request.statusText } }; } catch (err) { data = { status: { code: '500', text: 'Unknown Error' } }; } } if (data.status.code == 200 || data.status.code == 404 || data.status.code == 409) { // we have to include not found and conflict // so that handlers can handle these cases cache[req] = { data: data, time: Ox.getTime() }; callback(data); } else { $element.triggerEvent('error', data); } pending[options.id] = false; } // return dfd.promise(); return options.id; } }; }());