├── test ├── mocha.opts ├── babel-mocha.js ├── Store-test.js ├── ActionCreator-test.js └── EventEmitter-test.js ├── src ├── App.js ├── ActionCreator.js ├── Store.js ├── EventEmitter.js └── Component.js ├── index.html ├── README.md ├── LICENSE ├── package.json └── .gitignore /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --require ./test/babel-mocha.js -------------------------------------------------------------------------------- /test/babel-mocha.js: -------------------------------------------------------------------------------- 1 | require("babel/register")({ 2 | plugins: ["babel-plugin-espower"] 3 | }); -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import React from "react" 4 | import Component from './Component'; 5 | React.render( 6 | React.createElement(Component), 7 | document.body 8 | ); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | mini-flux 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/ActionCreator.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | export default class ActionCreator { 4 | constructor(dispatcher) { 5 | this.dispatcher = dispatcher; 6 | } 7 | 8 | // "Emit" event ----> Store 9 | countUp(data) { 10 | this.dispatcher.emit("countUp", data); 11 | } 12 | } -------------------------------------------------------------------------------- /src/Store.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import Emitter from "./EventEmitter" 4 | class Store extends Emitter { 5 | constructor(dispatcher) { 6 | super(); 7 | this.count = 0; 8 | // <--- observe event. 9 | dispatcher.on("countUp", this.onCountUp.bind(this)); 10 | } 11 | 12 | getCount() { 13 | return this.count; 14 | } 15 | 16 | onCountUp(count) { 17 | if (this.count === count) { 18 | return; 19 | } 20 | this.count = count; 21 | // emit "CHANGE" ---> self 22 | this.emit("CHANGE"); 23 | } 24 | } 25 | export default Store; -------------------------------------------------------------------------------- /test/Store-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import assert from "power-assert" 4 | import Store from "../src/Store" 5 | import EventEmitter from "../src/EventEmitter" 6 | describe("Store", function () { 7 | var instance; 8 | var dispatcher; 9 | beforeEach(function () { 10 | dispatcher = new EventEmitter(); 11 | instance = new Store(dispatcher); 12 | }); 13 | describe("onCountUp", function () { 14 | it("should emit `CHANGE` event", function (done) { 15 | var expectedCount = 42; 16 | instance.on("CHANGE", done); 17 | dispatcher.emit("countUp", expectedCount); 18 | }); 19 | }); 20 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mini-flux 2 | 3 | mini flux implementation for DEMO. 4 | 5 | - No dependent library 6 | - Use EventEmitter only.(not use Flux's Dispatch) 7 | - just mean that this implement not handle order of events 8 | 9 | 10 | ## Installation 11 | 12 | npm install 13 | 14 | ## Usage 15 | 16 | npm run build 17 | open index.html 18 | 19 | ## Test 20 | 21 | npm test 22 | 23 | ## Contributing 24 | 25 | 1. Fork it! 26 | 2. Create your feature branch: `git checkout -b my-new-feature` 27 | 3. Commit your changes: `git commit -am 'Add some feature'` 28 | 4. Push to the branch: `git push origin my-new-feature` 29 | 5. Submit a pull request :D 30 | 31 | ## License 32 | 33 | MIT 34 | -------------------------------------------------------------------------------- /test/ActionCreator-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import assert from "power-assert" 4 | import ActionCreator from "../src/ActionCreator" 5 | import EventEmitter from "../src/EventEmitter" 6 | describe("ActionCreator", function () { 7 | var dispatcher; 8 | var action; 9 | beforeEach(function () { 10 | dispatcher = new EventEmitter(); 11 | action = new ActionCreator(dispatcher); 12 | }); 13 | describe("countUp", function () { 14 | it("should emit `countUp` event", function (done) { 15 | var expectedCount = 42; 16 | dispatcher.on("countUp", function (count) { 17 | assert.equal(count, expectedCount); 18 | done(); 19 | }); 20 | action.countUp(expectedCount); 21 | }); 22 | }); 23 | }); -------------------------------------------------------------------------------- /src/EventEmitter.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | Simple EventEmitter 5 | */ 6 | export default class EventEmitter { 7 | constructor() { 8 | this._handlers = {}; 9 | } 10 | 11 | on(type, handler) { 12 | if (typeof this._handlers[type] === 'undefined') { 13 | this._handlers[type] = []; 14 | } 15 | 16 | this._handlers[type].push(handler); 17 | } 18 | 19 | emit(type, data) { 20 | var handlers = this._handlers[type] || []; 21 | for (var i = 0; i < handlers.length; i++) { 22 | var handler = handlers[i]; 23 | handler.call(this, data); 24 | } 25 | } 26 | 27 | off(type, handler) { 28 | var handlers = this._handlers[type] || []; 29 | for (var i = 0; i < handlers.length; i++) { 30 | var ownHandler = handlers[i]; 31 | if (ownHandler === handler) { 32 | handlers.splice(i, 1); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 azu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/Component.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import React from "react" 4 | import ActionCreator from "./ActionCreator" 5 | import Store from "./Store" 6 | import EventEmitter from "./EventEmitter" 7 | 8 | var dispatcher = new EventEmitter(); 9 | var action = new ActionCreator(dispatcher); 10 | var store = new Store(dispatcher); 11 | 12 | export default class Component extends React.Component { 13 | constructor(props) { 14 | super(props); 15 | this.state = {count: store.getCount()}; 16 | // <- Observe store's change 17 | store.on("CHANGE", () => { 18 | this._onChange(); 19 | }); 20 | } 21 | 22 | _onChange() { 23 | this.setState({count: store.getCount()}); 24 | } 25 | 26 | tick() { 27 | action.countUp(this.state.count + 1); 28 | } 29 | 30 | render() { 31 | return ( 32 |
33 | 34 | 35 |

36 | Count: {this.state.count} 37 |

38 |
39 | ); 40 | } 41 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mini-flux", 3 | "repository": { 4 | "type": "git", 5 | "url": "https://github.com/azu/mini-flux.git" 6 | }, 7 | "author": "azu", 8 | "email": "azuciao@gmail.com", 9 | "homepage": "https://github.com/azu/mini-flux", 10 | "license": "MIT", 11 | "bugs": { 12 | "url": "https://github.com/azu/mini-flux/issues" 13 | }, 14 | "version": "1.0.0", 15 | "description": "mini flux implementation for DEMO.", 16 | "main": "index.js", 17 | "directories": { 18 | "test": "test" 19 | }, 20 | "scripts": { 21 | "build": "browserify -d -e src/App.js -t [ babelify --loose es6.classes ] -o build.js", 22 | "watch": "watchify -d -e src/App.js -t [ babelify --loose es6.classes ] -o build.js", 23 | "test": "mocha test/**/*.js" 24 | }, 25 | "devDependencies": { 26 | "babel": "^5.1.11", 27 | "babel-core": "^5.1.11", 28 | "babel-plugin-espower": "^0.2.1", 29 | "babelify": "^6.0.2", 30 | "browserify": "^9.0.8", 31 | "mocha": "^2.2.4", 32 | "power-assert": "^0.11.0", 33 | "watchify": "^3.1.1" 34 | }, 35 | "dependencies": { 36 | "react": "^0.13.1" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/EventEmitter-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import assert from "power-assert" 4 | import EventEmitter from "../src/EventEmitter" 5 | describe("EventEmitter", function () { 6 | var emitter; 7 | beforeEach(function () { 8 | emitter = new EventEmitter(); 9 | }); 10 | describe("#on", function () { 11 | it("should set event handler to the key", function (done) { 12 | var key = "event-key"; 13 | emitter.on(key, function () { 14 | done(); 15 | }); 16 | emitter.emit(key) 17 | }); 18 | }); 19 | describe("#emit", function () { 20 | it("should pass data to the handlers", function (done) { 21 | var key = "event-key"; 22 | var passingData = {"key": "value"}; 23 | emitter.on(key, function (data) { 24 | assert.deepEqual(data, passingData); 25 | done(); 26 | }); 27 | emitter.emit(key, passingData) 28 | }); 29 | }); 30 | describe("#off", function () { 31 | it("should unset event handler ", function (done) { 32 | var key = "event-key"; 33 | var handler = function () { 34 | done(new Error("should not called")) 35 | }; 36 | emitter.on(key, handler); 37 | emitter.off(key, handler); 38 | emitter.emit(key); 39 | emitter.on(key, done); 40 | emitter.emit(key); 41 | }); 42 | }); 43 | }); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/408c616ae0ad8f4b8101d8e876b9b67ac6b14059/Node.gitignore 2 | 3 | # Logs 4 | logs 5 | *.log 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 19 | .grunt 20 | 21 | # node-waf configuration 22 | .lock-wscript 23 | 24 | # Compiled binary addons (http://nodejs.org/api/addons.html) 25 | build/Release 26 | 27 | # Dependency directory 28 | # Commenting this out is preferred by some people, see 29 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 30 | node_modules 31 | 32 | 33 | ### https://raw.github.com/github/gitignore/408c616ae0ad8f4b8101d8e876b9b67ac6b14059/Global/JetBrains.gitignore 34 | 35 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 36 | 37 | *.iml 38 | 39 | ## Directory-based project format: 40 | .idea/ 41 | # if you remove the above rule, at least ignore the following: 42 | 43 | # User-specific stuff: 44 | # .idea/workspace.xml 45 | # .idea/tasks.xml 46 | # .idea/dictionaries 47 | 48 | # Sensitive or high-churn files: 49 | # .idea/dataSources.ids 50 | # .idea/dataSources.xml 51 | # .idea/sqlDataSources.xml 52 | # .idea/dynamic.xml 53 | # .idea/uiDesigner.xml 54 | 55 | # Gradle: 56 | # .idea/gradle.xml 57 | # .idea/libraries 58 | 59 | # Mongo Explorer plugin: 60 | # .idea/mongoSettings.xml 61 | 62 | ## File-based project format: 63 | *.ipr 64 | *.iws 65 | 66 | ## Plugin-specific files: 67 | 68 | # IntelliJ 69 | out/ 70 | 71 | # mpeltonen/sbt-idea plugin 72 | .idea_modules/ 73 | 74 | # JIRA plugin 75 | atlassian-ide-plugin.xml 76 | 77 | # Crashlytics plugin (for Android Studio and IntelliJ) 78 | com_crashlytics_export_strings.xml 79 | crashlytics.properties 80 | crashlytics-build.properties 81 | 82 | 83 | 84 | build.js --------------------------------------------------------------------------------