diff --git a/dist/alt-browser-with-addons.js b/dist/alt-browser-with-addons.js index cced3789..e40aca4a 100644 --- a/dist/alt-browser-with-addons.js +++ b/dist/alt-browser-with-addons.js @@ -1049,23 +1049,23 @@ var getInternalMethods = function (obj, excluded) { }; var AltStore = (function () { - function AltStore(dispatcher, state) { - var _this7 = this; + function AltStore(dispatcher, model, state) { + var _this8 = this; _classCallCheck(this, AltStore); this[EE] = new EventEmitter(); this[LIFECYCLE] = {}; - this[STATE_CONTAINER] = state; + this[STATE_CONTAINER] = state || model; - assign(this[LIFECYCLE], state[LIFECYCLE]); - assign(this, state[PUBLIC_METHODS]); + assign(this[LIFECYCLE], model[LIFECYCLE]); + assign(this, model[PUBLIC_METHODS]); // Register dispatcher this.dispatchToken = dispatcher.register(function (payload) { - if (state[LISTENERS][payload.action]) { - var result = state[LISTENERS][payload.action](payload.data); - result !== false && _this7.emitChange(); + if (model[LISTENERS][payload.action]) { + var result = model[LISTENERS][payload.action](payload.data); + result !== false && _this8.emitChange(); } }); @@ -1127,7 +1127,7 @@ var ActionCreator = (function () { return ActionCreator; })(); -var StoreMixin = { +var StoreMixinListeners = { on: function on(lifecycleEvent, handler) { this[LIFECYCLE][lifecycleEvent] = handler.bind(this); }, @@ -1153,7 +1153,7 @@ var StoreMixin = { }, bindActions: function bindActions(actions) { - var _this7 = this; + var _this8 = this; Object.keys(actions).forEach(function (action) { var symbol = actions[action]; @@ -1163,44 +1163,45 @@ var StoreMixin = { }); var handler = null; - if (_this7[action] && _this7[assumedEventHandler]) { + if (_this8[action] && _this8[assumedEventHandler]) { // If you have both action and onAction throw new ReferenceError("You have multiple action handlers bound to an action: " + ("" + action + " and " + assumedEventHandler)); - } else if (_this7[action]) { + } else if (_this8[action]) { // action - handler = _this7[action]; - } else if (_this7[assumedEventHandler]) { + handler = _this8[action]; + } else if (_this8[assumedEventHandler]) { // onAction - handler = _this7[assumedEventHandler]; + handler = _this8[assumedEventHandler]; } if (handler) { - _this7.bindAction(symbol, handler); + _this8.bindAction(symbol, handler); } }); }, bindListeners: function bindListeners(obj) { - var _this7 = this; + var _this8 = this; Object.keys(obj).forEach(function (methodName) { var symbol = obj[methodName]; - var listener = _this7[methodName]; + var listener = _this8[methodName]; if (!listener) { - throw new ReferenceError("" + methodName + " defined but does not exist in " + _this7._storeName); + throw new ReferenceError("" + methodName + " defined but does not exist in " + _this8._storeName); } if (Array.isArray(symbol)) { symbol.forEach(function (action) { - return _this7.bindAction(action, listener); + return _this8.bindAction(action, listener); }); } else { - _this7.bindAction(symbol, listener); + _this8.bindAction(symbol, listener); } }); - }, + } }; +var StoreMixinEssentials = { waitFor: function waitFor(sources) { if (!sources) { throw new ReferenceError("Dispatch tokens not provided"); @@ -1220,15 +1221,19 @@ var StoreMixin = { }, exportPublicMethods: function exportPublicMethods(methods) { - var _this7 = this; + var _this8 = this; Object.keys(methods).forEach(function (methodName) { if (typeof methods[methodName] !== "function") { throw new TypeError("exportPublicMethods expects a function"); } - _this7[PUBLIC_METHODS][methodName] = methods[methodName]; + _this8[PUBLIC_METHODS][methodName] = methods[methodName]; }); + }, + + emitChange: function emitChange() { + this.getInstance().emitChange(); } }; @@ -1269,6 +1274,55 @@ var filterSnapshotOfStores = function (snapshot, storeNames) { return JSON.stringify(storesToReset); }; +var createStoreFromObject = function (alt, StoreModel, key, saveStore) { + var storeInstance = undefined; + + var StoreProto = {}; + StoreProto[LIFECYCLE] = {}; + StoreProto[LISTENERS] = {}; + + assign(StoreProto, { + _storeName: key, + alt: alt, + dispatcher: alt.dispatcher, + getInstance: function getInstance() { + return storeInstance; + }, + setState: function setState() { + var values = arguments[0] === undefined ? {} : arguments[0]; + + assign(this.state, values); + this.emitChange(); + return false; + } + }, StoreMixinListeners, StoreMixinEssentials, StoreModel); + + // bind the store listeners + /* istanbul ignore else */ + if (StoreProto.bindListeners) { + StoreMixinListeners.bindListeners.call(StoreProto, StoreProto.bindListeners); + } + + // bind the lifecycle events + /* istanbul ignore else */ + if (StoreProto.lifecycle) { + Object.keys(StoreProto.lifecycle).forEach(function (event) { + StoreMixinListeners.on.call(StoreProto, event, StoreProto.lifecycle[event]); + }); + } + + // create the instance and assign the public methods to the instance + storeInstance = assign(new AltStore(alt.dispatcher, StoreProto, StoreProto.state), StoreProto.publicMethods); + + /* istanbul ignore else */ + if (saveStore) { + alt.stores[key] = storeInstance; + saveInitialSnapshot(alt, key); + } + + return storeInstance; +}; + var Alt = (function () { function Alt() { _classCallCheck(this, Alt); @@ -1306,6 +1360,10 @@ var Alt = (function () { key = uid(this.stores, key); } + if (typeof StoreModel === "object") { + return createStoreFromObject(this, StoreModel, key, saveStore); + } + // Creating a class here so we don't overload the provided store's // prototype with the mixin behaviour and I'm extending from StoreModel // so we can inherit any extensions from the provided store. @@ -1322,16 +1380,13 @@ var Alt = (function () { return Store; })(StoreModel); - assign(Store.prototype, StoreMixin, { + assign(Store.prototype, StoreMixinListeners, StoreMixinEssentials, { _storeName: key, alt: this, dispatcher: this.dispatcher, getInstance: function getInstance() { return storeInstance; }, - emitChange: function emitChange() { - this.getInstance().emitChange(); - }, setState: function setState() { var values = arguments[0] === undefined ? {} : arguments[0]; @@ -1372,7 +1427,7 @@ var Alt = (function () { }, createActions: { value: function createActions(ActionsClass) { - var _this7 = this; + var _this8 = this; var exportObj = arguments[1] === undefined ? {} : arguments[1]; @@ -1419,7 +1474,7 @@ var Alt = (function () { var actionName = Symbol("" + key + "#" + action); // Wrap the action so we can provide a dispatch method - var newAction = new ActionCreator(_this7, actionName, actions[action], obj); + var newAction = new ActionCreator(_this8, actionName, actions[action], obj); // Set all the properties on action obj[action] = newAction[ACTION_HANDLER]; diff --git a/dist/alt-browser.js b/dist/alt-browser.js index b2081842..9d39d7a1 100644 --- a/dist/alt-browser.js +++ b/dist/alt-browser.js @@ -793,23 +793,23 @@ var getInternalMethods = function (obj, excluded) { }; var AltStore = (function () { - function AltStore(dispatcher, state) { - var _this7 = this; + function AltStore(dispatcher, model, state) { + var _this8 = this; _classCallCheck(this, AltStore); this[EE] = new EventEmitter(); this[LIFECYCLE] = {}; - this[STATE_CONTAINER] = state; + this[STATE_CONTAINER] = state || model; - assign(this[LIFECYCLE], state[LIFECYCLE]); - assign(this, state[PUBLIC_METHODS]); + assign(this[LIFECYCLE], model[LIFECYCLE]); + assign(this, model[PUBLIC_METHODS]); // Register dispatcher this.dispatchToken = dispatcher.register(function (payload) { - if (state[LISTENERS][payload.action]) { - var result = state[LISTENERS][payload.action](payload.data); - result !== false && _this7.emitChange(); + if (model[LISTENERS][payload.action]) { + var result = model[LISTENERS][payload.action](payload.data); + result !== false && _this8.emitChange(); } }); @@ -871,7 +871,7 @@ var ActionCreator = (function () { return ActionCreator; })(); -var StoreMixin = { +var StoreMixinListeners = { on: function on(lifecycleEvent, handler) { this[LIFECYCLE][lifecycleEvent] = handler.bind(this); }, @@ -897,7 +897,7 @@ var StoreMixin = { }, bindActions: function bindActions(actions) { - var _this7 = this; + var _this8 = this; Object.keys(actions).forEach(function (action) { var symbol = actions[action]; @@ -907,44 +907,45 @@ var StoreMixin = { }); var handler = null; - if (_this7[action] && _this7[assumedEventHandler]) { + if (_this8[action] && _this8[assumedEventHandler]) { // If you have both action and onAction throw new ReferenceError("You have multiple action handlers bound to an action: " + ("" + action + " and " + assumedEventHandler)); - } else if (_this7[action]) { + } else if (_this8[action]) { // action - handler = _this7[action]; - } else if (_this7[assumedEventHandler]) { + handler = _this8[action]; + } else if (_this8[assumedEventHandler]) { // onAction - handler = _this7[assumedEventHandler]; + handler = _this8[assumedEventHandler]; } if (handler) { - _this7.bindAction(symbol, handler); + _this8.bindAction(symbol, handler); } }); }, bindListeners: function bindListeners(obj) { - var _this7 = this; + var _this8 = this; Object.keys(obj).forEach(function (methodName) { var symbol = obj[methodName]; - var listener = _this7[methodName]; + var listener = _this8[methodName]; if (!listener) { - throw new ReferenceError("" + methodName + " defined but does not exist in " + _this7._storeName); + throw new ReferenceError("" + methodName + " defined but does not exist in " + _this8._storeName); } if (Array.isArray(symbol)) { symbol.forEach(function (action) { - return _this7.bindAction(action, listener); + return _this8.bindAction(action, listener); }); } else { - _this7.bindAction(symbol, listener); + _this8.bindAction(symbol, listener); } }); - }, + } }; +var StoreMixinEssentials = { waitFor: function waitFor(sources) { if (!sources) { throw new ReferenceError("Dispatch tokens not provided"); @@ -964,15 +965,19 @@ var StoreMixin = { }, exportPublicMethods: function exportPublicMethods(methods) { - var _this7 = this; + var _this8 = this; Object.keys(methods).forEach(function (methodName) { if (typeof methods[methodName] !== "function") { throw new TypeError("exportPublicMethods expects a function"); } - _this7[PUBLIC_METHODS][methodName] = methods[methodName]; + _this8[PUBLIC_METHODS][methodName] = methods[methodName]; }); + }, + + emitChange: function emitChange() { + this.getInstance().emitChange(); } }; @@ -1013,6 +1018,55 @@ var filterSnapshotOfStores = function (snapshot, storeNames) { return JSON.stringify(storesToReset); }; +var createStoreFromObject = function (alt, StoreModel, key, saveStore) { + var storeInstance = undefined; + + var StoreProto = {}; + StoreProto[LIFECYCLE] = {}; + StoreProto[LISTENERS] = {}; + + assign(StoreProto, { + _storeName: key, + alt: alt, + dispatcher: alt.dispatcher, + getInstance: function getInstance() { + return storeInstance; + }, + setState: function setState() { + var values = arguments[0] === undefined ? {} : arguments[0]; + + assign(this.state, values); + this.emitChange(); + return false; + } + }, StoreMixinListeners, StoreMixinEssentials, StoreModel); + + // bind the store listeners + /* istanbul ignore else */ + if (StoreProto.bindListeners) { + StoreMixinListeners.bindListeners.call(StoreProto, StoreProto.bindListeners); + } + + // bind the lifecycle events + /* istanbul ignore else */ + if (StoreProto.lifecycle) { + Object.keys(StoreProto.lifecycle).forEach(function (event) { + StoreMixinListeners.on.call(StoreProto, event, StoreProto.lifecycle[event]); + }); + } + + // create the instance and assign the public methods to the instance + storeInstance = assign(new AltStore(alt.dispatcher, StoreProto, StoreProto.state), StoreProto.publicMethods); + + /* istanbul ignore else */ + if (saveStore) { + alt.stores[key] = storeInstance; + saveInitialSnapshot(alt, key); + } + + return storeInstance; +}; + var Alt = (function () { function Alt() { _classCallCheck(this, Alt); @@ -1050,6 +1104,10 @@ var Alt = (function () { key = uid(this.stores, key); } + if (typeof StoreModel === "object") { + return createStoreFromObject(this, StoreModel, key, saveStore); + } + // Creating a class here so we don't overload the provided store's // prototype with the mixin behaviour and I'm extending from StoreModel // so we can inherit any extensions from the provided store. @@ -1066,16 +1124,13 @@ var Alt = (function () { return Store; })(StoreModel); - assign(Store.prototype, StoreMixin, { + assign(Store.prototype, StoreMixinListeners, StoreMixinEssentials, { _storeName: key, alt: this, dispatcher: this.dispatcher, getInstance: function getInstance() { return storeInstance; }, - emitChange: function emitChange() { - this.getInstance().emitChange(); - }, setState: function setState() { var values = arguments[0] === undefined ? {} : arguments[0]; @@ -1116,7 +1171,7 @@ var Alt = (function () { }, createActions: { value: function createActions(ActionsClass) { - var _this7 = this; + var _this8 = this; var exportObj = arguments[1] === undefined ? {} : arguments[1]; @@ -1163,7 +1218,7 @@ var Alt = (function () { var actionName = Symbol("" + key + "#" + action); // Wrap the action so we can provide a dispatch method - var newAction = new ActionCreator(_this7, actionName, actions[action], obj); + var newAction = new ActionCreator(_this8, actionName, actions[action], obj); // Set all the properties on action obj[action] = newAction[ACTION_HANDLER]; diff --git a/dist/alt-with-runtime.js b/dist/alt-with-runtime.js index 994dcd37..17622e3e 100644 --- a/dist/alt-with-runtime.js +++ b/dist/alt-with-runtime.js @@ -50,23 +50,23 @@ var getInternalMethods = function (obj, excluded) { }; var AltStore = (function () { - function AltStore(dispatcher, state) { - var _this7 = this; + function AltStore(dispatcher, model, state) { + var _this8 = this; babelHelpers.classCallCheck(this, AltStore); this[EE] = new EventEmitter(); this[LIFECYCLE] = {}; - this[STATE_CONTAINER] = state; + this[STATE_CONTAINER] = state || model; - assign(this[LIFECYCLE], state[LIFECYCLE]); - assign(this, state[PUBLIC_METHODS]); + assign(this[LIFECYCLE], model[LIFECYCLE]); + assign(this, model[PUBLIC_METHODS]); // Register dispatcher this.dispatchToken = dispatcher.register(function (payload) { - if (state[LISTENERS][payload.action]) { - var result = state[LISTENERS][payload.action](payload.data); - result !== false && _this7.emitChange(); + if (model[LISTENERS][payload.action]) { + var result = model[LISTENERS][payload.action](payload.data); + result !== false && _this8.emitChange(); } }); @@ -138,7 +138,7 @@ var ActionCreator = (function () { return ActionCreator; })(); -var StoreMixin = { +var StoreMixinListeners = { on: function on(lifecycleEvent, handler) { this[LIFECYCLE][lifecycleEvent] = handler.bind(this); }, @@ -164,7 +164,7 @@ var StoreMixin = { }, bindActions: function bindActions(actions) { - var _this7 = this; + var _this8 = this; Object.keys(actions).forEach(function (action) { var symbol = actions[action]; @@ -174,44 +174,45 @@ var StoreMixin = { }); var handler = null; - if (_this7[action] && _this7[assumedEventHandler]) { + if (_this8[action] && _this8[assumedEventHandler]) { // If you have both action and onAction throw new ReferenceError("You have multiple action handlers bound to an action: " + ("" + action + " and " + assumedEventHandler)); - } else if (_this7[action]) { + } else if (_this8[action]) { // action - handler = _this7[action]; - } else if (_this7[assumedEventHandler]) { + handler = _this8[action]; + } else if (_this8[assumedEventHandler]) { // onAction - handler = _this7[assumedEventHandler]; + handler = _this8[assumedEventHandler]; } if (handler) { - _this7.bindAction(symbol, handler); + _this8.bindAction(symbol, handler); } }); }, bindListeners: function bindListeners(obj) { - var _this7 = this; + var _this8 = this; Object.keys(obj).forEach(function (methodName) { var symbol = obj[methodName]; - var listener = _this7[methodName]; + var listener = _this8[methodName]; if (!listener) { - throw new ReferenceError("" + methodName + " defined but does not exist in " + _this7._storeName); + throw new ReferenceError("" + methodName + " defined but does not exist in " + _this8._storeName); } if (Array.isArray(symbol)) { symbol.forEach(function (action) { - return _this7.bindAction(action, listener); + return _this8.bindAction(action, listener); }); } else { - _this7.bindAction(symbol, listener); + _this8.bindAction(symbol, listener); } }); - }, + } }; +var StoreMixinEssentials = { waitFor: function waitFor(sources) { if (!sources) { throw new ReferenceError("Dispatch tokens not provided"); @@ -231,15 +232,19 @@ var StoreMixin = { }, exportPublicMethods: function exportPublicMethods(methods) { - var _this7 = this; + var _this8 = this; Object.keys(methods).forEach(function (methodName) { if (typeof methods[methodName] !== "function") { throw new TypeError("exportPublicMethods expects a function"); } - _this7[PUBLIC_METHODS][methodName] = methods[methodName]; + _this8[PUBLIC_METHODS][methodName] = methods[methodName]; }); + }, + + emitChange: function emitChange() { + this.getInstance().emitChange(); } }; @@ -280,6 +285,55 @@ var filterSnapshotOfStores = function (snapshot, storeNames) { return JSON.stringify(storesToReset); }; +var createStoreFromObject = function (alt, StoreModel, key, saveStore) { + var storeInstance = undefined; + + var StoreProto = {}; + StoreProto[LIFECYCLE] = {}; + StoreProto[LISTENERS] = {}; + + assign(StoreProto, { + _storeName: key, + alt: alt, + dispatcher: alt.dispatcher, + getInstance: function getInstance() { + return storeInstance; + }, + setState: function setState() { + var values = arguments[0] === undefined ? {} : arguments[0]; + + assign(this.state, values); + this.emitChange(); + return false; + } + }, StoreMixinListeners, StoreMixinEssentials, StoreModel); + + // bind the store listeners + /* istanbul ignore else */ + if (StoreProto.bindListeners) { + StoreMixinListeners.bindListeners.call(StoreProto, StoreProto.bindListeners); + } + + // bind the lifecycle events + /* istanbul ignore else */ + if (StoreProto.lifecycle) { + Object.keys(StoreProto.lifecycle).forEach(function (event) { + StoreMixinListeners.on.call(StoreProto, event, StoreProto.lifecycle[event]); + }); + } + + // create the instance and assign the public methods to the instance + storeInstance = assign(new AltStore(alt.dispatcher, StoreProto, StoreProto.state), StoreProto.publicMethods); + + /* istanbul ignore else */ + if (saveStore) { + alt.stores[key] = storeInstance; + saveInitialSnapshot(alt, key); + } + + return storeInstance; +}; + var Alt = (function () { function Alt() { babelHelpers.classCallCheck(this, Alt); @@ -319,6 +373,10 @@ var Alt = (function () { key = uid(this.stores, key); } + if (typeof StoreModel === "object") { + return createStoreFromObject(this, StoreModel, key, saveStore); + } + // Creating a class here so we don't overload the provided store's // prototype with the mixin behaviour and I'm extending from StoreModel // so we can inherit any extensions from the provided store. @@ -334,16 +392,13 @@ var Alt = (function () { return Store; })(StoreModel); - assign(Store.prototype, StoreMixin, { + assign(Store.prototype, StoreMixinListeners, StoreMixinEssentials, { _storeName: key, alt: this, dispatcher: this.dispatcher, getInstance: function getInstance() { return storeInstance; }, - emitChange: function emitChange() { - this.getInstance().emitChange(); - }, setState: function setState() { var values = arguments[0] === undefined ? {} : arguments[0]; @@ -388,7 +443,7 @@ var Alt = (function () { }, createActions: { value: function createActions(ActionsClass) { - var _this7 = this; + var _this8 = this; var exportObj = arguments[1] === undefined ? {} : arguments[1]; @@ -435,7 +490,7 @@ var Alt = (function () { var actionName = Symbol("" + key + "#" + action); // Wrap the action so we can provide a dispatch method - var newAction = new ActionCreator(_this7, actionName, actions[action], obj); + var newAction = new ActionCreator(_this8, actionName, actions[action], obj); // Set all the properties on action obj[action] = newAction[ACTION_HANDLER]; diff --git a/dist/alt.js b/dist/alt.js index 68f66c98..5316f6cb 100644 --- a/dist/alt.js +++ b/dist/alt.js @@ -62,23 +62,23 @@ var getInternalMethods = function (obj, excluded) { }; var AltStore = (function () { - function AltStore(dispatcher, state) { - var _this7 = this; + function AltStore(dispatcher, model, state) { + var _this8 = this; _classCallCheck(this, AltStore); this[EE] = new EventEmitter(); this[LIFECYCLE] = {}; - this[STATE_CONTAINER] = state; + this[STATE_CONTAINER] = state || model; - assign(this[LIFECYCLE], state[LIFECYCLE]); - assign(this, state[PUBLIC_METHODS]); + assign(this[LIFECYCLE], model[LIFECYCLE]); + assign(this, model[PUBLIC_METHODS]); // Register dispatcher this.dispatchToken = dispatcher.register(function (payload) { - if (state[LISTENERS][payload.action]) { - var result = state[LISTENERS][payload.action](payload.data); - result !== false && _this7.emitChange(); + if (model[LISTENERS][payload.action]) { + var result = model[LISTENERS][payload.action](payload.data); + result !== false && _this8.emitChange(); } }); @@ -152,7 +152,7 @@ var ActionCreator = (function () { return ActionCreator; })(); -var StoreMixin = { +var StoreMixinListeners = { on: function on(lifecycleEvent, handler) { this[LIFECYCLE][lifecycleEvent] = handler.bind(this); }, @@ -178,7 +178,7 @@ var StoreMixin = { }, bindActions: function bindActions(actions) { - var _this7 = this; + var _this8 = this; Object.keys(actions).forEach(function (action) { var symbol = actions[action]; @@ -188,44 +188,45 @@ var StoreMixin = { }); var handler = null; - if (_this7[action] && _this7[assumedEventHandler]) { + if (_this8[action] && _this8[assumedEventHandler]) { // If you have both action and onAction throw new ReferenceError("You have multiple action handlers bound to an action: " + ("" + action + " and " + assumedEventHandler)); - } else if (_this7[action]) { + } else if (_this8[action]) { // action - handler = _this7[action]; - } else if (_this7[assumedEventHandler]) { + handler = _this8[action]; + } else if (_this8[assumedEventHandler]) { // onAction - handler = _this7[assumedEventHandler]; + handler = _this8[assumedEventHandler]; } if (handler) { - _this7.bindAction(symbol, handler); + _this8.bindAction(symbol, handler); } }); }, bindListeners: function bindListeners(obj) { - var _this7 = this; + var _this8 = this; Object.keys(obj).forEach(function (methodName) { var symbol = obj[methodName]; - var listener = _this7[methodName]; + var listener = _this8[methodName]; if (!listener) { - throw new ReferenceError("" + methodName + " defined but does not exist in " + _this7._storeName); + throw new ReferenceError("" + methodName + " defined but does not exist in " + _this8._storeName); } if (Array.isArray(symbol)) { symbol.forEach(function (action) { - return _this7.bindAction(action, listener); + return _this8.bindAction(action, listener); }); } else { - _this7.bindAction(symbol, listener); + _this8.bindAction(symbol, listener); } }); - }, + } }; +var StoreMixinEssentials = { waitFor: function waitFor(sources) { if (!sources) { throw new ReferenceError("Dispatch tokens not provided"); @@ -245,15 +246,19 @@ var StoreMixin = { }, exportPublicMethods: function exportPublicMethods(methods) { - var _this7 = this; + var _this8 = this; Object.keys(methods).forEach(function (methodName) { if (typeof methods[methodName] !== "function") { throw new TypeError("exportPublicMethods expects a function"); } - _this7[PUBLIC_METHODS][methodName] = methods[methodName]; + _this8[PUBLIC_METHODS][methodName] = methods[methodName]; }); + }, + + emitChange: function emitChange() { + this.getInstance().emitChange(); } }; @@ -294,6 +299,55 @@ var filterSnapshotOfStores = function (snapshot, storeNames) { return JSON.stringify(storesToReset); }; +var createStoreFromObject = function (alt, StoreModel, key, saveStore) { + var storeInstance = undefined; + + var StoreProto = {}; + StoreProto[LIFECYCLE] = {}; + StoreProto[LISTENERS] = {}; + + assign(StoreProto, { + _storeName: key, + alt: alt, + dispatcher: alt.dispatcher, + getInstance: function getInstance() { + return storeInstance; + }, + setState: function setState() { + var values = arguments[0] === undefined ? {} : arguments[0]; + + assign(this.state, values); + this.emitChange(); + return false; + } + }, StoreMixinListeners, StoreMixinEssentials, StoreModel); + + // bind the store listeners + /* istanbul ignore else */ + if (StoreProto.bindListeners) { + StoreMixinListeners.bindListeners.call(StoreProto, StoreProto.bindListeners); + } + + // bind the lifecycle events + /* istanbul ignore else */ + if (StoreProto.lifecycle) { + Object.keys(StoreProto.lifecycle).forEach(function (event) { + StoreMixinListeners.on.call(StoreProto, event, StoreProto.lifecycle[event]); + }); + } + + // create the instance and assign the public methods to the instance + storeInstance = assign(new AltStore(alt.dispatcher, StoreProto, StoreProto.state), StoreProto.publicMethods); + + /* istanbul ignore else */ + if (saveStore) { + alt.stores[key] = storeInstance; + saveInitialSnapshot(alt, key); + } + + return storeInstance; +}; + var Alt = (function () { function Alt() { _classCallCheck(this, Alt); @@ -333,6 +387,10 @@ var Alt = (function () { key = uid(this.stores, key); } + if (typeof StoreModel === "object") { + return createStoreFromObject(this, StoreModel, key, saveStore); + } + // Creating a class here so we don't overload the provided store's // prototype with the mixin behaviour and I'm extending from StoreModel // so we can inherit any extensions from the provided store. @@ -349,16 +407,13 @@ var Alt = (function () { return Store; })(StoreModel); - assign(Store.prototype, StoreMixin, { + assign(Store.prototype, StoreMixinListeners, StoreMixinEssentials, { _storeName: key, alt: this, dispatcher: this.dispatcher, getInstance: function getInstance() { return storeInstance; }, - emitChange: function emitChange() { - this.getInstance().emitChange(); - }, setState: function setState() { var values = arguments[0] === undefined ? {} : arguments[0]; @@ -403,7 +458,7 @@ var Alt = (function () { }, createActions: { value: function createActions(ActionsClass) { - var _this7 = this; + var _this8 = this; var exportObj = arguments[1] === undefined ? {} : arguments[1]; @@ -452,7 +507,7 @@ var Alt = (function () { var actionName = Symbol("" + key + "#" + action); // Wrap the action so we can provide a dispatch method - var newAction = new ActionCreator(_this7, actionName, actions[action], obj); + var newAction = new ActionCreator(_this8, actionName, actions[action], obj); // Set all the properties on action obj[action] = newAction[ACTION_HANDLER]; diff --git a/src/alt.js b/src/alt.js index 515c6708..077db0b2 100644 --- a/src/alt.js +++ b/src/alt.js @@ -49,18 +49,18 @@ const getInternalMethods = (obj, excluded) => { } class AltStore { - constructor(dispatcher, state) { + constructor(dispatcher, model, state) { this[EE] = new EventEmitter() this[LIFECYCLE] = {} - this[STATE_CONTAINER] = state + this[STATE_CONTAINER] = state || model - assign(this[LIFECYCLE], state[LIFECYCLE]) - assign(this, state[PUBLIC_METHODS]) + assign(this[LIFECYCLE], model[LIFECYCLE]) + assign(this, model[PUBLIC_METHODS]) // Register dispatcher this.dispatchToken = dispatcher.register((payload) => { - if (state[LISTENERS][payload.action]) { - const result = state[LISTENERS][payload.action](payload.data) + if (model[LISTENERS][payload.action]) { + const result = model[LISTENERS][payload.action](payload.data) result !== false && this.emitChange() } }) @@ -105,7 +105,7 @@ class ActionCreator { } } -const StoreMixin = { +const StoreMixinListeners = { on(lifecycleEvent, handler) { this[LIFECYCLE][lifecycleEvent] = handler.bind(this) }, @@ -184,6 +184,9 @@ const StoreMixin = { }) }, +} + +const StoreMixinEssentials = { waitFor(sources) { if (!sources) { throw new ReferenceError('Dispatch tokens not provided') @@ -210,6 +213,10 @@ const StoreMixin = { this[PUBLIC_METHODS][methodName] = methods[methodName] }) + }, + + emitChange() { + this.getInstance().emitChange() } } @@ -252,6 +259,56 @@ const filterSnapshotOfStores = (snapshot, storeNames) => { return JSON.stringify(storesToReset) } +const createStoreFromObject = (alt, StoreModel, key, saveStore) => { + let storeInstance + + const StoreProto = {} + StoreProto[LIFECYCLE] = {} + StoreProto[LISTENERS] = {} + + assign(StoreProto, { + _storeName: key, + alt, + dispatcher: alt.dispatcher, + getInstance() { + return storeInstance + }, + setState(values = {}) { + assign(this.state, values) + this.emitChange() + return false + } + }, StoreMixinListeners, StoreMixinEssentials, StoreModel) + + // bind the store listeners + /* istanbul ignore else */ + if (StoreProto.bindListeners) { + StoreMixinListeners.bindListeners.call(StoreProto, StoreProto.bindListeners) + } + + // bind the lifecycle events + /* istanbul ignore else */ + if (StoreProto.lifecycle) { + Object.keys(StoreProto.lifecycle).forEach((event) => { + StoreMixinListeners.on.call(StoreProto, event, StoreProto.lifecycle[event]) + }) + } + + // create the instance and assign the public methods to the instance + storeInstance = assign( + new AltStore(alt.dispatcher, StoreProto, StoreProto.state), + StoreProto.publicMethods + ) + + /* istanbul ignore else */ + if (saveStore) { + alt.stores[key] = storeInstance + saveInitialSnapshot(alt, key) + } + + return storeInstance +} + class Alt { constructor() { this.dispatcher = new Dispatcher() @@ -285,6 +342,10 @@ class Alt { key = uid(this.stores, key) } + if (typeof StoreModel === 'object') { + return createStoreFromObject(this, StoreModel, key, saveStore) + } + // Creating a class here so we don't overload the provided store's // prototype with the mixin behaviour and I'm extending from StoreModel // so we can inherit any extensions from the provided store. @@ -294,16 +355,13 @@ class Alt { } } - assign(Store.prototype, StoreMixin, { + assign(Store.prototype, StoreMixinListeners, StoreMixinEssentials, { _storeName: key, alt: this, dispatcher: this.dispatcher, getInstance() { return storeInstance }, - emitChange() { - this.getInstance().emitChange() - }, setState(values = {}) { assign(this, values) this.emitChange() diff --git a/test/es3-module-pattern.js b/test/es3-module-pattern.js new file mode 100644 index 00000000..2ef1eb91 --- /dev/null +++ b/test/es3-module-pattern.js @@ -0,0 +1,136 @@ +import Alt from '../dist/alt-with-runtime' +import assert from 'assert' + +const alt = new Alt() + +const actions = alt.generateActions('fire') + +function MyStore() { + var privateVariable = true + + return { + displayName: 'MyStore', + + state: { + data: 1 + }, + + publicMethods: { + getData: function () { + return this.getState().data + } + }, + + testProperty: 4, + + bindListeners: { + handleFire: actions.FIRE + }, + + handleFire: function (data) { + this.state.data = data + } + } +} + +const myStore = alt.createStore(MyStore()) + +export default { + 'using the es3 module pattern': { + beforeEach() { + alt.recycle() + }, + + 'store method exists'() { + const storePrototype = Object.getPrototypeOf(myStore) + const assertMethods = ['constructor', 'getEventEmitter', 'emitChange', 'listen', 'unlisten', 'getState'] + assert.deepEqual(Object.getOwnPropertyNames(storePrototype), assertMethods, 'methods exist for store') + assert.equal(typeof myStore.addListener, 'undefined', 'event emitter methods not present') + assert.equal(typeof myStore.removeListener, 'undefined', 'event emitter methods not present') + assert.equal(typeof myStore.emit, 'undefined', 'event emitter methods not present') + }, + + 'public methods available'() { + assert.equal(typeof myStore.getData, 'function', 'public methods are available') + assert.equal(myStore.getData(), 1, 'initial store data is set') + }, + + 'private and instance variables are not available'() { + assert.equal(myStore.privateVariable, undefined, 'encapsulated variables are not available') + assert.equal(myStore.testProperty, undefined, 'instance variables are not available') + }, + + 'firing an action'() { + actions.fire(2) + + assert.equal(myStore.getState().data, 2, 'action was fired and handled correctly') + }, + + 'adding lifecycle events'() { + let called = false + + class TestStore { + constructor() { + this.lifecycle = { + init() { + called = true + } + } + + this.state = { + foo: 'bar' + } + } + } + + const store = alt.createStore(new TestStore()) + + assert.equal(called, true, 'lifecycle event was called') + assert.equal(store.getState().foo, 'bar', 'state is set') + }, + + 'set state'() { + const TestStore = { + state: { hello: null, inst: null }, + + bindListeners: { + handleFire: actions.FIRE + }, + + handleFire(data) { + this.state.inst = this.getInstance().getEventEmitter() + + this.setState({ + hello: data + }) + + this.setState() + } + } + + const store = alt.createStore(TestStore) + assert.equal(store.getState().hello, null, 'store state property has not been set yet') + assert.equal(store.getState().inst, null, 'store state property has not been set yet') + + actions.fire('world') + + assert.equal(store.getState().hello, 'world', 'store state was set using setState') + assert.equal(store.getState().inst, store.getEventEmitter(), 'get instance works') + }, + + 'set state in lifecycle'() { + const TestStore = { + state: { test: null }, + + lifecycle: { + init() { + this.state.test = 'i am here' + } + } + } + + const store = alt.createStore(TestStore) + assert.equal(store.getState().test, 'i am here', 'setting state on lifecycle') + }, + } +} diff --git a/test/helpers/SaaM.js b/test/helpers/SaaM.js new file mode 100644 index 00000000..a52074bb --- /dev/null +++ b/test/helpers/SaaM.js @@ -0,0 +1,13 @@ +import actions from './SampleActions' + +export const bindListeners = { + handleClick: actions.FIRE +} + +export const state = { + data: 1 +} + +export function handleClick(data) { + this.state.data = data +} diff --git a/test/helpers/SampleActions.js b/test/helpers/SampleActions.js new file mode 100644 index 00000000..43b5ea3e --- /dev/null +++ b/test/helpers/SampleActions.js @@ -0,0 +1,3 @@ +import alt from './alt' + +export default alt.generateActions('fire') diff --git a/test/helpers/alt.js b/test/helpers/alt.js new file mode 100644 index 00000000..97a145db --- /dev/null +++ b/test/helpers/alt.js @@ -0,0 +1,2 @@ +import Alt from '../../dist/alt-with-runtime' +export default new Alt() diff --git a/test/store-as-a-module.js b/test/store-as-a-module.js new file mode 100644 index 00000000..7e97c108 --- /dev/null +++ b/test/store-as-a-module.js @@ -0,0 +1,21 @@ +import assert from 'assert' + +import alt from './helpers/alt' +import actions from './helpers/SampleActions' +import * as StoreModel from './helpers/SaaM' + +const store = alt.createStore(StoreModel) + +export default { + beforeEach() { + alt.recycle() + }, + + 'store state is there'() { + assert.equal(store.getState().data, 1, 'store data is initialized to 1') + + actions.fire(2) + + assert.equal(store.getState().data, 2, 'store data was updated') + } +}