Skip to content

Instantly share code, notes, and snippets.

@pluma
Created July 10, 2012 07:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pluma/3081853 to your computer and use it in GitHub Desktop.
Save pluma/3081853 to your computer and use it in GitHub Desktop.
Knockout->Tastypie Resource classes
define(['ko', 'q-reqwest', 'q-tils', 'aug'], function(ko, qr, qt, aug) {
"use strict";
function propertyGetter(name) {
return function(obj) {
var prop = obj[name];
return (typeof prop === 'function' ? prop.call(obj) : prop);
}
}
function propertyFilter(name, value) {
var prop = propertyGetter(name);
return function(obj) {
return prop(obj) === value;
}
}
function Collection(Resource) {
var self = this;
self.all = ko.observableArray();
self.get = function(resource_uri, depth) {
depth = Math.max(0, +depth);
var obj = self.all().filter(propertyFilter('resource_uri', resource_uri))[0];
if (!obj) {
obj = new Resource({resource_uri: resource_uri, _stub: true});
self.all.push(obj);
}
if (obj._stub() && depth > 0) {
qt.cached(qr.get)(resource_uri).then(function(err, data) {
obj.update(aug(data, {_stub: false}), depth - 1);
});
}
return obj;
};
}
function define(init) {
function Resource(data) {
var self = this;
data || (data = {});
self.constructor = Resource;
self._stub = ko.observable(!!data._stub);
self.resource_uri = ko.observable();
init.apply(this, arguments);
self.update(data);
};
aug(Resource.prototype, {
update: function(data, depth) {
depth = Math.max(0, +depth);
Object.keys(data).forEach(function(key) {
var
value = data[key],
prop = self[key],
resource = prop && prop.resource;
if (typeof value === 'undefined') {
return;
}
if (typeof prop !== 'function') {
return;
}
if (resource) {
if (Array.isArray(prop.call(self))) {
prop.call(self, value.map(function(resource_uri) {
return resource.objects.get(resource_uri, depth);
}));
} else {
prop.call(self, resource.objects.get(value, depth));
}
} else {
prop.call(self, value);
}
});
},
save: function() {
var
self = this,
data = ko.toJS(self);
delete data._stub;
Object.keys(self).forEach(function(key) {
var
value = data[key],
prop = self[key],
value;
if (typeof value === 'function') {
delete data[key];
return;
}
if (typeof prop !== 'function' || !prop.resource) {
return;
}
if (Array.isArray(value)) {
data[key] = value.map(propertyGetter('resource_uri'));
} else {
data[key] = value.resource_uri();
}
});
console.log(JSON.stringify(data, 4, ' '));
}
});
Resource.constructor = define;
Resource.objects = new Collection(Resource);
return Resource;
}
return {
define: define
};
});
(function(context, definition) {
"use strict";
if (typeof context.define === 'function' && context.define.amd) {
define(['q', 'reqwest'], definition);
} else if (typeof module !== 'undefined') {
module.exports = definition(require('q'), require('reqwest'));
} else {
context.qReqwest = definition(context.Q, context.reqwest);
}
}(this, function(Q, reqwest) {
"use strict";
function ajax(config) {
var d = Q.defer();
if (typeof config === 'string') {
config = {url: config};
}
config.success = function() {
d.resolve.apply(d, arguments);
};
config.error = function() {
d.reject.apply(d, arguments);
};
reqwest(config);
return d.promise;
}
function _ajax(method) {
return function(config) {
if (typeof config === 'string') {
config = {url: config};
}
config.method = method;
return ajax(config);
}
}
return {
ajax: ajax,
get: _ajax('get'),
post: _ajax('post'),
put: _ajax('put'),
del: _ajax('delete'),
patch: _ajax('patch')
};
}));
(function(context, definition) {
"use strict";
if (typeof context.define === 'function' && context.define.amd) {
define(['q'], definition);
} else if (typeof module !== 'undefined') {
module.exports = definition(require('q'));
} else {
context.qReqwest = definition(context.Q);
}
}(this, function(Q) {
"use strict";
function cached(func, ttl) {
var
i = cached._keys.indexOf(func),
cache;
if (i === -1) {
i = cached._keys.push(func) - 1;
cached._cache[i] = {};
}
ttl || (ttl = cached.ttl);
cache = cached._cache[i];
return function() {
var
d = Q.defer(),
now = +(new Date()),
key = JSON.stringify(arguments),
cachedValue = cache[key];
if (!cachedValue || cachedValue.d.isRejected()) {
clearTimeout(cachedValue.t);
cachedValue = {
d: func.apply(this, arguments),
t: setTimeout(function() {
delete cache[key];
}, now + ttl)
};
cache[key] = cachedValue;
}
cachedValue.d.then(
function() {d.resolve.apply(d, arguments);},
function() {d.reject.apply(d, arguments);}
)
return d.promise;
};
}
cached.ttl = 60 * 1000;
cached._keys = [];
cached._cache = [];
return {
cached: cached
}
}));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment