backbone-model-overlay.js 3.6 KB
define(function(require) {
    'use strict';
    var module = require('module');
    var Backbone = require('backbone');
    var _ = require('underscore');

    var BackboneModelOverlay = Backbone.Model.extend({
        initialize: function(data, options) {
            BackboneModelOverlay.__super__.initialize.apply(this, arguments);
            var parent = this._parent = options.parent;
            if (parent) {
                parent.on('change', function(value, parentModel, options) {
                    var parentChanged = this._parent.changedAttributes();
                    this.changed = parentChanged;
                    _.each(parentChanged, function(value, key) {
                        this.trigger('change:' + key, value, this, options);
                    }, this);
                    this.trigger('change', this, options);
                }, this);
            }
            var override = this._override = {};
            _.each(_.keys(this.attributes), function(key) {
                override[key] = true;
            });
        },
        get: function(key) {
            if (this._override[key]) {
                return BackboneModelOverlay.__super__.get.apply(this, arguments);
            } else {
                var parent = this._parent;
                return parent && parent.get.apply(parent, arguments);
            }
        },
        previous: function(attr) {
            return this.previousAttributes()[attr];
        },
        previousAttributes: function() {
            var parent = this._parent;
            var data = BackboneModelOverlay.__super__.previousAttributes.apply(this, arguments);
            var parentData = parent ? parent.previousAttributes.apply(parent, arguments) : null;
            return _.extend({}, parentData, data);
        },
        changedAttributes: function() {
            var parent = this._parent;
            var data = BackboneModelOverlay.__super__.changedAttributes.apply(this, arguments);
            var parentData = parent ? parent.changedAttributes.apply(parent, arguments) : null;
            return _.extend({}, parentData, data);
        },
        set: function(key, value, options) {
            if (!!!key) {
                return this;
            }
            var attrs;
            if (typeof key === 'object') {
                attrs = key;
                options = value;
            } else {
                (attrs = {})[key] = value;
            }

            options || (options = {});
            var unset = options.unset;

            var parent = this._parent;
            if (parent) {
                if (!options.overlay) {
                    return parent.set.apply(parent, arguments);
                }
                var override = this._override;
                _.each(attrs, function(value, key) {
                    if (unset) {
                        delete override[key];
                    } else {
                        override[key] = true;
                    }
                });
            }
            return BackboneModelOverlay.__super__.set.apply(this, arguments);
        },
        toJSON: function(options) {
            var data = BackboneModelOverlay.__super__.toJSON.apply(this, arguments);
            var parent = this._parent;
            if (parent) {
                data = _.extend(data, parent.toJSON.apply(parent, arguments));
            }
            var superGet = BackboneModelOverlay.__super__.get;
            _.each(this._override, function(value, key) {
                data[key] = superGet.call(this, key, options);
            }, this);
            return data;
        },
    });
    return BackboneModelOverlay;
});