Skip to content

Commit c7768fd

Browse files
committed
Merge pull request #307 from chenglou/todomvc-director
sync with tastejs todomvc
2 parents 75aee17 + 2b9c34b commit c7768fd

File tree

12 files changed

+451
-733
lines changed

12 files changed

+451
-733
lines changed

examples/todomvc-director/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# TodoMVC-director
2+
3+
This is the exact copy of the React-powered [TodoMVC](http://todomvc.com/labs/architecture-examples/react/). To test it, use [bower](http://bower.io) to fetch the dependencies:
4+
5+
`bower install`
6+
7+
Then fire up a server here:
8+
9+
`python -m SimpleHTTPServer`
10+
11+
And go visit `localhost:8000`.

examples/todomvc-director/bower.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "todomvc-react",
3+
"version": "0.0.0",
4+
"dependencies": {
5+
"todomvc-common": "~0.1.7",
6+
"react": "~0.4.0",
7+
"director": "~1.2.0"
8+
}
9+
}

examples/todomvc-director/index.html

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!doctype html>
2+
<html lang="en" data-framework="react">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<title>React • TodoMVC</title>
7+
<link rel="stylesheet" href="bower_components/todomvc-common/base.css">
8+
</head>
9+
<body>
10+
<section id="todoapp"></section>
11+
<footer id="info"></footer>
12+
<div id="benchmark"></div>
13+
14+
<script src="bower_components/todomvc-common/base.js"></script>
15+
<script src="bower_components/react/react.js"></script>
16+
<script src="bower_components/react/JSXTransformer.js"></script>
17+
<script src="bower_components/director/build/director.min.js"></script>
18+
19+
<script type="text/jsx" src="js/utils.jsx"></script>
20+
<script type="text/jsx" src="js/todoItem.jsx"></script>
21+
<script type="text/jsx" src="js/footer.jsx"></script>
22+
<script type="text/jsx" src="js/app.jsx"></script>
23+
</body>
24+
</html>

examples/todomvc-director/js/app.jsx

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
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);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* @jsx React.DOM
3+
*/
4+
/*jshint quotmark:false */
5+
/*jshint white:false */
6+
/*jshint trailing:false */
7+
/*jshint newcap:false */
8+
/*global React, ALL_TODOS, ACTIVE_TODOS, Utils, COMPLETED_TODOS */
9+
(function (window) {
10+
'use strict';
11+
12+
window.TodoFooter = React.createClass({
13+
render: function () {
14+
var activeTodoWord = Utils.pluralize(this.props.count, 'item');
15+
var clearButton = null;
16+
17+
if (this.props.completedCount > 0) {
18+
clearButton = (
19+
<button
20+
id="clear-completed"
21+
onClick={this.props.onClearCompleted}>
22+
{''}Clear completed ({this.props.completedCount}){''}
23+
</button>
24+
);
25+
}
26+
27+
var show = {
28+
ALL_TODOS: '',
29+
ACTIVE_TODOS: '',
30+
COMPLETED_TODOS: ''
31+
};
32+
show[this.props.nowShowing] = 'selected';
33+
34+
return (
35+
<footer id="footer">
36+
<span id="todo-count">
37+
<strong>{this.props.count}</strong>
38+
{' '}{activeTodoWord}{' '}left{''}
39+
</span>
40+
<ul id="filters">
41+
<li>
42+
<a href="#/" class={show[ALL_TODOS]}>All</a>
43+
</li>
44+
{' '}
45+
<li>
46+
<a href="#/active" class={show[ACTIVE_TODOS]}>Active</a>
47+
</li>
48+
{' '}
49+
<li>
50+
<a href="#/completed" class={show[COMPLETED_TODOS]}>Completed</a>
51+
</li>
52+
</ul>
53+
{clearButton}
54+
</footer>
55+
);
56+
}
57+
});
58+
})(window);

0 commit comments

Comments
 (0)