• Jump To … +
    can.construct.proxy.js can.construct.super.js can.control.plugin.js can.dojo.js can.fixture.js can.jquery-all.js can.jquery.js can.model.queue.js can.mootools.js can.observe.attributes.js can.observe.backup.js can.observe.delegate.js can.observe.setter.js can.observe.validations.js can.view.modifiers.js can.view.mustache.js can.yui.js can.zepto.js
  • can.model.queue.js

  • ¶
    /*!
    * CanJS - 1.1.5 (2013-03-27)
    * http://canjs.us/
    * Copyright (c) 2013 Bitovi
    * Licensed MIT
    */
    (function (can, window, undefined) {
  • ¶

    can/model/queue/queue.js

        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);