fluxtuate
Version:
a javascript ES7 library for handling complex data transactions
313 lines (242 loc) • 12.3 kB
JavaScript
"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;