UNPKG

promised-models

Version:

promise based, typed attributes, nested models and collections

223 lines (200 loc) 5.39 kB
/** * Models list */ var Attribute = require('../attribute'), ModelsList, ModelsListStatic, List = require('../list'), /** * to calculate difference between arrays * @param {Array} ar1 * @param {Array} ar2 * @return {Array} */ diff = function (ar1, ar2) { return ar1.filter(function (item) { return ar2.indexOf(item) === -1; }); }, Vow = require('vow'), uniq = require('../uniq'); /** * Attribute with nested model * @class {Attribute} */ ModelsList = Attribute.inherit({ __constructor: function () { this.__base.apply(this, arguments); this.LISTEN_BRANCH = uniq(); this._registerEvents(); }, default: [], modelType: null, /** * @override {Attribute} */ isSet: function () { throw new Error('.isSet is not implemented for nested models'); }, /** * @override {Attribute} */ unset: function () { throw new Error('.unset is not implemented for nested models'); }, /** * @override {Attribute} */ get: function () { return (new List(this)); }, /** * @override {Attribute} */ ready: function () { return Vow.all(this.value.map(function (model) { return model.ready(); })); }, /** * @override {Attribute} */ validate: function () { return Vow.all(this.value.map(function (model) { return model.validate(); })).then(function () { return 1; }); }, /** * @override {Attribute} */ toJSON: function () { return this.value.map(function (model) { return model.toJSON(); }); }, /** * @override {Attribute} */ isEqual: function (value) { if (value instanceof List) { return value.isEqual(this.value); } else { return this.value === value; } }, /** * @override */ set: function (value) { if (!this.isEqual(value)) { this.value = this.parse(value); this.emitListChange(); } }, /** * @override {Attribute} */ isChanged: function (branch) { return this.__base(branch) || Boolean( this.value.length && Math.max.apply(Math, this.value.map(function (model) { return model.isChanged(branch); })) ); }, /** * @override {Attribute} */ commit: function (branch) { this.__base(branch); this.value.map(function (model) { return model.commit(branch); }); }, /** * @override {Attribute} */ revert: function (branch) { this.__base(branch); this.value.map(function (model) { return model.revert(branch); }); }, /** * @override {Attribute} */ parse: function (value) { var arr = [].concat(value), attribute = this; return arr.map(function (data) { if (data instanceof attribute.modelType) { return data; } else { return new attribute.modelType(data); } }); }, /** * is given array saved in branches * @param {Array} value * @return {Boolean} */ isListCashed: function (value) { var attribute = this; return Object.keys(attribute._cachBranches).some(function (branch) { return value === attribute._cachBranches[branch]; }); }, /** * notify that saved array changed */ emitListChange: function () { var attribute = this; attribute.value.forEach(function (value, key) { if (!(value instanceof attribute.modelType)) { attribute.value[key] = new attribute.modelType(value); } }); attribute._registerEvents(); attribute._emitChange(); }, _onModelCalculate: function () { this._emitChange(); }, _onModelDestruct: function () { this.set(this.value.filter(function (model) { return !model.isDestructed(); })); }, _registerEvents: function () { var listenCache = this._cachBranches[this.LISTEN_BRANCH] || [], lostModels = diff(listenCache, this.value), newModels = diff(this.value, listenCache), attribute = this; newModels.forEach(function (model) { model.on('calculate', attribute._onModelCalculate, attribute); model.on('destruct', attribute._onModelDestruct, attribute); }); lostModels.forEach(function (model) { model.un('calculate', attribute._onModelCalculate, attribute); model.un('destruct', attribute._onModelDestruct, attribute); }); attribute.commit(attribute.LISTEN_BRANCH); }, }); /** * Static constructor for ModelsList * @class */ ModelsListStatic = function (value) { if (this instanceof ModelsListStatic) { return new ModelsList(value); } else { return ModelsList.inherit({ modelType: value }); } }; ModelsListStatic.inherit = ModelsList.inherit.bind(ModelsList); module.exports = ModelsListStatic;