DoYouEvenBench: Add Facebook's React TodoMVC test case
[WebKit-https.git] / PerformanceTests / DoYouEvenBench / todomvc / labs / architecture-examples / react / js / app.jsx
1 /**
2  * @jsx React.DOM
3  */
4 /*jshint quotmark:false */
5 /*jshint white:false */
6 /*jshint trailing:false */
7 /*jshint newcap:false */
8 /*global Utils, ALL_TODOS, ACTIVE_TODOS, COMPLETED_TODOS,
9     TodoItem, TodoFooter, React, Router*/
10
11 (function (window, React) {
12     'use strict';
13
14     window.ALL_TODOS = 'all';
15     window.ACTIVE_TODOS = 'active';
16     window.COMPLETED_TODOS = 'completed';
17
18     var ENTER_KEY = 13;
19
20     var TodoApp = React.createClass({
21         getInitialState: function () {
22             var todos = Utils.store('react-todos');
23             return {
24                 todos: todos,
25                 nowShowing: ALL_TODOS,
26                 editing: null
27             };
28         },
29
30         componentDidMount: function () {
31             var router = Router({
32                 '/': this.setState.bind(this, {nowShowing: ALL_TODOS}),
33                 '/active': this.setState.bind(this, {nowShowing: ACTIVE_TODOS}),
34                 '/completed': this.setState.bind(this, {nowShowing: COMPLETED_TODOS})
35             });
36             router.init();
37             this.refs.newField.getDOMNode().focus();
38         },
39
40         handleNewTodoKeyDown: function (event) {
41             if (event.which !== ENTER_KEY) {
42                 return;
43             }
44
45             var val = this.refs.newField.getDOMNode().value.trim();
46             var todos;
47             var newTodo;
48
49             if (val) {
50                 todos = this.state.todos;
51                 newTodo = {
52                     id: Utils.uuid(),
53                     title: val,
54                     completed: false
55                 };
56                 this.setState({todos: todos.concat([newTodo])});
57                 this.refs.newField.getDOMNode().value = '';
58             }
59
60             return false;
61         },
62
63         toggleAll: function (event) {
64             var checked = event.target.checked;
65
66             this.state.todos.forEach(function (todo) {
67                 todo.completed = checked;
68             });
69
70             this.setState({todos: this.state.todos});
71         },
72
73         toggle: function (todo) {
74             todo.completed = !todo.completed;
75             this.setState({todos: this.state.todos});
76         },
77
78         destroy: function (todo) {
79             var newTodos = this.state.todos.filter(function (candidate) {
80                 return candidate.id !== todo.id;
81             });
82
83             this.setState({todos: newTodos});
84         },
85
86         edit: function (todo, callback) {
87             // refer to todoItem.js `handleEdit` for the reasoning behind the
88             // callback
89             this.setState({editing: todo.id}, function () {
90                 callback();
91             });
92         },
93
94         save: function (todo, text) {
95             todo.title = text;
96             this.setState({todos: this.state.todos, editing: null});
97         },
98
99         cancel: function () {
100             this.setState({editing: null});
101         },
102
103         clearCompleted: function () {
104             var newTodos = this.state.todos.filter(function (todo) {
105                 return !todo.completed;
106             });
107
108             this.setState({todos: newTodos});
109         },
110
111         componentDidUpdate: function () {
112             Utils.store('react-todos', this.state.todos);
113         },
114
115         render: function () {
116             var footer = null;
117             var main = null;
118             var todoItems = {};
119             var activeTodoCount;
120             var completedCount;
121
122             var shownTodos = this.state.todos.filter(function (todo) {
123                 switch (this.state.nowShowing) {
124                 case ACTIVE_TODOS:
125                     return !todo.completed;
126                 case COMPLETED_TODOS:
127                     return todo.completed;
128                 default:
129                     return true;
130                 }
131             }.bind(this));
132
133             shownTodos.forEach(function (todo) {
134                 todoItems[todo.id] = (
135                     <TodoItem
136                         todo={todo}
137                         onToggle={this.toggle.bind(this, todo)}
138                         onDestroy={this.destroy.bind(this, todo)}
139                         onEdit={this.edit.bind(this, todo)}
140                         editing={this.state.editing === todo.id}
141                         onSave={this.save.bind(this, todo)}
142                         onCancel={this.cancel}
143                     />
144                 );
145             }.bind(this));
146
147             activeTodoCount = this.state.todos.filter(function (todo) {
148                 return !todo.completed;
149             }).length;
150
151             completedCount = this.state.todos.length - activeTodoCount;
152
153             if (activeTodoCount || completedCount) {
154                 footer =
155                     <TodoFooter
156                         count={activeTodoCount}
157                         completedCount={completedCount}
158                         nowShowing={this.state.nowShowing}
159                         onClearCompleted={this.clearCompleted}
160                     />;
161             }
162
163             if (this.state.todos.length) {
164                 main = (
165                     <section id="main">
166                         <input
167                             id="toggle-all"
168                             type="checkbox"
169                             onChange={this.toggleAll}
170                             checked={activeTodoCount === 0}
171                         />
172                         <ul id="todo-list">
173                             {todoItems}
174                         </ul>
175                     </section>
176                 );
177             }
178
179             return (
180                 <div>
181                     <header id="header">
182                         <h1>todos</h1>
183                         <input
184                             ref="newField"
185                             id="new-todo"
186                             placeholder="What needs to be done?"
187                             onKeyDown={this.handleNewTodoKeyDown}
188                         />
189                     </header>
190                     {main}
191                     {footer}
192                 </div>
193             );
194         }
195     });
196
197     React.renderComponent(<TodoApp />, document.getElementById('todoapp'));
198     React.renderComponent(
199         <div>
200             <p>Double-click to edit a todo</p>
201             <p>Created by{' '}
202                 <a href="http://github.com/petehunt/">petehunt</a>
203             </p>
204             <p>Part of{' '}<a href="http://todomvc.com">TodoMVC</a></p>
205         </div>,
206         document.getElementById('info'));
207 })(window, React);