UNPKG

fluxtuate

Version:

a javascript ES7 library for handling complex data transactions

313 lines (242 loc) 12.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = undefined; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _internals = require("./_internals"); var _internals2 = require("../context/_internals"); var _getOwnKeys = require("../utils/getOwnKeys"); var _getOwnKeys2 = _interopRequireDefault(_getOwnKeys); var _reserved = require("../model/reserved"); var _reserved2 = _interopRequireDefault(_reserved); var _lang = require("lodash/lang"); var _arrayWrapper = require("./array-wrapper"); var _arrayWrapper2 = _interopRequireDefault(_arrayWrapper); var _dateWrapper = require("./date-wrapper"); var _dateWrapper2 = _interopRequireDefault(_dateWrapper); var _forEachPrototype = require("../utils/forEachPrototype"); var _forEachPrototype2 = _interopRequireDefault(_forEachPrototype); var _model = require("./model"); var _model2 = _interopRequireDefault(_model); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var listeners = Symbol("fluxtuateModelWrapper_listeners"); var refreshListener = Symbol("fluxtuateModelWrapper_refreshListener"); var dispatchUpdate = Symbol("fluxtuateModelWrapper_dispatchUpdate"); var updateTimer = Symbol("fluxtuateModelWrapper_updateTimer"); var setupModelValues = Symbol("fluxtuateModelWrapper_setupModelValues"); var detachModel = Symbol("fluxtuateModelWrapper_detachModel"); var changeModelListener = Symbol("fluxtuateModelWrapper_changeModelListener"); var destroyListener = Symbol("fluxtuateModelWrapper_destroyListener"); var propertiesCache = Symbol("fluxtuateModelWrapper_propertiesCache"); var ModelWrapper = function () { function ModelWrapper(wrappedModel, holderContext) { var _this = this; _classCallCheck(this, ModelWrapper); wrappedModel[_internals.configureDefaultValues](); this._modelName = wrappedModel.modelName; this[_internals.model] = wrappedModel; this[propertiesCache] = {}; this[listeners] = []; this[_internals.context] = holderContext; this[_internals.destroyed] = false; this[_internals.constructorProps] = [holderContext]; this[_internals.arrayConstructor] = _arrayWrapper2.default; this[_internals.dateConstructor] = _dateWrapper2.default; this[_internals.checkDestroyed] = function () { if (_this[_internals.destroyed]) { throw new Error("You are trying to access a destroyed model."); } }; this[dispatchUpdate] = function (callback, timerHolder, payload) { if (timerHolder[updateTimer]) { clearTimeout(timerHolder[updateTimer]); timerHolder[updateTimer] = undefined; } if (_this[_internals.destroyed]) return; timerHolder[updateTimer] = setTimeout(function () { timerHolder[updateTimer] = undefined; if (_this[_internals.destroyed]) return; callback({ model: _this, data: payload.data, name: payload.name }); }, 0); }; this[_internals.updateable] = false; this[detachModel] = function () { if (_this[refreshListener]) { _this[refreshListener].remove(); _this[refreshListener] = undefined; } if (_this[destroyListener]) { _this[destroyListener].remove(); _this[destroyListener] = undefined; } }; this[_internals.updateInnerObject] = function (wrappedModel) { _this[detachModel](); _this[_internals.model] = wrappedModel; var cacheKeys = Object.keys(_this[propertiesCache]); for (var i = 0; i < cacheKeys.length; i++) { var propValue = _this[propertiesCache][cacheKeys[i]]; if (propValue !== undefined) { if ((0, _lang.isFunction)(propValue[_internals.updateInnerObject]) && wrappedModel[cacheKeys[i]] !== undefined) { propValue[_internals.updateInnerObject](wrappedModel[cacheKeys[i]]); } else { if ((0, _lang.isFunction)(propValue.destroy)) { propValue.destroy(); } delete _this[propertiesCache][cacheKeys[i]]; } } } _this[refreshListener] = wrappedModel.onUpdate(_this[setupModelValues].bind(_this, wrappedModel)); _this[destroyListener] = wrappedModel.addListener("destroy", _this[detachModel]); _this[setupModelValues](wrappedModel); var oldListeners = _this[listeners]; _this[listeners] = []; while (oldListeners.length > 0) { var listener = oldListeners.pop(); listener.originalRemove(); _this.onUpdate(listener.callback); } }; this[setupModelValues] = function (wrappedModel) { var wrapperKeys = (0, _getOwnKeys2.default)(_this); var keys = (0, _getOwnKeys2.default)(wrappedModel); keys.forEach(function (key) { if (wrapperKeys.indexOf(key) !== -1 || _reserved2.default.indexOf(key) !== -1) return; Object.defineProperty(_this, key, { get: function get() { this[_internals.checkDestroyed](); if (this[propertiesCache][key]) return this[propertiesCache][key]; var propValue = void 0; if (wrappedModel[key] && (0, _lang.isFunction)(wrappedModel[key].onUpdate)) { if (wrappedModel[key][_internals.dataType] === "array") { propValue = new (Function.prototype.bind.apply(this[_internals.arrayConstructor], [this, wrappedModel[key]].concat(_toConsumableArray(this[_internals.constructorProps]))))(); } else if (wrappedModel[key][_internals.dataType] === "date") { propValue = new (Function.prototype.bind.apply(this[_internals.dateConstructor], [this, wrappedModel[key]].concat(_toConsumableArray(this[_internals.constructorProps]))))(); } else { propValue = new (Function.prototype.bind.apply(this.constructor, [this, wrappedModel[key]].concat(_toConsumableArray(this[_internals.constructorProps]))))(); } this[propertiesCache] = propValue; return propValue; } else { return wrappedModel[key]; } }, set: function set(value) { this[_internals.checkDestroyed](); if (!this[_internals.updateable]) { throw new Error("You can only set values to a model from a command!"); } wrappedModel.setKeyValue(key, value, this); }, configurable: true }); }); var descriptors = {}; (0, _forEachPrototype2.default)(wrappedModel, function (proto) { descriptors = Object.assign(descriptors, Object.getOwnPropertyDescriptors(proto)); }, _model2.default); Object.keys(descriptors).filter(function (key) { return keys.indexOf(key) === -1; }).forEach(function (key) { if (wrapperKeys.indexOf(key) !== -1 || _reserved2.default.indexOf(key) !== -1) return; if (descriptors[key].get) { Object.defineProperty(_this, key, { get: function get() { return wrappedModel[key]; } }); } }); }; this[refreshListener] = wrappedModel.onUpdate(this[setupModelValues].bind(this, wrappedModel)); this[destroyListener] = wrappedModel.onUpdate(this[detachModel]); this[setupModelValues](wrappedModel); if (holderContext) { this[changeModelListener] = holderContext[_internals2.contextDispatcher].addListener("changeModel", function (event, payload) { if (payload.model.modelName === _this._modelName) { _this[_internals.updateInnerObject](payload.model); } }); } } _createClass(ModelWrapper, [{ key: "compare", value: function compare(model) { this[_internals.checkDestroyed](); if (!this[model]) return; this[model].compare(model); } }, { key: "onUpdate", value: function onUpdate(callback) { var _this2 = this; this[_internals.checkDestroyed](); if (!this[_internals.model]) return; var listener = this[_internals.model].onUpdate(this[dispatchUpdate].bind(this, callback, {})); var removeFunction = listener.remove; var index = this[listeners].length; listener.callback = callback; listener.originalRemove = removeFunction; this[listeners].push(listener); listener.remove = function () { _this2[listeners].splice(index, 1); removeFunction(); }; return listener; } }, { key: "destroy", value: function destroy() { this[listeners].forEach(function (listener) { listener.remove(); }); var cacheKeys = Object.keys(this[propertiesCache]); for (var i = 0; i < cacheKeys.length; i++) { var propValue = this[propertiesCache][cacheKeys[i]]; if (propValue && (0, _lang.isFunction)(propValue.destroy)) { propValue.destroy(); } } this[_internals.destroyed] = true; if (this[refreshListener]) { this[refreshListener].remove(); this[refreshListener] = undefined; } if (this[destroyListener]) { this[destroyListener].remove(); this[destroyListener] = undefined; } if (this[changeModelListener]) { this[changeModelListener].remove(); this[changeModelListener] = undefined; } } }, { key: "modelData", get: function get() { this[_internals.checkDestroyed](); if (!this[_internals.model]) return; return this[_internals.model].modelData; } }, { key: "cleanData", get: function get() { this[_internals.checkDestroyed](); if (!this[_internals.model]) return; return this[_internals.model].cleanData; } }, { key: "modelName", get: function get() { this[_internals.checkDestroyed](); if (!this[_internals.model]) return; return this[_internals.model].modelName; } }]); return ModelWrapper; }(); exports.default = ModelWrapper;