Commit f50d5507 authored by Sam Saccone's avatar Sam Saccone

Merge pull request #1530 from dmethvin/kjs-require

knockoutjs_require: Cancel edits using Escape key
parents 77201888 d9abbdbd
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
<label data-bind="text: title, event: { dblclick: $root.editItem }"></label> <label data-bind="text: title, event: { dblclick: $root.editItem }"></label>
<button class="destroy" data-bind="click: $root.remove"></button> <button class="destroy" data-bind="click: $root.remove"></button>
</div> </div>
<input class="edit" data-bind="value: title, valueUpdate: 'afterkeydown', enterKey: $root.stopEditing, selectAndFocus: editing, event: { blur: $root.stopEditing }"> <input class="edit" data-bind="value: title, valueUpdate: 'afterkeydown', enterKey: $root.stopEditing, escapeKey: $root.cancelEditing, selectAndFocus: editing, event: { blur: $root.stopEditing }">
</li> </li>
</ul> </ul>
</section> </section>
......
...@@ -4,5 +4,6 @@ ...@@ -4,5 +4,6 @@
define({ define({
ENTER_KEY: 13, ENTER_KEY: 13,
ESCAPE_KEY: 27,
localStorageItem: 'todos-knockout-require' localStorageItem: 'todos-knockout-require'
}); });
...@@ -6,30 +6,33 @@ define([ ...@@ -6,30 +6,33 @@ define([
], function (ko, g) { ], function (ko, g) {
'use strict'; 'use strict';
// a custom binding to handle the enter key (could go in a separate library) function keyupBindingFactory(keyCode) {
ko.bindingHandlers.enterKey = { return {
init: function (element, valueAccessor, allBindingsAccessor, data, bindingContext) { init: function (element, valueAccessor, allBindingsAccessor, data, bindingContext) {
var wrappedHandler; var wrappedHandler, newValueAccessor;
var newValueAccessor;
// wrap the handler with a check for the enter key // wrap the handler with a check for the enter key
wrappedHandler = function (data, event) { wrappedHandler = function (data, event) {
if (event.keyCode === g.ENTER_KEY) { if (event.keyCode === keyCode) {
valueAccessor().call(this, data, event); valueAccessor().call(this, data, event);
} }
}; };
// create a valueAccessor with the options that we would want to pass to the event binding // create a valueAccessor with the options that we would want to pass to the event binding
newValueAccessor = function () { newValueAccessor = function () {
return { return {
keyup: wrappedHandler keyup: wrappedHandler
};
}; };
};
// call the real event binding's init function // call the real event binding's init function
ko.bindingHandlers.event.init(element, newValueAccessor, allBindingsAccessor, data, bindingContext); ko.bindingHandlers.event.init(element, newValueAccessor, allBindingsAccessor, data, bindingContext);
} }
}; };
}
ko.bindingHandlers.enterKey = keyupBindingFactory(g.ENTER_KEY);
ko.bindingHandlers.escapeKey = keyupBindingFactory(g.ESCAPE_KEY);
// wrapper to hasfocus that also selects text and applies focus async // wrapper to hasfocus that also selects text and applies focus async
ko.bindingHandlers.selectAndFocus = { ko.bindingHandlers.selectAndFocus = {
......
...@@ -44,6 +44,7 @@ define([ ...@@ -44,6 +44,7 @@ define([
// edit an item // edit an item
self.editItem = function (item) { self.editItem = function (item) {
item.editing(true); item.editing(true);
item.previousTitle = item.title();
}; };
// stop editing an item. Remove the item, if it is now empty // stop editing an item. Remove the item, if it is now empty
...@@ -54,7 +55,7 @@ define([ ...@@ -54,7 +55,7 @@ define([
var trimmedTitle = title.trim(); var trimmedTitle = title.trim();
// Observable value changes are not triggered if they're consisting of whitespaces only // Observable value changes are not triggered if they're consisting of whitespaces only
// Therefore we've to compare untrimmed version with a trimmed one to chech whether anything changed // Therefore, compare untrimmed version with a trimmed one to check whether anything changed
// And if yes, we've to set the new value manually // And if yes, we've to set the new value manually
if (title !== trimmedTitle) { if (title !== trimmedTitle) {
item.title(trimmedTitle); item.title(trimmedTitle);
...@@ -65,6 +66,12 @@ define([ ...@@ -65,6 +66,12 @@ define([
} }
}; };
// cancel editing an item and revert to the previous content
self.cancelEditing = function (item) {
item.editing(false);
item.title(item.previousTitle);
};
// count of all completed todos // count of all completed todos
self.completedCount = ko.computed(function () { self.completedCount = ko.computed(function () {
return ko.utils.arrayFilter(self.todos(), function (todo) { return ko.utils.arrayFilter(self.todos(), function (todo) {
...@@ -99,7 +106,8 @@ define([ ...@@ -99,7 +106,8 @@ define([
// internal computed observable that fires whenever anything changes in our todos // internal computed observable that fires whenever anything changes in our todos
ko.computed(function () { ko.computed(function () {
// store a clean copy to local storage, which also creates a dependency on the observableArray and all observables in each item // 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)); window.localStorage.setItem(g.localStorageItem, ko.toJSON(self.todos));
}).extend({ }).extend({
rateLimit: { timeout: 500, method: 'notifyWhenChangesStop' } rateLimit: { timeout: 500, method: 'notifyWhenChangesStop' }
......
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