├── .gitignore ├── Gruntfile.js ├── README.md ├── bower.json ├── dist ├── mockstate.js ├── mockstate.js.map └── mockstate.min.js ├── img ├── logo_full.png ├── logo_h.png ├── logo_h_small.png ├── mockstate-icon.png ├── mockstate-react.gif └── react-count.gif ├── package.json ├── src └── mockstate.js └── tests ├── actions.js ├── emit.js ├── index.html ├── setState.js └── store.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | require('time-grunt')(grunt); 3 | grunt.initConfig({ 4 | babel: { 5 | options: { 6 | sourceMap: true, 7 | presets: ['babel-preset-es2015-script'] 8 | }, 9 | dist: { 10 | files: { 11 | 'dist/mockstate.js': 'src/mockstate.js' 12 | } 13 | } 14 | }, 15 | uglify: { 16 | my_target: { 17 | files: { 18 | 'dist/mockstate.min.js': ['dist/mockstate.js'] 19 | } 20 | }, 21 | }, 22 | watch: { 23 | scripts: { 24 | files: 'src/**/*.js', tasks: ['babel', 'uglify'] 25 | } 26 | } 27 | }); 28 | grunt.loadNpmTasks('grunt-contrib-watch'); 29 | grunt.loadNpmTasks('grunt-contrib-uglify'); 30 | grunt.loadNpmTasks('grunt-babel'); 31 | grunt.registerTask('build', ['babel']); 32 | grunt.registerTask('default', ['babel', 'uglify']); 33 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Deprecated! Use [Dutier](https://github.com/luisvinicius167/dutier) instead. 4 | 5 | Mockstate is a centralized state management for Javascript applications. It provides more control of your state application with a simple and efficiently API and keep the state safe, when the user connection goes offline the state is saved in localStorage to be picked up when the connection back.
6 | 7 | ### :information_desk_person: See the [React.js Todo ➞](http://mockstate-react.surge.sh/)
8 | [![npm package](https://img.shields.io/badge/npm-0.0.7-blue.svg)](https://www.npmjs.com/package/state) 9 | [![CDN](https://img.shields.io/badge/cdn-0.0.7-ff69b4.svg)](https://unpkg.com/mockstate@0.0.7) 10 | 11 | 12 | ## Demos 13 | 14 | [React.js Todo with Mockstate ➞](http://mockstate-react.surge.sh/)
15 | [Preact.js + Mockstate ➞](http://mockstate-preact.surge.sh/) 16 | 17 | ### Influences 18 | Mockstate provides more control of your application state. It's envolve ideas of Redux and Flux, but explores all power of Promises, doing the work with async action easy. 19 | 20 | ## Getting Started 21 | 22 | ### Install 23 | * Npm: ``` npm install mockstate ``` 24 | * Bower: ``` bower install mockstate ``` 25 | * CDN: ```https://unpkg.com/mockstate@0.0.7``` 26 | 27 | ### Why you should be using Mockstate? 28 | * More control of you application state. 29 | * Safe State. 30 | * It's pure flux, the flow is unidirectional. 31 | * Tiny API. 32 | * Actively maintained and being used in production. 33 | 34 | ### The Gist 35 | The application state is stored in an object tree inside a single store. 36 | The only way to change the state tree is to emit an action, that always return a Promise. 37 | You can receive the result of your action using ``.then`` after your ``dispatch`` call. 38 | 39 | That's it! 40 | 41 | ```javascript 42 | import { setState, setActions, subscribe, dispatch } from 'mockstate'; 43 | 44 | /** 45 | * Set your store state in a single object. 46 | */ 47 | setState({ 48 | count: 0 49 | }) 50 | 51 | /** 52 | * Set your store state in a single object, 53 | * that always receive the store state as first argument. 54 | */ 55 | setActions({ 56 | increment: ( state, n ) => { 57 | let count = state.count += n 58 | return count; 59 | } 60 | }); 61 | 62 | /** 63 | * You can use subscribe() to update your UI in response to state changes. 64 | * `${this}` can be your UI component, where the subscribe handler will be applied. 65 | */ 66 | subscribe( this, ( data ) => { 67 | console.log(`Some action was called, Action name: ${data.action} Action Value: ${data.value}.`); 68 | }) 69 | 70 | /** 71 | * The only way to mutate the internal state is to dispatch an action. 72 | * You can receive the response of your action and do something, or not. 73 | */ 74 | dispatch('increment', 1).then( data => { 75 | console.log(`The result of this action ${data.action} is: ${data.value}`); 76 | }) 77 | //1 78 | dispatch('increment', 1); 79 | //2 80 | dispatch('increment', 1); 81 | //3 82 | ``` 83 | 84 | ### Simple and efficiently API. 85 | 86 | Dispatch 87 | * Trigger some action for do something. A Promise will be returned, that contain an Object with the
88 | keys ``action`` and ``value`` of your correspondent action response. 89 | ```javascript 90 | /** 91 | * @name dispatch 92 | * @description Trigger some action. 93 | * @param {string} actionName Action name 94 | * @param { arguments } Arguments You can pass the arguments after the actionName 95 | * @return {Promise} Return a Promise with an Object that contain the value 96 | * of the action and the action name. 97 | * {value, action} = data; 98 | */ 99 | 100 | // On your component 101 | import {dispatch} from 'mockstate'; 102 | 103 | // You can receive the response of your action and do something, or not. 104 | // If you whant, you can chaining the dispatch Promises. 105 | dispatch('increment', 1) 106 | .then( data => { 107 | console.log(`The action will be called. The result is: ${data.value}`); 108 | return data.value; 109 | }) 110 | .then( value => { 111 | console.log(`The response is: ${value}`); 112 | }) 113 | ``` 114 | 115 | Actions 116 | * Set your actions functions. Your actions always needs to return a value and receive the state as first argument. 117 | ```javascript 118 | /** 119 | * @name setActions 120 | * @description Set the actions functions. 121 | * @param {object} state The Store State as first argument 122 | * @param { any } args Other Arguments 123 | */ 124 | 125 | // actions/index.js 126 | import {setActions} from 'mockstate'; 127 | 128 | setActions({ 129 | // each action receive the state as first argument 130 | increment: (state, n) => { 131 | setTimeout(() => { 132 | let result = state.count += n; 133 | return result; 134 | }, 2000) 135 | } 136 | }); 137 | ``` 138 | 139 | Store State 140 | * Set the application Store state 141 | ```javascript 142 | /** 143 | * @name setState 144 | * @description Set you application store state 145 | * @param {object} state Your application state data 146 | */ 147 | 148 | // store/index.js 149 | import {setState} from 'mockstate'; 150 | 151 | setState({ 152 | count: 1 153 | }); 154 | ``` 155 | 156 | Getting the Store State 157 | * Get a state value of your store 158 | ```javascript 159 | /** 160 | * @name getState 161 | * @description Get the state value 162 | * @param {string} stateName The state name 163 | */ 164 | 165 | // store/index.js 166 | import {getState} from 'mockstate'; 167 | 168 | let count = getState('count'); 169 | ``` 170 | 171 | Middleware 172 | * Set a middleware function, that will be triggered after the action calls. 173 | ```javascript 174 | /** 175 | * @name middleware 176 | * @description Get the state value 177 | * @param {Function} callback The callback that will be triggered and 178 | * receives the data of your action and the all state of your store application. 179 | */ 180 | 181 | // state/index.js 182 | import { middleware } from 'mockstate'; 183 | 184 | middleware( (data, state) => { 185 | console.log('After action triggers:', data, ' and the Store State is: ', state); 186 | }) 187 | 188 | ``` 189 | Emit 190 | * Tell to store that something are happend and the handler function will be triggerd. 191 | ```javascript 192 | /** 193 | * @name emit 194 | * @description Tell to store that something happend, 195 | * and the handler function will be called. 196 | * @return void 197 | **/ 198 | 199 | // state/index.js 200 | import { emit } from 'mockstate'; 201 | 202 | emit() 203 | .then( () => { 204 | console.log('After emit called.'); 205 | }); 206 | ``` 207 | 208 | Subscribe/Unsubscribe 209 | * Subscribe some UI Component for trigger the handler function when some action are trigger. 210 | * Unsubscribe when you don't wnat to trigger the handler function. 211 | ```javascript 212 | /** 213 | * @name subscribe 214 | * @description Subscribe some UI Component for trigger the handler function when some action calls. 215 | * @param { object } BindComponent The UI element that the handler function will be applied. 216 | * @param { handler } handler Your function that will be triggered when some state change. 217 | */ 218 | 219 | // components/app/index.js 220 | import {subscribe, unsubscribe, getState} from 'mockstate'; 221 | 222 | componentWillMount(){ 223 | // when some state change, do something. 224 | subscribe(this, ( data ) => { 225 | this.setState({count: getState('count')}) 226 | }); 227 | } 228 | 229 | componentWillUnmount(){ 230 | // remove this component for observe the changes on the state 231 | unsubscribe(this) 232 | } 233 | ``` 234 | 235 | #### License 236 | MIT License. 237 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mockstate", 3 | "description": "A centralized state management for Javascript applications, made easy.", 4 | "main": "dist/mockstate.min.js", 5 | "authors": [ 6 | "Luis Vinícius " 7 | ], 8 | "license": "MIT", 9 | "keywords": [ 10 | "riotjs", 11 | "redux-flux", 12 | "riot.js", 13 | "flux", 14 | "redux", 15 | "mockstate" 16 | ], 17 | "homepage": "https://github.com/luisvinicius167/state", 18 | "moduleType": [], 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /dist/mockstate.js: -------------------------------------------------------------------------------- 1 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 2 | 3 | ; 4 | (function (root, factory) { 5 | if (typeof define === "function" && define.amd) { 6 | define([], factory); 7 | } else if ((typeof exports === "undefined" ? "undefined" : _typeof(exports)) === "object") { 8 | module.exports = { 9 | dispatch: factory.dispatch, 10 | getState: factory.getState, 11 | setState: factory.setState, 12 | setActions: factory.setActions, 13 | subscribe: factory.subscribe, 14 | middleware: factory.middleware, 15 | emit: factory.emit, 16 | unsubscribe: factory.unsubscribe 17 | }; 18 | } else { 19 | root.Mockstate = factory; 20 | } 21 | })(this, function (global) { 22 | var _this = this; 23 | 24 | /** 25 | * @name Mockstate 26 | * @description The object that will manage all application state 27 | */ 28 | var Mockstate = { 29 | /** 30 | * Persists the store state on localStorage 31 | * @name localState 32 | */ 33 | localState: { 34 | /** 35 | * @name recoveryStateWhenOffline 36 | * @description When the user will be offline, keep the store state safe. 37 | */ 38 | recoveryStateWhenOffline: function recoveryStateWhenOffline() { 39 | // verify if this === window 40 | if (_this.addEventListener !== undefined) { 41 | /** 42 | * When the page reloads, if the recovery state are present 43 | * recovery the store state. 44 | */ 45 | _this.addEventListener("load", function () { 46 | // verify if the recored state are present when the page loads 47 | if (localStorage.getItem('mockstate:StateToRecovery') !== null) { 48 | Mockstate.mockStoreState = JSON.parse(localStorage.getItem('mockstate:StateToRecovery')); 49 | // remove the temporary recovery state 50 | localStorage.removeItem('mockstate:StateToRecovery'); 51 | }; 52 | }); 53 | 54 | // if the network connection back whithout the user reload the page, recovery 55 | // the state. 56 | _this.addEventListener('online', function (e) { 57 | var recoveredState = JSON.parse(localStorage.getItem('mockstate:StateToRecovery')); 58 | Mockstate.mockStoreState = recoveredState; 59 | 60 | // remove the temporary recovery state 61 | localStorage.removeItem('mockstate:StateToRecovery'); 62 | }); 63 | 64 | _this.addEventListener('offline', function (e) { 65 | /** 66 | * when the network connection is offline, store the actual 67 | * state on localStorage to be recovered when the connection 68 | * become without reload the page or when reload in the same route, 69 | * keeping the state and UI component safe. 70 | */ 71 | localStorage.setItem('mockstate:StateToRecovery', JSON.stringify(Mockstate.mockStoreState)); 72 | }); 73 | } 74 | } 75 | }, 76 | /** 77 | * The copy of initial store state, that will be used to work 78 | * in application. Keeping the store state immutable. 79 | */ 80 | mockStoreState: {}, 81 | /** 82 | * @name _store 83 | * @description The private store 84 | */ 85 | _store: { 86 | /** 87 | * @name state 88 | * @description The Store application state 89 | */ 90 | state: {}, 91 | /** 92 | * @name actions 93 | * @description The Functions that will change the Store state 94 | */ 95 | actions: {}, 96 | /** 97 | * @name state 98 | * @description The Components that was subscribed 99 | */ 100 | components: [], 101 | middleware: {} 102 | }, 103 | /** 104 | * @name store 105 | * @description Public Store 106 | */ 107 | store: { 108 | /** 109 | * @name subscribe 110 | * @description Subscribe to call the handler function when the action will be triggered 111 | * @param {Component} component The Component 112 | * @param {Function} handler The function that will be called 113 | **/ 114 | subscribe: function subscribe(component, handler) { 115 | Mockstate._store.components.push({ component: component, handler: handler }); 116 | }, 117 | unsubscribe: function unsubscribe(component) { 118 | var components = Mockstate._store.components; 119 | components.forEach(el, function (index) { 120 | if (el === component) { 121 | components.splice(index, 1); 122 | } 123 | }); 124 | }, 125 | /** 126 | * @name middleware 127 | * @description The middleware function that will be triggered 128 | * every time when an action called. 129 | * @param {Function} callback A function that will be called 130 | **/ 131 | middleware: function middleware(callback) { 132 | Mockstate._store.middleware = callback; 133 | }, 134 | /** 135 | * @name emit 136 | * @description Tell to store that something happend, 137 | * and the handler function will be called. 138 | * @return void 139 | **/ 140 | emit: function emit() { 141 | return new Promise(function (resolve, reject) { 142 | // emit just update the components 143 | var state = { 144 | action: null, 145 | value: null 146 | }; 147 | var components = Mockstate._store.components; 148 | components.forEach(function (el, i) { 149 | if (el.component !== undefined && typeof el.handler === "function") { 150 | resolve(el.handler(state)); 151 | } 152 | }); 153 | }); 154 | }, 155 | /** 156 | * @name dispatch 157 | * @description Dispatch an action to change 158 | * the store state 159 | * @param { string } action The action name 160 | * @param { any } args Arguments sended to the action 161 | */ 162 | dispatch: function dispatch(action) { 163 | for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 164 | args[_key - 1] = arguments[_key]; 165 | } 166 | 167 | var state = void 0, 168 | components = Mockstate._store.components; 169 | 170 | var updateStoreData = function updateStoreData() { 171 | var updateStoreState = 172 | // actions don't need to return a promise 173 | Promise.resolve(Mockstate._store.actions[action].apply(null, [].concat(Mockstate.mockStoreState, args))).then(function (value) { 174 | var middleware = Mockstate._store.middleware; 175 | 176 | // state that will be returned 177 | var state = { 178 | action: action, 179 | value: value 180 | }; 181 | 182 | /** 183 | * has middleware? 184 | **/ 185 | if (typeof middleware === "function") { 186 | middleware.call(null, state, Mockstate.mockStoreState); 187 | } 188 | 189 | return state; 190 | }).then(function (state) { 191 | components.forEach(function (el, i) { 192 | if (el.component !== undefined && typeof el.handler === "function") { 193 | el.handler(state); 194 | } 195 | }); 196 | return state; 197 | }); 198 | 199 | return updateStoreState; 200 | }; 201 | return updateStoreData(); 202 | }, 203 | /** 204 | * @name setState 205 | * @description Sets the application data state 206 | * @param {object} data Simple Object that contain the State 207 | */ 208 | setState: function setState(data) { 209 | // setting the immutable initial state 210 | Object.assign(Mockstate._store.state, data); 211 | Object.assign(Mockstate.mockStoreState, data); 212 | Mockstate.localState.recoveryStateWhenOffline(); 213 | }, 214 | /** 215 | * @name get 216 | * @param {string} stateName The Store state name 217 | */ 218 | getState: function getState(stateName) { 219 | if (stateName === '*') { 220 | return Mockstate.mockStoreState; 221 | } 222 | return Mockstate.mockStoreState[stateName]; 223 | }, 224 | /** 225 | * @name setActions 226 | * @description Sets the application Actions 227 | * that will change the Store state 228 | */ 229 | setActions: function setActions(data) { 230 | Object.assign(Mockstate._store.actions, data); 231 | } 232 | } 233 | }; 234 | return Mockstate.store; 235 | }(this)); 236 | //# sourceMappingURL=mockstate.js.map 237 | -------------------------------------------------------------------------------- /dist/mockstate.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/mockstate.js"],"names":["root","factory","define","amd","exports","module","dispatch","getState","setState","setActions","subscribe","middleware","emit","unsubscribe","Mockstate","global","localState","recoveryStateWhenOffline","addEventListener","undefined","localStorage","getItem","mockStoreState","JSON","parse","removeItem","e","recoveredState","setItem","stringify","_store","state","actions","components","store","component","handler","push","forEach","el","splice","index","callback","Promise","resolve","reject","action","value","i","args","updateStoreData","updateStoreState","apply","concat","then","call","data","Object","assign","stateName"],"mappings":"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","file":"mockstate.js","sourcesContent":[";\n(function (root, factory) {\n if (typeof define === \"function\" && define.amd) {\n define([], factory);\n } else if (typeof exports === \"object\") {\n module.exports = {\n dispatch: factory.dispatch,\n getState: factory.getState,\n setState: factory.setState,\n setActions: factory.setActions,\n subscribe: factory.subscribe,\n middleware: factory.middleware,\n emit: factory.emit,\n unsubscribe: factory.unsubscribe\n }\n } else {\n root.Mockstate = factory;\n }\n}(this, function (global) {\n /**\n * @name Mockstate\n * @description The object that will manage all application state\n */\n let Mockstate = {\n /**\n * Persists the store state on localStorage\n * @name localState\n */\n localState: {\n /**\n * @name recoveryStateWhenOffline\n * @description When the user will be offline, keep the store state safe.\n */\n recoveryStateWhenOffline: () => {\n // verify if this === window\n if (this.addEventListener !== undefined) {\n /**\n * When the page reloads, if the recovery state are present\n * recovery the store state.\n */\n this.addEventListener(\"load\", () => {\n // verify if the recored state are present when the page loads\n if (localStorage.getItem('mockstate:StateToRecovery') !== null) {\n Mockstate.mockStoreState = JSON.parse(localStorage.getItem('mockstate:StateToRecovery'));\n // remove the temporary recovery state\n localStorage.removeItem('mockstate:StateToRecovery');\n };\n });\n\n // if the network connection back whithout the user reload the page, recovery\n // the state.\n this.addEventListener('online', (e) => {\n let recoveredState = JSON.parse(localStorage.getItem('mockstate:StateToRecovery'));\n Mockstate.mockStoreState = recoveredState;\n\n // remove the temporary recovery state\n localStorage.removeItem('mockstate:StateToRecovery');\n });\n\n this.addEventListener('offline', (e) => {\n /**\n * when the network connection is offline, store the actual\n * state on localStorage to be recovered when the connection\n * become without reload the page or when reload in the same route,\n * keeping the state and UI component safe.\n */\n localStorage.setItem('mockstate:StateToRecovery', JSON.stringify(Mockstate.mockStoreState));\n });\n }\n }\n },\n /**\n * The copy of initial store state, that will be used to work\n * in application. Keeping the store state immutable.\n */\n mockStoreState: {},\n /**\n * @name _store\n * @description The private store\n */\n _store: {\n /**\n * @name state\n * @description The Store application state\n */\n state: {},\n /**\n * @name actions\n * @description The Functions that will change the Store state\n */\n actions: {},\n /**\n * @name state\n * @description The Components that was subscribed\n */\n components: [],\n middleware: {}\n },\n /**\n * @name store\n * @description Public Store\n */\n store: {\n /**\n * @name subscribe\n * @description Subscribe to call the handler function when the action will be triggered\n * @param {Component} component The Component\n * @param {Function} handler The function that will be called\n **/\n subscribe: (component, handler) => {\n Mockstate\n ._store\n .components\n .push({component, handler});\n },\n unsubscribe: (component) => {\n let components = Mockstate._store.components;\n components.forEach(el, index => {\n if (el === component) {\n components.splice(index, 1);\n }\n });\n },\n /**\n * @name middleware\n * @description The middleware function that will be triggered\n * every time when an action called.\n * @param {Function} callback A function that will be called\n **/\n middleware: (callback) => {\n Mockstate._store.middleware = callback;\n },\n /**\n * @name emit\n * @description Tell to store that something happend,\n * and the handler function will be called.\n * @return void\n **/\n emit: () => {\n return new Promise((resolve, reject) => {\n // emit just update the components\n let state = {\n action: null,\n value: null\n };\n let components = Mockstate._store.components;\n components.forEach((el, i) => {\n if (el.component !== undefined && typeof el.handler === \"function\") {\n resolve(el.handler(state));\n }\n });\n });\n },\n /**\n * @name dispatch\n * @description Dispatch an action to change\n * the store state\n * @param { string } action The action name\n * @param { any } args Arguments sended to the action\n */\n dispatch: (action, ...args) => {\n let state,\n components = Mockstate._store.components;\n\n let updateStoreData = () => {\n let updateStoreState =\n // actions don't need to return a promise\n Promise\n .resolve(Mockstate._store.actions[action].apply(null, [].concat(Mockstate.mockStoreState, args)))\n .then(value => {\n let middleware = Mockstate._store.middleware;\n\n // state that will be returned\n let state = {\n action,\n value\n }\n\n /**\n * has middleware?\n **/\n if (typeof middleware === \"function\") {\n middleware.call(null, state, Mockstate.mockStoreState);\n }\n\n return state;\n\n })\n .then(state => {\n components.forEach((el, i) => {\n if (el.component !== undefined && typeof el.handler === \"function\") {\n el.handler(state)\n }\n });\n return state;\n });\n\n return updateStoreState;\n };\n return updateStoreData()\n },\n /**\n * @name setState\n * @description Sets the application data state\n * @param {object} data Simple Object that contain the State\n */\n setState: (data) => {\n // setting the immutable initial state\n Object.assign(Mockstate._store.state, data);\n Object.assign(Mockstate.mockStoreState, data);\n Mockstate\n .localState\n .recoveryStateWhenOffline();\n },\n /**\n * @name get\n * @param {string} stateName The Store state name\n */\n getState: (stateName) => {\n if (stateName === '*') {\n return Mockstate.mockStoreState;\n }\n return Mockstate.mockStoreState[stateName];\n },\n /**\n * @name setActions\n * @description Sets the application Actions\n * that will change the Store state\n */\n setActions: (data) => {\n Object.assign(Mockstate._store.actions, data);\n }\n }\n };\n return Mockstate.store;\n}(this)));"]} -------------------------------------------------------------------------------- /dist/mockstate.min.js: -------------------------------------------------------------------------------- 1 | var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a};!function(a,b){"function"==typeof define&&define.amd?define([],b):"object"===("undefined"==typeof exports?"undefined":_typeof(exports))?module.exports={dispatch:b.dispatch,getState:b.getState,setState:b.setState,setActions:b.setActions,subscribe:b.subscribe,middleware:b.middleware,emit:b.emit,unsubscribe:b.unsubscribe}:a.Mockstate=b}(this,function(a){var b=this,c={localState:{recoveryStateWhenOffline:function(){void 0!==b.addEventListener&&(b.addEventListener("load",function(){null!==localStorage.getItem("mockstate:StateToRecovery")&&(c.mockStoreState=JSON.parse(localStorage.getItem("mockstate:StateToRecovery")),localStorage.removeItem("mockstate:StateToRecovery"))}),b.addEventListener("online",function(a){var b=JSON.parse(localStorage.getItem("mockstate:StateToRecovery"));c.mockStoreState=b,localStorage.removeItem("mockstate:StateToRecovery")}),b.addEventListener("offline",function(a){localStorage.setItem("mockstate:StateToRecovery",JSON.stringify(c.mockStoreState))}))}},mockStoreState:{},_store:{state:{},actions:{},components:[],middleware:{}},store:{subscribe:function(a,b){c._store.components.push({component:a,handler:b})},unsubscribe:function(a){var b=c._store.components;b.forEach(el,function(c){el===a&&b.splice(c,1)})},middleware:function(a){c._store.middleware=a},emit:function(){return new Promise(function(a,b){var d={action:null,value:null},e=c._store.components;e.forEach(function(b,c){void 0!==b.component&&"function"==typeof b.handler&&a(b.handler(d))})})},dispatch:function(a){for(var b=arguments.length,d=Array(b>1?b-1:0),e=1;e", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/luisvinicius167/state/issues" 25 | }, 26 | "homepage": "https://github.com/luisvinicius167/state#readme", 27 | "devDependencies": { 28 | "babel-preset-es2015-script": "^1.1.0", 29 | "grunt": "latest", 30 | "grunt-babel": "^6.0.0", 31 | "grunt-contrib-uglify": "^2.0.0", 32 | "grunt-contrib-watch": "^1.0.0", 33 | "time-grunt": "^1.4.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/mockstate.js: -------------------------------------------------------------------------------- 1 | ; 2 | (function (root, factory) { 3 | if (typeof define === "function" && define.amd) { 4 | define([], factory); 5 | } else if (typeof exports === "object") { 6 | module.exports = { 7 | dispatch: factory.dispatch, 8 | getState: factory.getState, 9 | setState: factory.setState, 10 | setActions: factory.setActions, 11 | subscribe: factory.subscribe, 12 | middleware: factory.middleware, 13 | emit: factory.emit, 14 | unsubscribe: factory.unsubscribe 15 | } 16 | } else { 17 | root.Mockstate = factory; 18 | } 19 | }(this, function (global) { 20 | /** 21 | * @name Mockstate 22 | * @description The object that will manage all application state 23 | */ 24 | let Mockstate = { 25 | /** 26 | * Persists the store state on localStorage 27 | * @name localState 28 | */ 29 | localState: { 30 | /** 31 | * @name recoveryStateWhenOffline 32 | * @description When the user will be offline, keep the store state safe. 33 | */ 34 | recoveryStateWhenOffline: () => { 35 | // verify if this === window 36 | if (this.addEventListener !== undefined) { 37 | /** 38 | * When the page reloads, if the recovery state are present 39 | * recovery the store state. 40 | */ 41 | this.addEventListener("load", () => { 42 | // verify if the recored state are present when the page loads 43 | if (localStorage.getItem('mockstate:StateToRecovery') !== null) { 44 | Mockstate.mockStoreState = JSON.parse(localStorage.getItem('mockstate:StateToRecovery')); 45 | // remove the temporary recovery state 46 | localStorage.removeItem('mockstate:StateToRecovery'); 47 | }; 48 | }); 49 | 50 | // if the network connection back whithout the user reload the page, recovery 51 | // the state. 52 | this.addEventListener('online', (e) => { 53 | let recoveredState = JSON.parse(localStorage.getItem('mockstate:StateToRecovery')); 54 | Mockstate.mockStoreState = recoveredState; 55 | 56 | // remove the temporary recovery state 57 | localStorage.removeItem('mockstate:StateToRecovery'); 58 | }); 59 | 60 | this.addEventListener('offline', (e) => { 61 | /** 62 | * when the network connection is offline, store the actual 63 | * state on localStorage to be recovered when the connection 64 | * become without reload the page or when reload in the same route, 65 | * keeping the state and UI component safe. 66 | */ 67 | localStorage.setItem('mockstate:StateToRecovery', JSON.stringify(Mockstate.mockStoreState)); 68 | }); 69 | } 70 | } 71 | }, 72 | /** 73 | * The copy of initial store state, that will be used to work 74 | * in application. Keeping the store state immutable. 75 | */ 76 | mockStoreState: {}, 77 | /** 78 | * @name _store 79 | * @description The private store 80 | */ 81 | _store: { 82 | /** 83 | * @name state 84 | * @description The Store application state 85 | */ 86 | state: {}, 87 | /** 88 | * @name actions 89 | * @description The Functions that will change the Store state 90 | */ 91 | actions: {}, 92 | /** 93 | * @name state 94 | * @description The Components that was subscribed 95 | */ 96 | components: [], 97 | middleware: {} 98 | }, 99 | /** 100 | * @name store 101 | * @description Public Store 102 | */ 103 | store: { 104 | /** 105 | * @name subscribe 106 | * @description Subscribe to call the handler function when the action will be triggered 107 | * @param {Component} component The Component 108 | * @param {Function} handler The function that will be called 109 | **/ 110 | subscribe: (component, handler) => { 111 | Mockstate 112 | ._store 113 | .components 114 | .push({component, handler}); 115 | }, 116 | unsubscribe: (component) => { 117 | let components = Mockstate._store.components; 118 | components.forEach((el, index) => { 119 | if (el.component === component) { 120 | components.splice(index, 1); 121 | } 122 | }); 123 | }, 124 | /** 125 | * @name middleware 126 | * @description The middleware function that will be triggered 127 | * every time when an action called. 128 | * @param {Function} callback A function that will be called 129 | **/ 130 | middleware: (callback) => { 131 | Mockstate._store.middleware = callback; 132 | }, 133 | /** 134 | * @name emit 135 | * @description Tell to store that something happend, 136 | * and the handler function will be called. 137 | * @return void 138 | **/ 139 | emit: () => { 140 | return new Promise((resolve, reject) => { 141 | // emit just update the components 142 | let state = { 143 | action: null, 144 | value: null 145 | }; 146 | let components = Mockstate._store.components; 147 | components.forEach((el, i) => { 148 | if (el.component !== undefined && typeof el.handler === "function") { 149 | resolve(el.handler(state)); 150 | } 151 | }); 152 | }); 153 | }, 154 | /** 155 | * @name dispatch 156 | * @description Dispatch an action to change 157 | * the store state 158 | * @param { string } action The action name 159 | * @param { any } args Arguments sended to the action 160 | */ 161 | dispatch: (action, ...args) => { 162 | let state, 163 | components = Mockstate._store.components; 164 | 165 | let updateStoreData = () => { 166 | let updateStoreState = 167 | // actions don't need to return a promise 168 | Promise 169 | .resolve(Mockstate._store.actions[action].apply(null, [].concat(Mockstate.mockStoreState, args))) 170 | .then(value => { 171 | let middleware = Mockstate._store.middleware; 172 | 173 | // state that will be returned 174 | let state = { 175 | action, 176 | value 177 | } 178 | 179 | /** 180 | * has middleware? 181 | **/ 182 | if (typeof middleware === "function") { 183 | middleware.call(null, state, Mockstate.mockStoreState); 184 | } 185 | 186 | return state; 187 | 188 | }) 189 | .then(state => { 190 | components.forEach((el, i) => { 191 | if (el.component !== undefined && typeof el.handler === "function") { 192 | el.handler(state) 193 | } 194 | }); 195 | return state; 196 | }); 197 | 198 | return updateStoreState; 199 | }; 200 | return updateStoreData() 201 | }, 202 | /** 203 | * @name setState 204 | * @description Sets the application data state 205 | * @param {object} data Simple Object that contain the State 206 | */ 207 | setState: (data) => { 208 | // setting the immutable initial state 209 | Object.assign(Mockstate._store.state, data); 210 | Object.assign(Mockstate.mockStoreState, data); 211 | Mockstate 212 | .localState 213 | .recoveryStateWhenOffline(); 214 | }, 215 | /** 216 | * @name get 217 | * @param {string} stateName The Store state name 218 | */ 219 | getState: (stateName) => { 220 | if (stateName === '*') { 221 | return Mockstate.mockStoreState; 222 | } 223 | return Mockstate.mockStoreState[stateName]; 224 | }, 225 | /** 226 | * @name setActions 227 | * @description Sets the application Actions 228 | * that will change the Store state 229 | */ 230 | setActions: (data) => { 231 | Object.assign(Mockstate._store.actions, data); 232 | } 233 | } 234 | }; 235 | return Mockstate.store; 236 | }(this))); 237 | -------------------------------------------------------------------------------- /tests/actions.js: -------------------------------------------------------------------------------- 1 | Mockstate.setActions({ 2 | increment: function (state) { 3 | return state.count+=1; 4 | } 5 | }) -------------------------------------------------------------------------------- /tests/emit.js: -------------------------------------------------------------------------------- 1 | Mockstate.subscribe(this, function(){ 2 | console.log('Updated.'); 3 | }) 4 | 5 | setTimeout(function(){ 6 | Mockstate.emit().then(function(){ 7 | console.log('After emit called.') 8 | }); 9 | }, 3000) -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mocha Tests 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /tests/setState.js: -------------------------------------------------------------------------------- 1 | expect = chai.expect; 2 | 3 | describe('StoreState', function () { 4 | 5 | describe('#getState(count)', function () { 6 | it.only('should be 1', function () { 7 | expect(Mockstate.getState('count')).to.equal(1); 8 | }); 9 | }); 10 | 11 | describe('#IncrementCount', function () { 12 | it.only('The state count should be 2', function () { 13 | Mockstate.dispatch('increment').then(function (data) { 14 | expect(data.value).to.equal(2); 15 | }) 16 | }); 17 | }); 18 | 19 | describe('#IncrementCountInParalel', function () { 20 | 21 | it.only('Verify the result of the action', function () { 22 | Mockstate.dispatch('increment') 23 | .then(function (data) { 24 | expect(data.value).to.equal(3); 25 | }) 26 | Mockstate.dispatch('increment') 27 | .then(function (data) { 28 | expect(data.value).to.equal(4); 29 | }) 30 | }); 31 | 32 | it.only('Verify the value of count', function () { 33 | expect(Mockstate.getState('count')).to.equal(4); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /tests/store.js: -------------------------------------------------------------------------------- 1 | Mockstate.setState({ 2 | count: 1 3 | }); --------------------------------------------------------------------------------