Commit cc560c2b authored by TasteBot's avatar TasteBot

update the build files for gh-pages [ci skip]

parent 6f6feff3
......@@ -22,7 +22,7 @@
<label data-bind="text: title, event: { dblclick: $root.editItem }"></label>
<button class="destroy" data-bind="click: $root.remove"></button>
</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>
</ul>
</section>
......
......@@ -4,5 +4,6 @@
define({
ENTER_KEY: 13,
ESCAPE_KEY: 27,
localStorageItem: 'todos-knockout-require'
});
......@@ -6,15 +6,14 @@ define([
], function (ko, g) {
'use strict';
// a custom binding to handle the enter key (could go in a separate library)
ko.bindingHandlers.enterKey = {
function keyupBindingFactory(keyCode) {
return {
init: function (element, valueAccessor, allBindingsAccessor, data, bindingContext) {
var wrappedHandler;
var newValueAccessor;
var wrappedHandler, newValueAccessor;
// wrap the handler with a check for the enter key
wrappedHandler = function (data, event) {
if (event.keyCode === g.ENTER_KEY) {
if (event.keyCode === keyCode) {
valueAccessor().call(this, data, event);
}
};
......@@ -30,6 +29,10 @@ define([
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
ko.bindingHandlers.selectAndFocus = {
......
......@@ -44,6 +44,7 @@ define([
// edit an item
self.editItem = function (item) {
item.editing(true);
item.previousTitle = item.title();
};
// stop editing an item. Remove the item, if it is now empty
......@@ -54,7 +55,7 @@ define([
var trimmedTitle = title.trim();
// 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
if (title !== trimmedTitle) {
item.title(trimmedTitle);
......@@ -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
self.completedCount = ko.computed(function () {
return ko.utils.arrayFilter(self.todos(), function (todo) {
......@@ -99,7 +106,8 @@ define([
// 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
// 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({
rateLimit: { timeout: 500, method: 'notifyWhenChangesStop' }
......
......@@ -26,7 +26,7 @@
<button class="destroy" ng-click="vm.removeTodo(todo)"></button>
</div>
<form ng-submit="vm.doneEditing(todo)">
<input class="edit" ng-model="todo.title" todo-blur="vm.doneEditing(todo)" todo-focus="todo == editedTodo">
<input class="edit" ng-model="todo.title" todo-blur="vm.doneEditing(todo)" todo-focus="todo == editedTodo" todo-escape="vm.revertEdits(todo)">
</form>
</li>
</ul>
......
......@@ -53,6 +53,28 @@ var todos;
})(todos || (todos = {}));
/// <reference path='../_all.ts' />
var todos;
(function (todos) {
'use strict';
var ESCAPE_KEY = 27;
/**
* Directive that cancels editing a todo if the user presses the Esc key.
*/
function todoEscape() {
return {
link: function ($scope, element, attributes) {
element.bind('keydown', function (event) {
if (event.keyCode === ESCAPE_KEY) {
$scope.$apply(attributes.todoEscape);
}
});
$scope.$on('$destroy', function () { element.unbind('keydown'); });
}
};
}
todos.todoEscape = todoEscape;
})(todos || (todos = {}));
/// <reference path='../_all.ts' />
var todos;
(function (todos_1) {
'use strict';
/**
......@@ -125,9 +147,21 @@ var todos;
};
TodoCtrl.prototype.editTodo = function (todoItem) {
this.$scope.editedTodo = todoItem;
// Clone the original todo in case editing is cancelled.
this.$scope.originalTodo = angular.extend({}, todoItem);
};
TodoCtrl.prototype.revertEdits = function (todoItem) {
this.todos[this.todos.indexOf(todoItem)] = this.$scope.originalTodo;
this.$scope.reverted = true;
};
TodoCtrl.prototype.doneEditing = function (todoItem) {
this.$scope.editedTodo = null;
this.$scope.originalTodo = null;
if (this.$scope.reverted) {
// Todo edits were reverted, don't save.
this.$scope.reverted = null;
return;
}
todoItem.title = todoItem.title.trim();
if (!todoItem.title) {
this.removeTodo(todoItem);
......@@ -169,6 +203,7 @@ var todos;
.controller('todoCtrl', todos.TodoCtrl)
.directive('todoBlur', todos.todoBlur)
.directive('todoFocus', todos.todoFocus)
.directive('todoEscape', todos.todoEscape)
.service('todoStorage', todos.TodoStorage);
})(todos || (todos = {}));
/// <reference path='libs/jquery/jquery.d.ts' />
......@@ -178,6 +213,7 @@ var todos;
/// <reference path='interfaces/ITodoStorage.ts' />
/// <reference path='directives/TodoFocus.ts' />
/// <reference path='directives/TodoBlur.ts' />
/// <reference path='directives/TodoEscape.ts' />
/// <reference path='services/TodoStorage.ts' />
/// <reference path='controllers/TodoCtrl.ts' />
/// <reference path='Application.ts' />
......
......@@ -12,5 +12,6 @@ module todos {
.controller('todoCtrl', TodoCtrl)
.directive('todoBlur', todoBlur)
.directive('todoFocus', todoFocus)
.directive('todoEscape', todoEscape)
.service('todoStorage', TodoStorage);
}
......@@ -5,6 +5,7 @@
/// <reference path='interfaces/ITodoStorage.ts' />
/// <reference path='directives/TodoFocus.ts' />
/// <reference path='directives/TodoBlur.ts' />
/// <reference path='directives/TodoEscape.ts' />
/// <reference path='services/TodoStorage.ts' />
/// <reference path='controllers/TodoCtrl.ts' />
/// <reference path='Application.ts' />
/// <reference path='../_all.ts' />
var todos;
(function (todos) {
'use strict';
/**
* The main controller for the app. The controller:
* - retrieves and persists the model via the todoStorage service
* - exposes the model to the template and provides event handlers
*/
var TodoCtrl = (function () {
// dependencies are injected via AngularJS $injector
// controller's name is registered in Application.ts and specified from ng-controller attribute in index.html
function TodoCtrl($scope, $location, todoStorage, filterFilter) {
var _this = this;
this.$scope = $scope;
this.$location = $location;
this.todoStorage = todoStorage;
this.filterFilter = filterFilter;
this.todos = $scope.todos = todoStorage.get();
$scope.newTodo = '';
$scope.editedTodo = null;
// 'vm' stands for 'view model'. We're adding a reference to the controller to the scope
// for its methods to be accessible from view / HTML
$scope.vm = this;
// watching for events/changes in scope, which are caused by view/user input
// if you subscribe to scope or event with lifetime longer than this controller, make sure you unsubscribe.
$scope.$watch('todos', function () {
return _this.onTodos();
}, true);
$scope.$watch('location.path()', function (path) {
return _this.onPath(path);
});
if ($location.path() === '')
$location.path('/');
$scope.location = $location;
}
TodoCtrl.prototype.onPath = function (path) {
this.$scope.statusFilter = (path === '/active') ? { completed: false } : (path === '/completed') ? { completed: true } : null;
};
TodoCtrl.prototype.onTodos = function () {
this.$scope.remainingCount = this.filterFilter(this.todos, { completed: false }).length;
this.$scope.doneCount = this.todos.length - this.$scope.remainingCount;
this.$scope.allChecked = !this.$scope.remainingCount;
this.todoStorage.put(this.todos);
};
TodoCtrl.prototype.addTodo = function () {
if (!this.$scope.newTodo.length) {
return;
}
this.todos.push(new todos.TodoItem(this.$scope.newTodo, false));
this.$scope.newTodo = '';
};
TodoCtrl.prototype.editTodo = function (todoItem) {
this.$scope.editedTodo = todoItem;
};
TodoCtrl.prototype.doneEditing = function (todoItem) {
this.$scope.editedTodo = null;
if (!todoItem.title) {
this.removeTodo(todoItem);
}
};
TodoCtrl.prototype.removeTodo = function (todoItem) {
this.todos.splice(this.todos.indexOf(todoItem), 1);
};
TodoCtrl.prototype.clearDoneTodos = function () {
this.$scope.todos = this.todos = this.todos.filter(function (todoItem) {
return !todoItem.completed;
});
};
TodoCtrl.prototype.markAll = function (completed) {
this.todos.forEach(function (todoItem) {
todoItem.completed = completed;
});
};
TodoCtrl.$inject = [
'$scope',
'$location',
'todoStorage',
'filterFilter'
];
return TodoCtrl;
})();
todos.TodoCtrl = TodoCtrl;
})(todos || (todos = {}));
......@@ -74,10 +74,24 @@ module todos {
editTodo(todoItem: TodoItem) {
this.$scope.editedTodo = todoItem;
// Clone the original todo in case editing is cancelled.
this.$scope.originalTodo = angular.extend({}, todoItem);
}
revertEdits(todoItem: TodoItem) {
this.todos[this.todos.indexOf(todoItem)] = this.$scope.originalTodo;
this.$scope.reverted = true;
}
doneEditing(todoItem: TodoItem) {
this.$scope.editedTodo = null;
this.$scope.originalTodo = null;
if (this.$scope.reverted) {
// Todo edits were reverted, don't save.
this.$scope.reverted = null;
return;
}
todoItem.title = todoItem.title.trim();
if (!todoItem.title) {
this.removeTodo(todoItem);
......
/// <reference path='../_all.ts' />
var todos;
(function (todos) {
'use strict';
/**
* Directive that executes an expression when the element it is applied to loses focus.
*/
function todoBlur() {
return {
link: function ($scope, element, attributes) {
element.bind('blur', function () {
$scope.$apply(attributes.todoBlur);
});
}
};
}
todos.todoBlur = todoBlur;
})(todos || (todos = {}));
/// <reference path='../_all.ts' />
module todos {
'use strict';
const ESCAPE_KEY = 27;
/**
* Directive that cancels editing a todo if the user presses the Esc key.
*/
export function todoEscape(): ng.IDirective {
return {
link: ($scope: ng.IScope, element: JQuery, attributes: any) => {
element.bind('keydown', (event) => {
if (event.keyCode === ESCAPE_KEY) {
$scope.$apply(attributes.todoEscape);
}
});
$scope.$on('$destroy', () => { element.unbind('keydown'); });
}
};
}
}
/// <reference path='../_all.ts' />
var todos;
(function (todos) {
'use strict';
/**
* Directive that places focus on the element it is applied to when the expression it binds to evaluates to true.
*/
function todoFocus($timeout) {
return {
link: function ($scope, element, attributes) {
$scope.$watch(attributes.todoFocus, function (newval) {
if (newval) {
$timeout(function () {
return element[0].focus();
}, 0, false);
}
});
}
};
}
todos.todoFocus = todoFocus;
todoFocus.$inject = ['$timeout'];
})(todos || (todos = {}));
......@@ -5,9 +5,11 @@ module todos {
todos: TodoItem[];
newTodo: string;
editedTodo: TodoItem;
originalTodo: TodoItem;
remainingCount: number;
doneCount: number;
allChecked: boolean;
reverted: boolean;
statusFilter: { completed: boolean; };
location: ng.ILocationService;
vm: TodoCtrl;
......
/// <reference path='../_all.ts' />
var todos;
(function (todos) {
'use strict';
var TodoItem = (function () {
function TodoItem(title, completed) {
this.title = title;
this.completed = completed;
}
return TodoItem;
})();
todos.TodoItem = TodoItem;
})(todos || (todos = {}));
/// <reference path='../_all.ts' />
var todos;
(function (todos) {
'use strict';
/**
* Services that persists and retrieves TODOs from localStorage.
*/
var TodoStorage = (function () {
function TodoStorage() {
this.STORAGE_ID = 'todos-angularjs-typescript';
}
TodoStorage.prototype.get = function () {
return JSON.parse(localStorage.getItem(this.STORAGE_ID) || '[]');
};
TodoStorage.prototype.put = function (todos) {
localStorage.setItem(this.STORAGE_ID, JSON.stringify(todos));
};
return TodoStorage;
})();
todos.TodoStorage = TodoStorage;
})(todos || (todos = {}));
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