diff --git a/docs/_posts/2014-05-06-flux.md b/docs/_posts/2014-05-06-flux.md
index a852ab380dc..688c5c45053 100644
--- a/docs/_posts/2014-05-06-flux.md
+++ b/docs/_posts/2014-05-06-flux.md
@@ -14,4 +14,4 @@ In Flux, the Dispatcher is a singleton that directs the flow of data and ensures
When a user interacts with a React view, the view sends an action (usually represented as a JavaScript object with some fields) through the dispatcher, which notifies the various stores that hold the application's data and business logic. When the stores change state, they notify the views that something has updated. This works especially well with React's declarative model, which allows the stores to send updates without specifying how to transition views between states.
-Flux is more of a pattern than a formal framework, so you can start using Flux immediately without a lot of new code. An [example of this architecture](https://github.com/facebook/react/tree/master/examples/todomvc-flux) is available, along with more [detailed documentation](http://facebook.github.io/react/docs/flux-overview.html) and a [tutorial](http://facebook.github.io/react/docs/flux-todo-list.html). Look for more examples to come in the future.
+Flux is more of a pattern than a formal framework, so you can start using Flux immediately without a lot of new code. An [example of this architecture](https://github.com/facebook/flux/tree/master/examples/flux-todomvc) is available, along with more [detailed documentation](http://facebook.github.io/react/docs/flux-overview.html) and a [tutorial](http://facebook.github.io/react/docs/flux-todo-list.html). Look for more examples to come in the future.
diff --git a/docs/docs/flux-overview.md b/docs/docs/flux-overview.md
index e02339401b3..c93feee34e2 100644
--- a/docs/docs/flux-overview.md
+++ b/docs/docs/flux-overview.md
@@ -29,67 +29,67 @@ Views ---> (actions) ----> Dispatcher ---> (registered callback) ---> Stores ---
+-- (Controller-Views "change" event handlers) ---- (Stores emit "change" events) --+
-A unidirectional data flow is central to the Flux pattern, and in fact Flux takes its name from the Latin word for flow. In the above diagram, the dispatcher, stores and views are independent nodes with distinct inputs and outputs. The actions are simply discrete, semantic helper functions that facilitate passing data to the dispatcher.
+A unidirectional data flow is central to the Flux pattern, and in fact Flux takes its name from the Latin word for flow. In the above diagram, the dispatcher, stores and views are independent nodes with distinct inputs and outputs. The actions are simply discrete, semantic helper functions that facilitate passing data to the dispatcher.
All data flows through the dispatcher as a central hub. Actions most often originate from user interactions with the views, and are nothing more than a call into the dispatcher. The dispatcher then invokes the callbacks that the stores have registered with it, effectively dispatching the data payload contained in the actions to all stores. Within their registered callbacks, stores determine which actions they are interested in, and respond accordingly. The stores then emit a "change" event to alert the controller-views that a change to the data layer has occurred. Controller-views listen for these events and retrieve data from the stores in an event handler. The controller-views call their own `render()` method via `setState()` or `forceUpdate()`, updating themselves and all of their children.
-This structure allows us to reason easily about our application in a way that is reminiscent of functional reactive programming, or more specifically data-flow programming or flow-based programming, where data flows through the application in a single direction — there are no two-way bindings. Application state is maintained only in the stores, allowing the different parts of the application to remain highly decoupled. Where dependencies do occur between stores, they are kept in a strict hierarchy, with synchronous updates managed by the dispatcher.
+This structure allows us to reason easily about our application in a way that is reminiscent of functional reactive programming, or more specifically data-flow programming or flow-based programming, where data flows through the application in a single direction — there are no two-way bindings. Application state is maintained only in the stores, allowing the different parts of the application to remain highly decoupled. Where dependencies do occur between stores, they are kept in a strict hierarchy, with synchronous updates managed by the dispatcher.
We found that two-way data bindings led to cascading updates, where changing one object led to another object changing, which could also trigger more updates. As applications grew, these cascading updates made it very difficult to predict what would change as the result of one user interaction. When updates can only change data within a single round, the system as a whole becomes more predictable.
-Let's look at the various parts of the Flux update cycle up close. A good place to start is the dispatcher.
+Let's look at the various parts of the Flux update cycle up close. A good place to start is the dispatcher.
-### A Single Dispatcher
+### A Single Dispatcher
-The dispatcher is the central hub that manages all data flow in a Flux application. It is essentially a registry of callbacks into the stores. Each store registers itself and provides a callback. When the dispatcher responds to an action, all stores in the application are sent the data payload provided by the action via the callbacks in the registry.
+The dispatcher is the central hub that manages all data flow in a Flux application. It is essentially a registry of callbacks into the stores. Each store registers itself and provides a callback. When the dispatcher responds to an action, all stores in the application are sent the data payload provided by the action via the callbacks in the registry.
As an application grows, the dispatcher becomes more vital, as it can manage dependencies between stores by invoking the registered callbacks in a specific order. Stores can declaratively wait for other stores to finish updating, and then update themselves accordingly.
-### Stores
+### Stores
-Stores contain the application state and logic. Their role is somewhat similar to a model in a traditional MVC, but they manage the state of many objects — they are not instances of one object. Nor are they the same as Backbone's collections. More than simply managing a collection of ORM-style objects, stores manage the application state for a particular __domain__ within the application.
+Stores contain the application state and logic. Their role is somewhat similar to a model in a traditional MVC, but they manage the state of many objects — they are not instances of one object. Nor are they the same as Backbone's collections. More than simply managing a collection of ORM-style objects, stores manage the application state for a particular __domain__ within the application.
-For example, Facebook's [Lookback Video Editor](https://facebook.com/lookback/edit) utilized a TimeStore that kept track of the playback time position and the playback state. On the other hand, the same application's ImageStore kept track of a collection of images. The TodoStore in our [TodoMVC example](https://github.com/facebook/react/tree/master/examples/todomvc-flux) is similar in that it manages a collection of to-do items. A store exhibits characteristics of both a collection of models and a singleton model of a logical domain.
+For example, Facebook's [Lookback Video Editor](https://facebook.com/lookback/edit) utilized a TimeStore that kept track of the playback time position and the playback state. On the other hand, the same application's ImageStore kept track of a collection of images. The TodoStore in our [TodoMVC example](https://github.com/facebook/flux/tree/master/examples/flux-todomvc) is similar in that it manages a collection of to-do items. A store exhibits characteristics of both a collection of models and a singleton model of a logical domain.
-As mentioned above, a store registers itself with the dispatcher and provides it with a callback. This callback receives the action's data payload as a parameter. The payload contains a type attribute, identifying the action's type. Within the store's registered callback, a switch statement based on the action's type is used to interpret the payload and to provide the proper hooks into the store's internal methods. This allows an action to result in an update to the state of the store, via the dispatcher. After the stores are updated, they broadcast an event declaring that their state has changed, so the views may query the new state and update themselves.
+As mentioned above, a store registers itself with the dispatcher and provides it with a callback. This callback receives the action's data payload as a parameter. The payload contains a type attribute, identifying the action's type. Within the store's registered callback, a switch statement based on the action's type is used to interpret the payload and to provide the proper hooks into the store's internal methods. This allows an action to result in an update to the state of the store, via the dispatcher. After the stores are updated, they broadcast an event declaring that their state has changed, so the views may query the new state and update themselves.
-### Views and Controller-Views
-
+### Views and Controller-Views
+
React provides the kind of composable views we need for the view layer. Close to the top of the nested view hierarchy, a special kind of view listens for events that are broadcast by the stores that it depends on. One could call this a controller-view, as it provides the glue code to get the data from the stores and to pass this data down the chain of its descendants. We might have one of these controller-views governing any significant section of the page.
-When it receives the event from the store, it first requests the new data it needs via the stores' public getter methods. It then calls its own `setState()` or `forceUpdate()` methods, causing its `render()` method and the `render()` method of all its descendants to run.
+When it receives the event from the store, it first requests the new data it needs via the stores' public getter methods. It then calls its own `setState()` or `forceUpdate()` methods, causing its `render()` method and the `render()` method of all its descendants to run.
-We often pass the entire state of the store down the chain of views in a single object, allowing different descendants to use what they need. In addition to keeping the controller-like behavior at the top of the hierarchy, and thus keeping our descendant views as functionally pure as possible, passing down the entire state of the store in a single object also has the effect of reducing the number of props we need to manage.
+We often pass the entire state of the store down the chain of views in a single object, allowing different descendants to use what they need. In addition to keeping the controller-like behavior at the top of the hierarchy, and thus keeping our descendant views as functionally pure as possible, passing down the entire state of the store in a single object also has the effect of reducing the number of props we need to manage.
Occasionally we may need to add additional controller-views deeper in the hierarchy to keep components simple. This might help us to better encapsulate a section of the hierarchy related to a specific data domain. Be aware, however, that controller-views deeper in the hierarchy can violate the singular flow of data by introducing a new, potentially conflicting entry point for the data flow. In making the decision of whether to add a deep controller-view, balance the gain of simpler components against the complexity of multiple data updates flowing into the hierarchy at different points. These multiple data updates can lead to odd effects, with React's render method getting invoked repeatedly by updates from different controller-views, potentially increasing the difficulty of debugging.
-### Actions
+### Actions
-The dispatcher exposes a method that allows a view to trigger a dispatch to the stores, and to include a payload of data, or an action. The action construction may be wrapped into a semantic helper method which sends the payload to the dispatcher. For example, we may want to change the text of a to-do item in a to-do list application. We would create an action with a function signature like `updateText(todoId, newText)` in our `TodoActions` module. This method may be invoked from within our views' event handlers, so we can call it in response to a user action. This action method also adds the action type to the payload, so that when the payload is interpreted in the store, it can respond appropriately to a payload with a particular action type. In our example, this type might be named something like `TODO_UPDATE_TEXT`.
+The dispatcher exposes a method that allows a view to trigger a dispatch to the stores, and to include a payload of data, or an action. The action construction may be wrapped into a semantic helper method which sends the payload to the dispatcher. For example, we may want to change the text of a to-do item in a to-do list application. We would create an action with a function signature like `updateText(todoId, newText)` in our `TodoActions` module. This method may be invoked from within our views' event handlers, so we can call it in response to a user action. This action method also adds the action type to the payload, so that when the payload is interpreted in the store, it can respond appropriately to a payload with a particular action type. In our example, this type might be named something like `TODO_UPDATE_TEXT`.
Actions may also come from other places, such as the server. This happens, for example, during data initialization. It may also happen when the server returns an error code or when the server has updates to provide to the application. We'll talk more about server actions in a future article. In this post we're only concerned with the basics of the data flow.
-### What About that Dispatcher?
+### What About that Dispatcher?
-As mentioned earlier, the dispatcher is also able to manage dependencies between stores. This functionality is available through the `waitFor()` method within the Dispatcher class. We did not need to use this method within the extremely simple [TodoMVC application](https://github.com/facebook/react/tree/master/examples/todomvc-flux), but we have included it [in the example dispatcher](https://github.com/facebook/react/blob/master/examples/todomvc-flux/js/dispatcher/Dispatcher.js#L110) as an example of what a dispatcher should be able to do in a larger, more complex application.
+As mentioned earlier, the dispatcher is also able to manage dependencies between stores. This functionality is available through the `waitFor()` method within the Dispatcher class. We did not need to use this method within the extremely simple [TodoMVC application](https://github.com/facebook/flux/tree/master/examples/flux-todomvc), but we have included it [in the example dispatcher](https://github.com/facebook/flux/blob/master/examples/flux-todomvc/js/dispatcher/Dispatcher.js#L110) as an example of what a dispatcher should be able to do in a larger, more complex application.
-Within the TodoStore's registered callback we could explicitly wait for any dependencies to first update before moving forward:
+Within the TodoStore's registered callback we could explicitly wait for any dependencies to first update before moving forward:
```javascript
-case 'TODO_CREATE':
- Dispatcher.waitFor([
- PrependedTextStore.dispatcherIndex,
- YetAnotherStore.dispatcherIndex
- ], function() {
- TodoStore.create(PrependedTextStore.getText() + ' ' + action.text);
- TodoStore.emit('change');
- });
- break;
+case 'TODO_CREATE':
+ Dispatcher.waitFor([
+ PrependedTextStore.dispatcherIndex,
+ YetAnotherStore.dispatcherIndex
+ ], function() {
+ TodoStore.create(PrependedTextStore.getText() + ' ' + action.text);
+ TodoStore.emit('change');
+ });
+ break;
```
The arguments for `waitFor()` are an array of dispatcher registry indexes, and a final callback to invoke after the callbacks at the given indexes have completed. Thus the store that is invoking `waitFor()` can depend on the state of another store to inform how it should update its own state.
diff --git a/docs/docs/flux-todo-list.md b/docs/docs/flux-todo-list.md
index 906f70c67ca..6df4e2fd1b6 100644
--- a/docs/docs/flux-todo-list.md
+++ b/docs/docs/flux-todo-list.md
@@ -5,54 +5,54 @@ layout: docs
prev: flux-overview.html
---
-To demonstrate the Flux architecture with some example code, let's take on the classic TodoMVC application. The entire application is available in the React GitHub repo within the [todomvc-flux](https://github.com/facebook/react/tree/master/examples/todomvc-flux) example directory, but let's walk through the development of it a step at a time.
+To demonstrate the Flux architecture with some example code, let's take on the classic TodoMVC application. The entire application is available in the Flux GitHub repo within the [flux-todomvc](https://github.com/facebook/flux/tree/master/examples/flux-todomvc) example directory, but let's walk through the development of it a step at a time.
To begin, we'll need some boilerplate and get up and running with a module system. Node's module system, based on CommonJS, will fit the bill very nicely and we can build off of [react-boilerplate](https://github.com/petehunt/react-boilerplate) to get up and running quickly. Assuming you have npm installed, simply clone the react-boilerplate code from GitHub, and navigate into the resulting directory in Terminal (or whatever CLI application you like). Next run the npm scripts to get up and running: `npm install`, then `npm run build`, and lastly `npm start` to continuously build using Browserify.
-The TodoMVC example has all this built into it as well, but if you're starting with react-boilerplate make sure you edit your package.json file to match the file structure and dependencies described in the TodoMVC example's [package.json](https://github.com/facebook/react/tree/master/examples/todomvc-flux/package.json), or else your code won't match up with the explanations below.
+The TodoMVC example has all this built into it as well, but if you're starting with react-boilerplate make sure you edit your package.json file to match the file structure and dependencies described in the TodoMVC example's [package.json](https://github.com/facebook/flux/tree/master/examples/flux-todomvc/package.json), or else your code won't match up with the explanations below.
Source Code Structure
----------------------
-The resulting index.js file may be used as the entry point into our app, but we'll put most of our code in a 'js' directory. Let's let Browserify do its thing, and now we'll open a new tab in Terminal (or a GUI file browser) to look at the directory. It should look something like this:
+---------------------
+The resulting index.js file may be used as the entry point into our app, but we'll put most of our code in a 'js' directory. Let's let Browserify do its thing, and now we'll open a new tab in Terminal (or a GUI file browser) to look at the directory. It should look something like this:
-```
-myapp
- |
- + ...
+```
+myapp
+ |
+ + ...
+ js
|
+ app.js
- + bundle.js // generated by Browserify whenever we make changes.
- + index.html
- + ...
-```
-
-Next we'll dive into the js directory, and layout our application's primary directory structure:
-
-```
-myapp
- |
- + ...
- + js
- |
- + actions
+ + bundle.js // generated by Browserify whenever we make changes.
+ + index.html
+ + ...
+```
+
+Next we'll dive into the js directory, and layout our application's primary directory structure:
+
+```
+myapp
+ |
+ + ...
+ + js
+ |
+ + actions
+ components // all React components, both views and controller-views
+ constants
- + dispatcher
- + stores
+ + dispatcher
+ + stores
+ app.js
+ bundle.js
+ index.html
+ ...
-```
+```
-Creating a Dispatcher
----------------------
+Creating a Dispatcher
+---------------------
-Now we are ready to create a dispatcher. Here is an naive example of a Dispatcher class, written with JavaScript promises, polyfilled with Jake Archibald's [ES6-Promises](https://github.com/jakearchibald/ES6-Promises) module.
+Now we are ready to create a dispatcher. Here is an naive example of a Dispatcher class, written with JavaScript promises, polyfilled with Jake Archibald's [ES6-Promises](https://github.com/jakearchibald/ES6-Promises) module.
-```javascript
+```javascript
var Promise = require('es6-promise').Promise;
var merge = require('react/lib/merge');
@@ -98,16 +98,16 @@ Dispatcher.prototype = merge(Dispatcher.prototype, {
});
_promises = [];
}
-});
-
-module.exports = Dispatcher;
-```
+});
-The public API of this basic Dispatcher consists of only two methods: register() and dispatch(). We'll use register() within our stores to register each store's callback. We'll use dispatch() within our actions to trigger the invocation of the callbacks.
+module.exports = Dispatcher;
+```
-Now we are all set to create a dispatcher that is more specific to our app, which we'll call AppDispatcher.
+The public API of this basic Dispatcher consists of only two methods: register() and dispatch(). We'll use register() within our stores to register each store's callback. We'll use dispatch() within our actions to trigger the invocation of the callbacks.
-```javascript
+Now we are all set to create a dispatcher that is more specific to our app, which we'll call AppDispatcher.
+
+```javascript
var Dispatcher = require('./Dispatcher');
var merge = require('react/lib/merge');
@@ -129,144 +129,144 @@ var AppDispatcher = merge(Dispatcher.prototype, {
});
module.exports = AppDispatcher;
-```
+```
+
+Now we've created an implementation that is a bit more specific to our needs, with a helper function we can use in the actions coming from our views' event handlers. We might expand on this later to provide a separate helper for server updates, but for now this is all we need.
+
+
+Creating Stores
+----------------
-Now we've created an implementation that is a bit more specific to our needs, with a helper function we can use in the actions coming from our views' event handlers. We might expand on this later to provide a separate helper for server updates, but for now this is all we need.
+We can use Node's EventEmitter to get started with a store. We need EventEmitter to broadcast the 'change' event to our controller-views. So let's take a look at what that looks like. I've omitted some of the code for the sake of brevity, but for the full version see [TodoStore.js](https://github.com/Facebook/flux/blob/master/examples/flux-todomvc/js/stores/TodoStore.js) in the TodoMVC example code.
+
+```javascript
+var AppDispatcher = require('../dispatcher/AppDispatcher');
+var EventEmitter = require('events').EventEmitter;
+var TodoConstants = require('../constants/TodoConstants');
+var merge = require('react/lib/merge');
+var CHANGE_EVENT = 'change';
-Creating Stores
-----------------
+var _todos = {}; // collection of todo items
-We can use Node's EventEmitter to get started with a store. We need EventEmitter to broadcast the 'change' event to our controller-views. So let's take a look at what that looks like. I've omitted some of the code for the sake of brevity, but for the full version see [TodoStore.js](https://github.com/Facebook/react/blob/master/examples/todomvc-flux/js/stores/TodoStore.js) in the TodoMVC example code.
+/**
+ * Create a TODO item.
+ * @param {string} text The content of the TODO
+ */
+function create(text) {
+ // Using the current timestamp in place of a real id.
+ var id = Date.now();
+ _todos[id] = {
+ id: id,
+ complete: false,
+ text: text
+ };
+}
-```javascript
-var AppDispatcher = require('../dispatcher/AppDispatcher');
-var EventEmitter = require('events').EventEmitter;
-var TodoConstants = require('../constants/TodoConstants');
-var merge = require('react/lib/merge');
-
-var CHANGE_EVENT = 'change';
-
-var _todos = {}; // collection of todo items
-
/**
- * Create a TODO item.
- * @param {string} text The content of the TODO
- */
-function create(text) {
- // Using the current timestamp in place of a real id.
- var id = Date.now();
- _todos[id] = {
- id: id,
- complete: false,
- text: text
- };
-}
-
-/**
- * Delete a TODO item.
- * @param {string} id
- */
-function destroy(id) {
- delete _todos[id];
-}
-
-var TodoStore = merge(EventEmitter.prototype, {
-
- /**
- * Get the entire collection of TODOs.
- * @return {object}
- */
- getAll: function() {
- return _todos;
- },
-
- emitChange: function() {
- this.emit(CHANGE_EVENT);
- },
-
- /**
- * @param {function} callback
- */
- addChangeListener: function(callback) {
- this.on(CHANGE_EVENT, callback);
- },
-
- /**
- * @param {function} callback
- */
- removeChangeListener: function(callback) {
- this.removeListener(CHANGE_EVENT, callback);
- }
-
- dispatcherIndex: AppDispatcher.register(function(payload) {
- var action = payload.action;
- var text;
-
- switch(action.actionType) {
- case TodoConstants.TODO_CREATE:
- text = action.text.trim();
- if (text !== '') {
- create(text);
- TodoStore.emitChange();
- }
- break;
-
- case TodoConstants.TODO_DESTROY:
- destroy(action.id);
- TodoStore.emitChange();
- break;
-
- // add more cases for other actionTypes, like TODO_UPDATE, etc.
+ * Delete a TODO item.
+ * @param {string} id
+ */
+function destroy(id) {
+ delete _todos[id];
+}
+
+var TodoStore = merge(EventEmitter.prototype, {
+
+ /**
+ * Get the entire collection of TODOs.
+ * @return {object}
+ */
+ getAll: function() {
+ return _todos;
+ },
+
+ emitChange: function() {
+ this.emit(CHANGE_EVENT);
+ },
+
+ /**
+ * @param {function} callback
+ */
+ addChangeListener: function(callback) {
+ this.on(CHANGE_EVENT, callback);
+ },
+
+ /**
+ * @param {function} callback
+ */
+ removeChangeListener: function(callback) {
+ this.removeListener(CHANGE_EVENT, callback);
+ }
+
+ dispatcherIndex: AppDispatcher.register(function(payload) {
+ var action = payload.action;
+ var text;
+
+ switch(action.actionType) {
+ case TodoConstants.TODO_CREATE:
+ text = action.text.trim();
+ if (text !== '') {
+ create(text);
+ TodoStore.emitChange();
+ }
+ break;
+
+ case TodoConstants.TODO_DESTROY:
+ destroy(action.id);
+ TodoStore.emitChange();
+ break;
+
+ // add more cases for other actionTypes, like TODO_UPDATE, etc.
}
-
- return true; // No errors. Needed by promise in Dispatcher.
- })
-
-});
-
-module.exports = TodoStore;
-```
-
-There are a few important things to note in the above code. To start, we are maintaining a private data structure called _todos. This object contains all the individual to-do items. Because this variable lives outside the class, but within the closure of the module, it remains private — it cannot be directly changed from the outside. This helps us preserve a distinct input/output interface for the flow of data by making it impossible to update the store without using an action.
-
-Another important part is the registration of the store's callback with the dispatcher. We pass in our payload handling callback to the dispatcher and preserve the index that this store has in the dispatcher's registry. The callback function currently only handles two actionTypes, but later we can add as many as we need.
-
-
-Listening to Changes with a Controller-View
--------------------------------------------
-
-We need a React component near the top of our component hierarchy to listen for changes in the store. In a larger app, we would have more of these listening components, perhaps one for every section of the page. In Facebook's Ads Creation Tool, we have many of these controller-like views, each governing a specific section of the UI. In the Lookback Video Editor, we only had two: one for the animated preview and one for the image selection interface. Here's one for our TodoMVC example. Again, this is slightly abbreviated, but for the full code you can take a look at the TodoMVC example's [TodoApp.react.js](https://github.com/facebook/react/blob/master/examples/todomvc-flux/js/components/TodoApp.react.js)
-
+
+ return true; // No errors. Needed by promise in Dispatcher.
+ })
+
+});
+
+module.exports = TodoStore;
+```
+
+There are a few important things to note in the above code. To start, we are maintaining a private data structure called _todos. This object contains all the individual to-do items. Because this variable lives outside the class, but within the closure of the module, it remains private — it cannot be directly changed from the outside. This helps us preserve a distinct input/output interface for the flow of data by making it impossible to update the store without using an action.
+
+Another important part is the registration of the store's callback with the dispatcher. We pass in our payload handling callback to the dispatcher and preserve the index that this store has in the dispatcher's registry. The callback function currently only handles two actionTypes, but later we can add as many as we need.
+
+
+Listening to Changes with a Controller-View
+-------------------------------------------
+
+We need a React component near the top of our component hierarchy to listen for changes in the store. In a larger app, we would have more of these listening components, perhaps one for every section of the page. In Facebook's Ads Creation Tool, we have many of these controller-like views, each governing a specific section of the UI. In the Lookback Video Editor, we only had two: one for the animated preview and one for the image selection interface. Here's one for our TodoMVC example. Again, this is slightly abbreviated, but for the full code you can take a look at the TodoMVC example's [TodoApp.react.js](https://github.com/facebook/flux/blob/master/examples/flux-todomvc/js/components/TodoApp.react.js)
+
```javascript
-/** @jsx React.DOM */
-
-var Footer = require('./Footer.react');
-var Header = require('./Header.react');
-var MainSection = require('./MainSection.react');
-var React = require('react');
-var TodoStore = require('../stores/TodoStore');
-
-function getTodoState() {
- return {
- allTodos: TodoStore.getAll()
- };
-}
-
-var TodoApp = React.createClass({
-
- getInitialState: function() {
- return getTodoState();
- },
-
- componentDidMount: function() {
- TodoStore.addChangeListener(this._onChange);
- },
-
- componentWillUnmount: function() {
- TodoStore.removeChangeListener(this._onChange);
- },
-
+/** @jsx React.DOM */
+
+var Footer = require('./Footer.react');
+var Header = require('./Header.react');
+var MainSection = require('./MainSection.react');
+var React = require('react');
+var TodoStore = require('../stores/TodoStore');
+
+function getTodoState() {
+ return {
+ allTodos: TodoStore.getAll()
+ };
+}
+
+var TodoApp = React.createClass({
+
+ getInitialState: function() {
+ return getTodoState();
+ },
+
+ componentDidMount: function() {
+ TodoStore.addChangeListener(this._onChange);
+ },
+
+ componentWillUnmount: function() {
+ TodoStore.removeChangeListener(this._onChange);
+ },
+
/**
* @return {object}
*/
@@ -281,189 +281,189 @@ var TodoApp = React.createClass({
);
- },
-
- _onChange: function() {
- this.setState(getTodoState());
- }
-
-});
-
-module.exports = TodoApp;
-```
+ },
-Now we're in our familiar React territory, utilizing React's lifecycle methods. We set up the initial state of this controller-view in getInitialState(), register an event listener in componentDidMount(), and then clean up after ourselves within componentWillUnmount(). We render a containing div and pass down the collection of states we got from the TodoStore.
+ _onChange: function() {
+ this.setState(getTodoState());
+ }
+
+});
-The Header component contains the primary text input for the application, but it does not need to know the state of the store. The MainSection and Footer do need this data, so we pass it down to them.
+module.exports = TodoApp;
+```
-More Views
-----------
-At a high level, the React component hierarchy of the app looks like this:
+Now we're in our familiar React territory, utilizing React's lifecycle methods. We set up the initial state of this controller-view in getInitialState(), register an event listener in componentDidMount(), and then clean up after ourselves within componentWillUnmount(). We render a containing div and pass down the collection of states we got from the TodoStore.
+
+The Header component contains the primary text input for the application, but it does not need to know the state of the store. The MainSection and Footer do need this data, so we pass it down to them.
+
+More Views
+----------
+At a high level, the React component hierarchy of the app looks like this:
```javascript
-
-
-
-
-
-
-
-
-
-
-
-```
-If a TodoItem is in edit mode, it will also render a TodoTextInput as a child. Let's take a look at how some of these components display the data they receive as props, and how they communicate through actions with the dispatcher.
-The MainSection needs to iterate over the collection of to-do items it received from TodoApp to create the list of TodoItems. In the component's render() method, we can do that iteration like so:
+
+
+
+
+
+
+
+
+
+
+
+```
+If a TodoItem is in edit mode, it will also render a TodoTextInput as a child. Let's take a look at how some of these components display the data they receive as props, and how they communicate through actions with the dispatcher.
+The MainSection needs to iterate over the collection of to-do items it received from TodoApp to create the list of TodoItems. In the component's render() method, we can do that iteration like so:
```javascript
-var allTodos = this.props.allTodos;
-
-for (var key in allTodos) {
- todos.push();
-}
-
-return (
-
-
-);
-```
-Now each TodoItem can display its own text, and perform actions utilizing its own ID. Explaining all the different actions that a TodoItem can invoke in the TodoMVC example goes beyond the scope of this article, but let's just take a look at the action that deletes one of the to-do items. Here is an abbreviated version of the TodoItem:
+);
+```
+Now each TodoItem can display its own text, and perform actions utilizing its own ID. Explaining all the different actions that a TodoItem can invoke in the TodoMVC example goes beyond the scope of this article, but let's just take a look at the action that deletes one of the to-do items. Here is an abbreviated version of the TodoItem:
```javascript
-/** @jsx React.DOM */
-
-var React = require('react');
-var TodoActions = require('../actions/TodoActions');
-var TodoTextInput = require('./TodoTextInput.react');
-
-var TodoItem = React.createClass({
-
- propTypes: {
- todo: React.PropTypes.object.isRequired
- },
-
- render: function() {
- var todo = this.props.todo;
-
- return (
-
-
-
-
- );
- },
-
- _onDestroyClick: function() {
- TodoActions.destroy(this.props.todo.id);
- }
-
-});
-
-module.exports = TodoItem;
-```
-
-With a destroy action available in our library of TodoActions, and a store ready to handle it, connecting the user's interaction with application state changes could not be simpler. We just wrap our onClick handler around the destroy action, provide it with the id, and we're done. Now the user can click the destroy button and kick off the Flux cycle to update the rest of the application.
-
-Text input, on the other hand, is just a bit more complicated because we need to hang on to the state of the text input within the React component itself. Let's take a look at how TodoTextInput works.
-
-As you'll see below, with every change to the input, React expects us to update the state of the component. So when we are finally ready to save the text inside the input, we will put the value held in the component's state in the action's payload. This is UI state, rather than application state, and keeping that distinction in mind is a good guide for where state should live. All application state should live in the store, while components occasionally hold on to UI state. Ideally, React components preserve as little state as possible.
-
-Because TodoTextInput is being used in multiple places within our application, with different behaviors, we'll need to pass the onSave method in as a prop from the component's parent. This allows onSave to invoke different actions depending on where it is used.
+/** @jsx React.DOM */
+
+var React = require('react');
+var TodoActions = require('../actions/TodoActions');
+var TodoTextInput = require('./TodoTextInput.react');
+
+var TodoItem = React.createClass({
+
+ propTypes: {
+ todo: React.PropTypes.object.isRequired
+ },
+
+ render: function() {
+ var todo = this.props.todo;
+
+ return (
+
+
+
+
+ );
+ },
+
+ _onDestroyClick: function() {
+ TodoActions.destroy(this.props.todo.id);
+ }
+
+});
+
+module.exports = TodoItem;
+```
+
+With a destroy action available in our library of TodoActions, and a store ready to handle it, connecting the user's interaction with application state changes could not be simpler. We just wrap our onClick handler around the destroy action, provide it with the id, and we're done. Now the user can click the destroy button and kick off the Flux cycle to update the rest of the application.
+
+Text input, on the other hand, is just a bit more complicated because we need to hang on to the state of the text input within the React component itself. Let's take a look at how TodoTextInput works.
+
+As you'll see below, with every change to the input, React expects us to update the state of the component. So when we are finally ready to save the text inside the input, we will put the value held in the component's state in the action's payload. This is UI state, rather than application state, and keeping that distinction in mind is a good guide for where state should live. All application state should live in the store, while components occasionally hold on to UI state. Ideally, React components preserve as little state as possible.
+
+Because TodoTextInput is being used in multiple places within our application, with different behaviors, we'll need to pass the onSave method in as a prop from the component's parent. This allows onSave to invoke different actions depending on where it is used.
```javascript
-/** @jsx React.DOM */
-
-var React = require('react');
-var ReactPropTypes = React.PropTypes;
-
-var ENTER_KEY_CODE = 13;
-
-var TodoTextInput = React.createClass({
-
- propTypes: {
- className: ReactPropTypes.string,
- id: ReactPropTypes.string,
- placeholder: ReactPropTypes.string,
- onSave: ReactPropTypes.func.isRequired,
- value: ReactPropTypes.string
- },
-
- getInitialState: function() {
- return {
- value: this.props.value || ''
- };
+/** @jsx React.DOM */
+
+var React = require('react');
+var ReactPropTypes = React.PropTypes;
+
+var ENTER_KEY_CODE = 13;
+
+var TodoTextInput = React.createClass({
+
+ propTypes: {
+ className: ReactPropTypes.string,
+ id: ReactPropTypes.string,
+ placeholder: ReactPropTypes.string,
+ onSave: ReactPropTypes.func.isRequired,
+ value: ReactPropTypes.string
+ },
+
+ getInitialState: function() {
+ return {
+ value: this.props.value || ''
+ };
},
-
- /**
- * @return {object}
- */
- render: function() /*object*/ {
- return (
-
- );
- },
-
- /**
- * Invokes the callback passed in as onSave, allowing this component to be
- * used in different ways.
- */
- _save: function() {
- this.props.onSave(this.state.value);
- this.setState({
- value: ''
- });
- },
-
- /**
- * @param {object} event
- */
- _onChange: function(/*object*/ event) {
- this.setState({
- value: event.target.value
- });
- },
-
- /**
- * @param {object} event
- */
-
- _onKeyDown: function(event) {
- if (event.keyCode === ENTER_KEY_CODE) {
- this._save();
- }
- }
-
-});
-
-module.exports = TodoTextInput;
-```
-
-The Header passes in the onSave method as a prop to allow the TodoTextInput to create new
-to-do items:
+
+ /**
+ * @return {object}
+ */
+ render: function() /*object*/ {
+ return (
+
+ );
+ },
+
+ /**
+ * Invokes the callback passed in as onSave, allowing this component to be
+ * used in different ways.
+ */
+ _save: function() {
+ this.props.onSave(this.state.value);
+ this.setState({
+ value: ''
+ });
+ },
+
+ /**
+ * @param {object} event
+ */
+ _onChange: function(/*object*/ event) {
+ this.setState({
+ value: event.target.value
+ });
+ },
+
+ /**
+ * @param {object} event
+ */
+
+ _onKeyDown: function(event) {
+ if (event.keyCode === ENTER_KEY_CODE) {
+ this._save();
+ }
+ }
+
+});
+
+module.exports = TodoTextInput;
+```
+
+The Header passes in the onSave method as a prop to allow the TodoTextInput to create new
+to-do items:
```javascript
-/** @jsx React.DOM */
-
-var React = require('react');
-var TodoActions = require('../actions/TodoActions');
-var TodoTextInput = require('./TodoTextInput.react');
-
-var Header = React.createClass({
-
+/** @jsx React.DOM */
+
+var React = require('react');
+var TodoActions = require('../actions/TodoActions');
+var TodoTextInput = require('./TodoTextInput.react');
+
+var Header = React.createClass({
+
/**
* @return {object}
*/
@@ -478,8 +478,8 @@ var Header = React.createClass({
/>
);
- },
-
+ },
+
/**
* Event handler called within TodoTextInput.
* Defining this here allows TodoTextInput to be used in multiple places
@@ -488,26 +488,26 @@ var Header = React.createClass({
*/
_onSave: function(text) {
TodoActions.create(text);
- }
-
-});
-
-module.exports = Header;
-```
+ }
-In a different context, such as in editing mode for an existing to-do item, we might pass an onSave callback that invokes `TodoActions.update(text)` instead.
+});
+module.exports = Header;
+```
-Creating Semantic Actions
--------------------------
+In a different context, such as in editing mode for an existing to-do item, we might pass an onSave callback that invokes `TodoActions.update(text)` instead.
-Here is the basic code for the two actions we used above in our views:
-```javascript
-/**
- * TodoActions
- */
-
+Creating Semantic Actions
+-------------------------
+
+Here is the basic code for the two actions we used above in our views:
+
+```javascript
+/**
+ * TodoActions
+ */
+
var AppDispatcher = require('../dispatcher/AppDispatcher');
var TodoConstants = require('../constants/TodoConstants');
@@ -521,8 +521,8 @@ var TodoActions = {
actionType: TodoConstants.TODO_CREATE,
text: text
});
- },
-
+ },
+
/**
* @param {string} id
*/
@@ -531,51 +531,51 @@ var TodoActions = {
actionType: TodoConstants.TODO_DESTROY,
id: id
});
- },
-
-};
-
-module.exports = TodoActions;
-```
-
-As you can see, we really would not need to have the helpers AppDispatcher.handleViewAction() or TodoActions.create(). We could, in theory, call AppDispatcher.dispatch() directly and provide a payload. But as our application grows, having these helpers keeps the code clean and semantic. It's just a lot cleaner to write TodoActions.destroy(id) instead of writing a whole lot of things that our TodoItem shouldn't have to know about.
-
-The payload produced by the TodoActions.create() will look like:
-
-```javascript
-{
- source: 'VIEW_ACTION',
- action: {
- type: 'TODO_CREATE',
- text: 'Write blog post about Flux'
- }
-}
-```
-
-This payload is provided to the TodoStore through its registered callback. The TodoStore then broadcasts the 'change' event, and the MainSection responds by fetching the new collection of to-do items from the TodoStore and changing its state. This change in state causes the TodoApp component to call its own render() method, and the render() method of all of its descendents.
-
-Start Me Up
+ },
+
+};
+
+module.exports = TodoActions;
+```
+
+As you can see, we really would not need to have the helpers AppDispatcher.handleViewAction() or TodoActions.create(). We could, in theory, call AppDispatcher.dispatch() directly and provide a payload. But as our application grows, having these helpers keeps the code clean and semantic. It's just a lot cleaner to write TodoActions.destroy(id) instead of writing a whole lot of things that our TodoItem shouldn't have to know about.
+
+The payload produced by the TodoActions.create() will look like:
+
+```javascript
+{
+ source: 'VIEW_ACTION',
+ action: {
+ type: 'TODO_CREATE',
+ text: 'Write blog post about Flux'
+ }
+}
+```
+
+This payload is provided to the TodoStore through its registered callback. The TodoStore then broadcasts the 'change' event, and the MainSection responds by fetching the new collection of to-do items from the TodoStore and changing its state. This change in state causes the TodoApp component to call its own render() method, and the render() method of all of its descendents.
+
+Start Me Up
-----------
-The bootstrap file of our application is app.js. It simply takes the TodoApp component and renders it in the root element of the application.
-
+The bootstrap file of our application is app.js. It simply takes the TodoApp component and renders it in the root element of the application.
+
```javascript
-/** @jsx React.DOM */
-
-var React = require('react');
-
-var TodoApp = require('./components/TodoApp.react');
-
-React.renderComponent(
- ,
- document.getElementById('todoapp')
-);
-```
-
-Adding Dependency Management to the Dispatcher
+/** @jsx React.DOM */
+
+var React = require('react');
+
+var TodoApp = require('./components/TodoApp.react');
+
+React.renderComponent(
+ ,
+ document.getElementById('todoapp')
+);
+```
+
+Adding Dependency Management to the Dispatcher
----------------------------------------------
-As I said previously, our Dispatcher implementation is a bit naive. It's pretty good, but it will not suffice for most applications. We need a way to be able to manage dependencies between Stores. Let's add that functionality with a waitFor() method within the main body of the Dispatcher class.
+As I said previously, our Dispatcher implementation is a bit naive. It's pretty good, but it will not suffice for most applications. We need a way to be able to manage dependencies between Stores. Let's add that functionality with a waitFor() method within the main body of the Dispatcher class.
We'll need another public method, waitFor(). Note that it returns a Promise that can in turn be returned from the Store callback.
@@ -590,12 +590,12 @@ We'll need another public method, waitFor(). Note that it returns a Promise that
});
return Promise.all(selectedPromises).then(callback);
}
-```
+```
Now within the TodoStore callback we can explicitly wait for any dependencies to first update before moving forward. However, if Store A waits for Store B, and B waits for A, then a circular dependency will occur. A more robust dispatcher is required to flag this scenario with warnings in the console.
-The Future of Flux
-------------------
+The Future of Flux
+------------------
A lot of people ask if Facebook will release Flux as an open source framework. Really, Flux is just an architecture, not a framework. But perhaps a Flux boilerplate project might make sense, if there is enough interest. Please let us know if you'd like to see us do this.
diff --git a/examples/todomvc-flux/.gitignore b/examples/todomvc-flux/.gitignore
deleted file mode 100644
index 8ffdbe0ef62..00000000000
--- a/examples/todomvc-flux/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/js/bundle.js
-/js/bundle.min.js
diff --git a/examples/todomvc-flux/README.md b/examples/todomvc-flux/README.md
deleted file mode 100644
index 07bf26bfd27..00000000000
--- a/examples/todomvc-flux/README.md
+++ /dev/null
@@ -1,177 +0,0 @@
-# Flux TodoMVC Example
-
-> An application architecture for React utilizing a unidirectional data flow.
-
-
-## Learning Flux
-
-The [React website](http://facebook.github.io/react) is a great resource for getting started.
-
-Read the blog post announcing Flux: ["An Application Architecture for React"](http://facebook.github.io/react/blog/2014/05/06/flux.html), then read more about the [Flux architecture](http://facebook.github.io/react/docs/flux-overview.html) and a [TodoMVC tutorial](http://facebook.github.io/react/docs/flux-todo-list.html) explaining the structure of the files in this folder.
-
-
-## Overview
-
-Flux applications have three major parts: the ___dispatcher___, the ___stores___, and the ___views___ (React components). These should not be confused with Model-View-Controller. Controllers do exist in a Flux application, but they are ___controller-views___ -- views often found at the top of the hierarchy that retrieve data from the stores and pass this data down to their children. Additionally, ___actions___ — dispatcher helper methods — are often used to support a semantic dispatcher API. It can be useful to think of them as a fourth part of the Flux update cycle.
-
-Flux eschews MVC in favor of a unidirectional data flow. When a user interacts with a React ___view___, the view propagates an ___action___ through a central ___dispatcher___, to the various ___stores___ that hold the application's data and business logic, which updates all of the views that are affected. This works especially well with React's declarative programming style, which allows the store to send updates without specifying how to transition views between states.
-
-We originally set out to deal correctly with derived data: for example, we wanted to show an unread count for message threads while another view showed a list of threads, with the unread ones highlighted. This was difficult to handle with MVC — marking a single thread as read would update the thread model, and then also need to update the unread count model. These dependencies and cascading updates often occur in a large MVC application, leading to a tangled weave of data flow and unpredictable results.
-
-Control is inverted with ___stores___: the stores accept updates and reconcile them as appropriate, rather than depending on something external to update its data in a consistent way. Nothing outside the store has any insight into how it manages the data for its domain, helping to keep a clear separation of concerns. This also makes stores more testable than models, especially since stores have no direct setter methods like `setAsRead()`, but instead have only an input point for the payload, which is delivered through the ___dispatcher___ and originates with ___actions___.
-
-
-## Structure and Data Flow
-
-Data in a Flux application flows in a single direction, in a cycle:
-
-
-
-A unidirectional data flow is central to the Flux pattern, and in fact Flux takes its name from the Latin word for flow. In the above diagram, the ___dispatcher___, ___stores___ and ___views___ are independent nodes with distinct inputs and outputs. The ___actions___ are simply discrete, semantic helper functions that facilitate passing data to the ___dispatcher___.
-
-All data flows through the ___dispatcher___ as a central hub. ___Actions___ most often originate from user interactions with the ___views___, and are nothing more than a call into the ___dispatcher___. The ___dispatcher___ then invokes the callbacks that the ___stores___ have registered with it, effectively dispatching the data payload contained in the ___actions___ to all ___stores___. Within their registered callbacks, ___stores___ determine which ___actions___ they are interested in, and respond accordingly. The ___stores___ then emit a "change" event to alert the ___controller-views___ that a change to the data layer has occurred. ___Controller-views___ listen for these events and retrieve data from the ___stores___ in an event handler. The ___controller-views___ call their own `render()` method via `setState()` or `forceUpdate()`, updating themselves and all of their children.
-
-This structure allows us to reason easily about our application in a way that is reminiscent of functional reactive programming, or more specifically data-flow programming or flow-based programming, where data flows through the application in a single direction — there are no two-way bindings. Application state is maintained only in the ___stores___, allowing the different parts of the application to remain highly decoupled. Where dependencies do occur between ___stores___, they are kept in a strict hierarchy, with synchronous updates managed by the ___dispatcher___.
-
-We found that two-way data bindings led to cascading updates, where changing one object led to another object changing, which could also trigger more updates. As applications grew, these cascading updates made it very difficult to predict what would change as the result of one user interaction. When updates can only change data within a single round, the system as a whole becomes more predictable.
-
-Let's look at the various parts of the Flux update cycle up close. A good place to start is the dispatcher.
-
-
-### A Single Dispatcher
-
-The dispatcher is the central hub that manages all data flow in a Flux application. It is essentially a registry of callbacks into the stores. Each store registers itself and provides a callback. When the dispatcher responds to an action, all stores in the application are sent the data payload provided by the action via the callbacks in the registry.
-
-As an application grows, the dispatcher becomes more vital, as it can manage dependencies between stores by invoking the registered callbacks in a specific order. Stores can declaratively wait for other stores to finish updating, and then update themselves accordingly.
-
-
-### Stores
-
-Stores contain the application state and logic. Their role is somewhat similar to a model in a traditional MVC, but they manage the state of many objects — they are not instances of one object. Nor are they the same as Backbone's collections. More than simply managing a collection of ORM-style objects, stores manage the application state for a particular __domain__ within the application.
-
-For example, Facebook's [Lookback Video Editor](https://facebook.com/lookback/edit) utilized a TimeStore that kept track of the playback time position and the playback state. On the other hand, the same application's ImageStore kept track of a collection of images. The TodoStore in our TodoMVC example is similar in that it manages a collection of to-do items. A store exhibits characteristics of both a collection of models and a singleton model of a logical domain.
-
-As mentioned above, a store registers itself with the dispatcher and provides it with a callback. This callback receives the action's data payload as a parameter. The payload contains a type attribute, identifying the action's type. Within the store's registered callback, a switch statement based on the action's type is used to interpret the payload and to provide the proper hooks into the store's internal methods. This allows an action to result in an update to the state of the store, via the dispatcher. After the stores are updated, they broadcast an event declaring that their state has changed, so the views may query the new state and update themselves.
-
-
-### Views and Controller-Views
-
-React provides the kind of composable views we need for the view layer. Close to the top of the nested view hierarchy, a special kind of view listens for events that are broadcast by the stores that it depends on. One could call this a ___controller-view___, as it provides the glue code to get the data from the stores and to pass this data down the chain of its descendants. We might have one of these controller-views governing any significant section of the page.
-
-When it receives the event from the store, it first requests the new data it needs via the stores' public getter methods. It then calls its own `setState()` or `forceUpdate()` methods, causing its `render()` method and the `render()` method of all its descendants to run.
-
-We often pass the entire state of the store down the chain of views in a single object, allowing different descendants to use what they need. In addition to keeping the controller-like behavior at the top of the hierarchy, and thus keeping our descendant views as functionally pure as possible, passing down the entire state of the store in a single object also has the effect of reducing the number of props we need to manage.
-
-Occasionally we may need to add additional controller-views deeper in the hierarchy to keep components simple. This might help us to better encapsulate a section of the hierarchy related to a specific data domain. Be aware, however, that controller-views deeper in the hierarchy can violate the singular flow of data by introducing a new, potentially conflicting entry point for the data flow. In making the decision of whether to add a deep controller-view, balance the gain of simpler components against the complexity of multiple data updates flowing into the hierarchy at different points. These multiple data updates can lead to odd effects, with React's render method getting invoked repeatedly by updates from different controller-views, potentially increasing the difficulty of debugging.
-
-
-### Actions
-
-The dispatcher exposes a method that allows a view to trigger a dispatch to the stores, and to include a payload of data, or an action. The action construction may be wrapped into a semantic helper method which sends the payload to the dispatcher. For example, we may want to change the text of a to-do item in a to-do list application. We would create an action with a function signature like `updateText(todoId, newText)` in our `TodoActions` module. This method may be invoked from within our views' event handlers, so we can call it in response to a user action. This action method also adds the action type to the payload, so that when the payload is interpreted in the store, it can respond appropriately to a payload with a particular action type. In our example, this type might be named something like `TODO_UPDATE_TEXT`.
-
-Actions may also come from other places, such as the server. This happens, for example, during data initialization. It may also happen when the server returns an error code or when the server has updates to provide to the application. We'll talk more about server actions in a future article. In this post we're only concerned with the basics of the data flow.
-
-
-### What About that Dispatcher?
-
-As mentioned earlier, the dispatcher is also able to manage dependencies between stores. This functionality is available through the `waitFor()` method within the Dispatcher class. The TodoMVC application is extremely simple, so we did not need to use this method, but we have included it here as an example of what a dispatcher should be able to do in a larger, more complex application.
-
-Within the TodoStore's registered callback we can explicitly wait for any dependencies to first update before moving forward:
-
-```
-case 'TODO_CREATE':
- Dispatcher.waitFor([
- PrependedTextStore.dispatcherIndex,
- YetAnotherStore.dispatcherIndex
- ], function() {
- TodoStore.create(PrependedTextStore.getText() + ' ' + action.text);
- TodoStore.emit('change');
- });
- break;
-```
-
-The arguments for `waitFor()` are an array of dipatcher registry indexes, and a final callback to invoke after the callbacks at the given indexes have completed. Thus the store that is invoking `waitFor()` can depend on the state of another store to inform how it should update its own state.
-
-A problem arises if we create circular dependencies. If Store A waits for Store B, and B waits for A, then we'll have a very bad situation on our hands. We'll need a more robust dispatcher that flags these circular dependencies with console errors, and this is not easily accomplished with promises. Unfortunately, that's a bit beyond the scope of this documentation. In future blog posts, we hope to cover how to build a more robust dispatcher and how to initialize, update, and save the state of the application with persistent data, like a web service API.
-
-
-## TodoMVC Example Implementation
-
-In this TodoMVC example application, we can see the elements of Flux in our directory structure. Views here are referred to as "components" as they are React components.
-
-
-
-The primary entry point into the application is app.js. This file bootstraps the React rendering inside of index.html. TodoApp.js is our controller-view and it passes all data down into its child React components.
-
-TodoActions.js is a collection of actions that views may call from within their event handlers, in response to user interactions. They are nothing more than helpers that call into the AppDispatcher.
-
-Dispatcher.js is a base class for AppDispatcher.js which extends it with a small amount of application-specific code. This dispatcher is a naive implementation based on promises, but much more robust implementations are possible.
-
-TodoStore.js is our only store. It provides all of the application logic and in-memory storage. Based on EventEmitter from Node.js, it emits "change" events after responding to actions in the callback it registers with the dispatcher.
-
-The bundle.js file is automatically genenerated by the build process, explained below.
-
-
-## Running
-
-You must have [npm](https://www.npmjs.org/) installed on your computer.
-From the root project directory run these commands from the command line:
-
- npm install
-
-This will install all dependencies.
-
-To build the project, first run this command:
-
- npm start
-
-This will perform an initial build and start a watcher process that will update build.js with any changes you wish to make. This watcher is based on [Browserify](http://browserify.org/) and [Watchify](https://github.com/substack/watchify), and it transforms React's JSX syntax into standard JavaScript with [Reactify](https://github.com/andreypopp/reactify).
-
-To run the app, spin up an HTTP server and visit http://localhost/.../todomvc-flux/.
-
-
-## Credit
-
-This TodoMVC application was created by [Bill Fisher](https://www.facebook.com/bill.fisher.771). This README document was written by Bill Fisher and the principal creator of Flux, [Jing Chen](https://www.facebook.com/jing).
-
-
-## License
-
-> Copyright 2013-2014 Facebook, Inc.
->
-> Licensed under the Apache License, Version 2.0 (the "License");
-> you may not use this file except in compliance with the License.
-> You may obtain a copy of the License at
->
-> http://www.apache.org/licenses/LICENSE-2.0
->
-> Unless required by applicable law or agreed to in writing, software
-> distributed under the License is distributed on an "AS IS" BASIS,
-> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-> See the License for the specific language governing permissions and
-> limitations under the License.
diff --git a/examples/todomvc-flux/css/app.css b/examples/todomvc-flux/css/app.css
deleted file mode 100644
index 2baee13e9a3..00000000000
--- a/examples/todomvc-flux/css/app.css
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * base.css overrides
- */
-
-/**
- * We are not changing from display:none, but rather re-rendering instead.
- * Therefore this needs to be displayed normally by default.
- */
-#todo-list li .edit {
- display: inline;
-}
\ No newline at end of file
diff --git a/examples/todomvc-flux/index.html b/examples/todomvc-flux/index.html
deleted file mode 100644
index b38cfb511e2..00000000000
--- a/examples/todomvc-flux/index.html
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
- Flux • TodoMVC
-
-
-
-
-
-
-
-
-
diff --git a/examples/todomvc-flux/js/actions/TodoActions.js b/examples/todomvc-flux/js/actions/TodoActions.js
deleted file mode 100644
index ae86061a5ed..00000000000
--- a/examples/todomvc-flux/js/actions/TodoActions.js
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * TodoActions
- */
-
-var AppDispatcher = require('../dispatcher/AppDispatcher');
-var TodoConstants = require('../constants/TodoConstants');
-
-var TodoActions = {
-
- /**
- * @param {string} text
- */
- create: function(text) {
- AppDispatcher.handleViewAction({
- actionType: TodoConstants.TODO_CREATE,
- text: text
- });
- },
-
- /**
- * @param {string} id The ID of the ToDo item
- * @param {string} text
- */
- updateText: function(id, text) {
- AppDispatcher.handleViewAction({
- actionType: TodoConstants.TODO_UPDATE_TEXT,
- id: id,
- text: text
- });
- },
-
- /**
- * Toggle whether a single ToDo is complete
- * @param {object} todo
- */
- toggleComplete: function(todo) {
- var id = todo.id;
- if (todo.complete) {
- AppDispatcher.handleViewAction({
- actionType: TodoConstants.TODO_UNDO_COMPLETE,
- id: id
- });
- } else {
- AppDispatcher.handleViewAction({
- actionType: TodoConstants.TODO_COMPLETE,
- id: id
- });
- }
- },
-
- /**
- * Mark all ToDos as complete
- */
- toggleCompleteAll: function() {
- AppDispatcher.handleViewAction({
- actionType: TodoConstants.TODO_TOGGLE_COMPLETE_ALL
- });
- },
-
- /**
- * @param {string} id
- */
- destroy: function(id) {
- AppDispatcher.handleViewAction({
- actionType: TodoConstants.TODO_DESTROY,
- id: id
- });
- },
-
- /**
- * Delete all the completed ToDos
- */
- destroyCompleted: function() {
- AppDispatcher.handleViewAction({
- actionType: TodoConstants.TODO_DESTROY_COMPLETED
- });
- }
-
-};
-
-module.exports = TodoActions;
diff --git a/examples/todomvc-flux/js/app.js b/examples/todomvc-flux/js/app.js
deleted file mode 100644
index a2c793a22e5..00000000000
--- a/examples/todomvc-flux/js/app.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @jsx React.DOM
- */
-
-var React = require('react');
-
-var TodoApp = require('./components/TodoApp.react');
-
-React.renderComponent(
- ,
- document.getElementById('todoapp')
-);
\ No newline at end of file
diff --git a/examples/todomvc-flux/js/components/Footer.react.js b/examples/todomvc-flux/js/components/Footer.react.js
deleted file mode 100644
index 3403183faf0..00000000000
--- a/examples/todomvc-flux/js/components/Footer.react.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @jsx React.DOM
- */
-
-var React = require('react');
-var ReactPropTypes = React.PropTypes;
-var TodoActions = require('../actions/TodoActions');
-
-var Footer = React.createClass({
-
- propTypes: {
- allTodos: ReactPropTypes.object.isRequired
- },
-
- /**
- * @return {object}
- */
- render: function() {
- var allTodos = this.props.allTodos;
- var total = Object.keys(allTodos).length;
-
- if (total === 0) {
- return null;
- }
-
- var completed = 0;
- for (var key in allTodos) {
- if (allTodos[key].complete) {
- completed++;
- }
- }
-
- var itemsLeft = total - completed;
- var itemsLeftPhrase = itemsLeft === 1 ? ' item ' : ' items ';
- itemsLeftPhrase += 'left';
-
- // Undefined and thus not rendered if no completed items are left.
- var clearCompletedButton;
- if (completed) {
- clearCompletedButton =
- ;
- }
-
- return (
-
- );
- },
-
- /**
- * Event handler to delete all completed TODOs
- */
- _onClearCompletedClick: function() {
- TodoActions.destroyCompleted();
- }
-
-});
-
-module.exports = Footer;
diff --git a/examples/todomvc-flux/js/components/Header.react.js b/examples/todomvc-flux/js/components/Header.react.js
deleted file mode 100644
index 188bbc4534b..00000000000
--- a/examples/todomvc-flux/js/components/Header.react.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @jsx React.DOM
- */
-
-var React = require('react');
-var TodoActions = require('../actions/TodoActions');
-var TodoTextInput = require('./TodoTextInput.react');
-
-var Header = React.createClass({
-
- /**
- * @return {object}
- */
- render: function() {
- return (
-
-
todos
-
-
- );
- },
-
- /**
- * Event handler called within TodoTextInput.
- * Defining this here allows TodoTextInput to be used in multiple places
- * in different ways.
- * @param {string} text
- */
- _onSave: function(text) {
- if (text.trim()){
- TodoActions.create(text);
- }
-
- }
-
-});
-
-module.exports = Header;
diff --git a/examples/todomvc-flux/js/components/MainSection.react.js b/examples/todomvc-flux/js/components/MainSection.react.js
deleted file mode 100644
index 1fb381cb159..00000000000
--- a/examples/todomvc-flux/js/components/MainSection.react.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @jsx React.DOM
- */
-
-var React = require('react');
-var ReactPropTypes = React.PropTypes;
-var TodoActions = require('../actions/TodoActions');
-var TodoItem = require('./TodoItem.react');
-
-var MainSection = React.createClass({
-
- propTypes: {
- allTodos: ReactPropTypes.object.isRequired,
- areAllComplete: ReactPropTypes.bool.isRequired
- },
-
- /**
- * @return {object}
- */
- render: function() {
- // This section should be hidden by default
- // and shown when there are todos.
- if (Object.keys(this.props.allTodos).length < 1) {
- return null;
- }
-
- var allTodos = this.props.allTodos;
- var todos = [];
-
- for (var key in allTodos) {
- todos.push();
- }
-
- return (
-
-
-
-
{todos}
-
- );
- },
-
- /**
- * Event handler to mark all TODOs as complete
- */
- _onToggleCompleteAll: function() {
- TodoActions.toggleCompleteAll();
- }
-
-});
-
-module.exports = MainSection;
diff --git a/examples/todomvc-flux/js/components/TodoApp.react.js b/examples/todomvc-flux/js/components/TodoApp.react.js
deleted file mode 100644
index 803476685f8..00000000000
--- a/examples/todomvc-flux/js/components/TodoApp.react.js
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @jsx React.DOM
- */
-
-/**
- * This component operates as a "Controller-View". It listens for changes in
- * the TodoStore and passes the new data to its children.
- */
-
-var Footer = require('./Footer.react');
-var Header = require('./Header.react');
-var MainSection = require('./MainSection.react');
-var React = require('react');
-var TodoStore = require('../stores/TodoStore');
-
-/**
- * Retrieve the current TODO data from the TodoStore
- */
-function getTodoState() {
- return {
- allTodos: TodoStore.getAll(),
- areAllComplete: TodoStore.areAllComplete()
- };
-}
-
-var TodoApp = React.createClass({
-
- getInitialState: function() {
- return getTodoState();
- },
-
- componentDidMount: function() {
- TodoStore.addChangeListener(this._onChange);
- },
-
- componentWillUnmount: function() {
- TodoStore.removeChangeListener(this._onChange);
- },
-
- /**
- * @return {object}
- */
- render: function() {
- return (
-
-
-
-
-
- );
- },
-
- /**
- * Event handler for 'change' events coming from the TodoStore
- */
- _onChange: function() {
- this.setState(getTodoState());
- }
-
-});
-
-module.exports = TodoApp;
diff --git a/examples/todomvc-flux/js/components/TodoItem.react.js b/examples/todomvc-flux/js/components/TodoItem.react.js
deleted file mode 100644
index 6dd9ae78a8a..00000000000
--- a/examples/todomvc-flux/js/components/TodoItem.react.js
+++ /dev/null
@@ -1,108 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @jsx React.DOM
- */
-
-var React = require('react');
-var ReactPropTypes = React.PropTypes;
-var TodoActions = require('../actions/TodoActions');
-var TodoTextInput = require('./TodoTextInput.react');
-
-var cx = require('react/lib/cx');
-
-var TodoItem = React.createClass({
-
- propTypes: {
- todo: ReactPropTypes.object.isRequired
- },
-
- getInitialState: function() {
- return {
- isEditing: false
- };
- },
-
- /**
- * @return {object}
- */
- render: function() {
- var todo = this.props.todo;
-
- var input;
- if (this.state.isEditing) {
- input =
- ;
- }
-
- // List items should get the class 'editing' when editing
- // and 'completed' when marked as completed.
- // Note that 'completed' is a classification while 'complete' is a state.
- // This differentiation between classification and state becomes important
- // in the naming of view actions toggleComplete() vs. destroyCompleted().
- return (
-
-
-
-
-
-
- {input}
-
- );
- },
-
- _onToggleComplete: function() {
- TodoActions.toggleComplete(this.props.todo);
- },
-
- _onDoubleClick: function() {
- this.setState({isEditing: true});
- },
-
- /**
- * Event handler called within TodoTextInput.
- * Defining this here allows TodoTextInput to be used in multiple places
- * in different ways.
- * @param {string} text
- */
- _onSave: function(text) {
- TodoActions.updateText(this.props.todo.id, text);
- this.setState({isEditing: false});
- },
-
- _onDestroyClick: function() {
- TodoActions.destroy(this.props.todo.id);
- }
-
-});
-
-module.exports = TodoItem;
diff --git a/examples/todomvc-flux/js/components/TodoTextInput.react.js b/examples/todomvc-flux/js/components/TodoTextInput.react.js
deleted file mode 100644
index 2253fa50c8c..00000000000
--- a/examples/todomvc-flux/js/components/TodoTextInput.react.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @jsx React.DOM
- */
-
-var React = require('react');
-var ReactPropTypes = React.PropTypes;
-
-var ENTER_KEY_CODE = 13;
-
-var TodoTextInput = React.createClass({
-
- propTypes: {
- className: ReactPropTypes.string,
- id: ReactPropTypes.string,
- placeholder: ReactPropTypes.string,
- onSave: ReactPropTypes.func.isRequired,
- value: ReactPropTypes.string
- },
-
- getInitialState: function() {
- return {
- value: this.props.value || ''
- };
- },
-
- /**
- * @return {object}
- */
- render: function() /*object*/ {
- return (
-
- );
- },
-
- /**
- * Invokes the callback passed in as onSave, allowing this component to be
- * used in different ways.
- */
- _save: function() {
- this.props.onSave(this.state.value);
- this.setState({
- value: ''
- });
- },
-
- /**
- * @param {object} event
- */
- _onChange: function(/*object*/ event) {
- this.setState({
- value: event.target.value
- });
- },
-
- /**
- * @param {object} event
- */
- _onKeyDown: function(event) {
- if (event.keyCode === ENTER_KEY_CODE) {
- this._save();
- }
- }
-
-});
-
-module.exports = TodoTextInput;
diff --git a/examples/todomvc-flux/js/constants/TodoConstants.js b/examples/todomvc-flux/js/constants/TodoConstants.js
deleted file mode 100644
index 73127c504c8..00000000000
--- a/examples/todomvc-flux/js/constants/TodoConstants.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * TodoConstants
- */
-
-var keyMirror = require('react/lib/keyMirror');
-
-module.exports = keyMirror({
- TODO_CREATE: null,
- TODO_COMPLETE: null,
- TODO_DESTROY: null,
- TODO_DESTROY_COMPLETED: null,
- TODO_TOGGLE_COMPLETE_ALL: null,
- TODO_UNDO_COMPLETE: null,
- TODO_UPDATE_TEXT: null
-});
diff --git a/examples/todomvc-flux/js/dispatcher/AppDispatcher.js b/examples/todomvc-flux/js/dispatcher/AppDispatcher.js
deleted file mode 100644
index 7e3b32babe2..00000000000
--- a/examples/todomvc-flux/js/dispatcher/AppDispatcher.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * AppDispatcher
- *
- * A singleton that operates as the central hub for application updates.
- */
-
-var Dispatcher = require('./Dispatcher');
-
-var merge = require('react/lib/merge');
-
-var AppDispatcher = merge(Dispatcher.prototype, {
-
- /**
- * A bridge function between the views and the dispatcher, marking the action
- * as a view action. Another variant here could be handleServerAction.
- * @param {object} action The data coming from the view.
- */
- handleViewAction: function(action) {
- this.dispatch({
- source: 'VIEW_ACTION',
- action: action
- });
- }
-
-});
-
-module.exports = AppDispatcher;
diff --git a/examples/todomvc-flux/js/dispatcher/Dispatcher.js b/examples/todomvc-flux/js/dispatcher/Dispatcher.js
deleted file mode 100644
index 32a798b9b7b..00000000000
--- a/examples/todomvc-flux/js/dispatcher/Dispatcher.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Dispatcher
- *
- * The Dispatcher is capable of registering callbacks and invoking them.
- * More robust implementations than this would include a way to order the
- * callbacks for dependent Stores, and to guarantee that no two stores
- * created circular dependencies.
- */
-
-var Promise = require('es6-promise').Promise;
-var merge = require('react/lib/merge');
-
-var _callbacks = [];
-var _promises = [];
-
-var Dispatcher = function() {};
-Dispatcher.prototype = merge(Dispatcher.prototype, {
-
- /**
- * Register a Store's callback so that it may be invoked by an action.
- * @param {function} callback The callback to be registered.
- * @return {number} The index of the callback within the _callbacks array.
- */
- register: function(callback) {
- _callbacks.push(callback);
- return _callbacks.length - 1; // index
- },
-
- /**
- * dispatch
- * @param {object} payload The data from the action.
- */
- dispatch: function(payload) {
- // First create array of promises for callbacks to reference.
- var resolves = [];
- var rejects = [];
- _promises = _callbacks.map(function(_, i) {
- return new Promise(function(resolve, reject) {
- resolves[i] = resolve;
- rejects[i] = reject;
- });
- });
- // Dispatch to callbacks and resolve/reject promises.
- _callbacks.forEach(function(callback, i) {
- // Callback can return an obj, to resolve, or a promise, to chain.
- // See waitFor() for why this might be useful.
- Promise.resolve(callback(payload)).then(function() {
- resolves[i](payload);
- }, function() {
- rejects[i](new Error('Dispatcher callback unsuccessful'));
- });
- });
- _promises = [];
- },
-
- /**
- * Allows a store to wait for the registered callbacks of other stores
- * to get invoked before its own does.
- * This function is not used by this TodoMVC example application, but
- * it is very useful in a larger, more complex application.
- *
- * Example usage where StoreB waits for StoreA:
- *
- * var StoreA = merge(EventEmitter.prototype, {
- * // other methods omitted
- *
- * dispatchIndex: Dispatcher.register(function(payload) {
- * // switch statement with lots of cases
- * })
- * }
- *
- * var StoreB = merge(EventEmitter.prototype, {
- * // other methods omitted
- *
- * dispatchIndex: Dispatcher.register(function(payload) {
- * switch(payload.action.actionType) {
- *
- * case MyConstants.FOO_ACTION:
- * Dispatcher.waitFor([StoreA.dispatchIndex], function() {
- * // Do stuff only after StoreA's callback returns.
- * });
- * }
- * })
- * }
- *
- * It should be noted that if StoreB waits for StoreA, and StoreA waits for
- * StoreB, a circular dependency will occur, but no error will be thrown.
- * A more robust Dispatcher would issue a warning in this scenario.
- */
- waitFor: function(/*array*/ promiseIndexes, /*function*/ callback) {
- var selectedPromises = promiseIndexes.map(function(index) {
- return _promises[index];
- });
- return Promise.all(selectedPromises).then(callback);
- }
-
-});
-
-module.exports = Dispatcher;
diff --git a/examples/todomvc-flux/js/dispatcher/__tests__/AppDispatcher-test.js b/examples/todomvc-flux/js/dispatcher/__tests__/AppDispatcher-test.js
deleted file mode 100644
index b8665fdca18..00000000000
--- a/examples/todomvc-flux/js/dispatcher/__tests__/AppDispatcher-test.js
+++ /dev/null
@@ -1,76 +0,0 @@
-"use strict";
-
-jest.autoMockOff();
-
-describe('AppDispatcher', function() {
- var AppDispatcher;
-
- beforeEach(function() {
- AppDispatcher = require('../AppDispatcher.js');
- });
-
- it('sends actions to subscribers', function() {
- var listener = jest.genMockFunction();
- AppDispatcher.register(listener);
-
- var payload = {};
- AppDispatcher.dispatch(payload);
- expect(listener.mock.calls.length).toBe(1);
- expect(listener.mock.calls[0][0]).toBe(payload);
- });
-
- it('waits with chained dependencies properly', function() {
- var payload = {};
-
- var listener1Done = false;
- var listener1 = function(pl) {
- return AppDispatcher.waitFor([index2, index4], function() {
- // Second, third, and fourth listeners should have now been called
- expect(listener2Done).toBe(true);
- expect(listener3Done).toBe(true);
- expect(listener4Done).toBe(true);
- listener1Done = true;
- });
- };
- var index1 = AppDispatcher.register(listener1);
-
- var listener2Done = false;
- var listener2 = function(pl) {
- return AppDispatcher.waitFor([index3], function() {
- expect(listener3Done).toBe(true);
- listener2Done = true;
- });
- };
- var index2 = AppDispatcher.register(listener2);
-
- var listener3Done = false;
- var listener3 = function(pl) {
- listener3Done = true;
- return true;
- };
- var index3 = AppDispatcher.register(listener3);
-
- var listener4Done = false;
- var listener4 = function(pl) {
- return AppDispatcher.waitFor([index3], function() {
- expect(listener3Done).toBe(true);
- listener4Done = true;
- });
- };
- var index4 = AppDispatcher.register(listener4);
-
- runs(function() {
- AppDispatcher.dispatch(payload);
- });
-
- waitsFor(function() {
- return listener1Done;
- }, "Not all subscribers were properly called", 500);
-
- runs(function() {
- expect(listener1Done).toBe(true);
- expect(listener2Done).toBe(true);
- expect(listener3Done).toBe(true);
- });
- });
-});
diff --git a/examples/todomvc-flux/js/stores/TodoStore.js b/examples/todomvc-flux/js/stores/TodoStore.js
deleted file mode 100644
index b37900aac43..00000000000
--- a/examples/todomvc-flux/js/stores/TodoStore.js
+++ /dev/null
@@ -1,186 +0,0 @@
-/**
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * TodoStore
- */
-
-var AppDispatcher = require('../dispatcher/AppDispatcher');
-var EventEmitter = require('events').EventEmitter;
-var TodoConstants = require('../constants/TodoConstants');
-var merge = require('react/lib/merge');
-
-var CHANGE_EVENT = 'change';
-
-var _todos = {};
-
-/**
- * Create a TODO item.
- * @param {string} text The content of the TODO
- */
-function create(text) {
- // Hand waving here -- not showing how this interacts with XHR or persistent
- // server-side storage.
- // Using the current timestamp in place of a real id.
- var id = Date.now();
- _todos[id] = {
- id: id,
- complete: false,
- text: text
- };
-}
-
-/**
- * Update a TODO item.
- * @param {string} id
- * @param {object} updates An object literal containing only the data to be
- * updated.
- */
-function update(id, updates) {
- _todos[id] = merge(_todos[id], updates);
-}
-
-/**
- * Update all of the TODO items with the same object.
- * the data to be updated. Used to mark all TODOs as completed.
- * @param {object} updates An object literal containing only the data to be
- * updated.
-
- */
-function updateAll(updates) {
- for (var id in _todos) {
- update(id, updates);
- }
-}
-
-/**
- * Delete a TODO item.
- * @param {string} id
- */
-function destroy(id) {
- delete _todos[id];
-}
-
-/**
- * Delete all the completed TODO items.
- */
-function destroyCompleted() {
- for (var id in _todos) {
- if (_todos[id].complete) {
- destroy(id);
- }
- }
-}
-
-var TodoStore = merge(EventEmitter.prototype, {
-
- /**
- * Tests whether all the remaining TODO items are marked as completed.
- * @return {boolean}
- */
- areAllComplete: function() {
- for (id in _todos) {
- if (!_todos[id].complete) {
- return false;
- break;
- }
- }
- return true;
- },
-
- /**
- * Get the entire collection of TODOs.
- * @return {object}
- */
- getAll: function() {
- return _todos;
- },
-
- emitChange: function() {
- this.emit(CHANGE_EVENT);
- },
-
- /**
- * @param {function} callback
- */
- addChangeListener: function(callback) {
- this.on(CHANGE_EVENT, callback);
- },
-
- /**
- * @param {function} callback
- */
- removeChangeListener: function(callback) {
- this.removeListener(CHANGE_EVENT, callback);
- }
-});
-
-// Register to handle all updates
-AppDispatcher.register(function(payload) {
- var action = payload.action;
- var text;
-
- switch(action.actionType) {
- case TodoConstants.TODO_CREATE:
- text = action.text.trim();
- if (text !== '') {
- create(text);
- }
- break;
-
- case TodoConstants.TODO_TOGGLE_COMPLETE_ALL:
- if (TodoStore.areAllComplete()) {
- updateAll({complete: false});
- } else {
- updateAll({complete: true});
- }
- break;
-
- case TodoConstants.TODO_UNDO_COMPLETE:
- update(action.id, {complete: false});
- break;
-
- case TodoConstants.TODO_COMPLETE:
- update(action.id, {complete: true});
- break;
-
- case TodoConstants.TODO_UPDATE_TEXT:
- text = action.text.trim();
- if (text !== '') {
- update(action.id, {text: text});
- }
- break;
-
- case TodoConstants.TODO_DESTROY:
- destroy(action.id);
- break;
-
- case TodoConstants.TODO_DESTROY_COMPLETED:
- destroyCompleted();
- break;
-
- default:
- return true;
- }
-
- // This often goes in each case that should trigger a UI change. This store
- // needs to trigger a UI change after every view action, so we can make the
- // code less repetitive by putting it here. We need the default case,
- // however, to make sure this only gets called after one of the cases above.
- TodoStore.emitChange();
-
- return true; // No errors. Needed by promise in Dispatcher.
-});
-
-module.exports = TodoStore;
diff --git a/examples/todomvc-flux/package.json b/examples/todomvc-flux/package.json
deleted file mode 100644
index 6741bd71c0b..00000000000
--- a/examples/todomvc-flux/package.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "name": "todomvc-flux",
- "version": "0.0.1",
- "description": "Example Flux architecture.",
- "main": "js/app.js",
- "dependencies": {
- "es6-promise": "~0.1.1",
- "react": "~0.11.0"
- },
- "devDependencies": {
- "browserify": "~2.36.0",
- "envify": "~1.2.0",
- "reactify": "~0.4.0",
- "statics": "~0.1.0",
- "uglify-js": "~2.4.13",
- "watchify": "~0.4.1",
- "jest-cli": "~0.1.5"
- },
- "scripts": {
- "start": "STATIC_ROOT=./static watchify -o js/bundle.js -v -d .",
- "build": "STATIC_ROOT=./static NODE_ENV=production browserify . | uglifyjs -cm > js/bundle.min.js",
- "collect-static": "collect-static . ./static",
- "test": "jest"
- },
- "author": "Bill Fisher",
- "license": "Apache 2",
- "browserify": {
- "transform": [
- "reactify",
- "envify"
- ]
- },
- "jest": {
- "rootDir": "./js"
- }
-}
diff --git a/examples/todomvc-flux/todomvc-common/.bower.json b/examples/todomvc-flux/todomvc-common/.bower.json
deleted file mode 100644
index 16d4ea667e3..00000000000
--- a/examples/todomvc-flux/todomvc-common/.bower.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "name": "todomvc-common",
- "version": "0.1.9",
- "homepage": "https://github.com/tastejs/todomvc-common",
- "_release": "0.1.9",
- "_resolution": {
- "type": "version",
- "tag": "v0.1.9",
- "commit": "7dd61b0ebf56c020e719a69444442cc7ae7242ff"
- },
- "_source": "git://github.com/tastejs/todomvc-common.git",
- "_target": "~0.1.4",
- "_originalSource": "todomvc-common"
-}
\ No newline at end of file
diff --git a/examples/todomvc-flux/todomvc-common/base.css b/examples/todomvc-flux/todomvc-common/base.css
deleted file mode 100644
index d151ededea4..00000000000
--- a/examples/todomvc-flux/todomvc-common/base.css
+++ /dev/null
@@ -1,556 +0,0 @@
-html,
-body {
- margin: 0;
- padding: 0;
-}
-
-button {
- margin: 0;
- padding: 0;
- border: 0;
- background: none;
- font-size: 100%;
- vertical-align: baseline;
- font-family: inherit;
- color: inherit;
- -webkit-appearance: none;
- -ms-appearance: none;
- -o-appearance: none;
- appearance: none;
-}
-
-body {
- font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
- line-height: 1.4em;
- background: #eaeaea url('bg.png');
- color: #4d4d4d;
- width: 550px;
- margin: 0 auto;
- -webkit-font-smoothing: antialiased;
- -moz-font-smoothing: antialiased;
- -ms-font-smoothing: antialiased;
- -o-font-smoothing: antialiased;
- font-smoothing: antialiased;
-}
-
-button,
-input[type="checkbox"] {
- outline: none;
-}
-
-#todoapp {
- background: #fff;
- background: rgba(255, 255, 255, 0.9);
- margin: 130px 0 40px 0;
- border: 1px solid #ccc;
- position: relative;
- border-top-left-radius: 2px;
- border-top-right-radius: 2px;
- box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2),
- 0 25px 50px 0 rgba(0, 0, 0, 0.15);
-}
-
-#todoapp:before {
- content: '';
- border-left: 1px solid #f5d6d6;
- border-right: 1px solid #f5d6d6;
- width: 2px;
- position: absolute;
- top: 0;
- left: 40px;
- height: 100%;
-}
-
-#todoapp input::-webkit-input-placeholder {
- font-style: italic;
-}
-
-#todoapp input::-moz-placeholder {
- font-style: italic;
- color: #a9a9a9;
-}
-
-#todoapp h1 {
- position: absolute;
- top: -120px;
- width: 100%;
- font-size: 70px;
- font-weight: bold;
- text-align: center;
- color: #b3b3b3;
- color: rgba(255, 255, 255, 0.3);
- text-shadow: -1px -1px rgba(0, 0, 0, 0.2);
- -webkit-text-rendering: optimizeLegibility;
- -moz-text-rendering: optimizeLegibility;
- -ms-text-rendering: optimizeLegibility;
- -o-text-rendering: optimizeLegibility;
- text-rendering: optimizeLegibility;
-}
-
-#header {
- padding-top: 15px;
- border-radius: inherit;
-}
-
-#header:before {
- content: '';
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- height: 15px;
- z-index: 2;
- border-bottom: 1px solid #6c615c;
- background: #8d7d77;
- background: -webkit-gradient(linear, left top, left bottom, from(rgba(132, 110, 100, 0.8)),to(rgba(101, 84, 76, 0.8)));
- background: -webkit-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
- background: linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');
- border-top-left-radius: 1px;
- border-top-right-radius: 1px;
-}
-
-#new-todo,
-.edit {
- position: relative;
- margin: 0;
- width: 100%;
- font-size: 24px;
- font-family: inherit;
- line-height: 1.4em;
- border: 0;
- outline: none;
- color: inherit;
- padding: 6px;
- border: 1px solid #999;
- box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
- -moz-box-sizing: border-box;
- -ms-box-sizing: border-box;
- -o-box-sizing: border-box;
- box-sizing: border-box;
- -webkit-font-smoothing: antialiased;
- -moz-font-smoothing: antialiased;
- -ms-font-smoothing: antialiased;
- -o-font-smoothing: antialiased;
- font-smoothing: antialiased;
-}
-
-#new-todo {
- padding: 16px 16px 16px 60px;
- border: none;
- background: rgba(0, 0, 0, 0.02);
- z-index: 2;
- box-shadow: none;
-}
-
-#main {
- position: relative;
- z-index: 2;
- border-top: 1px dotted #adadad;
-}
-
-label[for='toggle-all'] {
- display: none;
-}
-
-#toggle-all {
- position: absolute;
- top: -42px;
- left: -4px;
- width: 40px;
- text-align: center;
- /* Mobile Safari */
- border: none;
-}
-
-#toggle-all:before {
- content: '»';
- font-size: 28px;
- color: #d9d9d9;
- padding: 0 25px 7px;
-}
-
-#toggle-all:checked:before {
- color: #737373;
-}
-
-#todo-list {
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-#todo-list li {
- position: relative;
- font-size: 24px;
- border-bottom: 1px dotted #ccc;
-}
-
-#todo-list li:last-child {
- border-bottom: none;
-}
-
-#todo-list li.editing {
- border-bottom: none;
- padding: 0;
-}
-
-#todo-list li.editing .edit {
- display: block;
- width: 506px;
- padding: 13px 17px 12px 17px;
- margin: 0 0 0 43px;
-}
-
-#todo-list li.editing .view {
- display: none;
-}
-
-#todo-list li .toggle {
- text-align: center;
- width: 40px;
- /* auto, since non-WebKit browsers doesn't support input styling */
- height: auto;
- position: absolute;
- top: 0;
- bottom: 0;
- margin: auto 0;
- /* Mobile Safari */
- border: none;
- -webkit-appearance: none;
- -ms-appearance: none;
- -o-appearance: none;
- appearance: none;
-}
-
-#todo-list li .toggle:after {
- content: '✔';
- /* 40 + a couple of pixels visual adjustment */
- line-height: 43px;
- font-size: 20px;
- color: #d9d9d9;
- text-shadow: 0 -1px 0 #bfbfbf;
-}
-
-#todo-list li .toggle:checked:after {
- color: #85ada7;
- text-shadow: 0 1px 0 #669991;
- bottom: 1px;
- position: relative;
-}
-
-#todo-list li label {
- white-space: pre;
- word-break: break-word;
- padding: 15px 60px 15px 15px;
- margin-left: 45px;
- display: block;
- line-height: 1.2;
- -webkit-transition: color 0.4s;
- transition: color 0.4s;
-}
-
-#todo-list li.completed label {
- color: #a9a9a9;
- text-decoration: line-through;
-}
-
-#todo-list li .destroy {
- display: none;
- position: absolute;
- top: 0;
- right: 10px;
- bottom: 0;
- width: 40px;
- height: 40px;
- margin: auto 0;
- font-size: 22px;
- color: #a88a8a;
- -webkit-transition: all 0.2s;
- transition: all 0.2s;
-}
-
-#todo-list li .destroy:hover {
- text-shadow: 0 0 1px #000,
- 0 0 10px rgba(199, 107, 107, 0.8);
- -webkit-transform: scale(1.3);
- -ms-transform: scale(1.3);
- transform: scale(1.3);
-}
-
-#todo-list li .destroy:after {
- content: '✖';
-}
-
-#todo-list li:hover .destroy {
- display: block;
-}
-
-#todo-list li .edit {
- display: none;
-}
-
-#todo-list li.editing:last-child {
- margin-bottom: -1px;
-}
-
-#footer {
- color: #777;
- padding: 0 15px;
- position: absolute;
- right: 0;
- bottom: -31px;
- left: 0;
- height: 20px;
- z-index: 1;
- text-align: center;
-}
-
-#footer:before {
- content: '';
- position: absolute;
- right: 0;
- bottom: 31px;
- left: 0;
- height: 50px;
- z-index: -1;
- box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3),
- 0 6px 0 -3px rgba(255, 255, 255, 0.8),
- 0 7px 1px -3px rgba(0, 0, 0, 0.3),
- 0 43px 0 -6px rgba(255, 255, 255, 0.8),
- 0 44px 2px -6px rgba(0, 0, 0, 0.2);
-}
-
-#todo-count {
- float: left;
- text-align: left;
-}
-
-#filters {
- margin: 0;
- padding: 0;
- list-style: none;
- position: absolute;
- right: 0;
- left: 0;
-}
-
-#filters li {
- display: inline;
-}
-
-#filters li a {
- color: #83756f;
- margin: 2px;
- text-decoration: none;
-}
-
-#filters li a.selected {
- font-weight: bold;
-}
-
-#clear-completed {
- float: right;
- position: relative;
- line-height: 20px;
- text-decoration: none;
- background: rgba(0, 0, 0, 0.1);
- font-size: 11px;
- padding: 0 10px;
- border-radius: 3px;
- box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.2);
-}
-
-#clear-completed:hover {
- background: rgba(0, 0, 0, 0.15);
- box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3);
-}
-
-#info {
- margin: 65px auto 0;
- color: #a6a6a6;
- font-size: 12px;
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
- text-align: center;
-}
-
-#info a {
- color: inherit;
-}
-
-/*
- Hack to remove background from Mobile Safari.
- Can't use it globally since it destroys checkboxes in Firefox and Opera
-*/
-
-@media screen and (-webkit-min-device-pixel-ratio:0) {
- #toggle-all,
- #todo-list li .toggle {
- background: none;
- }
-
- #todo-list li .toggle {
- height: 40px;
- }
-
- #toggle-all {
- top: -56px;
- left: -15px;
- width: 65px;
- height: 41px;
- -webkit-transform: rotate(90deg);
- -ms-transform: rotate(90deg);
- transform: rotate(90deg);
- -webkit-appearance: none;
- appearance: none;
- }
-}
-
-.hidden {
- display: none;
-}
-
-hr {
- margin: 20px 0;
- border: 0;
- border-top: 1px dashed #C5C5C5;
- border-bottom: 1px dashed #F7F7F7;
-}
-
-.learn a {
- font-weight: normal;
- text-decoration: none;
- color: #b83f45;
-}
-
-.learn a:hover {
- text-decoration: underline;
- color: #787e7e;
-}
-
-.learn h3,
-.learn h4,
-.learn h5 {
- margin: 10px 0;
- font-weight: 500;
- line-height: 1.2;
- color: #000;
-}
-
-.learn h3 {
- font-size: 24px;
-}
-
-.learn h4 {
- font-size: 18px;
-}
-
-.learn h5 {
- margin-bottom: 0;
- font-size: 14px;
-}
-
-.learn ul {
- padding: 0;
- margin: 0 0 30px 25px;
-}
-
-.learn li {
- line-height: 20px;
-}
-
-.learn p {
- font-size: 15px;
- font-weight: 300;
- line-height: 1.3;
- margin-top: 0;
- margin-bottom: 0;
-}
-
-.quote {
- border: none;
- margin: 20px 0 60px 0;
-}
-
-.quote p {
- font-style: italic;
-}
-
-.quote p:before {
- content: '“';
- font-size: 50px;
- opacity: .15;
- position: absolute;
- top: -20px;
- left: 3px;
-}
-
-.quote p:after {
- content: '”';
- font-size: 50px;
- opacity: .15;
- position: absolute;
- bottom: -42px;
- right: 3px;
-}
-
-.quote footer {
- position: absolute;
- bottom: -40px;
- right: 0;
-}
-
-.quote footer img {
- border-radius: 3px;
-}
-
-.quote footer a {
- margin-left: 5px;
- vertical-align: middle;
-}
-
-.speech-bubble {
- position: relative;
- padding: 10px;
- background: rgba(0, 0, 0, .04);
- border-radius: 5px;
-}
-
-.speech-bubble:after {
- content: '';
- position: absolute;
- top: 100%;
- right: 30px;
- border: 13px solid transparent;
- border-top-color: rgba(0, 0, 0, .04);
-}
-
-.learn-bar > .learn {
- position: absolute;
- width: 272px;
- top: 8px;
- left: -300px;
- padding: 10px;
- border-radius: 5px;
- background-color: rgba(255, 255, 255, .6);
- -webkit-transition-property: left;
- transition-property: left;
- -webkit-transition-duration: 500ms;
- transition-duration: 500ms;
-}
-
-@media (min-width: 899px) {
- .learn-bar {
- width: auto;
- margin: 0 0 0 300px;
- }
-
- .learn-bar > .learn {
- left: 8px;
- }
-
- .learn-bar #todoapp {
- width: 550px;
- margin: 130px auto 40px auto;
- }
-}
diff --git a/examples/todomvc-flux/todomvc-common/bg.png b/examples/todomvc-flux/todomvc-common/bg.png
deleted file mode 100644
index b2a7600825e..00000000000
Binary files a/examples/todomvc-flux/todomvc-common/bg.png and /dev/null differ
diff --git a/examples/todomvc-flux/todomvc-common/bower.json b/examples/todomvc-flux/todomvc-common/bower.json
deleted file mode 100644
index cdc4a4321c3..00000000000
--- a/examples/todomvc-flux/todomvc-common/bower.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "todomvc-common",
- "version": "0.1.9"
-}
diff --git a/examples/todomvc-flux/todomvc-common/readme.md b/examples/todomvc-flux/todomvc-common/readme.md
deleted file mode 100644
index 566a64c2529..00000000000
--- a/examples/todomvc-flux/todomvc-common/readme.md
+++ /dev/null
@@ -1,8 +0,0 @@
-# todomvc-common
-
-> Bower component for some common utilities we use in every app
-
-
-## License
-
-MIT
diff --git a/grunt/tasks/release.js b/grunt/tasks/release.js
index 7abd67ece0b..3b23f793c97 100644
--- a/grunt/tasks/release.js
+++ b/grunt/tasks/release.js
@@ -15,22 +15,7 @@ var GH_PAGES_PATH = '../react-gh-pages/';
var GH_PAGES_GLOB = [GH_PAGES_PATH + '*'];
var EXAMPLES_PATH = 'examples/';
-var EXAMPLES_GLOB = [
- // todomvc-flux has too many other dependencies, so we'll leave it out
- EXAMPLES_PATH + '/README.md',
- EXAMPLES_PATH + '/ballmer-peak/**/*.*',
- EXAMPLES_PATH + '/basic/**/*.*',
- EXAMPLES_PATH + '/basic-commonjs/**/*.*',
- EXAMPLES_PATH + '/basic-jsx/**/*.*',
- EXAMPLES_PATH + '/basic-jsx-external/**/*.*',
- EXAMPLES_PATH + '/basic-jsx-harmony/**/*.*',
- EXAMPLES_PATH + '/basic-jsx-precompile/**/*.*',
- EXAMPLES_PATH + '/jquery-bootstrap/**/*.*',
- EXAMPLES_PATH + '/jquery-mobile/**/*.*',
- EXAMPLES_PATH + '/server-rendering/**/*.*',
- EXAMPLES_PATH + '/shared/**/*.*',
- EXAMPLES_PATH + '/transitions/**/*.*'
-];
+var EXAMPLES_GLOB = [EXAMPLES_PATH + '**/*.*'];
var STARTER_PATH = 'starter/';
var STARTER_GLOB = [STARTER_PATH + '/**/*.*'];