TodoMVC - Unobtrusive Knockout.js

Original App: https://github.com/addyosmani/todomvc/tree/master/architecture-examples/knockoutjs Unobtrusive KO: https://gist.github.com/1006808

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="http://ajax.cdnjs.com/ajax/libs/json2/20110223/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-class="newTodo" placeholder="What needs to be done?" />
                <span class="ui-tooltip-top" data-class="taskTooltip" style="display: none;">Press Enter to save this task</span>
            </div>
            <div id="todos">
                <div data-class="checkAllContainer" >
                    <input id="check-all" class="check" type="checkbox" data-class="checkAll" />
                    <label for="check-all">Mark all as complete</label>
                </div>
                <ul id="todo-list" data-class="todos" >
                    <li data-class="todoListItem" >
                        <div class="todo" data-class="todoListItemWrapper" >
                            <div class="display">
                                <input class="check" type="checkbox" data-class="todoCheckBox" />
                                <div class="todo-content" data-class="todoContent" style="cursor: pointer;"></div>
                                <span class="todo-destroy" data-class="todoDestroy"></span>
                            </div>
                            <div class="edit">
                                <input class="todo-input" data-class="todoEdit"/>
                            </div>
                        </div>
                    </li>
                </ul>
            </div>
            <div id="todo-stats">
                <span class="todo-count" data-class="todoCount">
                    <span class="number" data-class="remainingCount"></span>
                    <span...

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() {
    
    //You can now create a bindingProvider that uses something different than data-bind attributes
    ko.customBindingProvider = function(bindingObject) {
        this.bindingObject = bindingObject;
        
        //determine if an element has any bindings
        this.nodeHasBindings = function(node) {
            return node.getAttribute ? node.getAttribute("data-class") : false;
        };
        
        //return the bindings given a node and the bindingContext
        this.getBindings = function(node, bindingContext) {
            var result = {};
            var classes = node.getAttribute("data-class");
            if (classes) {
                classes = classes.split(' ');  
                //evaluate each class, build a single object to return
                for (var i = 0, j = classes.length; i < j; i++) {
                   var bindingAccessor = this.bindingObject[classes[i]];
                   if (bindingAccessor) {
                       var binding = typeof bindingAccessor == "function" ? bindingAccessor.call(bindingContext.$data) : bindingAccessor;
                       ko.utils.extend(result, binding);               
                   }            
                }
            }
        
            return result;
        }; 
    };
    //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:...