TodoMVC - Knockout.js
https://github.com/addyosmani/todomvc/tree/master/architecture-examples/knockoutjs
by nkerkin
HTML
<script src="http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-2.0.0.js"></script>
<script src="https://raw.github.com/appendto/amplify/master/store/amplify.store.js"></script>
<script src="https://github.com/douglascrockford/JSON-js/blob/master/json2.js"></script>
<div id="todoapp">
<div class="title">
<h1>Todos</h1>
</div>
<div class="content">
<div id="create-todo">
<input id="new-todo" data-bind="value: current, valueUpdate: 'afterkeydown', enterKey: add" placeholder="What needs to be done?" />
<span class="ui-tooltip-top" data-bind="visible: showTooltip" style="display: none;">Press Enter to save this task</span>
</div>
<div id="todos">
<div data-bind="visible: todos().length">
<input id="check-all" class="check" type="checkbox" data-bind="checked: allCompleted" />
<label for="check-all">Mark all as complete</label>
</div>
<ul id="todo-list" data-bind="foreach: todos">
<li data-bind="css: { editing: editing }">
<div class="todo" data-bind="css: { done : done }">
<div class="display">
<input class="check" type="checkbox" data-bind="checked: done" />
<div class="todo-content" data-bind="text: content, event: { dblclick: edit }" style="cursor: pointer;"></div>
<span class="todo-destroy" data-bind="click: $root.remove"></span>
</div>
<div class="edit">
<input class="todo-input" data-bind="value: content, valueUpdate: 'afterkeydown', enterKey: stopEditing, event: { blur: stopEditing }"/>
</div>
</div>
</li>
</ul>
...
CSS
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-weight: inherit;
font-style: inherit;
font-size: 100%;
font-family: inherit;
vertical-align: baseline;
}
body {
line-height: 1;
color: black;
background: white;
}
ol, ul {
list-style: none;
}
a img {
border: none;
}
html {
background: #eeeeee;
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.4em;
background: #eeeeee;
color: #333333;
}
#todoapp {
width: 480px;
margin: 0 auto 40px;
background: white;
padding: 20px;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
-moz-border-radius: 0 0 5px 5px;
-o-border-radius: 0 0 5px 5px;
-webkit-border-radius: 0 0 5px 5px;
border-radius: 0 0 5px 5px;
}
#todoapp h1 {
font-size: 36px;
font-weight: bold;
text-align: center;
padding: 20px 0 30px 0;
line-height: 1;
}
#create-todo {
position: relative;
}
#create-todo input {
width: 466px;
font-size: 24px;
font-family: inherit;
line-height: 1.4em;
border: 0;
outline: none;
padding: 6px;
border: 1px solid #999999;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-webkit-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;
}
#create-todo input::-webkit-input-placeholder {
font-style: italic;
}
#create-todo span {
...
JavaScript
(function() {
//a custom binding to handle the enter key (could go in a separate library)
ko.bindingHandlers.enterKey = {
init: function(element, valueAccessor, allBindingsAccessor, data) {
var wrappedHandler, newValueAccessor;
//wrap the handler with a check for the enter key
wrappedHandler = function(data, event) {
if (event.keyCode === 13) {
valueAccessor().call(this, data, event);
}
};
//create a valueAccessor with the options that we would want to pass to the event binding
newValueAccessor = function() {
return {
keyup: wrappedHandler
};
};
//call the real event binding's init function
ko.bindingHandlers.event.init(element, newValueAccessor, allBindingsAccessor, data);
}
};
//represent a single todo item
var Todo = function(content, done) {
this.content = ko.observable(content);
this.done = ko.observable(done);
this.editing = ko.observable(false);
};
//can place methods on prototype, as there can be many todos
ko.utils.extend(Todo.prototype, {
edit: function() {
this.editing(true);
},
stopEditing: function() {
this.editing(false);
}
});
//our main view model
var ViewModel = function(todos) {
var self = this;
//map array of passed in todos to an observableArray of Todo objects
self.todos = ko.observableArray(ko.utils.arrayMap(todos, function(todo) {
return new Todo(todo.content, todo.done);
}));
//store the new todo value being entered
self.current = ko.observable();
//add a new todo, when enter key is pressed
self.add = function(data, event) {
var newTodo = new Todo(self.current());
...