Commit 904aa5a8 authored by Pascal Hartig's avatar Pascal Hartig

Merge pull request #855 from chenglou/new-react

[React] New main todomvc with fixes and React version bump
parents f0079582 156d0859
......@@ -3,7 +3,7 @@
"version": "0.0.0",
"dependencies": {
"todomvc-common": "~0.1.7",
"react": "~0.8.0",
"director": "~1.2.0"
"director": "~1.2.0",
"react": "~0.9.0"
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -8,15 +8,22 @@
<body>
<section id="todoapp"></section>
<footer id="info"></footer>
<div id="benchmark"></div>
<footer id="info">
<p>Double-click to edit a todo</p>
<p>Created by <a href="http://github.com/petehunt/">petehunt</a></p>
<p>Part of<a href="http://todomvc.com">TodoMVC</a></p>
</footer>
<script src="bower_components/todomvc-common/base.js"></script>
<script src="bower_components/react/react-with-addons.js"></script>
<script src="bower_components/react/JSXTransformer.js"></script>
<script src="bower_components/director/build/director.js"></script>
<script type="text/jsx" src="js/utils.jsx"></script>
<script src="js/utils.js"></script>
<script src="js/todoModel.js"></script>
<!-- jsx is an optional syntactic sugar that transforms methods in React's
`render` into an HTML-looking format. Since the two models above are
unrelated to React, we didn't need those transforms. -->
<script type="text/jsx" src="js/todoItem.jsx"></script>
<script type="text/jsx" src="js/footer.jsx"></script>
<script type="text/jsx" src="js/app.jsx"></script>
......
......@@ -5,35 +5,36 @@
/*jshint white:false */
/*jshint trailing:false */
/*jshint newcap:false */
/*global Utils, TodoModel, ALL_TODOS, ACTIVE_TODOS,
COMPLETED_TODOS, TodoItem, TodoFooter, React, Router*/
/*global React, Router*/
var app = app || {};
(function (window, React) {
(function () {
'use strict';
window.ALL_TODOS = 'all';
window.ACTIVE_TODOS = 'active';
window.COMPLETED_TODOS = 'completed';
app.ALL_TODOS = 'all';
app.ACTIVE_TODOS = 'active';
app.COMPLETED_TODOS = 'completed';
var TodoFooter = app.TodoFooter;
var TodoItem = app.TodoItem;
var ENTER_KEY = 13;
var TodoApp = React.createClass({
getInitialState: function () {
return {
nowShowing: ALL_TODOS,
nowShowing: app.ALL_TODOS,
editing: null
};
},
componentDidMount: function () {
var setState = this.setState;
var router = Router({
'/': this.setState.bind(this, {nowShowing: ALL_TODOS}),
'/active': this.setState.bind(this, {nowShowing: ACTIVE_TODOS}),
'/completed': this.setState.bind(this, {nowShowing: COMPLETED_TODOS})
'/': setState.bind(this, {nowShowing: app.ALL_TODOS}),
'/active': setState.bind(this, {nowShowing: app.ACTIVE_TODOS}),
'/completed': setState.bind(this, {nowShowing: app.COMPLETED_TODOS})
});
router.init();
this.refs.newField.getDOMNode().focus();
router.init('/');
},
handleNewTodoKeyDown: function (event) {
......@@ -86,14 +87,15 @@
},
render: function () {
var footer = null;
var main = null;
var footer;
var main;
var todos = this.props.model.todos;
var shownTodos = this.props.model.todos.filter(function (todo) {
var shownTodos = todos.filter(function (todo) {
switch (this.state.nowShowing) {
case ACTIVE_TODOS:
case app.ACTIVE_TODOS:
return !todo.completed;
case COMPLETED_TODOS:
case app.COMPLETED_TODOS:
return todo.completed;
default:
return true;
......@@ -115,11 +117,11 @@
);
}, this);
var activeTodoCount = this.props.model.todos.reduce(function(accum, todo) {
var activeTodoCount = todos.reduce(function (accum, todo) {
return todo.completed ? accum : accum + 1;
}, 0);
var completedCount = this.props.model.todos.length - activeTodoCount;
var completedCount = todos.length - activeTodoCount;
if (activeTodoCount || completedCount) {
footer =
......@@ -131,7 +133,7 @@
/>;
}
if (this.props.model.todos.length) {
if (todos.length) {
main = (
<section id="main">
<input
......@@ -156,6 +158,7 @@
id="new-todo"
placeholder="What needs to be done?"
onKeyDown={this.handleNewTodoKeyDown}
autoFocus={true}
/>
</header>
{main}
......@@ -165,7 +168,7 @@
}
});
var model = new TodoModel('react-todos');
var model = new app.TodoModel('react-todos');
function render() {
React.renderComponent(
......@@ -176,14 +179,4 @@
model.subscribe(render);
render();
React.renderComponent(
<div>
<p>Double-click to edit a todo</p>
<p>Created by{' '}
<a href="http://github.com/petehunt/">petehunt</a>
</p>
<p>Part of{' '}<a href="http://todomvc.com">TodoMVC</a></p>
</div>,
document.getElementById('info'));
})(window, React);
})();
......@@ -5,13 +5,15 @@
/*jshint white:false */
/*jshint trailing:false */
/*jshint newcap:false */
/*global React, ALL_TODOS, ACTIVE_TODOS, Utils, COMPLETED_TODOS */
(function (window) {
/*global React */
var app = app || {};
(function () {
'use strict';
window.TodoFooter = React.createClass({
app.TodoFooter = React.createClass({
render: function () {
var activeTodoWord = Utils.pluralize(this.props.count, 'item');
var activeTodoWord = app.Utils.pluralize(this.props.count, 'item');
var clearButton = null;
if (this.props.completedCount > 0) {
......@@ -19,35 +21,42 @@
<button
id="clear-completed"
onClick={this.props.onClearCompleted}>
{''}Clear completed ({this.props.completedCount}){''}
Clear completed ({this.props.completedCount})
</button>
);
}
var show = {
ALL_TODOS: '',
ACTIVE_TODOS: '',
COMPLETED_TODOS: ''
};
show[this.props.nowShowing] = 'selected';
// React idiom for shortcutting to `classSet` since it'll be used often
var cx = React.addons.classSet;
var nowShowing = this.props.nowShowing;
return (
<footer id="footer">
<span id="todo-count">
<strong>{this.props.count}</strong>
{' '}{activeTodoWord}{' '}left{''}
<strong>{this.props.count}</strong> {activeTodoWord} left
</span>
<ul id="filters">
<li>
<a href="#/" className={show[ALL_TODOS]}>All</a>
<a
href="#/"
className={cx({selected: nowShowing === app.ALL_TODOS})}>
All
</a>
</li>
{' '}
<li>
<a href="#/active" className={show[ACTIVE_TODOS]}>Active</a>
<a
href="#/active"
className={cx({selected: nowShowing === app.ACTIVE_TODOS})}>
Active
</a>
</li>
{' '}
<li>
<a href="#/completed" className={show[COMPLETED_TODOS]}>Completed</a>
<a
href="#/completed"
className={cx({selected: nowShowing === app.COMPLETED_TODOS})}>
Completed
</a>
</li>
</ul>
{clearButton}
......@@ -55,4 +64,4 @@
);
}
});
})(window);
})();
......@@ -5,14 +5,16 @@
/*jshint white: false */
/*jshint trailing: false */
/*jshint newcap: false */
/*global React, Utils */
(function (window) {
/*global React */
var app = app || {};
(function () {
'use strict';
var ESCAPE_KEY = 27;
var ENTER_KEY = 13;
window.TodoItem = React.createClass({
app.TodoItem = React.createClass({
handleSubmit: function () {
var val = this.state.editText.trim();
if (val) {
......@@ -38,10 +40,10 @@
},
handleKeyDown: function (event) {
if (event.keyCode === ESCAPE_KEY) {
if (event.which === ESCAPE_KEY) {
this.setState({editText: this.props.todo.title});
this.props.onCancel();
} else if (event.keyCode === ENTER_KEY) {
} else if (event.which === ENTER_KEY) {
this.handleSubmit();
}
},
......@@ -98,4 +100,4 @@
);
}
});
})(window);
})();
......@@ -5,32 +5,33 @@
/*jshint white:false */
/*jshint trailing:false */
/*jshint newcap:false */
/*global Utils */
var app = app || {};
(function (window) {
(function () {
'use strict';
var Utils = app.Utils;
// Generic "model" object. You can use whatever
// framework you want. For this application it
// may not even be worth separating this logic
// out, but we do this to demonstrate one way to
// separate out parts of your application.
window.TodoModel = function (key) {
app.TodoModel = function (key) {
this.key = key;
this.todos = Utils.store(key);
this.onChanges = [];
};
window.TodoModel.prototype.subscribe = function (onChange) {
app.TodoModel.prototype.subscribe = function (onChange) {
this.onChanges.push(onChange);
};
window.TodoModel.prototype.inform = function () {
app.TodoModel.prototype.inform = function () {
Utils.store(this.key, this.todos);
this.onChanges.forEach(function (cb) { cb(); });
};
window.TodoModel.prototype.addTodo = function (title) {
app.TodoModel.prototype.addTodo = function (title) {
this.todos = this.todos.concat({
id: Utils.uuid(),
title: title,
......@@ -40,10 +41,11 @@
this.inform();
};
window.TodoModel.prototype.toggleAll = function (checked) {
// Note: it's usually better to use immutable data structures since they're easier to
// reason about and React works very well with them. That's why we use map() and filter()
// everywhere instead of mutating the array or todo items themselves.
app.TodoModel.prototype.toggleAll = function (checked) {
// Note: it's usually better to use immutable data structures since they're
// easier to reason about and React works very well with them. That's why we
// use map() and filter() everywhere instead of mutating the array or todo
// items themselves.
this.todos = this.todos.map(function (todo) {
return Utils.extend({}, todo, {completed: checked});
});
......@@ -51,15 +53,17 @@
this.inform();
};
window.TodoModel.prototype.toggle = function (todoToToggle) {
app.TodoModel.prototype.toggle = function (todoToToggle) {
this.todos = this.todos.map(function (todo) {
return todo !== todoToToggle ? todo : Utils.extend({}, todo, {completed: !todo.completed});
return todo !== todoToToggle ?
todo :
Utils.extend({}, todo, {completed: !todo.completed});
});
this.inform();
};
window.TodoModel.prototype.destroy = function (todo) {
app.TodoModel.prototype.destroy = function (todo) {
this.todos = this.todos.filter(function (candidate) {
return candidate !== todo;
});
......@@ -67,7 +71,7 @@
this.inform();
};
window.TodoModel.prototype.save = function (todoToSave, text) {
app.TodoModel.prototype.save = function (todoToSave, text) {
this.todos = this.todos.map(function (todo) {
return todo !== todoToSave ? todo : Utils.extend({}, todo, {title: text});
});
......@@ -75,7 +79,7 @@
this.inform();
};
window.TodoModel.prototype.clearCompleted = function () {
app.TodoModel.prototype.clearCompleted = function () {
this.todos = this.todos.filter(function (todo) {
return !todo.completed;
});
......@@ -83,4 +87,4 @@
this.inform();
};
})(this);
\ No newline at end of file
})();
(function (window) {
var app = app || {};
(function () {
'use strict';
window.Utils = {
app.Utils = {
uuid: function () {
/*jshint bitwise:false */
var i, random;
......@@ -45,5 +47,4 @@
return newObj;
}
};
})(window);
})();
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment