ff-stream-web

git clone git://archive.git.mtrnord.blog/MTRNord/ff-stream-web.git
Log | Files | Refs | README | LICENSE

commit 800b8388c0090e889263d53c8c4f3c3b5383508c
parent 35fdd34c62a034741fbe877dddc0d3badec7b200
Author: Konstantin Tarkus <hello@tarkus.me>
Date:   Thu, 13 Nov 2014 18:47:26 +0300

Move src/AppDispatcher.js to src/core/Dispatcher.js; create Flux Store base class

Diffstat:
MREADME.md | 6+++---
Mgulpfile.js | 4++--
Dsrc/AppDispatcher.js | 47-----------------------------------------------
Msrc/actions/PageActions.js | 4++--
Msrc/actions/RouteActions.js | 4++--
Msrc/app.js | 8++++----
Asrc/core/Dispatcher.js | 47+++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/Store.js | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/layouts/DefaultLayout.js | 13+++++--------
Msrc/stores/PageStore.js | 29++++++-----------------------
10 files changed, 140 insertions(+), 91 deletions(-)

diff --git a/README.md b/README.md @@ -28,15 +28,15 @@ ├── /src/ # The source code of the application │ ├── /actions/ # Action creators that allow to trigger a dispatch to stores │ ├── /assets/ # Static files which are copied to ./build on compile -│ ├── /constants/ # Enumerations used in action creators and stores │ ├── /components/ # React components. E.g. Navbar.jsx, Calendar.jsx +│ ├── /constants/ # Enumerations used in action creators and stores +│ ├── /core/ # Core components (Flux dispatcher, base classes) │ ├── /images/ # Graphics (.png, .jpg, .svg etc.) │ ├── /layouts/ # Shared layouts for top-level components │ ├── /pages/ # Top-level, URL-bound React components │ ├── /stores/ # Stores contain the application state and logic │ ├── /styles/ # CSS style sheets (or LESS, SASS, Stylus) -│ ├── /app.js # The application's bootstrap file, entry point -│ └── /AppDispatcher.js # The central hub that manages all data flow (see Flux) +│ ├── /app.js # The application's main file (entry point) ├── /test/ # Unit, integration and load tests │ ├── /e2e/ # End-to-end tests │ └── /unit/ # Unit tests diff --git a/gulpfile.js b/gulpfile.js @@ -110,11 +110,11 @@ gulp.task('pages', function() { src.pages = ['src/pages/**/*.js', 'src/pages/404.html']; var currentPage = {}; + var Dispatcher = require('./src/core/Dispatcher'); var ActionTypes = require('./src/constants/ActionTypes'); - var AppDispatcher = require('./src/AppDispatcher'); // Capture document.title and other page metadata changes - AppDispatcher.register(function(payload) { + Dispatcher.register(function(payload) { if (payload.action.actionType == ActionTypes.SET_CURRENT_PAGE) { currentPage = payload.action.page; diff --git a/src/AppDispatcher.js b/src/AppDispatcher.js @@ -1,47 +0,0 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ - -'use strict'; - -var {Dispatcher} = require('flux'); -var PayloadSources = require('./constants/PayloadSources'); -var assign = require('object-assign'); - -/** - * A singleton that operates as the central hub for application updates. - * For more information visit https://facebook.github.io/flux/ - */ -var AppDispatcher = assign(new Dispatcher(), { - - /** - * @param {object} action The details of the action, including the action's - * type and additional data coming from the server. - */ - handleServerAction(action) { - var payload = { - source: PayloadSources.SERVER_ACTION, - action: action - }; - this.dispatch(payload); - }, - - /** - * @param {object} action The details of the action, including the action's - * type and additional data coming from the view. - */ - handleViewAction(action) { - var payload = { - source: PayloadSources.VIEW_ACTION, - action: action - }; - this.dispatch(payload); - } - -}); - -module.exports = AppDispatcher; diff --git a/src/actions/PageActions.js b/src/actions/PageActions.js @@ -8,7 +8,7 @@ 'use strict'; -var AppDispatcher = require('../AppDispatcher'); +var Dispatcher = require('../core/Dispatcher'); var ActionTypes = require('../constants/ActionTypes'); var pageDefaults = require('../constants/Settings').defaults.page; var assign = require('object-assign'); @@ -20,7 +20,7 @@ module.exports = { * @param {object} The page object. */ set(page) { - AppDispatcher.handleViewAction({ + Dispatcher.handleViewAction({ actionType: ActionTypes.SET_CURRENT_PAGE, page: assign({}, pageDefaults, page) }); diff --git a/src/actions/RouteActions.js b/src/actions/RouteActions.js @@ -8,7 +8,7 @@ 'use strict'; -var AppDispatcher = require('../AppDispatcher'); +var Dispatcher = require('../core/Dispatcher'); var ActionTypes = require('../constants/ActionTypes'); module.exports = { @@ -18,7 +18,7 @@ module.exports = { * @param {string} route Supply a route value, such as `todos/completed`. */ setRoute(route) { - AppDispatcher.handleViewAction({ + Dispatcher.handleViewAction({ actionType: ActionTypes.SET_CURRENT_ROUTE, route: route }); diff --git a/src/app.js b/src/app.js @@ -11,14 +11,14 @@ var React = require('react'); var ExecutionEnvironment = require('react/lib/ExecutionEnvironment'); var {Router} = require('director'); -var AppDispatcher = require('./AppDispatcher'); +var Dispatcher = require('./core/Dispatcher'); var ActionTypes = require('./constants/ActionTypes'); var router; // Export React so the dev tools can find it (window !== window.top ? window.top : window).React = React; -AppDispatcher.register((payload) => { +Dispatcher.register((payload) => { var action = payload.action; @@ -28,9 +28,9 @@ AppDispatcher.register((payload) => { router.setRoute(action.route); break; - case ActionTypes.SET_PAGE_TITLE: + case ActionTypes.SET_CURRENT_PAGE: if (ExecutionEnvironment.canUseDOM) { - document.title = action.text; + document.title = action.page.title; } break; } diff --git a/src/core/Dispatcher.js b/src/core/Dispatcher.js @@ -0,0 +1,47 @@ +/* + * React.js Starter Kit + * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. + */ + +'use strict'; + +var Flux = require('flux'); +var PayloadSources = require('../constants/PayloadSources'); +var assign = require('object-assign'); + +/** + * A singleton that operates as the central hub for application updates. + * For more information visit https://facebook.github.io/flux/ + */ +var Dispatcher = assign(new Flux.Dispatcher(), { + + /** + * @param {object} action The details of the action, including the action's + * type and additional data coming from the server. + */ + handleServerAction(action) { + var payload = { + source: PayloadSources.SERVER_ACTION, + action: action + }; + this.dispatch(payload); + }, + + /** + * @param {object} action The details of the action, including the action's + * type and additional data coming from the view. + */ + handleViewAction(action) { + var payload = { + source: PayloadSources.VIEW_ACTION, + action: action + }; + this.dispatch(payload); + } + +}); + +module.exports = Dispatcher; diff --git a/src/core/Store.js b/src/core/Store.js @@ -0,0 +1,69 @@ +/* + * React.js Starter Kit + * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. + */ + +'use strict'; + +var EventEmitter = require('events').EventEmitter; +var assign = require('object-assign'); +var invariant = require('react/lib/invariant'); + +var CHANGE_EVENT = 'change'; + +class Store { + + constructor(methods) { + + var self = this; + + invariant(!methods.dispatcherToken,'"dispatcherToken" is a reserved name and cannot be used as a method name.'); + invariant(!methods.mixin,'"mixin" is a reserved name and cannot be used as a method name.'); + + assign(this, EventEmitter.prototype, methods); + + this.dispatcherToken = null; + this.mixin = { + + componentDidMount: function() { + self.addChangeListener(this.onChange); + }, + + componentWillUnmount: function() { + self.removeChangeListener(this.onChange); + } + + }; + } + + /** + * Emits change event. + */ + emitChange() { + this.emit(CHANGE_EVENT); + } + + /** + * Adds a change listener. + * + * @param {function} callback Callback function. + */ + addChangeListener(callback) { + this.on(CHANGE_EVENT, callback); + } + + /** + * Removes a change listener. + * + * @param {function} callback Callback function. + */ + removeChangeListener(callback) { + this.removeListener(CHANGE_EVENT, callback); + } + +} + +module.exports = Store; diff --git a/src/layouts/DefaultLayout.js b/src/layouts/DefaultLayout.js @@ -14,7 +14,7 @@ var Link = require('../components/Link'); var Navbar = require('../components/Navbar'); /** - * Retrieve the current page metadata from the PageStore. + * Retrieves the current page metadata from the PageStore. * @returns {{title: string}} */ function getState() { @@ -25,19 +25,16 @@ function getState() { var DefaultLayout = React.createClass({ + mixins: [PageStore.mixin], + getInitialState() { return getState(); }, componentDidMount() { - PageStore.addEventListener(this._onChange); PageStore.emitChange(); }, - componentWillUnmount() { - PageStore.removeEventListener(this._onChange); - }, - render() { var header = this.props.children.type.breadcrumb ? ( <div className="container"> @@ -72,9 +69,9 @@ var DefaultLayout = React.createClass({ }, /** - * Event handler for 'change' events coming from the PageStore + * Event handler for 'change' events coming from the PageStore. */ - _onChange() { + onChange() { this.setState(getState()); } }); diff --git a/src/stores/PageStore.js b/src/stores/PageStore.js @@ -8,12 +8,9 @@ 'use strict'; -var AppDispatcher = require('../AppDispatcher'); +var Store = require('../core/Store'); +var Dispatcher = require('../core/Dispatcher'); var ActionTypes = require('../constants/ActionTypes'); -var EventEmitter = require('events').EventEmitter; -var assign = require('object-assign'); - -var CHANGE_EVENT = 'change'; /** * @typedef Page @@ -22,36 +19,21 @@ var CHANGE_EVENT = 'change'; * @property {string} description * @property {string} keywords */ - -/** @type {Page} */ var _page; -var PageStore = assign({}, EventEmitter.prototype, { +var PageStore = new Store({ /** - * Get the current page. + * Gets metadata associated with the current page. * @returns {Page} */ get() { return _page || require('../constants/Settings').defaults.page; - }, - - emitChange() { - this.emit(CHANGE_EVENT); - }, - - addEventListener(callback) { - this.on(CHANGE_EVENT, callback); - }, - - removeEventListener(callback) { - this.removeListener(CHANGE_EVENT, callback); } }); - -AppDispatcher.register(function(payload) { +PageStore.dispatcherToken = Dispatcher.register(payload => { var action = payload.action; @@ -61,6 +43,7 @@ AppDispatcher.register(function(payload) { } return true; // No errors. Needed by promise in Dispatcher. + }); module.exports = PageStore;