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
1 parent
27850ea
commit fcc5981
Showing
7 changed files
with
178 additions
and
173 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
6 changes: 4 additions & 2 deletions
6
labs/dependency-examples/knockoutjs_require/js/config/global.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 |
---|---|---|
@@ -1,6 +1,8 @@ | ||
/*global define */ | ||
|
||
// Author: Loïc Knuchel <loicknuchel@gmail.com> | ||
|
||
define({ | ||
ENTER_KEY: 13, | ||
localStorageItem: 'todos-knockout-require' | ||
ENTER_KEY: 13, | ||
localStorageItem: 'todos-knockout-require' | ||
}); |
84 changes: 44 additions & 40 deletions
84
labs/dependency-examples/knockoutjs_require/js/extends/handlers.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 |
---|---|---|
@@ -1,46 +1,50 @@ | ||
/*global define */ | ||
|
||
define([ | ||
'knockout', | ||
'config/global' | ||
], function(ko, g){ | ||
'use strict'; | ||
// 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; | ||
'knockout', | ||
'config/global' | ||
], function (ko, g) { | ||
'use strict'; | ||
|
||
// 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; | ||
var newValueAccessor; | ||
|
||
// wrap the handler with a check for the enter key | ||
wrappedHandler = function( data, event ) { | ||
if ( event.keyCode === g.ENTER_KEY ) { | ||
valueAccessor().call( this, data, event ); | ||
} | ||
}; | ||
// wrap the handler with a check for the enter key | ||
wrappedHandler = function (data, event) { | ||
if (event.keyCode === g.ENTER_KEY) { | ||
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 | ||
}; | ||
}; | ||
// 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 ); | ||
} | ||
}; | ||
// call the real event binding's init function | ||
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() { | ||
element.focus(); | ||
} ); | ||
}, | ||
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 ); | ||
}, 0 ); | ||
} | ||
}; | ||
// 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 () { | ||
element.focus(); | ||
}); | ||
}, | ||
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); | ||
}, 0); | ||
} | ||
}; | ||
}); |
9 changes: 0 additions & 9 deletions
9
labs/dependency-examples/knockoutjs_require/js/extends/native.js
This file was deleted.
Oops, something went wrong.
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 |
---|---|---|
@@ -1,24 +1,26 @@ | ||
/*global require, window */ | ||
|
||
// Author: Loïc Knuchel <loicknuchel@gmail.com> | ||
|
||
// Require.js allows us to configure shortcut alias | ||
require.config({ | ||
paths: { | ||
knockout: '../bower_components/knockout.js/knockout' | ||
} | ||
paths: { | ||
knockout: '../bower_components/knockout.js/knockout' | ||
} | ||
}); | ||
|
||
require([ | ||
'knockout', | ||
'config/global', | ||
'viewmodels/todo', | ||
'extends/handlers', | ||
'extends/native' | ||
], function(ko, g, TodoViewModel){ | ||
'use strict'; | ||
// var app_view = new AppView(); | ||
// check local storage for todos | ||
var todos = ko.utils.parseJson( localStorage.getItem( g.localStorageItem ) ); | ||
'knockout', | ||
'config/global', | ||
'viewmodels/todo', | ||
'extends/handlers' | ||
], function (ko, g, TodoViewModel) { | ||
'use strict'; | ||
|
||
// var app_view = new AppView(); | ||
// check local storage for todos | ||
var todos = ko.utils.parseJson(window.localStorage.getItem(g.localStorageItem)); | ||
|
||
// bind a new instance of our view model to the page | ||
ko.applyBindings( new TodoViewModel( todos || [] ) ); | ||
// bind a new instance of our view model to the page | ||
ko.applyBindings(new TodoViewModel(todos || [])); | ||
}); |
24 changes: 14 additions & 10 deletions
24
labs/dependency-examples/knockoutjs_require/js/models/Todo.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 |
---|---|---|
@@ -1,12 +1,16 @@ | ||
/*global define */ | ||
|
||
define([ | ||
'knockout' | ||
], function(ko){ | ||
'use strict'; | ||
// 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 ); | ||
}; | ||
return Todo; | ||
'knockout' | ||
], function (ko) { | ||
'use strict'; | ||
|
||
// 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); | ||
}; | ||
|
||
return Todo; | ||
}); |
193 changes: 98 additions & 95 deletions
193
labs/dependency-examples/knockoutjs_require/js/viewmodels/todo.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 |
---|---|---|
@@ -1,97 +1,100 @@ | ||
/*global define, window */ | ||
|
||
define([ | ||
'knockout', | ||
'config/global', | ||
'models/Todo' | ||
], function(ko, g, Todo){ | ||
'use strict'; | ||
// 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.title, todo.completed ); | ||
})); | ||
|
||
// store the new todo value being entered | ||
self.current = ko.observable(); | ||
|
||
|
||
|
||
// 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 ) ); | ||
self.current( '' ); | ||
} | ||
}; | ||
|
||
// remove a single todo | ||
self.remove = function( todo ) { | ||
self.todos.remove( todo ); | ||
}; | ||
|
||
// remove all completed todos | ||
self.removeCompleted = function() { | ||
self.todos.remove(function( todo ) { | ||
return todo.completed(); | ||
}); | ||
}; | ||
|
||
// edit an item | ||
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 ); | ||
} | ||
}; | ||
|
||
// count of all completed todos | ||
self.completedCount = ko.computed(function() { | ||
return ko.utils.arrayFilter( self.todos(), function(todo) { | ||
return todo.completed(); | ||
} ).length; | ||
}); | ||
|
||
// count of todos that are not complete | ||
self.remainingCount = ko.computed(function() { | ||
return self.todos().length - self.completedCount(); | ||
}); | ||
|
||
// writeable computed observable to handle marking all complete/incomplete | ||
self.allCompleted = ko.computed({ | ||
//always return true/false based on the done flag of all todos | ||
read: function() { | ||
return !self.remainingCount(); | ||
}, | ||
// set all todos to the written value (true/false) | ||
write: function( newValue ) { | ||
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 ); | ||
}); | ||
} | ||
}); | ||
|
||
// helper function to keep expressions out of markup | ||
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( g.localStorageItem, ko.toJSON( self.todos ) ); | ||
}).extend({ | ||
throttle: 500 | ||
}); // save at most twice per second | ||
|
||
}; | ||
return ViewModel; | ||
'knockout', | ||
'config/global', | ||
'models/Todo' | ||
], function (ko, g, Todo) { | ||
'use strict'; | ||
|
||
// 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.title, todo.completed); | ||
})); | ||
|
||
// store the new todo value being entered | ||
self.current = ko.observable(); | ||
|
||
// 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)); | ||
self.current(''); | ||
} | ||
}; | ||
|
||
// remove a single todo | ||
self.remove = function (todo) { | ||
self.todos.remove(todo); | ||
}; | ||
|
||
// remove all completed todos | ||
self.removeCompleted = function () { | ||
self.todos.remove(function (todo) { | ||
return todo.completed(); | ||
}); | ||
}; | ||
|
||
// edit an item | ||
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); | ||
} | ||
}; | ||
|
||
// count of all completed todos | ||
self.completedCount = ko.computed(function () { | ||
return ko.utils.arrayFilter(self.todos(), function (todo) { | ||
return todo.completed(); | ||
}).length; | ||
}); | ||
|
||
// count of todos that are not complete | ||
self.remainingCount = ko.computed(function () { | ||
return self.todos().length - self.completedCount(); | ||
}); | ||
|
||
// writeable computed observable to handle marking all complete/incomplete | ||
self.allCompleted = ko.computed({ | ||
//always return true/false based on the done flag of all todos | ||
read: function () { | ||
return !self.remainingCount(); | ||
}, | ||
// set all todos to the written value (true/false) | ||
write: function (newValue) { | ||
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); | ||
}); | ||
} | ||
}); | ||
|
||
// helper function to keep expressions out of markup | ||
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 | ||
window.localStorage.setItem(g.localStorageItem, ko.toJSON(self.todos)); | ||
}).extend({ | ||
throttle: 500 | ||
}); // save at most twice per second | ||
}; | ||
|
||
return ViewModel; | ||
}); |