Commit f0b82920 authored by Pavel Savara's avatar Pavel Savara

processed feedback, improved dependency injection

parent 949463d8
*.suo
*.user
*.map
/bin
/obj
\ No newline at end of file
TypeScript
http://go.microsoft.com/fwlink/?LinkID=266563
http://visualstudiogallery.msdn.microsoft.com/07d54d12-7133-4e15-becb-6f451ea3bea6
# TypeScript + AngularJS #
NodeJs http://nodejs.org/
## Motivation ##
[Typescript](http://www.typescriptlang.org/)
is superset of JavaScript, with optional type annotations.
As any JS is valid TS, there is no interoperability issue.
You could slowly convert existing JS codebase and use JS libraries natively.
You already know most of the langulage.
It compiles back to JS.
It's attractive to people with strongly typed languages background,
who are willing to pay with more ceremony while coding.
Receiving benefit of type checking on compile time.
Also intellisense works better.
Generally recommended for large projects.
## Editors ##
Editor for TypeScript is at the moment Visual Studio 2012 with
[TypeScript](http://go.microsoft.com/fwlink/?LinkID=266563) and
[Web Essentials 2012](http://visualstudiogallery.msdn.microsoft.com/07d54d12-7133-4e15-becb-6f451ea3bea6) plugins.
[Webstorm is comming soon](http://joeriks.com/2012/11/20/a-first-look-at-the-typescript-support-in-webstorm-6-eap/).
## Node.js ##
standalone compiler is available as Node.js package.
```
npm install -g typescript
```
To compile the TS code in this project run in this directory
```
tsc -sourcemap js/_all.ts
```
## Ambient declarations ##
It is useful to have type information for API of libraries you use. Nice collection is by [Boris Yankov](https://github.com/borisyankov/DefinitelyTyped)
It's used for AngularJS interface definitions in this project.
## Files ##
All .ts are source code.
All .js files are generated by compiler, except files in js/libs folder.
All .d.ts are ambient declarations for libraries.
File _all.ts is used to enumerate add files in the project for benefit of TypeScript compiler.
If number of files grows, you could put _all.ts file into each folder, move all nested references to it and reference nested _all.ts from parent _all.ts.
Start reading TodoCtrl.ts first and continue with Application.ts and Index.html, rest of it is easy.
AngularJS knowledge is steeper learning curve than TypeScript.
## AngularJS ##
There is very litte difference between this project and AngularJS TODO, in the way how AngularJS is used.
Only significant difference is, that dependency injection is done via annotated constructors, which allows minification of javascript.
run compileTs.cmd
It's definitely possible to convert vanillajs TODO into TypeScript,
but demonstration TypeScript's benefit is clearer with full blown framework and project structure.
I used https://github.com/borisyankov/DefinitelyTyped for Angular and JQuery interface definitions.
\ No newline at end of file
AngularJS documentation and tutorials are worth reading in detail.
\ No newline at end of file
@echo off
tsc -sourcemap js/_all.ts
\ No newline at end of file
......@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>AngularJS - TodoMVC</title>
<title>AngularJS + Typescript - TodoMVC</title>
<link rel="stylesheet" href="../../../assets/base.css">
<style>[ng-cloak] {display: none}</style>
<!--[if IE]>
......@@ -58,16 +58,18 @@
<p>Credits:
<a href="http://twitter.com/cburgdorf">Christoph Burgdorf</a>,
<a href="http://ericbidelman.com">Eric Bidelman</a>,
<a href="http://jacobmumm.com">Jacob Mumm</a> and
<a href="http://igorminar.com">Igor Minar</a>
<a href="http://jacobmumm.com">Jacob Mumm</a>
<a href="http://igorminar.com">Igor Minar</a> and
<a href="http://zamboch.blogspot.com">Pavel Savara</a>
</p>
</footer>
<script src="../../../assets/base.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
<script src="js/libs/angular/angular.min.js"></script>
<script src="js/models/TodoItem.js"></script>
<script src="js/controllers/TodoCtrl.js"></script>
<script src="js/services/TodoStorage.js"></script>
<script src="js/directives/TodoFocus.js"></script>
<script src="js/directives/TodoBlur.js"></script>
<script src="js/app.js"></script>
<script src="js/Application.js"></script>
</body>
</html>
var todos;
(function (todos) {
'use strict';
var todomvc = angular.module('todomvc', []).controller('todoCtrl', todos.TodoCtrl.prototype.injection()).directive('todoBlur', todos.TodoBlur.prototype.injection()).directive('todoFocus', todos.TodoFocus.prototype.injection()).service('todoStorage', todos.TodoStorage.prototype.injection());
})(todos || (todos = {}));
//@ sourceMappingURL=Application.js.map
{"version":3,"file":"Application.js","sources":["Application.ts"],"names":["todos"],"mappings":"AAAA,IAOO,KAAK;AAQX,CARD,UAAO,KAAK;IACRA,YAAaA;IAEbA,IAAIA,OAAOA,GAAGA,OAAOA,CAACA,MAAMA,CAACA,SAASA,EAAEA,EAAEA,CAACA,CAClCA,UAAUA,CAACA,UAAUA,EAAEA,cAAQA,CAACA,SAASA,CAACA,SAASA,EAAEA,CAACA,CACtDA,SAASA,CAACA,UAAUA,EAAEA,cAAQA,CAACA,SAASA,CAACA,SAASA,EAAEA,CAACA,CACrDA,SAASA,CAACA,WAAWA,EAAEA,eAASA,CAACA,SAASA,CAACA,SAASA,EAAEA,CAACA,CACvDA,OAAOA,CAACA,aAAaA,EAAEA,iBAAWA,CAACA,SAASA,CAACA,SAASA,EAAEA,CAACA,CAACA;AACvEA,CAACA;AAAA"}
\ No newline at end of file
/// <reference path='_all.ts' />
/**
* The main TodoMVC app module.
*
* @type {angular.Module}
*/
module todos {
'use strict';
var todomvc = angular.module('todomvc', [])
.controller('todoCtrl', TodoCtrl.prototype.injection())
.directive('todoBlur', TodoBlur.prototype.injection())
.directive('todoFocus', TodoFocus.prototype.injection())
.service('todoStorage', TodoStorage.prototype.injection());
}
\ No newline at end of file
/// <reference path='app.ts' />
/// <reference path='models/TodoItem.js' />
/// <reference path='interfaces/ITodoScope.js' />
/// <reference path='interfaces/ITodoStorage.js' />
/// <reference path='libs/jquery-1.8.d.ts' />
/// <reference path='libs/angular-1.0.d.ts' />
/// <reference path='models/TodoItem.ts' />
/// <reference path='interfaces/ITodoScope.ts' />
/// <reference path='interfaces/ITodoStorage.ts' />
/// <reference path='directives/TodoFocus.ts' />
/// <reference path='directives/TodoBlur.ts' />
/// <reference path='services/TodoStorage.ts' />
/// <reference path='controllers/TodoCtrl.ts' />
/// <reference path='Application.ts' />
'use strict';
var todomvc = angular.module('todomvc', []).controller('todoCtrl', TodoCtrl).directive('todoBlur', function () {
return new TodoBlur();
}).directive('todoFocus', function ($timeout) {
return new TodoFocus($timeout);
}).service('todoStorage', TodoStorage);
//@ sourceMappingURL=app.js.map
/// <reference path='libs/angular-1.0.d.ts' />
/// <reference path='directives/TodoFocus.ts' />
/// <reference path='directives/TodoBlur.ts' />
/// <reference path='controllers/TodoCtrl.ts' />
/// <reference path='services/TodoStorage.ts' />
'use strict';
/**
* The main TodoMVC app module.
*
* @type {angular.Module}
*/
var todomvc = angular.module('todomvc', [])
.controller('todoCtrl', TodoCtrl)
.directive('todoBlur', () => { return new TodoBlur(); })
.directive('todoFocus', ($timeout: ng.ITimeoutService) => { return new TodoFocus($timeout); })
.service('todoStorage', TodoStorage)
;
'use strict';
var TodoCtrl = (function () {
function TodoCtrl($scope, $location, todoStorage, filterFilter) {
this.$scope = $scope;
this.todoStorage = todoStorage;
this.filterFilter = filterFilter;
var _this = this;
this.todos = $scope.todos = todoStorage.get();
$scope.newTodo = "";
$scope.editedTodo = null;
$scope.addTodo = function () {
return _this.addTodo();
var todos;
(function (todos) {
'use strict';
var TodoCtrl = (function () {
function TodoCtrl($scope, $location, todoStorage, filterFilter) {
this.$scope = $scope;
this.$location = $location;
this.todoStorage = todoStorage;
this.filterFilter = filterFilter;
var _this = this;
this.todos = $scope.todos = todoStorage.get();
$scope.newTodo = '';
$scope.editedTodo = null;
$scope.addTodo = function () {
return _this.addTodo();
};
$scope.editTodo = function (todoItem) {
return _this.editTodo(todoItem);
};
$scope.doneEditing = function (todoItem) {
return _this.doneEditing(todoItem);
};
$scope.removeTodo = function (todoItem) {
return _this.removeTodo(todoItem);
};
$scope.clearDoneTodos = function () {
return _this.clearDoneTodos();
};
$scope.markAll = function (done) {
return _this.markAll(done);
};
$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.injection = function () {
return [
'$scope',
'$location',
'todoStorage',
'filterFilter',
TodoCtrl
];
};
$scope.editTodo = function (t) {
return _this.editTodo(t);
TodoCtrl.prototype.onPath = function (path) {
this.$scope.statusFilter = (path == '/active') ? {
completed: false
} : (path == '/completed') ? {
completed: true
} : null;
};
$scope.doneEditing = function (t) {
return _this.doneEditing(t);
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);
};
$scope.removeTodo = function (t) {
return _this.removeTodo(t);
TodoCtrl.prototype.addTodo = function () {
if(!this.$scope.newTodo.length) {
return;
}
this.todos.push(new todos.TodoItem(this.$scope.newTodo, false));
this.$scope.newTodo = '';
};
$scope.clearDoneTodos = function () {
return _this.clearDoneTodos();
TodoCtrl.prototype.editTodo = function (todoItem) {
this.$scope.editedTodo = todoItem;
};
$scope.markAll = function (d) {
return _this.markAll(d);
TodoCtrl.prototype.doneEditing = function (todoItem) {
this.$scope.editedTodo = null;
if(!todoItem.title) {
this.$scope.removeTodo(todoItem);
}
};
$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({
title: this.$scope.newTodo,
completed: false
});
this.$scope.newTodo = '';
};
TodoCtrl.prototype.editTodo = function (todo) {
this.$scope.editedTodo = todo;
};
TodoCtrl.prototype.doneEditing = function (todo) {
this.$scope.editedTodo = null;
if(!todo.title) {
this.$scope.removeTodo(todo);
}
};
TodoCtrl.prototype.removeTodo = function (todo) {
this.todos.splice(this.todos.indexOf(todo), 1);
};
TodoCtrl.prototype.clearDoneTodos = function () {
this.$scope.todos = this.todos = this.todos.filter(function (val) {
return !val.completed;
});
};
TodoCtrl.prototype.markAll = function (done) {
this.todos.forEach(function (todo) {
todo.completed = done;
});
};
return TodoCtrl;
})();
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 (done) {
this.todos.forEach(function (todoItem) {
todoItem.completed = done;
});
};
return TodoCtrl;
})();
todos.TodoCtrl = TodoCtrl;
})(todos || (todos = {}));
//@ sourceMappingURL=TodoCtrl.js.map
{"version":3,"file":"TodoCtrl.js","sources":["TodoCtrl.ts"],"names":["todos","todos.TodoCtrl","todos.TodoCtrl.constructor","todos.TodoCtrl.constructor.addTodo","todos.TodoCtrl.constructor.editTodo","todos.TodoCtrl.constructor.doneEditing","todos.TodoCtrl.constructor.removeTodo","todos.TodoCtrl.constructor.clearDoneTodos","todos.TodoCtrl.constructor.markAll","","","todos.TodoCtrl.injection","todos.TodoCtrl.onPath","todos.TodoCtrl.onTodos","todos.TodoCtrl.addTodo","todos.TodoCtrl.editTodo","todos.TodoCtrl.doneEditing","todos.TodoCtrl.removeTodo","todos.TodoCtrl.clearDoneTodos","","todos.TodoCtrl.markAll",""],"mappings":"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"}
\ No newline at end of file
/// <reference path='../libs/angular-1.0.d.ts' />
/// <reference path='../services/TodoStorage.ts' />
/// <reference path='../models/TodoItem.ts' />
/// <reference path='../interfaces/ITodoStorage.ts' />
/// <reference path='../interfaces/ITodoScope.ts' />
'use strict';
/**
* The main controller for the app. The controller:
* - retrieves and persist the model via the todoStorage service
* - exposes the model to the template and provides event handlers
*/
class TodoCtrl {
private todos;
constructor(private $scope: ITodoScope, $location: ng.ILocationService, private todoStorage: ITodoStorage, private filterFilter) {
this.todos = $scope.todos = todoStorage.get();
$scope.newTodo = "";
$scope.editedTodo = null;
$scope.addTodo = () => this.addTodo();
$scope.editTodo = (t) => this.editTodo(t);
$scope.doneEditing = (t) => this.doneEditing(t);
$scope.removeTodo = (t) => this.removeTodo(t);
$scope.clearDoneTodos = () => this.clearDoneTodos();
$scope.markAll = (d) => this.markAll(d);
$scope.$watch('todos', () => this.onTodos(), true);
$scope.$watch('location.path()', (path) => this.onPath(path));
if ($location.path() === '') $location.path('/');
$scope.location = $location;
}
onPath(path) {
this.$scope.statusFilter = (path == '/active') ?
{ completed: false } : (path == '/completed') ?
{ completed: true } : null;
}
onTodos() {
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);
}
addTodo() {
if (!this.$scope.newTodo.length) {
return;
/// <reference path='../_all.ts' />
module todos {
'use strict';
/**
* The main controller for the app. The controller:
* - retrieves and persist the model via the todoStorage service
* - exposes the model to the template and provides event handlers
*/
export class TodoCtrl {
private todos: TodoItem[];
// this method is called on prototype during registration into IoC container.
// It provides $injector with information about dependencies to be injected into constructor
// it is better to have it close to the constructor, because the parameters must match in count and type.
public injection(): any[] {
return [
'$scope',
'$location',
'todoStorage',
'filterFilter',
TodoCtrl
]
}
this.todos.push({
title: this.$scope.newTodo,
completed: false
});
this.$scope.newTodo = '';
};
editTodo(todo: TodoItem) {
this.$scope.editedTodo = todo;
};
doneEditing(todo: TodoItem) {
this.$scope.editedTodo = null;
if (!todo.title) {
this.$scope.removeTodo(todo);
// dependencies are injected via AngularJS $injector
// controller's name is registered in App.ts and invoked from ng-controller attribute in index.html
constructor(
private $scope: ITodoScope,
private $location: ng.ILocationService,
private todoStorage: ITodoStorage,
private filterFilter
) {
this.todos = $scope.todos = todoStorage.get();
$scope.newTodo = '';
$scope.editedTodo = null;
// adding event handlers to the scope, so they could be bound from view/HTML
// these lambdas fix this keyword in JS world
$scope.addTodo = () => this.addTodo();
$scope.editTodo = (todoItem) => this.editTodo(todoItem);
$scope.doneEditing = (todoItem) => this.doneEditing(todoItem);
$scope.removeTodo = (todoItem) => this.removeTodo(todoItem);
$scope.clearDoneTodos = () => this.clearDoneTodos();
$scope.markAll = (done) => this.markAll(done);
// 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', () => this.onTodos(), true);
$scope.$watch('location.path()', (path) => this.onPath(path))
if ($location.path() === '') $location.path('/');
$scope.location = $location;
}
};
removeTodo(todo: TodoItem) {
this.todos.splice(this.todos.indexOf(todo), 1);
};
onPath(path: string) {
this.$scope.statusFilter =
(path == '/active')
? { completed: false }
: (path == '/completed')
? { completed: true }
: null;
}
clearDoneTodos() {
this.$scope.todos = this.todos = this.todos.filter((val) => {
return !val.completed;
});
};
onTodos() {
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);
}
markAll(done: bool) {
this.todos.forEach((todo: TodoItem) => {
todo.completed = done;
});
};
}
addTodo() {
if (!this.$scope.newTodo.length) {
return;
}
this.todos.push(new TodoItem(this.$scope.newTodo, false));
this.$scope.newTodo = '';
};
editTodo(todoItem: TodoItem) {
this.$scope.editedTodo = todoItem;
};
doneEditing(todoItem: TodoItem) {
this.$scope.editedTodo = null;
if (!todoItem.title) {
this.$scope.removeTodo(todoItem);
}
};
removeTodo(todoItem: TodoItem) {
this.todos.splice(this.todos.indexOf(todoItem), 1);
};
clearDoneTodos() {
this.$scope.todos = this.todos = this.todos.filter((todoItem) => {
return !todoItem.completed;
});
};
markAll(done: bool) {
this.todos.forEach((todoItem: TodoItem) => {
todoItem.completed = done;
});
};
}
}
\ No newline at end of file
'use strict';
var TodoBlur = (function () {
function TodoBlur() {
var _this = this;
this.link = function (s, e, a) {
return _this.linkFn(s, e, a);
var todos;
(function (todos) {
'use strict';
var TodoBlur = (function () {
function TodoBlur() {
var _this = this;
this.link = function ($scope, element, attributes) {
return _this.linkFn($scope, element, attributes);
};
}
TodoBlur.prototype.injection = function () {
return [
function () {
return new TodoBlur();
} ];
};
}
TodoBlur.prototype.linkFn = function ($scope, elem, attrs) {
elem.bind('blur', function () {
$scope.$apply(attrs.todoBlur);
});
};
return TodoBlur;
})();
TodoBlur.prototype.linkFn = function ($scope, element, attributes) {
element.bind('blur', function () {
$scope.$apply(attributes.todoBlur);
});
};
return TodoBlur;
})();
todos.TodoBlur = TodoBlur;
})(todos || (todos = {}));
//@ sourceMappingURL=TodoBlur.js.map
{"version":3,"file":"TodoBlur.js","sources":["TodoBlur.ts"],"names":["todos","todos.TodoBlur","todos.TodoBlur.constructor","todos.TodoBlur.constructor.link","todos.TodoBlur.injection","","todos.TodoBlur.linkFn",""],"mappings":"AAAA,IAEO,KAAK;AAyBX,CAzBD,UAAO,KAAK;IACRA,YAAaA;IAKbA;QASIC,SATSA,QAAQA;YASjBC,iBAECA;YADGA,IAAIA,CAACA,IAAIA,GAAGA,UAACA,MAAMA,EAAEA,OAAOA,EAAEA,UAAWA;gBAAIC,OAAAA,KAAIA,CAACA,MAAMA,CAACA,MAAMA,EAAEA,OAAOA,EAAEA,UAAUA,CAACA,CAAAA;YAAxCA,CAAwCA;QACzFD,CAACA;QARDD,+BAAAA;YACIG,OAAOA;gBACHA;oBAAQC,OAAOA,IAAIA,QAAQA,EAAEA,CAACA;gBAACA,CAACA,aACnCD,CAAAA;QACLA,CAACA;QAMDH,4BAAAA,UAAOA,MAAiBA,EAAEA,OAAeA,EAAEA,UAAeA;YACtDK,OAAOA,CAACA,IAAIA,CAACA,MAAMA,EAAEA;gBACjBC,MAAMA,CAACA,MAAMA,CAACA,UAAUA,CAACA,QAAQA,CAACA;YACtCA,CAACA,CAACD;QACNA,CAACA;QACLL;AAACA,IAADA,CAACA,IAAAD;IAlBDA,0BAkBCA,IAAAA;AACLA,CAACA;AAAA"}
\ No newline at end of file
/// <reference path='../libs/angular-1.0.d.ts' />
'use strict';
/// <reference path='../_all.ts' />
module todos {
'use strict';
/**
* Directive that executes an expression when the element it is applied to loses focus.
*/
export class TodoBlur {
public link: ($scope: ng.IScope, element: JQuery, attributes: any) => any;
/**
* Directive that executes an expression when the element it is applied to loses focus.
*/
class TodoBlur {
public link: ($scope: ng.IScope, elem: JQuery, attrs: any) => any;
public injection(): any[] {
return [
() => { return new TodoBlur(); }
]
}
constructor() {
this.link = (s, e, a) => this.linkFn(s, e, a);
}
constructor() {
this.link = ($scope, element, attributes) => this.linkFn($scope, element, attributes);
}
linkFn($scope: ng.IScope, elem: JQuery, attrs: any): any {
elem.bind('blur', () => {
$scope.$apply(attrs.todoBlur);
});
};
}
linkFn($scope: ng.IScope, element: JQuery, attributes: any): any {
element.bind('blur', () => {
$scope.$apply(attributes.todoBlur);
});
};
}
}
\ No newline at end of file
'use strict';
var TodoFocus = (function () {
function TodoFocus($timeout) {
this.$timeout = $timeout;
var _this = this;
this.link = function (s, e, a) {
return _this.linkFn(s, e, a);
var todos;
(function (todos) {
'use strict';
var TodoFocus = (function () {
function TodoFocus($timeout) {
this.$timeout = $timeout;
var _this = this;
this.link = function ($scope, element, attributes) {
return _this.linkFn($scope, element, attributes);
};
}
TodoFocus.prototype.injection = function () {
return [
'$timeout',
function ($timeout) {
return new TodoFocus($timeout);
} ];
};
}
TodoFocus.prototype.linkFn = function ($scope, elem, attrs) {
var _this = this;
$scope.$watch(attrs.todoFocus, function (newval) {
if(newval) {
_this.$timeout(function () {
elem[0].focus();
}, 0, false);
}
});
};
return TodoFocus;
})();
TodoFocus.prototype.linkFn = function ($scope, element, attributes) {
var _this = this;
$scope.$watch(attributes.todoFocus, function (newval) {
if(newval) {
_this.$timeout(function () {
element[0].focus();
}, 0, false);
}
});
};
return TodoFocus;
})();
todos.TodoFocus = TodoFocus;
})(todos || (todos = {}));
//@ sourceMappingURL=TodoFocus.js.map
{"version":3,"file":"TodoFocus.js","sources":["TodoFocus.ts"],"names":["todos","todos.TodoFocus","todos.TodoFocus.constructor","todos.TodoFocus.constructor.link","todos.TodoFocus.injection","","todos.TodoFocus.linkFn","",""],"mappings":"AAAA,IAEO,KAAK;AA+BX,CA/BD,UAAO,KAAK;IACRA,YAAaA;IAKbA;QAWIC,SAXSA,SAASA,CAWNA,QAAoCA;YAApCC,aAAgBA,GAARA,QAAQA;AAAoBA,YAAhDA,iBAECA;YADGA,IAAIA,CAACA,IAAIA,GAAGA,UAACA,MAAMA,EAAEA,OAAOA,EAAEA,UAAWA;gBAAIC,OAAAA,KAAIA,CAACA,MAAMA,CAACA,MAAMA,EAAEA,OAAOA,EAAEA,UAAUA,CAACA,CAAAA;YAAxCA,CAAwCA;QACzFD,CAACA;QATDD,gCAAAA;YACIG,OAAOA;gBACHA,UAAUA;gBACVA,UAACA,QAASA;oBAAMC,OAAOA,IAAIA,SAASA,CAACA,QAAQA,CAACA,CAACA;gBAACA,CAACA,aACpDD,CAAAA;QACLA,CAACA;QAMDH,6BAAAA,UAAOA,MAAiBA,EAAEA,OAAeA,EAAEA,UAAeA;YAA1DK,iBAQCA;YAPGA,MAAMA,CAACA,MAAMA,CAACA,UAAUA,CAACA,SAASA,EAAEA,UAACA,MAAOA;gBACxCC,GAAIA,MAAMA,CAACA;oBACPA,KAAIA,CAACA,QAAQA,CAACA;wBACVC,OAAOA,CAACA,CAACA,CAACA,CAACA,KAAKA,EAAEA;oBACtBA,CAACA,EAAED,CAACA,EAAEA,KAAKA,CAACA;iBACfA;YACLA,CAACA,CAACD;QACNA,CAACA;QACLL;AAACA,IAADA,CAACA,IAAAD;IAxBDA,4BAwBCA,IAAAA;AACLA,CAACA;AAAA"}
\ No newline at end of file
/// <reference path='../libs/angular-1.0.d.ts' />
'use strict';
/// <reference path='../_all.ts' />
/**
* Directive that places focus on the element it is applied to when the expression it binds to evaluates to true.
*/
class TodoFocus {
module todos {
'use strict';
public link: ($scope: ng.IScope, elem: JQuery, attrs: any) => any;
/**
* Directive that places focus on the element it is applied to when the expression it binds to evaluates to true.
*/
export class TodoFocus {
constructor(private $timeout: ng.ITimeoutService) {
this.link = (s, e, a) => this.linkFn(s, e, a);
}
public link: ($scope: ng.IScope, element: JQuery, attributes: any) => any;
public injection(): any[] {
return [
'$timeout',
($timeout) => { return new TodoFocus($timeout); }
]
}
linkFn($scope: ng.IScope, elem: JQuery, attrs: any): any {
$scope.$watch(attrs.todoFocus, (newval) => {
if (newval) {
this.$timeout(() => {
elem[0].focus();
}, 0, false);
}
});
};
}
constructor(private $timeout: ng.ITimeoutService) {
this.link = ($scope, element, attributes) => this.linkFn($scope, element, attributes);
}
linkFn($scope: ng.IScope, element: JQuery, attributes: any): any {
$scope.$watch(attributes.todoFocus, (newval) => {
if (newval) {
this.$timeout(() => {
element[0].focus();
}, 0, false);
}
});
};
}
}
\ No newline at end of file
'use strict';
var todos;
(function (todos) {
'use strict';
})(todos || (todos = {}));
//@ sourceMappingURL=ITodoScope.js.map
{"version":3,"file":"ITodoScope.js","sources":["ITodoScope.ts"],"names":["todos"],"mappings":"AAAA,IAEO,KAAK;AAoBX,CApBD,UAAO,KAAK;IACRA,YAAaA;AAmBjBA,CAACA;AAAA"}
\ No newline at end of file
/// <reference path='../libs/angular-1.0.d.ts' />
/// <reference path='../models/TodoItem.ts' />
/// <reference path='../_all.ts' />
'use strict';
module todos {
'use strict';
interface ITodoScope extends ng.IScope {
todos: TodoItem[];
newTodo: string;
editedTodo: TodoItem;
remainingCount: number;
doneCount: number;
allChecked: bool;
statusFilter: { completed: bool; };
location: ng.ILocationService;
export interface ITodoScope extends ng.IScope {
todos: TodoItem[];
newTodo: string;
editedTodo: TodoItem;
remainingCount: number;
doneCount: number;
allChecked: bool;
statusFilter: { completed: bool; };
location: ng.ILocationService;
addTodo: () =>void;
editTodo: (item: TodoItem) =>void;
doneEditing: (item: TodoItem) =>void;
removeTodo: (item: TodoItem) =>void;
clearDoneTodos: () =>void;
markAll: (done: bool) =>void;
}
addTodo: () => void;
editTodo: (todoItem: TodoItem) => void;
doneEditing: (todoItem: TodoItem) => void;
removeTodo: (todoItem: TodoItem) => void;
clearDoneTodos: () => void;
markAll: (done: bool) => void;
}
}
\ No newline at end of file
'use strict';
var todos;
(function (todos) {
'use strict';
})(todos || (todos = {}));
//@ sourceMappingURL=ITodoStorage.js.map
{"version":3,"file":"ITodoStorage.js","sources":["ITodoStorage.ts"],"names":["todos"],"mappings":"AAAA,IAEO,KAAK;AAOX,CAPD,UAAO,KAAK;IACRA,YAAaA;AAMjBA,CAACA;AAAA"}
\ No newline at end of file
/// <reference path='../libs/angular-1.0.d.ts' />
/// <reference path='../models/TodoItem.ts' />
/// <reference path='../_all.ts' />
'use strict';
module todos {
'use strict';
interface ITodoStorage {
get(): TodoItem[];
put(todos: TodoItem[]);
}
export interface ITodoStorage {
get (): TodoItem[];
put(todos: TodoItem[]);
}
}
\ No newline at end of file
......@@ -79,6 +79,7 @@ module ng {
provider(name: string, serviceProviderConstructor: Function): IModule;
run(initializationFunction: Function): IModule;
service(name: string, serviceConstructor: Function): IModule;
service(name: string, inlineAnnotadedConstructor: any[]): IModule;
value(name: string, value: any): IModule;
// Properties
......
'use strict';
var TodoItem = (function () {
function TodoItem() { }
return TodoItem;
})();
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 = {}));
//@ sourceMappingURL=TodoItem.js.map
{"version":3,"file":"TodoItem.js","sources":["TodoItem.ts"],"names":["todos","todos.TodoItem","todos.TodoItem.constructor"],"mappings":"AAAA,IAEO,KAAK;AASX,CATD,UAAO,KAAK;IACRA,YAAaA;IAEbA;QACIC,SADSA,QAAQA,CAEbA,KAAoBA,EACpBA,SAAsBA;YADtBC,UAAYA,GAALA,KAAKA;AAAQA,YACpBA,cAAgBA,GAATA,SAASA;AAAMA,QAClBA,CAACA;QACbD;AAACA,IAADA,CAACA,IAAAD;IALDA,0BAKCA,IAAAA;AACLA,CAACA;AAAA"}
\ No newline at end of file
/// <reference path='../libs/angular-1.0.d.ts' />
/// <reference path='../_all.ts' />
'use strict';
module todos {
'use strict';
class TodoItem {
public completed: bool;
public title: string;
export class TodoItem {
constructor(
public title: string,
public completed: bool
) { }
}
}
'use strict';
var TodoStorage = (function () {
function TodoStorage() {
this.STORAGE_ID = 'todos-angularjs-requirejs';
}
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;
})();
var todos;
(function (todos) {
'use strict';
var TodoStorage = (function () {
function TodoStorage() {
this.STORAGE_ID = 'todos-angularjs-typescript';
}
TodoStorage.prototype.injection = function () {
return [
TodoStorage
];
};
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 = {}));
//@ sourceMappingURL=TodoStorage.js.map
{"version":3,"file":"TodoStorage.js","sources":["TodoStorage.ts"],"names":["todos","todos.TodoStorage","todos.TodoStorage.constructor","todos.TodoStorage.injection","todos.TodoStorage.get","todos.TodoStorage.put"],"mappings":"AAAA,IAEO,KAAK;AA2BX,CA3BD,UAAO,KAAK;IACRA,YAAaA;IAKbA;QAQIC,SARSA,WAAWA;YAWpBC,KAAAA,UAAUA,GAAGA,4BAA4BA,CAAAA;QAFzCA,CAACA;QAPDD,kCAAAA;YACIE,OAAOA;gBACHA,WAAWA;aACdA,CAAAA;QACLA,CAACA;QAODF,4BAAAA;YACIG,OAAOA,IAAIA,CAACA,KAAKA,CAACA,YAAYA,CAACA,OAAOA,CAACA,IAAIA,CAACA,UAAUA,CAACA,IAAIA,IAAIA,CAACA,CAACA;QACrEA,CAACA;QAEDH,4BAAAA,UAAIA,KAAiBA;YACjBI,YAAYA,CAACA,OAAOA,CAACA,IAAIA,CAACA,UAAUA,EAAEA,IAAIA,CAACA,SAASA,CAACA,KAAKA,CAACA,CAACA;QAChEA,CAACA;QACLJ;AAACA,IAADA,CAACA,IAAAD;IApBDA,gCAoBCA,IAAAA;AACLA,CAACA;AAAA"}
\ No newline at end of file
/// <reference path='../libs/angular-1.0.d.ts' />
/// <reference path='../models/TodoItem.js' />
/// <reference path='../interfaces/ITodoStorage.js' />
'use strict';
/// <reference path='../_all.ts' />
/**
* Services that persists and retrieves TODOs from localStorage.
*/
class TodoStorage implements ITodoStorage {
STORAGE_ID = 'todos-angularjs-requirejs';
module todos {
'use strict';
get(): TodoItem[] {
return JSON.parse(localStorage.getItem(this.STORAGE_ID) || '[]');
}
/**
* Services that persists and retrieves TODOs from localStorage.
*/
export class TodoStorage implements ITodoStorage {
public injection(): any[] {
return [
TodoStorage
]
}
constructor() {
}
STORAGE_ID = 'todos-angularjs-typescript';
get (): TodoItem[] {
return JSON.parse(localStorage.getItem(this.STORAGE_ID) || '[]');
}
put(todos: TodoItem[]) {
localStorage.setItem(this.STORAGE_ID, JSON.stringify(todos));
put(todos: TodoItem[]) {
localStorage.setItem(this.STORAGE_ID, JSON.stringify(todos));
}
}
}
\ No newline at end of file
......@@ -69,9 +69,9 @@
<ItemGroup>
<Content Include="index.html" />
<Content Include="js\app.js">
<DependentUpon>app.ts</DependentUpon>
<DependentUpon>Application.ts</DependentUpon>
</Content>
<Content Include="js\app.ts" />
<Content Include="js\Application.ts" />
<Content Include="js\controllers\TodoCtrl.js">
<DependentUpon>TodoCtrl.ts</DependentUpon>
</Content>
......@@ -120,7 +120,7 @@
</ItemGroup>
<ItemGroup>
<Content Include="js\app.js.map">
<DependentUpon>app.ts</DependentUpon>
<DependentUpon>Application.ts</DependentUpon>
</Content>
</ItemGroup>
<ItemGroup>
......@@ -138,9 +138,6 @@
<DependentUpon>TodoItem.ts</DependentUpon>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="compileTs.cmd" />
</ItemGroup>
<ItemGroup>
<Content Include="js\interfaces\ITodoScope.js.map">
<DependentUpon>ITodoScope.ts</DependentUpon>
......
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