Permalink
Browse files

Initial port to TodoMVC and DoneJS

  • Loading branch information...
1 parent ee7eb33 commit 29521abfa0f95e19962d1fdee941d73cb9a20608 @daffl daffl committed May 2, 2012
Showing with 450 additions and 392 deletions.
  1. +1 −0 .gitignore
  2. +3 −3 .gitmodules
  3. +1 −0 can
  4. +0 −1 jquery
  5. +0 −52 todo/index.html
  6. +97 −0 todo/model.js
  7. +0 −1 todo/production.css
  8. +0 −7 todo/production.js
  9. +208 −0 todo/styles/base.css
  10. +5 −0 todo/styles/todo.css
  11. +0 −43 todo/todo.css
  12. +23 −49 todo/todo.html
  13. +87 −236 todo/todo.js
  14. +25 −0 todo/views/todo.ejs
View
1 .gitignore
@@ -0,0 +1 @@
+.idea
View
6 .gitmodules
@@ -1,9 +1,9 @@
-[submodule "jquery"]
- path = jquery
- url = git://github.com/jupiterjs/jquerymx.git
[submodule "funcunit"]
path = funcunit
url = git://github.com/jupiterjs/funcunit.git
[submodule "steal"]
path = steal
url = git://github.com/jupiterjs/steal.git
+[submodule "can"]
+ path = can
+ url = git@github.com:jupiterjs/canjs.git
1 can
@@ -0,0 +1 @@
+Subproject commit 3259501518e8f1afef6257b63811c185e0080fba
1 jquery
@@ -1 +0,0 @@
-Subproject commit 9ce150fa768eb0fe42257f54d9e9dddd420a8c61
View
52 todo/index.html
@@ -1,52 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html lang="en">
- <head>
- <link rel="stylesheet" type='text/css' href='production.css' />
- <title>todo</title>
- </head>
- <body>
- <div id='todos'>
- <h1>Todos</h1>
- <input type='text' class='create'/>
- <ul id='list'></ul>
- <div id='todo-stats'>
-
- </div>
- </div>
-
- <script type='text/ejs' id='todosEJS'>
- <% for(var i =0; i < this.length ; i++){ %>
- <li <%= this[i]%>>
- <%== $.View('todoEJS',this[i] ) %>
- </li>
- <% } %>
- </script>
- <script type='text/ejs' id='todoEJS'>
- <input type='checkbox' name='complete'
- <%= this.complete ? "checked" : "" %>>
- <span class=''><%= (this.text || "empty todo ...")%></span>
- <span class='destroy'></span>
- </script>
- <script type='text/ejs' id='statsEJS'>
- <% if (total) { %>
- <span class="todo-count">
- <span class="number"><%= remaining %></span>
- <span class="word"><%= remaining == 1 ? 'item' : 'items' %></span> left.
- </span>
- <% } %>
- <% if (completed) { %>
- <span class="todo-clear">
- <a href="#">
- Clear <span class="number-done"><%= completed %></span>
- completed <span class="word-done"><%= completed == 1 ? 'item' : 'items' %></span>
- </a>
- </span>
- <% } %>
-
- </script>
- <script type='text/javascript'
- src='../steal/steal.production.js?todo'>
- </script>
- </body>
-</html>
View
97 todo/model.js
@@ -0,0 +1,97 @@
+steal('can/model').then(function() {
+
+ // Basic Todo entry model
+ // { text: 'todo', complete: false }
+ can.Model('Todo', {
+
+ // Implement local storage handling
+ localStore: function(cb){
+ var name = 'todos-canjs-jquery',
+ data = JSON.parse( window.localStorage[name] || (window.localStorage[name] = '[]') ),
+ res = cb.call(this, data);
+ if(res !== false){
+ can.each(data, function(i, todo) {
+ delete todo.editing;
+ });
+ window.localStorage[name] = JSON.stringify(data);
+ }
+ },
+
+ findAll: function(params){
+ var def = new can.Deferred();
+ this.localStore(function(todos){
+ var instances = [],
+ self = this;
+ can.each(todos, function(i, todo) {
+ instances.push(new self(todo));
+ });
+ def.resolve({data: instances});
+ })
+ return def;
+ },
+
+ destroy: function(id){
+ var def = new can.Deferred();
+ this.localStore(function(todos){
+ for (var i = 0; i < todos.length; i++) {
+ if (todos[i].id === id) {
+ todos.splice(i, 1);
+ break;
+ }
+ }
+ def.resolve({});
+ });
+ return def
+ },
+
+ create: function(attrs){
+ var def = new can.Deferred();
+ this.localStore(function(todos){
+ attrs.id = attrs.id || parseInt(100000 *Math.random());
+ todos.push(attrs);
+ });
+ def.resolve({id : attrs.id});
+ return def
+ },
+
+ update: function(id, attrs){
+ var def = new can.Deferred();
+ this.localStore(function(todos){
+ for (var i = 0; i < todos.length; i++) {
+ if (todos[i].id === id) {
+ var todo = todos[i];
+ break;
+ }
+ }
+ can.extend(todo, attrs);
+ });
+ def.resolve({});
+ return def
+ }
+
+ },{});
+
+ // List for Todos
+ can.Model.List('Todo.List', {
+
+ completed: function() {
+ // Ensure this triggers on length change
+ this.attr('length');
+
+ var completed = 0;
+ this.each(function(todo, i) {
+ completed += todo.attr('complete') ? 1 : 0
+ });
+ return completed;
+ },
+
+ remaining: function() {
+ return this.attr('length') - this.completed();
+ },
+
+ allComplete: function() {
+ return this.attr('length') === this.completed();
+ }
+ });
+
+});
View
1 todo/production.css
@@ -1 +0,0 @@
-body{font-family:verdana;background-image:url("http://javascriptmvc.com/jmvc/images/backgrounds/body.png");padding:0;margin:0}#todos{-moz-background-clip:border;-moz-background-origin:padding;-moz-background-size:auto auto;-moz-box-shadow:0 5px 6px 0 rgba(0,0,0,0.2);background-attachment:scroll;background-color:white;background-image:none;background-position:0 0;background-repeat:repeat;margin:0 auto 40px auto;padding:20px;width:480px}h1{text-align:center}.create,input.text{font-size:1.4em;width:100%}ul{margin:0;padding:0}.todo{list-style:none;border-bottom:solid 1px #ccc;padding:5px 1px;font-size:1.4em}#todo-stats{margin-top:20px}#list{margin-top:20px}
View
7 todo/production.js
0 additions, 7 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
208 todo/styles/base.css
@@ -0,0 +1,208 @@
+html,
+body {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ font: 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
+ line-height: 1.4em;
+ background: #eeeeee;
+ color: #333333;
+ width: 520px;
+ margin: 0 auto;
+ -webkit-font-smoothing: antialiased;
+}
+
+#todoapp {
+ background: #fff;
+ padding: 20px;
+ margin-bottom: 40px;
+ -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
+ -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
+ -ms-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
+ -o-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
+ box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
+ -webkit-border-radius: 0 0 5px 5px;
+ -moz-border-radius: 0 0 5px 5px;
+ -ms-border-radius: 0 0 5px 5px;
+ -o-border-radius: 0 0 5px 5px;
+ border-radius: 0 0 5px 5px;
+}
+
+#todoapp h1 {
+ font-size: 36px;
+ font-weight: bold;
+ text-align: center;
+ padding: 0 0 10px 0;
+}
+
+#todoapp input[type="text"] {
+ width: 466px;
+ font-size: 24px;
+ font-family: inherit;
+ line-height: 1.4em;
+ border: 0;
+ outline: none;
+ padding: 6px;
+ border: 1px solid #999999;
+ -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
+ -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
+ -ms-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
+ -o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
+ box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
+}
+
+#todoapp input::-webkit-input-placeholder {
+ font-style: italic;
+}
+
+#main {
+ display: none;
+}
+
+#todo-list {
+ margin: 10px 0;
+ padding: 0;
+ list-style: none;
+}
+
+#todo-list li {
+ padding: 18px 20px 18px 0;
+ position: relative;
+ font-size: 24px;
+ border-bottom: 1px solid #cccccc;
+}
+
+#todo-list li:last-child {
+ border-bottom: none;
+}
+
+#todo-list li.done label {
+ color: #777777;
+ text-decoration: line-through;
+}
+
+#todo-list li .destroy {
+ display: none;
+ position: absolute;
+ top: 20px;
+ right: 10px;
+ cursor: pointer;
+ width: 20px;
+ height: 20px;
+ background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUBAMAAAB/pwA+AAAABGdBTUEAALGPC/xhBQAAACdQTFRFzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMAAAA////zMzMhnu0WAAAAAt0Uk5T5u3pqtV3jFQEKAC0bVelAAAAfUlEQVQI12NYtWpFsc8R865VqxhWrZpyBgg8QcylZ8AgCsjMgTCPrWJYfgYKqhjWwJgaDDVnzpw+c2bPmTPHGWzOnNm95/TuM2cOM/AARXfvBooeZAAp270bRCIz4QoOIGtDMqwJZoUEQzvCYrhzuhhWtUKYEahOX7UK6iEA3A6NUGwCTZIAAAAASUVORK5CYII=') no-repeat center center;
+}
+
+#todo-list li:hover .destroy {
+ display: block;
+}
+
+#todo-list li.editing {
+ border-bottom: none;
+ margin-top: -1px;
+ padding: 0;
+}
+
+#todo-list li.editing:last-child {
+ margin-bottom: -1px;
+}
+
+#todo-list li.editing .edit {
+ display: block;
+ width: 444px;
+ padding: 13px 15px 14px 20px;
+ margin: 0;
+}
+
+#todo-list li.editing .view {
+ display: none;
+}
+
+#todo-list li .view label {
+ word-break: break-word;
+}
+
+#todo-list li .edit {
+ display: none;
+}
+
+#todoapp footer {
+ display: none;
+ margin: 0 -20px -20px -20px;
+ overflow: hidden;
+ color: #555555;
+ background: #f4fce8;
+ border-top: 1px solid #ededed;
+ padding: 0 20px;
+ line-height: 37px;
+ -webkit-border-radius: 0 0 5px 5px;
+ -moz-border-radius: 0 0 5px 5px;
+ -ms-border-radius: 0 0 5px 5px;
+ -o-border-radius: 0 0 5px 5px;
+ border-radius: 0 0 5px 5px;
+}
+
+#clear-completed {
+ display: none;
+ float: right;
+ line-height: 20px;
+ text-decoration: none;
+ background: rgba(0, 0, 0, 0.1);
+ color: #555555;
+ font-size: 11px;
+ margin-top: 8px;
+ margin-bottom: 8px;
+ padding: 0 10px 1px;
+ cursor: pointer;
+ -webkit-border-radius: 12px;
+ -moz-border-radius: 12px;
+ -ms-border-radius: 12px;
+ -o-border-radius: 12px;
+ border-radius: 12px;
+ -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
+ -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
+ -ms-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
+ -o-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
+ box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
+}
+
+#clear-completed:hover {
+ background: rgba(0, 0, 0, 0.15);
+ -webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
+ -moz-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
+ -ms-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
+ -o-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
+ box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
+}
+
+#clear-completed:active {
+ position: relative;
+ top: 1px;
+}
+
+#todo-count span {
+ font-weight: bold;
+}
+
+#instructions {
+ margin: 10px auto;
+ color: #777777;
+ text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
+ text-align: center;
+}
+
+#instructions a {
+ color: #336699;
+}
+
+#credits {
+ margin: 30px auto;
+ color: #999;
+ text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
+ text-align: center;
+}
+
+#credits a {
+ color: #888;
+}
View
5 todo/styles/todo.css
@@ -0,0 +1,5 @@
+#main.show,
+#stats.show,
+#stats.show #clear-completed {
+ display: block;
+}
View
43 todo/todo.css
@@ -1,43 +0,0 @@
-body {
- font-family: verdana;
- background-image: url("http://javascriptmvc.com/jmvc/images/backgrounds/body.png");
- padding: 0px; margin: 0px;
-}
-#todos {
- -moz-background-clip: border;
- -moz-background-origin: padding;
- -moz-background-size: auto auto;
- -moz-box-shadow: 0 5px 6px 0 rgba(0, 0, 0, 0.2);
- background-attachment: scroll;
- background-color: white;
- background-image: none;
- background-position: 0 0;
- background-repeat: repeat;
- margin: 0 auto 40px auto;
- padding: 20px;
- width: 480px;
-}
-
-h1{
- text-align: center;
-}
-.create, input.text {
- font-size: 1.4em;
- width: 100%;
-}
-
-ul {
- margin: 0px;padding: 0px;
-}
-.todo {
- list-style: none;
- border-bottom: solid 1px #CCCCCC;
- padding: 5px 1px;
- font-size: 1.4em;
-}
-#todo-stats {
- margin-top: 20px;
-}
-#list {
- margin-top: 20px;
-}
View
72 todo/todo.html 100644 → 100755
@@ -1,51 +1,25 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
+<!doctype html>
<html lang="en">
- <head>
- <title>todo</title>
- </head>
- <body>
- <div id='todos'>
- <h1>Todos</h1>
- <input type='text' class='create'/>
- <ul id='list'></ul>
- <div id='todo-stats'>
-
- </div>
- </div>
-
- <script type='text/ejs' id='todosEJS'>
- <% for(var i =0; i < this.length ; i++){ %>
- <li <%= this[i]%>>
- <%== $.View('todoEJS',this[i] ) %>
- </li>
- <% } %>
- </script>
- <script type='text/ejs' id='todoEJS'>
- <input type='checkbox' name='complete'
- <%= this.complete ? "checked" : "" %>>
- <span class=''><%= (this.text || "empty todo ...")%></span>
- <span class='destroy'></span>
- </script>
- <script type='text/ejs' id='statsEJS'>
- <% if (total) { %>
- <span class="todo-count">
- <span class="number"><%= remaining %></span>
- <span class="word"><%= remaining == 1 ? 'item' : 'items' %></span> left.
- </span>
- <% } %>
- <% if (completed) { %>
- <span class="todo-clear">
- <a href="#">
- Clear <span class="number-done"><%= completed %></span>
- completed <span class="word-done"><%= completed == 1 ? 'item' : 'items' %></span>
- </a>
- </span>
- <% } %>
-
- </script>
- <script type='text/javascript'
- src='../steal/steal.js?todo,development'>
- </script>
- </body>
+<head>
+ <meta charset="utf-8">
+ <title>Todo - DoneJS with jQuery</title>
+ <!--[if lt IE 9]>
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+</head>
+<body>
+ <div id="todoapp">
+ <header>
+ <h1>Todos</h1>
+ <input id="new-todo" type="text" placeholder="What needs to be done?">
+ </header>
+ </div>
+ <div id="instructions">
+ Double-click to edit a todo.
+ </div>
+ <div id="credits">
+ Created by <a href="http://bitovi.com/">Bitovi</a>.
+ </div>
+ <script src="../steal/steal.js?todo,development"></script>
+</body>
</html>
View
323 todo/todo.js 100644 → 100755
@@ -1,248 +1,99 @@
-// Load what we need
-steal('jquery/model/list',
- 'jquery/controller',
- 'jquery/view/ejs',
- 'jquery/lang/json',
- './todo.css',
- function($){
+steal('can/control', 'can/view/ejs')
+ .then('./model.js',
+ './styles/base.css',
+ './styles/todo.css')
+ .then(function() {
-/**
- * A todo model for CRUDing todos.
- */
-$.Model('Todo',{
- /**
- * Gets JSON data from localStorage. Any changes that
- * get made in cb get written back to localStorage.
- *
- * This is unimportant for understanding JavaScriptMVC!
- */
- localStore: function(cb){
- var name = this.shortName,
- data = $.evalJSON( window.localStorage[name] || (window.localStorage[name] = "{}") ),
- res = cb.call(this, data);
- if(res !== false){
- window.localStorage[name] = $.toJSON(data);
- }
- },
- /**
- * Gets todos from localStorage.
- *
- * Todo.findAll({}, success(todos))
- */
- findAll: function(params , success){
- this.localStore(function(todos){
- var instances = [];
- for(var id in todos){
- instances.push( new this( todos[id]) )
+ can.Control('Todos', {
+
+ // Initialize the Todos list
+ init : function(){
+ // Render the Todos
+ this.element.append(can.view('//todo/views/todo.ejs', {
+ todos: this.options.todos
+ }));
+
+ // Clear the new todo field
+ $('#new-todo').val('').focus();
+ },
+
+ // Listen for when a new Todo has been entered
+ '#new-todo keyup' : function(el, ev){
+ if(ev.keyCode == 13){
+ new Todo({
+ text : el.val(),
+ complete : false
+ }).save(function() {
+ el.val('');
+ });
}
- success && success(instances)
- })
- },
- /**
- * Destroys a single todo by id
- *
- * Todo.destroy(1, success())
- */
- destroy: function(id, success){
- this.List.destroy([id], success)
- },
- /**
- * Creates a todo with the provided attrs. This allows:
- *
- * new Todo({text: 'hello'}).save( success(todo) );
- */
- create: function(attrs, success){
- this.localStore(function(todos){
- attrs.id = attrs.id || parseInt(100000 *Math.random())
- todos[attrs.id] = attrs;
- });
- success({id : attrs.id})
- },
- /**
- * Updates a todo by id with the provided attrs. This allows:
- *
- * todo.update({text: 'world'}, success(todos) )
- */
- update: function(id, attrs, success){
- this.localStore(function(todos){
- var todo = todos[id];
- $.extend(todo, attrs);
- });
- success({});
- }
-
-},{});
+ },
+
+ // Handle a newly created Todo
+ '{Todo} created' : function(list, ev, item){
+ this.options.todos.push(item);
+ },
-/**
- * Helper methods on collections of todos. But lists can also use their model's
- * methods. Ex:
- *
- * var todos = [new Todo({id: 5}) , new Todo({id: 6})],
- * list = new Todo.List(todos);
- *
- * list.destroyAll() -> calls Todo.destroyAll with [5,6].
- */
-$.Model.List('Todo.List',
-{
- /**
- * Destroys a list of todos by id from localStorage
- *
- * Todo.destroy([1,2], success())
- */
- destroy : function(ids, success, error){
- this.namespace.localStore(function(todos){
- $.each(ids, function(){
- delete todos[this]
+ // Listen for editing a Todo
+ '.todo dblclick' : function(el, ev) {
+ el.data('todo').attr('editing', true).save(function() {
+ el.children('.edit').focus().select();
});
- });
- success();
- }
-},
-{
-
- /**
- * Return a new Todo.List of only complete items
- */
- completed : function(){
- return this.grep(function(item){
- return item.complete === true;
- })
- }
-});
+ },
+ // Update a todo
+ updateTodo: function(el) {
+ el.closest('.todo').data('todo')
+ .attr({
+ editing: false,
+ text: el.val()
+ }).save();
+ },
-/**
- * A Todos widget created like
- *
- * $("#todos").todos({ list: new Todo.List() });
- *
- * It listens on changes to the list and items in the list with the following actions:
- *
- * - "{list} add" - todos being added to the list
- * - "{list} remove" - todos being removed from the list
- * - "{list} update" - todos being updated in the list
- *
- */
-$.Controller('Todos',{
-
- // sets up the widget
- init : function(){
-
- // empties the create input element
- this.find(".create").val("")[0].focus();
-
- // fills this list of items (creates add events on the list)
- this.options.list.findAll();
- },
-
- // adds existing and created to the list
- "{list} add" : function(list, ev, items){
-
- // uses the todosEJS template (in todo.html) to render a list of items
- // then adds those items to #list
- this.find('#list').append("todosEJS",items)
-
- // calls a helper to update the stats info
- this.updateStats();
- },
-
- // Creating a todo --------------
-
- // listens for key events and creates a new todo
- ".create keyup" : function(el, ev){
-
- if(ev.keyCode == 13){
- new Todo({
- text : el.val(),
- complete : false
- }).save(this.callback('created'));
-
- el.val("");
- }
- },
-
- // When a todo is created, add it to this list
- "created" : function(todo){
- this.options.list.push(todo); //triggers 'add' on the list
- },
-
- // Destroying a todo --------------
-
- // the clear button is clicked
- ".todo-clear click" : function(){
- // gets completed todos in the list, destroys them
- this.options.list.completed()
- .destroy();
+ // Listen for an edited Todo
+ '.todo .edit keyup' : function(el, ev){
+ if(ev.keyCode == 13){
+ this.updateTodo(el);
+ }
+ },
+ '.todo .edit focusout' : function(el, ev) {
+ this.updateTodo(el);
+ },
- },
-
- // When a todo's destroy button is clicked.
- ".todo .destroy click" : function(el){
- el.closest('.todo').model().destroy();
- },
-
- // when an item is removed from the list ...
- "{list} remove" : function(list, ev, items){
-
- // get the elements in the list and remove them
- items.elements(this.element).slideUp(function(){
- $(this).remove();
- });
-
- this.updateStats();
- },
-
-
- // Updating a todo --------------
-
- // when the checkbox changes, update the model
- ".todo [name=complete] change" : function(el, ev){
- var todo = el.closest('.todo').model().update({
- complete : el.is(':checked')
- });
- },
-
- // switch to edit mode
- ".todo dblclick" : function(el){
- var input = $("<input name='text' class='text'/>").val(el.model().text)
- el.html(input);
- input[0].focus();
- },
-
- // update the todo's text on blur
- ".todo [name=text] focusout" : function(el, ev){
-
- var todo = el.closest('.todo').model().update({
- text : el.val()
- });
- },
-
- // when an item is updated
- "{list} updated" : function(list, ev, item){
- item.elements().html("todoEJS", item);
- this.updateStats();
- //update completed
- },
-
- // a helper that updates the stats
- updateStats : function(){
- var list = this.options.list,
- completed = list.completed().length;
- $("#todo-stats").html("statsEJS",{
- completed : completed,
- total : list.length,
- remaining : list.length - completed
- })
- }
-})
+ // Listen for the toggled completion of a Todo
+ '.todo .toggle click' : function(el, ev) {
+ el.closest('.todo').data('todo')
+ .attr('complete', el.is(':checked'))
+ .save();
+ },
+
+ // Listen for a removed Todo
+ '.todo .destroy click' : function(el){
+ el.closest('.todo').data('todo').destroy();
+ },
+ // Listen for toggle all completed Todos
+ '#toggle-all click' : function(el, ev) {
+ var toggle = el.prop('checked');
+ can.each(this.options.todos, function(i, todo) {
+ todo.attr('complete', toggle).save();
+ });
+ },
+ // Listen for removing all completed Todos
+ '#clear-completed click' : function() {
+ for (var i = this.options.todos.length - 1, todo; i > -1 && (todo = this.options.todos[i]); i--) {
+ todo.attr('complete') && todo.destroy();
+ }
+ }
-$(function(){
-
- // create a todos widget with a list
- $("#todos").todos({list : new Todo.List()});
-})
+ })
+ // Initialize the app
+ Todo.findAll({}, function(todos) {
+ new Todos('#todoapp', {
+ todos: todos
+ });
+ });
-});
+});
View
25 todo/views/todo.ejs
@@ -0,0 +1,25 @@
+<section id="main" class="<%= todos.attr("length") > 0 ? "show" : "" %>">
+ <input id="toggle-all" type="checkbox" <%= todos.allComplete() ? "checked" : "" %>>
+ <label for="toggle-all">Mark all as complete</label>
+ <ul id="todo-list">
+ <% list(todos, function( todo ) { %>
+ <li class="todo
+ <%= todo.attr("complete") ? "done" : "" %>
+ <%= todo.attr("editing") ? "editing" : "" %>"
+ <%= (el)-> el.data('todo', todo) %>>
+ <div class="view">
+ <input class="toggle" type="checkbox" <%= todo.attr("complete") ? "checked" : "" %>>
+ <label><%= todo.attr("text") %></label>
+ <a class="destroy"></a>
+ </div>
+ <input class="edit" type="text" value="<%= todo.attr("text") %>">
+ </li>
+ <% }) %>
+ </ul>
+</section>
+<footer id="stats" class="<%= todos.attr("length") > 0 ? "show" : "" %>">
+ <a id="clear-completed">Clear <%= todos.completed() %>
+ completed item<%= todos.completed() == 1 ? "" : "s" %></a>
+ <div id="todo-count"><span><%= todos.remaining() %></span>
+ item<%= todos.remaining() == 1 ? "" : "s" %> left</div>
+</footer>

0 comments on commit 29521ab

Please sign in to comment.