Commit c3741e0f authored by Sindre Sorhus's avatar Sindre Sorhus

Knockout: Code style

parent 60406854
/*global ko, crossroads */
(function() {
'use strict';
var ENTER_KEY = 13;
// trim polyfill
if(!String.prototype.trim) {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
};
}
var ENTER_KEY = 13;
// a custom binding to handle the enter key (could go in a separate library)
ko.bindingHandlers.enterKey = {
init: function(element, valueAccessor, allBindingsAccessor, data) {
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 === ENTER_KEY) {
valueAccessor().call(this, data, event);
wrappedHandler = function( data, event ) {
if ( event.keyCode === ENTER_KEY ) {
valueAccessor().call( this, data, event );
}
};
......@@ -29,40 +24,41 @@
};
// call the real event binding's init function
ko.bindingHandlers.event.init(element, newValueAccessor, allBindingsAccessor, data);
ko.bindingHandlers.event.init( element, newValueAccessor, allBindingsAccessor, data );
}
};
// wrapper to hasfocus that also selects text and applies focus async
ko.bindingHandlers.selectAndFocus = {
init: function(element, valueAccessor, allBindingsAccessor) {
ko.bindingHandlers.hasfocus.init(element, valueAccessor, allBindingsAccessor);
ko.utils.registerEventHandler(element, 'focus', function() {
init: function( element, valueAccessor, allBindingsAccessor ) {
ko.bindingHandlers.hasfocus.init( element, valueAccessor, allBindingsAccessor );
ko.utils.registerEventHandler( element, 'focus', function() {
element.select();
});
},
update: function(element, valueAccessor) {
ko.utils.unwrapObservable(valueAccessor()); // for dependency
update: function( element, valueAccessor ) {
ko.utils.unwrapObservable( valueAccessor() ); // for dependency
// ensure that element is visible before trying to focus
setTimeout(function() {
ko.bindingHandlers.hasfocus.update(element, valueAccessor);
ko.bindingHandlers.hasfocus.update( element, valueAccessor );
}, 0);
}
};
// represent a single todo item
var Todo = function(title, completed) {
this.title = ko.observable(title);
this.completed = ko.observable(completed);
this.editing = ko.observable(false);
var Todo = function( title, completed ) {
this.title = ko.observable( title );
this.completed = ko.observable( completed );
this.editing = ko.observable( false );
};
// our main view model
var ViewModel = function(todos) {
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.title, todo.completed);
self.todos = ko.observableArray(ko.utils.arrayMap( todos, function( todo ) {
return new Todo( todo.title, todo.completed );
}));
// store the new todo value being entered
......@@ -71,11 +67,15 @@
self.showMode = ko.observable('all');
self.filteredTodos = ko.computed(function() {
switch(self.showMode()) {
switch( self.showMode() ) {
case 'active':
return self.todos().filter(function(todo) { return !todo.completed(); });
return self.todos().filter(function( todo ) {
return !todo.completed();
});
case 'completed':
return self.todos().filter(function(todo) { return todo.completed(); });
return self.todos().filter(function( todo ) {
return todo.completed();
});
default:
return self.todos();
}
......@@ -84,40 +84,41 @@
// add a new todo, when enter key is pressed
self.add = function() {
var current = self.current().trim();
if(current) {
self.todos.push(new Todo(current));
if ( current ) {
self.todos.push( new Todo( current ) );
self.current('');
}
};
// remove a single todo
self.remove = function(todo) {
self.todos.remove(todo);
self.remove = function( todo ) {
self.todos.remove( todo );
};
// remove all completed todos
self.removeCompleted = function() {
self.todos.remove(function(todo) {
self.todos.remove(function( todo ) {
return todo.completed();
});
};
// edit an item
self.editItem = function(item) {
item.editing(true);
self.editItem = function( item ) {
item.editing( true );
};
// stop editing an item. Remove the item, if it is now empty
self.stopEditing = function(item) {
item.editing(false);
if(!item.title().trim()) {
self.remove(item);
self.stopEditing = function( item ) {
item.editing( false );
if ( !item.title().trim() ) {
self.remove( item );
}
};
// count of all completed todos
self.completedCount = ko.computed(function() {
return ko.utils.arrayFilter(self.todos(), function(todo) {
return ko.utils.arrayFilter( self.todos(), function( todo ) {
return todo.completed();
}).length;
});
......@@ -135,42 +136,50 @@
},
// set all todos to the written value (true/false)
write: function(newValue) {
ko.utils.arrayForEach(self.todos(), function(todo) {
ko.utils.arrayForEach( self.todos(), function( todo ) {
// set even if value is the same, as subscribers are not notified in that case
todo.completed(newValue);
todo.completed( newValue );
});
}
});
// helper function to keep expressions out of markup
self.getLabel = function(count) {
return ko.utils.unwrapObservable(count) === 1 ? 'item' : 'items';
self.getLabel = function( count ) {
return ko.utils.unwrapObservable( count ) === 1 ? 'item' : 'items';
};
// internal computed observable that fires whenever anything changes in our todos
ko.computed(function() {
// store a clean copy to local storage, which also creates a dependency on the observableArray and all observables in each item
localStorage.setItem('todos-knockout', ko.toJSON(self.todos));
localStorage.setItem('todos-knockout', ko.toJSON( self.todos ) );
}).extend({
throttle: 500
}); // save at most twice per second
};
// check local storage for todos
var todos = ko.utils.parseJson(localStorage.getItem('todos-knockout'));
var todos = ko.utils.parseJson( localStorage.getItem('todos-knockout') );
// bind a new instance of our view model to the page
var viewModel = new ViewModel(todos || [])
ko.applyBindings(viewModel);
var viewModel = new ViewModel( todos || [] );
ko.applyBindings( viewModel );
//setup crossroads
crossroads.addRoute('all', function() { viewModel.showMode('all'); });
crossroads.addRoute('active', function() { viewModel.showMode('active'); });
crossroads.addRoute('completed', function() { viewModel.showMode('completed'); });
crossroads.addRoute('all', function() {
viewModel.showMode('all');
});
crossroads.addRoute('active', function() {
viewModel.showMode('active');
});
crossroads.addRoute('completed', function() {
viewModel.showMode('completed');
});
window.onhashchange = function() {
crossroads.parse(location.hash.replace("#", ""));
crossroads.parse( location.hash.replace('#', '') );
};
crossroads.parse(location.hash.replace("#", ""));
})();
\ No newline at end of file
crossroads.parse( location.hash.replace('#', '') );
}());
\ No newline at end of file
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