diff --git a/README.md b/README.md index b2b3908a9559ea..ae5e2029ab9f83 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,11 @@ Flux is more of a pattern than a framework, and does not have any hard dependenc ## Installing Flux -Flux is available as a [npm module](https://www.npmjs.org/package/flux), so you can add it to your package.json file or run `npm install flux`. The dispatcher will be available as Flux.Dispatcher. +Flux is available as a [npm module](https://www.npmjs.org/package/flux), so you can add it to your package.json file or run `npm install flux`. The dispatcher will be available as `Flux.Dispatcher` and can be required like this: + +```javascript +var Dispatcher = require('flux').Dispatcher; +``` ## Building Flux from a Cloned Repo diff --git a/examples/flux-chat/js/dispatcher/ChatAppDispatcher.js b/examples/flux-chat/js/dispatcher/ChatAppDispatcher.js index 23b6cccc4ce962..0beee317c0e7ec 100644 --- a/examples/flux-chat/js/dispatcher/ChatAppDispatcher.js +++ b/examples/flux-chat/js/dispatcher/ChatAppDispatcher.js @@ -11,7 +11,7 @@ */ var ChatConstants = require('../constants/ChatConstants'); -var Dispatcher = require('./Dispatcher'); +var Dispatcher = require('flux').Dispatcher; var copyProperties = require('react/lib/copyProperties'); var PayloadSources = ChatConstants.PayloadSources; diff --git a/examples/flux-chat/js/dispatcher/Dispatcher.js b/examples/flux-chat/js/dispatcher/Dispatcher.js deleted file mode 100644 index c8856d45d02d4f..00000000000000 --- a/examples/flux-chat/js/dispatcher/Dispatcher.js +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2014, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @providesModule Dispatcher - * @typechecks - */ - -var invariant = require('./invariant'); - -var _lastID = 1; -var _prefix = 'ID_'; - -/** - * Dispatcher is used to broadcast payloads to registered callbacks. This is - * different from generic pub-sub systems in two ways: - * - * 1) Callbacks are not subscribed to particular events. Every payload is - * dispatched to every registered callback. - * 2) Callbacks can be deferred in whole or part until other callbacks have - * been executed. - * - * For example, consider this hypothetical flight destination form, which - * selects a default city when a country is selected: - * - * var flightDispatcher = new Dispatcher(); - * - * // Keeps track of which country is selected - * var CountryStore = {country: null}; - * - * // Keeps track of which city is selected - * var CityStore = {city: null}; - * - * // Keeps track of the base flight price of the selected city - * var FlightPriceStore = {price: null} - * - * When a user changes the selected city, we dispatch the payload: - * - * flightDispatcher.dispatch({ - * actionType: 'city-update', - * selectedCity: 'paris' - * }); - * - * This payload is digested by `CityStore`: - * - * flightDispatcher.register(function(payload)) { - * if (payload.actionType === 'city-update') { - * CityStore.city = payload.selectedCity; - * } - * }); - * - * When the user selects a country, we dispatch the payload: - * - * flightDispatcher.dispatch({ - * actionType: 'country-update', - * selectedCountry: 'australia' - * }); - * - * This payload is digested by both stores: - * - * CountryStore.dispatchToken = flightDispatcher.register(function(payload) { - * if (payload.actionType === 'country-update') { - * CountryStore.country = payload.selectedCountry; - * } - * }); - * - * When the callback to update `CountryStore` is registered, we save a reference - * to the returned token. Using this token with `waitFor()`, we can guarantee - * that `CountryStore` is updated before the callback that updates `CityStore` - * needs to query its data. - * - * CityStore.dispatchToken = flightDispatcher.register(function(payload) { - * if (payload.actionType === 'country-update') { - * // `CountryStore.country` may not be updated. - * flightDispatcher.waitFor([CountryStore.dispatchToken]); - * // `CountryStore.country` is now guaranteed to be updated. - * - * // Select the default city for the new country - * CityStore.city = getDefaultCityForCountry(CountryStore.country); - * } - * }); - * - * The usage of `waitFor()` can be chained, for example: - * - * FlightPriceStore.dispatchToken = - * flightDispatcher.register(function(payload)) { - * switch (payload.actionType) { - * case 'country-update': - * flightDispatcher.waitFor([CityStore.dispatchToken]); - * FlightPriceStore.price = - * getFlightPriceStore(CountryStore.country, CityStore.city); - * break; - * - * case 'city-update': - * FlightPriceStore.price = - * FlightPriceStore(CountryStore.country, CityStore.city); - * break; - * } - * }); - * - * The `country-update` payload will be guaranteed to invoke the stores' - * registered callbacks in order: `CountryStore`, `CityStore`, then - * `FlightPriceStore`. - */ - - function Dispatcher() {"use strict"; - this.$Dispatcher_callbacks = {}; - this.$Dispatcher_isPending = {}; - this.$Dispatcher_isHandled = {}; - this.$Dispatcher_isDispatching = false; - this.$Dispatcher_pendingPayload = null; - } - - /** - * Registers a callback to be invoked with every dispatched payload. Returns - * a token that can be used with `waitFor()`. - * - * @param {function} callback - * @return {string} - */ - Dispatcher.prototype.register=function(callback) {"use strict"; - var id = _prefix + _lastID++; - this.$Dispatcher_callbacks[id] = callback; - return id; - }; - - /** - * Removes a callback based on its token. - * - * @param {string} id - */ - Dispatcher.prototype.unregister=function(id) {"use strict"; - invariant( - this.$Dispatcher_callbacks[id], - 'Dispatcher.unregister(...): `%s` does not map to a registered callback.', - id - ); - delete this.$Dispatcher_callbacks[id]; - }; - - /** - * Waits for the callbacks specified to be invoked before continuing execution - * of the current callback. This method should only be used by a callback in - * response to a dispatched payload. - * - * @param {array} ids - */ - Dispatcher.prototype.waitFor=function(ids) {"use strict"; - invariant( - this.$Dispatcher_isDispatching, - 'Dispatcher.waitFor(...): Must be invoked while dispatching.' - ); - for (var ii = 0; ii < ids.length; ii++) { - var id = ids[ii]; - if (this.$Dispatcher_isPending[id]) { - invariant( - this.$Dispatcher_isHandled[id], - 'Dispatcher.waitFor(...): Circular dependency detected while ' + - 'waiting for `%s`.', - id - ); - continue; - } - invariant( - this.$Dispatcher_callbacks[id], - 'Dispatcher.waitFor(...): `%s` does not map to a registered callback.', - id - ); - this.$Dispatcher_invokeCallback(id); - } - }; - - /** - * Dispatches a payload to all registered callbacks. - * - * @param {object} payload - */ - Dispatcher.prototype.dispatch=function(payload) {"use strict"; - invariant( - !this.$Dispatcher_isDispatching, - 'Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.' - ); - this.$Dispatcher_startDispatching(payload); - try { - for (var id in this.$Dispatcher_callbacks) { - if (this.$Dispatcher_isPending[id]) { - continue; - } - this.$Dispatcher_invokeCallback(id); - } - } finally { - this.$Dispatcher_stopDispatching(); - } - }; - - /** - * Is this Dispatcher currently dispatching. - * - * @return {boolean} - */ - Dispatcher.prototype.isDispatching=function() {"use strict"; - return this.$Dispatcher_isDispatching; - }; - - /** - * Call the calback stored with the given id. Also do some internal - * bookkeeping. - * - * @param {string} id - * @internal - */ - Dispatcher.prototype.$Dispatcher_invokeCallback=function(id) {"use strict"; - this.$Dispatcher_isPending[id] = true; - this.$Dispatcher_callbacks[id](this.$Dispatcher_pendingPayload); - this.$Dispatcher_isHandled[id] = true; - }; - - /** - * Set up bookkeeping needed when dispatching. - * - * @param {object} payload - * @internal - */ - Dispatcher.prototype.$Dispatcher_startDispatching=function(payload) {"use strict"; - for (var id in this.$Dispatcher_callbacks) { - this.$Dispatcher_isPending[id] = false; - this.$Dispatcher_isHandled[id] = false; - } - this.$Dispatcher_pendingPayload = payload; - this.$Dispatcher_isDispatching = true; - }; - - /** - * Clear bookkeeping used for dispatching. - * - * @internal - */ - Dispatcher.prototype.$Dispatcher_stopDispatching=function() {"use strict"; - this.$Dispatcher_pendingPayload = null; - this.$Dispatcher_isDispatching = false; - }; - - -module.exports = Dispatcher; diff --git a/examples/flux-chat/js/dispatcher/invariant.js b/examples/flux-chat/js/dispatcher/invariant.js deleted file mode 100644 index 68a3e06ae5e692..00000000000000 --- a/examples/flux-chat/js/dispatcher/invariant.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2014, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @providesModule invariant - */ - -"use strict"; - -/** - * Use invariant() to assert state which your program assumes to be true. - * - * Provide sprintf-style format (only %s is supported) and arguments - * to provide information about what broke and what you were - * expecting. - * - * The invariant message will be stripped in production, but the invariant - * will remain to ensure logic does not differ in production. - */ - -var invariant = function(condition, format, a, b, c, d, e, f) { - if (false) { - if (format === undefined) { - throw new Error('invariant requires an error message argument'); - } - } - - if (!condition) { - var error; - if (format === undefined) { - error = new Error( - 'Minified exception occurred; use the non-minified dev environment ' + - 'for the full error message and additional helpful warnings.' - ); - } else { - var args = [a, b, c, d, e, f]; - var argIndex = 0; - error = new Error( - 'Invariant Violation: ' + - format.replace(/%s/g, function() { return args[argIndex++]; }) - ); - } - - error.framesToPop = 1; // we don't care about invariant's own frame - throw error; - } -}; - -module.exports = invariant; diff --git a/examples/flux-chat/package.json b/examples/flux-chat/package.json index 120f3b5fcfc7e6..3ab75e15992d12 100644 --- a/examples/flux-chat/package.json +++ b/examples/flux-chat/package.json @@ -5,6 +5,7 @@ "repository": "https://github.com/facebook/flux", "main": "js/app.js", "dependencies": { + "flux": "^2.0.0", "react": "~0.11" }, "devDependencies": { diff --git a/examples/flux-todomvc/js/dispatcher/AppDispatcher.js b/examples/flux-todomvc/js/dispatcher/AppDispatcher.js index 6ae92028e19218..95d9b32a8a1aac 100644 --- a/examples/flux-todomvc/js/dispatcher/AppDispatcher.js +++ b/examples/flux-todomvc/js/dispatcher/AppDispatcher.js @@ -11,10 +11,8 @@ * A singleton that operates as the central hub for application updates. */ -var Dispatcher = require('./Dispatcher'); - +var Dispatcher = require('flux').Dispatcher; var copyProperties = require('react/lib/copyProperties'); - var AppDispatcher = copyProperties(new Dispatcher(), { /** diff --git a/examples/flux-todomvc/js/dispatcher/Dispatcher.js b/examples/flux-todomvc/js/dispatcher/Dispatcher.js deleted file mode 100644 index c8856d45d02d4f..00000000000000 --- a/examples/flux-todomvc/js/dispatcher/Dispatcher.js +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2014, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @providesModule Dispatcher - * @typechecks - */ - -var invariant = require('./invariant'); - -var _lastID = 1; -var _prefix = 'ID_'; - -/** - * Dispatcher is used to broadcast payloads to registered callbacks. This is - * different from generic pub-sub systems in two ways: - * - * 1) Callbacks are not subscribed to particular events. Every payload is - * dispatched to every registered callback. - * 2) Callbacks can be deferred in whole or part until other callbacks have - * been executed. - * - * For example, consider this hypothetical flight destination form, which - * selects a default city when a country is selected: - * - * var flightDispatcher = new Dispatcher(); - * - * // Keeps track of which country is selected - * var CountryStore = {country: null}; - * - * // Keeps track of which city is selected - * var CityStore = {city: null}; - * - * // Keeps track of the base flight price of the selected city - * var FlightPriceStore = {price: null} - * - * When a user changes the selected city, we dispatch the payload: - * - * flightDispatcher.dispatch({ - * actionType: 'city-update', - * selectedCity: 'paris' - * }); - * - * This payload is digested by `CityStore`: - * - * flightDispatcher.register(function(payload)) { - * if (payload.actionType === 'city-update') { - * CityStore.city = payload.selectedCity; - * } - * }); - * - * When the user selects a country, we dispatch the payload: - * - * flightDispatcher.dispatch({ - * actionType: 'country-update', - * selectedCountry: 'australia' - * }); - * - * This payload is digested by both stores: - * - * CountryStore.dispatchToken = flightDispatcher.register(function(payload) { - * if (payload.actionType === 'country-update') { - * CountryStore.country = payload.selectedCountry; - * } - * }); - * - * When the callback to update `CountryStore` is registered, we save a reference - * to the returned token. Using this token with `waitFor()`, we can guarantee - * that `CountryStore` is updated before the callback that updates `CityStore` - * needs to query its data. - * - * CityStore.dispatchToken = flightDispatcher.register(function(payload) { - * if (payload.actionType === 'country-update') { - * // `CountryStore.country` may not be updated. - * flightDispatcher.waitFor([CountryStore.dispatchToken]); - * // `CountryStore.country` is now guaranteed to be updated. - * - * // Select the default city for the new country - * CityStore.city = getDefaultCityForCountry(CountryStore.country); - * } - * }); - * - * The usage of `waitFor()` can be chained, for example: - * - * FlightPriceStore.dispatchToken = - * flightDispatcher.register(function(payload)) { - * switch (payload.actionType) { - * case 'country-update': - * flightDispatcher.waitFor([CityStore.dispatchToken]); - * FlightPriceStore.price = - * getFlightPriceStore(CountryStore.country, CityStore.city); - * break; - * - * case 'city-update': - * FlightPriceStore.price = - * FlightPriceStore(CountryStore.country, CityStore.city); - * break; - * } - * }); - * - * The `country-update` payload will be guaranteed to invoke the stores' - * registered callbacks in order: `CountryStore`, `CityStore`, then - * `FlightPriceStore`. - */ - - function Dispatcher() {"use strict"; - this.$Dispatcher_callbacks = {}; - this.$Dispatcher_isPending = {}; - this.$Dispatcher_isHandled = {}; - this.$Dispatcher_isDispatching = false; - this.$Dispatcher_pendingPayload = null; - } - - /** - * Registers a callback to be invoked with every dispatched payload. Returns - * a token that can be used with `waitFor()`. - * - * @param {function} callback - * @return {string} - */ - Dispatcher.prototype.register=function(callback) {"use strict"; - var id = _prefix + _lastID++; - this.$Dispatcher_callbacks[id] = callback; - return id; - }; - - /** - * Removes a callback based on its token. - * - * @param {string} id - */ - Dispatcher.prototype.unregister=function(id) {"use strict"; - invariant( - this.$Dispatcher_callbacks[id], - 'Dispatcher.unregister(...): `%s` does not map to a registered callback.', - id - ); - delete this.$Dispatcher_callbacks[id]; - }; - - /** - * Waits for the callbacks specified to be invoked before continuing execution - * of the current callback. This method should only be used by a callback in - * response to a dispatched payload. - * - * @param {array} ids - */ - Dispatcher.prototype.waitFor=function(ids) {"use strict"; - invariant( - this.$Dispatcher_isDispatching, - 'Dispatcher.waitFor(...): Must be invoked while dispatching.' - ); - for (var ii = 0; ii < ids.length; ii++) { - var id = ids[ii]; - if (this.$Dispatcher_isPending[id]) { - invariant( - this.$Dispatcher_isHandled[id], - 'Dispatcher.waitFor(...): Circular dependency detected while ' + - 'waiting for `%s`.', - id - ); - continue; - } - invariant( - this.$Dispatcher_callbacks[id], - 'Dispatcher.waitFor(...): `%s` does not map to a registered callback.', - id - ); - this.$Dispatcher_invokeCallback(id); - } - }; - - /** - * Dispatches a payload to all registered callbacks. - * - * @param {object} payload - */ - Dispatcher.prototype.dispatch=function(payload) {"use strict"; - invariant( - !this.$Dispatcher_isDispatching, - 'Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.' - ); - this.$Dispatcher_startDispatching(payload); - try { - for (var id in this.$Dispatcher_callbacks) { - if (this.$Dispatcher_isPending[id]) { - continue; - } - this.$Dispatcher_invokeCallback(id); - } - } finally { - this.$Dispatcher_stopDispatching(); - } - }; - - /** - * Is this Dispatcher currently dispatching. - * - * @return {boolean} - */ - Dispatcher.prototype.isDispatching=function() {"use strict"; - return this.$Dispatcher_isDispatching; - }; - - /** - * Call the calback stored with the given id. Also do some internal - * bookkeeping. - * - * @param {string} id - * @internal - */ - Dispatcher.prototype.$Dispatcher_invokeCallback=function(id) {"use strict"; - this.$Dispatcher_isPending[id] = true; - this.$Dispatcher_callbacks[id](this.$Dispatcher_pendingPayload); - this.$Dispatcher_isHandled[id] = true; - }; - - /** - * Set up bookkeeping needed when dispatching. - * - * @param {object} payload - * @internal - */ - Dispatcher.prototype.$Dispatcher_startDispatching=function(payload) {"use strict"; - for (var id in this.$Dispatcher_callbacks) { - this.$Dispatcher_isPending[id] = false; - this.$Dispatcher_isHandled[id] = false; - } - this.$Dispatcher_pendingPayload = payload; - this.$Dispatcher_isDispatching = true; - }; - - /** - * Clear bookkeeping used for dispatching. - * - * @internal - */ - Dispatcher.prototype.$Dispatcher_stopDispatching=function() {"use strict"; - this.$Dispatcher_pendingPayload = null; - this.$Dispatcher_isDispatching = false; - }; - - -module.exports = Dispatcher; diff --git a/examples/flux-todomvc/js/dispatcher/invariant.js b/examples/flux-todomvc/js/dispatcher/invariant.js deleted file mode 100644 index 68a3e06ae5e692..00000000000000 --- a/examples/flux-todomvc/js/dispatcher/invariant.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2014, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @providesModule invariant - */ - -"use strict"; - -/** - * Use invariant() to assert state which your program assumes to be true. - * - * Provide sprintf-style format (only %s is supported) and arguments - * to provide information about what broke and what you were - * expecting. - * - * The invariant message will be stripped in production, but the invariant - * will remain to ensure logic does not differ in production. - */ - -var invariant = function(condition, format, a, b, c, d, e, f) { - if (false) { - if (format === undefined) { - throw new Error('invariant requires an error message argument'); - } - } - - if (!condition) { - var error; - if (format === undefined) { - error = new Error( - 'Minified exception occurred; use the non-minified dev environment ' + - 'for the full error message and additional helpful warnings.' - ); - } else { - var args = [a, b, c, d, e, f]; - var argIndex = 0; - error = new Error( - 'Invariant Violation: ' + - format.replace(/%s/g, function() { return args[argIndex++]; }) - ); - } - - error.framesToPop = 1; // we don't care about invariant's own frame - throw error; - } -}; - -module.exports = invariant; diff --git a/examples/flux-todomvc/package.json b/examples/flux-todomvc/package.json index df6934fdff16d2..71f6d5b3987682 100644 --- a/examples/flux-todomvc/package.json +++ b/examples/flux-todomvc/package.json @@ -5,6 +5,7 @@ "repository": "https://github.com/facebook/flux", "main": "js/app.js", "dependencies": { + "flux": "^2.0.0", "react": "~0.11.0" }, "devDependencies": {