Commit e2380422 authored by Trek Glowacki's avatar Trek Glowacki Committed by Sindre Sorhus

Ember app improvements

Some slightly stylistic changes more recent versions of Ember let's us do.

A combination of children route getting their parent model by default and being able to supply a route's template name let's us use {{outlet}} instead of mutating the state on a shared controller object.

Automatic component lookup let's us remove the explicit registration of the todo input. We can also re-use the component for both new todos and editing todos.

Closes #943
parent 67072a72
...@@ -6,49 +6,56 @@ ...@@ -6,49 +6,56 @@
<link rel="stylesheet" href="bower_components/todomvc-common/base.css"> <link rel="stylesheet" href="bower_components/todomvc-common/base.css">
</head> </head>
<body> <body>
<script type="text/x-handlebars" data-template-name="todo-list">
{{#if length}}
<section id="main">
{{#if canToggle}}
{{input type="checkbox" id="toggle-all" checked=allTodos.allAreDone}}
{{/if}}
<ul id="todo-list">
{{#each}}
<li {{bind-attr class="isCompleted:completed isEditing:editing"}}>
{{#if isEditing}}
{{todo-input type="text" class="edit" value=bufferedTitle focus-out="doneEditing" insert-newline="doneEditing" escape-press="cancelEditing"}}
{{else}}
{{input type="checkbox" class="toggle" checked=isCompleted}}
<label {{action "editTodo" on="doubleClick"}}>{{title}}</label>
<button {{action "removeTodo"}} class="destroy"></button>
{{/if}}
</li>
{{/each}}
</ul>
</section>
{{/if}}
</script>
<script type="text/x-handlebars" data-template-name="todos"> <script type="text/x-handlebars" data-template-name="todos">
<section id="todoapp"> <section id="todoapp">
<header id="header"> <header id="header">
<h1>todos</h1> <h1>todos</h1>
{{input id="new-todo" type="text" value=newTitle action="createTodo" placeholder="What needs to be done?"}} {{todo-input id="new-todo" type="text" value=newTitle action="createTodo" placeholder="What needs to be done?"}}
</header> </header>
{{#if length}} {{outlet}}
<section id="main"> {{#if length}}
<ul id="todo-list"> <footer id="footer">
{{#each filteredTodos itemController="todo"}} <span id="todo-count"><strong>{{remaining.length}}</strong> {{pluralize 'item' remaining.length}} left</span>
<li {{bind-attr class="isCompleted:completed isEditing:editing"}}> <ul id="filters">
{{#if isEditing}} <li>
{{edit-todo class="edit" value=bufferedTitle focus-out="doneEditing" insert-newline="doneEditing" escape-press="cancelEditing"}} {{#link-to "todos.index" activeClass="selected"}}All{{/link-to}}
{{else}} </li>
{{input type="checkbox" class="toggle" checked=isCompleted}} <li>
<label {{action "editTodo" on="doubleClick"}}>{{title}}</label> {{#link-to "todos.active" activeClass="selected"}}Active{{/link-to}}
<button {{action "removeTodo"}} class="destroy"></button> </li>
{{/if}} <li>
</li> {{#link-to "todos.completed" activeClass="selected"}}Completed{{/link-to}}
{{/each}} </li>
</ul> </ul>
{{input type="checkbox" id="toggle-all" checked=allAreDone}} {{#if completed.length}}
</section> <button id="clear-completed" {{action "clearCompleted"}}>
<footer id="footer"> Clear completed ({{completed.length}})
<span id="todo-count"><strong>{{remaining.length}}</strong> {{pluralize 'item' remaining.length}} left</span> </button>
<ul id="filters"> {{/if}}
<li> </footer>
{{#link-to "todos.index" activeClass="selected"}}All{{/link-to}} {{/if}}
</li>
<li>
{{#link-to "todos.active" activeClass="selected"}}Active{{/link-to}}
</li>
<li>
{{#link-to "todos.completed" activeClass="selected"}}Completed{{/link-to}}
</li>
</ul>
{{#if completed.length}}
<button id="clear-completed" {{action "clearCompleted"}}>
Clear completed ({{completed.length}})
</button>
{{/if}}
</footer>
{{/if}}
</section> </section>
<footer id="info"> <footer id="info">
<p>Double-click to edit a todo</p> <p>Double-click to edit a todo</p>
...@@ -74,9 +81,9 @@ ...@@ -74,9 +81,9 @@
<script src="js/router.js"></script> <script src="js/router.js"></script>
<script src="js/models/todo.js"></script> <script src="js/models/todo.js"></script>
<script src="js/controllers/todos_controller.js"></script> <script src="js/controllers/todos_controller.js"></script>
<script src="js/controllers/todos_list_controller.js"></script>
<script src="js/controllers/todo_controller.js"></script> <script src="js/controllers/todo_controller.js"></script>
<script src="js/views/edit_todo_view.js"></script> <script src="js/views/todo_input_component.js"></script>
<script src="js/views/todos_view.js"></script>
<script src="js/helpers/pluralize.js"></script> <script src="js/helpers/pluralize.js"></script>
</body> </body>
</html> </html>
...@@ -33,8 +33,8 @@ ...@@ -33,8 +33,8 @@
/* properties */ /* properties */
remaining: Ember.computed.filterBy('content', 'isCompleted', false), remaining: Ember.computed.filterBy('model', 'isCompleted', false),
completed: Ember.computed.filterBy('content', 'isCompleted', true), completed: Ember.computed.filterBy('model', 'isCompleted', true),
allAreDone: function (key, value) { allAreDone: function (key, value) {
if (value !== undefined) { if (value !== undefined) {
......
/*global Todos, Ember */
(function () {
'use strict';
Todos.TodosListController = Ember.ArrayController.extend({
needs: ['todos'],
allTodos: Ember.computed.alias('controllers.todos'),
itemController: 'todo',
canToggle: function () {
var anyTodos = this.get('allTodos.length');
var isEditing = this.isAny('isEditing');
return anyTodos && !isEditing;
}.property('allTodos.length', '@each.isEditing')
});
})();
...@@ -15,29 +15,24 @@ ...@@ -15,29 +15,24 @@
} }
}); });
Todos.TodosIndexRoute = Ember.Route.extend({ Todos.TodosIndexRoute = Todos.TodosRoute.extend({
setupController: function () { templateName: 'todo-list',
this.controllerFor('todos').set('filteredTodos', this.modelFor('todos')); controllerName: 'todos-list'
}
}); });
Todos.TodosActiveRoute = Ember.Route.extend({ Todos.TodosActiveRoute = Todos.TodosIndexRoute.extend({
setupController: function () { model: function () {
var todos = this.store.filter('todo', function (todo) { return this.store.filter('todo', function (todo) {
return !todo.get('isCompleted'); return !todo.get('isCompleted');
}); });
this.controllerFor('todos').set('filteredTodos', todos);
} }
}); });
Todos.TodosCompletedRoute = Ember.Route.extend({ Todos.TodosCompletedRoute = Todos.TodosIndexRoute.extend({
setupController: function () { model: function () {
var todos = this.store.filter('todo', function (todo) { return this.store.filter('todo', function (todo) {
return todo.get('isCompleted'); return todo.get('isCompleted');
}); });
this.controllerFor('todos').set('filteredTodos', todos);
} }
}); });
})(); })();
...@@ -2,13 +2,11 @@ ...@@ -2,13 +2,11 @@
(function () { (function () {
'use strict'; 'use strict';
Todos.EditTodoView = Ember.TextField.extend({ Todos.TodoInputComponent = Ember.TextField.extend({
focusOnInsert: function () { focusOnInsert: function () {
// Re-set input value to get rid of a reduntant text selection // Re-set input value to get rid of a reduntant text selection
this.$().val(this.$().val()); this.$().val(this.$().val());
this.$().focus(); this.$().focus();
}.on('didInsertElement') }.on('didInsertElement')
}); });
Ember.Handlebars.helper('edit-todo', Todos.EditTodoView);
})(); })();
/*global Todos, Ember */
(function () {
'use strict';
Todos.TodosView = Ember.View.extend({
focusInput: function () {
this.$('#new-todo').focus();
}.on('didInsertElement')
});
})();
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