/*!
* CanJS - 1.1.5 (2013-03-27)
* http://canjs.us/
* Copyright (c) 2013 Bitovi
* Licensed MIT
*/
(function (can, window, undefined) {
/*!
* CanJS - 1.1.5 (2013-03-27)
* http://canjs.us/
* Copyright (c) 2013 Bitovi
* Licensed MIT
*/
(function (can, window, undefined) {
var cleanAttrs = function (changedAttrs, attrs) {
var newAttrs = can.extend(true, {}, attrs),
attr, current, path;
if (changedAttrs) {
go through the attributes returned from the server and remove those that were changed during the current request batch
for (var i = 0; i < changedAttrs.length; i++) {
current = newAttrs;
path = changedAttrs[i].split('.');
while (path.length > 1) {
current = current && current[path.shift()];
}
current && delete current[path.shift()];
}
}
return newAttrs;
},
queueRequests = function (success, error, method, callback) {
this._changedAttrs = this._changedAttrs || [];
var def = new can.Deferred,
self = this,
attrs = this.attr(),
queue = this._requestQueue,
changedAttrs = this._changedAttrs,
reqFn, index;
reqFn = (function (self, type, success, error) {
Function that performs actual request
return function () {
pass already serialized attributes because we want to save model in state it was when request was queued, not when request is ran
return self.constructor._makeRequest([self, attrs], type || (self.isNew() ? 'create' : 'update'), success, error, callback)
}
})(this, method, function () {
resolve deferred with results from the request
def.resolveWith(self, arguments);
remove current deferred from the queue
queue.splice(0, 1);
if (queue.length > 0) {
replace queued wrapper function with deferred
returned from the makeRequest function so we
can access it's abort
function
queue[0] = queue[0]();
} else {
clean up changed attrs since there is no more requests in the queue
changedAttrs.splice(0);
}
}, function () {
reject deferred with results from the request
def.rejectWith(self, arguments);
since we failed remove all pending requests from the queue
queue.splice(0);
clean up changed attrs since there is no more requests in the queue
changedAttrs.splice(0);
})
Add our fn to the queue
index = queue.push(reqFn) - 1;
If there is only one request in the queue, run it immediately.
if (queue.length === 1) {
replace queued wrapper function with deferred
returned from the makeRequest function so we
can access it's abort
function
queue[0] = queue[0]();
}
def.abort = function () {
var abort;
check if this request is running, if it's not just remove it from the queue also all subsequent requests should be removed too
abort = queue[index].abort && queue[index].abort();
remove aborted request and any requests after it
queue.splice(index);
if there is no more requests in the queue clean up the changed attributes array
if (queue.length === 0) {
changedAttrs.splice(0);
}
return abort;
}
deferred will be resolved with original success and error functions
def.then(success, error);
return def;
},
_changes = can.Model.prototype._changes,
destroyFn = can.Model.prototype.destroy,
setupFn = can.Model.prototype.setup;
can.each(["created", "updated", "destroyed"], function (fn) {
var prototypeFn = can.Model.prototype[fn];
can.Model.prototype[fn] = function (attrs) {
if (attrs && typeof attrs == 'object') {
attrs = attrs.attr ? attrs.attr() : attrs;
Create backup of last good known state returned from the server. This allows users to restore it if API returns error
this._backupStore = attrs;
attrs = cleanAttrs(this._changedAttrs || [], attrs);
}
call the original function with the cleaned up attributes
prototypeFn.call(this, attrs);
}
})
can.extend(can.Model.prototype, {
setup: function () {
setupFn.apply(this, arguments);
this._requestQueue = new can.Observe.List;
},
_changes: function (ev, attr, how, newVal, oldVal) {
record changes if there is a request running
this._changedAttrs && this._changedAttrs.push(attr);
_changes.apply(this, arguments);
},
hasQueuedRequests: function () {
return this._requestQueue.attr('length') > 1;
},
call queued save request
save: function () {
return queueRequests.apply(this, arguments);
},
destroy: function (success, error) {
if (this.isNew()) {
if it's a new instance, call default destroy method
return destroyFn.call(this, success, error);
}
return queueRequests.call(this, success, error, 'destroy', 'destroyed');
}
})
})(can, this);