forked from tastejs/todomvc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
15,789 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
node_modules/blocks/* | ||
!node_modules/blocks/blocks.js | ||
|
||
node_modules/todomvc-app-css/* | ||
!node_modules/todomvc-app-css/index.css | ||
|
||
node_modules/todomvc-common/* | ||
!node_modules/todomvc-common/base.css | ||
!node_modules/todomvc-common/base.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<!doctype html> | ||
<html lang="en" data-framework="jsblocks"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<title>jsblocks • TodoMVC</title> | ||
<link rel="stylesheet" href="node_modules/todomvc-common/base.css"> | ||
<link rel="stylesheet" href="node_modules/todomvc-app-css/index.css"> | ||
</head> | ||
<body> | ||
<section data-query="view(Todos)" class="todoapp"> | ||
<header class="header"> | ||
<h1>todos</h1> | ||
<input data-query="val(newTodo.title).keydown(addTodo)" class="new-todo" placeholder="What needs to be done?" autofocus> | ||
</header> | ||
<section data-query="visible(todos().length > 0)" style="display: none;" class="main"> | ||
<input data-query="checked(todos.remaining() == 0).click(todos.toggleAll)" class="toggle-all" type="checkbox"> | ||
<label for="toggle-all">Mark all as complete</label> | ||
<ul data-query="each(todos.view)" class="todo-list"> | ||
<li data-query="setClass('completed', completed).setClass('editing', editing).dblclick(edit)"> | ||
<div class="view"> | ||
<input data-query="checked(completed).click(toggleComplete)" class="toggle" type="checkbox"> | ||
<label>{{title}}</label> | ||
<button data-query="click(destroy)" class="destroy"></button> | ||
</div> | ||
<input data-query="val(title).keydown(handleAction).blur(closeEdit).focused(editing)" class="edit" /> | ||
</li> | ||
</ul> | ||
</section> | ||
<footer data-query="visible(todos().length > 0)" style="display: none;" class="footer"> | ||
<span class="todo-count"> | ||
<strong>{{todos.remaining}}</strong> {{todos.remaining() == 1 ? 'item' : 'items'}} left | ||
</span> | ||
<ul class="filters"> | ||
<li> | ||
<a data-query="setClass('selected', filter() == 'all')" href="#/">All</a> | ||
</li> | ||
<li> | ||
<a data-query="setClass('selected', filter() == 'active')" href="#/active">Active</a> | ||
</li> | ||
<li> | ||
<a data-query="setClass('selected', filter() == 'completed')" href="#/completed">Completed</a> | ||
</li> | ||
</ul> | ||
<button data-query="visible(todos().length != todos.remaining()).click(todos.clearCompleted)" class="clear-completed"> | ||
Clear completed | ||
</button> | ||
</footer> | ||
</section> | ||
<footer class="info"> | ||
<p>Double-click to edit a todo</p> | ||
<p>Created by <a href="https://github.com/astoilkov">Antonio Stoilkov</a></p> | ||
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p> | ||
</footer> | ||
<script src="node_modules/todomvc-common/base.js"></script> | ||
<script src="node_modules/blocks/blocks.js"></script> | ||
<script src="js/app.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
/*global blocks */ | ||
|
||
(function () { | ||
'use strict'; | ||
|
||
var ENTER_KEY = 13; | ||
var ESCAPE_KEY = 27; | ||
|
||
var App = blocks.Application(); | ||
|
||
var Todo = App.Model({ | ||
title: App.Property(), | ||
|
||
completed: App.Property(), | ||
|
||
editing: blocks.observable(), | ||
|
||
init: function () { | ||
var collection = this.collection(); | ||
|
||
// collection is undefined when a Todo is still not part of the Todos collection | ||
if (collection) { | ||
// save to Local Storage on each attribute change | ||
this.title.on('change', collection.save); | ||
this.completed.on('change', collection.save); | ||
} | ||
|
||
this.title.on('change', function (newValue) { | ||
this.title((newValue || '').trim()); | ||
}); | ||
}, | ||
|
||
toggleComplete: function () { | ||
this.completed(!this.completed()); | ||
}, | ||
|
||
edit: function () { | ||
this.lastValue = this.title(); | ||
this.editing(true); | ||
}, | ||
|
||
closeEdit: function () { | ||
if (this.title()) { | ||
this.editing(false); | ||
} else { | ||
this.destroy(); | ||
} | ||
}, | ||
|
||
handleAction: function (e) { | ||
if (e.which === ENTER_KEY) { | ||
this.closeEdit(); | ||
} else if (e.which === ESCAPE_KEY) { | ||
this.title(this.lastValue); | ||
this.editing(false); | ||
} | ||
} | ||
}); | ||
|
||
var Todos = App.Collection(Todo, { | ||
remaining: blocks.observable(), | ||
|
||
init: function () { | ||
this | ||
// load the data from the Local Storage | ||
.reset(JSON.parse(localStorage.getItem('todos-jsblocks')) || []) | ||
// save to Local Storage on each item add or remove | ||
.on('add remove', this.save) | ||
.updateRemaining(); | ||
}, | ||
|
||
// set all todos as completed | ||
toggleAll: function () { | ||
var complete = this.remaining() === 0 ? false : true; | ||
this.each(function (todo) { | ||
todo.completed(complete); | ||
}); | ||
}, | ||
|
||
// remove all completed todos | ||
clearCompleted: function () { | ||
this.removeAll(function (todo) { | ||
return todo.completed(); | ||
}); | ||
}, | ||
|
||
// saves all data back to the Local Storage | ||
save: function () { | ||
var result = []; | ||
|
||
blocks.each(this(), function (model) { | ||
result.push(model.dataItem()); | ||
}); | ||
|
||
localStorage.setItem('todos-jsblocks', JSON.stringify(result)); | ||
|
||
this.updateRemaining(); | ||
}, | ||
|
||
// updates the observable | ||
updateRemaining: function () { | ||
this.remaining(this.reduce(function (memo, todo) { | ||
return todo.completed() ? memo : memo + 1; | ||
}, 0)); | ||
} | ||
}); | ||
|
||
App.View('Todos', { | ||
options: { | ||
// creates a route for the View in order to handle | ||
// /all, /active, /completed filters | ||
route: blocks.route('{{filter}}').optional('filter') | ||
}, | ||
|
||
filter: blocks.observable(), | ||
|
||
newTodo: new Todo(), | ||
|
||
// holds all todos for the current view | ||
// todos are filtered if "Active" or "Completed" is clicked | ||
todos: new Todos().extend('filter', function (value) { | ||
var mode = this.filter(); | ||
var completed = value.completed(); | ||
var include = true; | ||
|
||
if (mode === 'active') { | ||
include = !completed; | ||
} else if (mode === 'completed') { | ||
include = completed; | ||
} | ||
|
||
return include; | ||
}), | ||
|
||
// filter the data when the route have changed | ||
// the callback is fired when "All", "Active" or "Completed" have been clicked | ||
routed: function (params) { | ||
if (params.filter !== 'active' && params.filter !== 'completed') { | ||
params.filter = 'all'; | ||
} | ||
this.filter(params.filter); | ||
}, | ||
|
||
addTodo: function (e) { | ||
if (e.which === ENTER_KEY && this.newTodo.title()) { | ||
this.todos.push(this.newTodo); | ||
// return all Todo values to their defaults | ||
this.newTodo.reset(); | ||
} | ||
} | ||
}); | ||
})(); |
Oops, something went wrong.