Commit f0b82920 authored by Pavel Savara's avatar Pavel Savara

processed feedback, improved dependency injection

parent 949463d8
*.suo *.suo
*.user *.user
*.map
/bin /bin
/obj /obj
\ No newline at end of file
TypeScript # TypeScript + AngularJS #
http://go.microsoft.com/fwlink/?LinkID=266563
http://visualstudiogallery.msdn.microsoft.com/07d54d12-7133-4e15-becb-6f451ea3bea6
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 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. AngularJS documentation and tutorials are worth reading in detail.
\ No newline at end of file \ No newline at end of file
@echo off
tsc -sourcemap js/_all.ts
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <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"> <link rel="stylesheet" href="../../../assets/base.css">
<style>[ng-cloak] {display: none}</style> <style>[ng-cloak] {display: none}</style>
<!--[if IE]> <!--[if IE]>
...@@ -58,16 +58,18 @@ ...@@ -58,16 +58,18 @@
<p>Credits: <p>Credits:
<a href="http://twitter.com/cburgdorf">Christoph Burgdorf</a>, <a href="http://twitter.com/cburgdorf">Christoph Burgdorf</a>,
<a href="http://ericbidelman.com">Eric Bidelman</a>, <a href="http://ericbidelman.com">Eric Bidelman</a>,
<a href="http://jacobmumm.com">Jacob Mumm</a> and <a href="http://jacobmumm.com">Jacob Mumm</a>
<a href="http://igorminar.com">Igor Minar</a> <a href="http://igorminar.com">Igor Minar</a> and
<a href="http://zamboch.blogspot.com">Pavel Savara</a>
</p> </p>
</footer> </footer>
<script src="../../../assets/base.js"></script> <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/controllers/TodoCtrl.js"></script>
<script src="js/services/TodoStorage.js"></script> <script src="js/services/TodoStorage.js"></script>
<script src="js/directives/TodoFocus.js"></script> <script src="js/directives/TodoFocus.js"></script>
<script src="js/directives/TodoBlur.js"></script> <script src="js/directives/TodoBlur.js"></script>
<script src="js/app.js"></script> <script src="js/Application.js"></script>
</body> </body>
</html> </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='libs/jquery-1.8.d.ts' />
/// <reference path='models/TodoItem.js' /> /// <reference path='libs/angular-1.0.d.ts' />
/// <reference path='interfaces/ITodoScope.js' /> /// <reference path='models/TodoItem.ts' />
/// <reference path='interfaces/ITodoStorage.js' /> /// <reference path='interfaces/ITodoScope.ts' />
/// <reference path='interfaces/ITodoStorage.ts' />
/// <reference path='directives/TodoFocus.ts' /> /// <reference path='directives/TodoFocus.ts' />
/// <reference path='directives/TodoBlur.ts' /> /// <reference path='directives/TodoBlur.ts' />
/// <reference path='services/TodoStorage.ts' /> /// <reference path='services/TodoStorage.ts' />
/// <reference path='controllers/TodoCtrl.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 todos;
var TodoCtrl = (function () { (function (todos) {
function TodoCtrl($scope, $location, todoStorage, filterFilter) { 'use strict';
this.$scope = $scope; var TodoCtrl = (function () {
this.todoStorage = todoStorage; function TodoCtrl($scope, $location, todoStorage, filterFilter) {
this.filterFilter = filterFilter; this.$scope = $scope;
var _this = this; this.$location = $location;
this.todos = $scope.todos = todoStorage.get(); this.todoStorage = todoStorage;
$scope.newTodo = ""; this.filterFilter = filterFilter;
$scope.editedTodo = null; var _this = this;
$scope.addTodo = function () { this.todos = $scope.todos = todoStorage.get();
return _this.addTodo(); $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) { TodoCtrl.prototype.onPath = function (path) {
return _this.editTodo(t); this.$scope.statusFilter = (path == '/active') ? {
completed: false
} : (path == '/completed') ? {
completed: true
} : null;
}; };
$scope.doneEditing = function (t) { TodoCtrl.prototype.onTodos = function () {
return _this.doneEditing(t); 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) { TodoCtrl.prototype.addTodo = function () {
return _this.removeTodo(t); if(!this.$scope.newTodo.length) {
return;
}
this.todos.push(new todos.TodoItem(this.$scope.newTodo, false));
this.$scope.newTodo = '';
}; };
$scope.clearDoneTodos = function () { TodoCtrl.prototype.editTodo = function (todoItem) {
return _this.clearDoneTodos(); this.$scope.editedTodo = todoItem;
}; };
$scope.markAll = function (d) { TodoCtrl.prototype.doneEditing = function (todoItem) {
return _this.markAll(d); this.$scope.editedTodo = null;
if(!todoItem.title) {
this.$scope.removeTodo(todoItem);
}
}; };
$scope.$watch('todos', function () { TodoCtrl.prototype.removeTodo = function (todoItem) {
return _this.onTodos(); this.todos.splice(this.todos.indexOf(todoItem), 1);
}, true); };
$scope.$watch('location.path()', function (path) { TodoCtrl.prototype.clearDoneTodos = function () {
return _this.onPath(path); this.$scope.todos = this.todos = this.todos.filter(function (todoItem) {
}); return !todoItem.completed;
if($location.path() === '') { });
$location.path('/'); };
} TodoCtrl.prototype.markAll = function (done) {
$scope.location = $location; this.todos.forEach(function (todoItem) {
} todoItem.completed = done;
TodoCtrl.prototype.onPath = function (path) { });
this.$scope.statusFilter = (path == '/active') ? { };
completed: false return TodoCtrl;
} : (path == '/completed') ? { })();
completed: true todos.TodoCtrl = TodoCtrl;
} : null; })(todos || (todos = {}));
};
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;
})();
//@ sourceMappingURL=TodoCtrl.js.map //@ 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='../_all.ts' />
/// <reference path='../services/TodoStorage.ts' />
/// <reference path='../models/TodoItem.ts' /> module todos {
/// <reference path='../interfaces/ITodoStorage.ts' /> 'use strict';
/// <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
* The main controller for the app. The controller: */
* - retrieves and persist the model via the todoStorage service export class TodoCtrl {
* - exposes the model to the template and provides event handlers
*/ private todos: TodoItem[];
class TodoCtrl {
private todos; // this method is called on prototype during registration into IoC container.
// It provides $injector with information about dependencies to be injected into constructor
constructor(private $scope: ITodoScope, $location: ng.ILocationService, private todoStorage: ITodoStorage, private filterFilter) { // it is better to have it close to the constructor, because the parameters must match in count and type.
this.todos = $scope.todos = todoStorage.get(); public injection(): any[] {
return [
$scope.newTodo = ""; '$scope',
$scope.editedTodo = null; '$location',
'todoStorage',
$scope.addTodo = () => this.addTodo(); 'filterFilter',
$scope.editTodo = (t) => this.editTodo(t); TodoCtrl
$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;
} }
this.todos.push({ // dependencies are injected via AngularJS $injector
title: this.$scope.newTodo, // controller's name is registered in App.ts and invoked from ng-controller attribute in index.html
completed: false constructor(
}); private $scope: ITodoScope,
private $location: ng.ILocationService,
this.$scope.newTodo = ''; private todoStorage: ITodoStorage,
}; private filterFilter
) {
editTodo(todo: TodoItem) { this.todos = $scope.todos = todoStorage.get();
this.$scope.editedTodo = todo;
}; $scope.newTodo = '';
$scope.editedTodo = null;
doneEditing(todo: TodoItem) {
this.$scope.editedTodo = null; // adding event handlers to the scope, so they could be bound from view/HTML
if (!todo.title) { // these lambdas fix this keyword in JS world
this.$scope.removeTodo(todo); $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) { onPath(path: string) {
this.todos.splice(this.todos.indexOf(todo), 1); this.$scope.statusFilter =
}; (path == '/active')
? { completed: false }
: (path == '/completed')
? { completed: true }
: null;
}
clearDoneTodos() { onTodos() {
this.$scope.todos = this.todos = this.todos.filter((val) => { this.$scope.remainingCount = this.filterFilter(this.todos, { completed: false }).length;
return !val.completed; this.$scope.doneCount = this.todos.length - this.$scope.remainingCount;
}); this.$scope.allChecked = !this.$scope.remainingCount
}; this.todoStorage.put(this.todos);
}
markAll(done: bool) { addTodo() {
this.todos.forEach((todo: TodoItem) => { if (!this.$scope.newTodo.length) {
todo.completed = done; 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 todos;
var TodoBlur = (function () { (function (todos) {
function TodoBlur() { 'use strict';
var _this = this; var TodoBlur = (function () {
this.link = function (s, e, a) { function TodoBlur() {
return _this.linkFn(s, e, a); 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, element, attributes) {
TodoBlur.prototype.linkFn = function ($scope, elem, attrs) { element.bind('blur', function () {
elem.bind('blur', function () { $scope.$apply(attributes.todoBlur);
$scope.$apply(attrs.todoBlur); });
}); };
}; return TodoBlur;
return TodoBlur; })();
})(); todos.TodoBlur = TodoBlur;
})(todos || (todos = {}));
//@ sourceMappingURL=TodoBlur.js.map //@ 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' /> /// <reference path='../_all.ts' />
'use strict';
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;
/** public injection(): any[] {
* Directive that executes an expression when the element it is applied to loses focus. return [
*/ () => { return new TodoBlur(); }
class TodoBlur { ]
public link: ($scope: ng.IScope, elem: JQuery, attrs: any) => any; }
constructor() { constructor() {
this.link = (s, e, a) => this.linkFn(s, e, a); this.link = ($scope, element, attributes) => this.linkFn($scope, element, attributes);
} }
linkFn($scope: ng.IScope, elem: JQuery, attrs: any): any { linkFn($scope: ng.IScope, element: JQuery, attributes: any): any {
elem.bind('blur', () => { element.bind('blur', () => {
$scope.$apply(attrs.todoBlur); $scope.$apply(attributes.todoBlur);
}); });
}; };
} }
}
\ No newline at end of file
'use strict'; var todos;
var TodoFocus = (function () { (function (todos) {
function TodoFocus($timeout) { 'use strict';
this.$timeout = $timeout; var TodoFocus = (function () {
var _this = this; function TodoFocus($timeout) {
this.link = function (s, e, a) { this.$timeout = $timeout;
return _this.linkFn(s, e, a); 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, element, attributes) {
TodoFocus.prototype.linkFn = function ($scope, elem, attrs) { var _this = this;
var _this = this; $scope.$watch(attributes.todoFocus, function (newval) {
$scope.$watch(attrs.todoFocus, function (newval) { if(newval) {
if(newval) { _this.$timeout(function () {
_this.$timeout(function () { element[0].focus();
elem[0].focus(); }, 0, false);
}, 0, false); }
} });
}); };
}; return TodoFocus;
return TodoFocus; })();
})(); todos.TodoFocus = TodoFocus;
})(todos || (todos = {}));
//@ sourceMappingURL=TodoFocus.js.map //@ 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' /> /// <reference path='../_all.ts' />
'use strict';
/** module todos {
* Directive that places focus on the element it is applied to when the expression it binds to evaluates to true. 'use strict';
*/
class TodoFocus {
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) { public link: ($scope: ng.IScope, element: JQuery, attributes: any) => any;
this.link = (s, e, a) => this.linkFn(s, e, a);
} public injection(): any[] {
return [
'$timeout',
($timeout) => { return new TodoFocus($timeout); }
]
}
linkFn($scope: ng.IScope, elem: JQuery, attrs: any): any { constructor(private $timeout: ng.ITimeoutService) {
$scope.$watch(attrs.todoFocus, (newval) => { this.link = ($scope, element, attributes) => this.linkFn($scope, element, attributes);
if (newval) { }
this.$timeout(() => {
elem[0].focus(); linkFn($scope: ng.IScope, element: JQuery, attributes: any): any {
}, 0, false); $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 //@ 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='../_all.ts' />
/// <reference path='../models/TodoItem.ts' />
'use strict'; module todos {
'use strict';
interface ITodoScope extends ng.IScope { export interface ITodoScope extends ng.IScope {
todos: TodoItem[]; todos: TodoItem[];
newTodo: string; newTodo: string;
editedTodo: TodoItem; editedTodo: TodoItem;
remainingCount: number; remainingCount: number;
doneCount: number; doneCount: number;
allChecked: bool; allChecked: bool;
statusFilter: { completed: bool; }; statusFilter: { completed: bool; };
location: ng.ILocationService; location: ng.ILocationService;
addTodo: () =>void; addTodo: () => void;
editTodo: (item: TodoItem) =>void; editTodo: (todoItem: TodoItem) => void;
doneEditing: (item: TodoItem) =>void; doneEditing: (todoItem: TodoItem) => void;
removeTodo: (item: TodoItem) =>void; removeTodo: (todoItem: TodoItem) => void;
clearDoneTodos: () =>void; clearDoneTodos: () => void;
markAll: (done: bool) =>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 //@ 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='../_all.ts' />
/// <reference path='../models/TodoItem.ts' />
'use strict'; module todos {
'use strict';
interface ITodoStorage { export interface ITodoStorage {
get(): TodoItem[]; get (): TodoItem[];
put(todos: TodoItem[]); put(todos: TodoItem[]);
} }
}
\ No newline at end of file
...@@ -79,6 +79,7 @@ module ng { ...@@ -79,6 +79,7 @@ module ng {
provider(name: string, serviceProviderConstructor: Function): IModule; provider(name: string, serviceProviderConstructor: Function): IModule;
run(initializationFunction: Function): IModule; run(initializationFunction: Function): IModule;
service(name: string, serviceConstructor: Function): IModule; service(name: string, serviceConstructor: Function): IModule;
service(name: string, inlineAnnotadedConstructor: any[]): IModule;
value(name: string, value: any): IModule; value(name: string, value: any): IModule;
// Properties // Properties
......
'use strict'; var todos;
var TodoItem = (function () { (function (todos) {
function TodoItem() { } 'use strict';
return TodoItem; var TodoItem = (function () {
})(); function TodoItem(title, completed) {
this.title = title;
this.completed = completed;
}
return TodoItem;
})();
todos.TodoItem = TodoItem;
})(todos || (todos = {}));
//@ sourceMappingURL=TodoItem.js.map //@ 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 { export class TodoItem {
public completed: bool; constructor(
public title: string; public title: string,
public completed: bool
) { }
}
} }
'use strict'; var todos;
var TodoStorage = (function () { (function (todos) {
function TodoStorage() { 'use strict';
this.STORAGE_ID = 'todos-angularjs-requirejs'; var TodoStorage = (function () {
} function TodoStorage() {
TodoStorage.prototype.get = function () { this.STORAGE_ID = 'todos-angularjs-typescript';
return JSON.parse(localStorage.getItem(this.STORAGE_ID) || '[]'); }
}; TodoStorage.prototype.injection = function () {
TodoStorage.prototype.put = function (todos) { return [
localStorage.setItem(this.STORAGE_ID, JSON.stringify(todos)); TodoStorage
}; ];
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 //@ 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='../_all.ts' />
/// <reference path='../models/TodoItem.js' />
/// <reference path='../interfaces/ITodoStorage.js' />
'use strict';
/** module todos {
* Services that persists and retrieves TODOs from localStorage. 'use strict';
*/
class TodoStorage implements ITodoStorage {
STORAGE_ID = 'todos-angularjs-requirejs';
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[]) { put(todos: TodoItem[]) {
localStorage.setItem(this.STORAGE_ID, JSON.stringify(todos)); localStorage.setItem(this.STORAGE_ID, JSON.stringify(todos));
}
} }
} }
\ No newline at end of file
...@@ -69,9 +69,9 @@ ...@@ -69,9 +69,9 @@
<ItemGroup> <ItemGroup>
<Content Include="index.html" /> <Content Include="index.html" />
<Content Include="js\app.js"> <Content Include="js\app.js">
<DependentUpon>app.ts</DependentUpon> <DependentUpon>Application.ts</DependentUpon>
</Content> </Content>
<Content Include="js\app.ts" /> <Content Include="js\Application.ts" />
<Content Include="js\controllers\TodoCtrl.js"> <Content Include="js\controllers\TodoCtrl.js">
<DependentUpon>TodoCtrl.ts</DependentUpon> <DependentUpon>TodoCtrl.ts</DependentUpon>
</Content> </Content>
...@@ -120,7 +120,7 @@ ...@@ -120,7 +120,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="js\app.js.map"> <Content Include="js\app.js.map">
<DependentUpon>app.ts</DependentUpon> <DependentUpon>Application.ts</DependentUpon>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
...@@ -138,9 +138,6 @@ ...@@ -138,9 +138,6 @@
<DependentUpon>TodoItem.ts</DependentUpon> <DependentUpon>TodoItem.ts</DependentUpon>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Include="compileTs.cmd" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="js\interfaces\ITodoScope.js.map"> <Content Include="js\interfaces\ITodoScope.js.map">
<DependentUpon>ITodoScope.ts</DependentUpon> <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