├── .gitignore
├── Gruntfile.js
├── bower.json
├── index.html
├── js
├── app.js
├── controllers
│ └── todoCtrl.js
├── directives
│ ├── todoBlur.js
│ ├── todoEscape.js
│ └── todoFocus.js
├── services
│ └── todoStorage.js
└── translations.js
├── package.json
├── po
├── nl.po
└── template.pot
├── readme.md
└── test
├── config
└── testacular.conf.js
├── package.json
├── readme.md
└── unit
├── directivesSpec.js
└── todoCtrlSpec.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .*.swp
2 | node_modules
3 | /bower_components
4 | po/*.mo
5 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function (grunt) {
4 | grunt.initConfig({
5 | nggettext_extract: {
6 | pot: {
7 | files: {
8 | 'po/template.pot': ['*.html']
9 | }
10 | },
11 | },
12 |
13 | nggettext_compile: {
14 | all: {
15 | files: {
16 | 'js/translations.js': ['po/*.po']
17 | }
18 | },
19 | },
20 | });
21 |
22 | grunt.loadNpmTasks('grunt-angular-gettext');
23 |
24 | grunt.registerTask('default', ['nggettext_extract', 'nggettext_compile']);
25 | };
26 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todomvc-angular-gettext-example",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "todomvc-common": "~0.1.4",
6 | "angular-gettext": "~2.1.0",
7 | "angular": "~1.2.21",
8 | "angular-mocks": "~1.2.21"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | AngularJS • TodoMVC
7 |
8 |
9 |
10 |
11 |
53 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/js/app.js:
--------------------------------------------------------------------------------
1 | /*global angular */
2 | /*jshint unused:false */
3 | 'use strict';
4 |
5 | /**
6 | * The main TodoMVC app module
7 | *
8 | * @type {angular.Module}
9 | */
10 | var todomvc = angular.module('todomvc', ['gettext']);
11 |
12 | todomvc.run(function (gettextCatalog) {
13 | gettextCatalog.currentLanguage = 'nl';
14 | });
15 |
--------------------------------------------------------------------------------
/js/controllers/todoCtrl.js:
--------------------------------------------------------------------------------
1 | /*global todomvc, angular */
2 | 'use strict';
3 |
4 | /**
5 | * The main controller for the app. The controller:
6 | * - retrieves and persists the model via the todoStorage service
7 | * - exposes the model to the template and provides event handlers
8 | */
9 | todomvc.controller('TodoCtrl', function TodoCtrl($scope, $location, todoStorage, filterFilter, gettextCatalog) {
10 | var todos = $scope.todos = todoStorage.get();
11 |
12 | $scope.newTodo = '';
13 | $scope.editedTodo = null;
14 |
15 | $scope.$watch('todos', function (newValue, oldValue) {
16 | $scope.remainingCount = filterFilter(todos, function (todo) {
17 | return todo.completed === false;
18 | }).length;
19 | $scope.completedCount = todos.length - $scope.remainingCount;
20 | $scope.allChecked = !$scope.remainingCount;
21 | if (newValue !== oldValue) { // This prevents unneeded calls to the local storage
22 | todoStorage.put(todos);
23 | }
24 | }, true);
25 |
26 | if ($location.path() === '') {
27 | $location.path('/');
28 | }
29 |
30 | $scope.location = $location;
31 |
32 | $scope.$watch('location.path()', function (path) {
33 | $scope.statusFilter = (path === '/active') ?
34 | { completed: false } : (path === '/completed') ?
35 | { completed: true } : null;
36 | });
37 |
38 | $scope.addTodo = function () {
39 | var newTodo = $scope.newTodo.trim();
40 | if (!newTodo.length) {
41 | return;
42 | }
43 |
44 | todos.push({
45 | title: newTodo,
46 | completed: false
47 | });
48 |
49 | $scope.newTodo = '';
50 | };
51 |
52 | $scope.editTodo = function (todo) {
53 | $scope.editedTodo = todo;
54 | // Clone the original todo to restore it on demand.
55 | $scope.originalTodo = angular.extend({}, todo);
56 | };
57 |
58 | $scope.doneEditing = function (todo) {
59 | $scope.editedTodo = null;
60 | todo.title = todo.title.trim();
61 |
62 | if (!todo.title) {
63 | $scope.removeTodo(todo);
64 | }
65 | };
66 |
67 | $scope.revertEditing = function (todo) {
68 | todos[todos.indexOf(todo)] = $scope.originalTodo;
69 | $scope.doneEditing($scope.originalTodo);
70 | };
71 |
72 | $scope.removeTodo = function (todo) {
73 | todos.splice(todos.indexOf(todo), 1);
74 | };
75 |
76 | $scope.clearCompletedTodos = function () {
77 | $scope.todos = todos = todos.filter(function (val) {
78 | return !val.completed;
79 | });
80 | };
81 |
82 | $scope.markAll = function (completed) {
83 | todos.forEach(function (todo) {
84 | todo.completed = completed;
85 | });
86 | };
87 |
88 | // Language switcher
89 | $scope.languages = {
90 | current: gettextCatalog.currentLanguage,
91 | available: {
92 | 'nl': 'Nederlands',
93 | 'en': 'English'
94 | }
95 | };
96 |
97 | $scope.$watch('languages.current', function (lang) {
98 | if (!lang) {
99 | return;
100 | }
101 |
102 | gettextCatalog.setCurrentLanguage(lang);
103 | });
104 | });
105 |
--------------------------------------------------------------------------------
/js/directives/todoBlur.js:
--------------------------------------------------------------------------------
1 | /*global todomvc */
2 | 'use strict';
3 |
4 | /**
5 | * Directive that executes an expression when the element it is applied to loses focus
6 | */
7 | todomvc.directive('todoBlur', function () {
8 | return function (scope, elem, attrs) {
9 | elem.bind('blur', function () {
10 | scope.$apply(attrs.todoBlur);
11 | });
12 | };
13 | });
14 |
--------------------------------------------------------------------------------
/js/directives/todoEscape.js:
--------------------------------------------------------------------------------
1 | /*global todomvc */
2 | 'use strict';
3 |
4 | /**
5 | * Directive that executes an expression when the element it is applied to gets
6 | * an `escape` keydown event.
7 | */
8 | todomvc.directive('todoEscape', function () {
9 | var ESCAPE_KEY = 27;
10 | return function (scope, elem, attrs) {
11 | elem.bind('keydown', function (event) {
12 | if (event.keyCode === ESCAPE_KEY) {
13 | scope.$apply(attrs.todoEscape);
14 | }
15 | });
16 | };
17 | });
18 |
19 |
--------------------------------------------------------------------------------
/js/directives/todoFocus.js:
--------------------------------------------------------------------------------
1 | /*global todomvc */
2 | 'use strict';
3 |
4 | /**
5 | * Directive that places focus on the element it is applied to when the expression it binds to evaluates to true
6 | */
7 | todomvc.directive('todoFocus', function todoFocus($timeout) {
8 | return function (scope, elem, attrs) {
9 | scope.$watch(attrs.todoFocus, function (newVal) {
10 | if (newVal) {
11 | $timeout(function () {
12 | elem[0].focus();
13 | }, 0, false);
14 | }
15 | });
16 | };
17 | });
18 |
--------------------------------------------------------------------------------
/js/services/todoStorage.js:
--------------------------------------------------------------------------------
1 | /*global todomvc */
2 | 'use strict';
3 |
4 | /**
5 | * Services that persists and retrieves TODOs from localStorage
6 | */
7 | todomvc.factory('todoStorage', function () {
8 | var STORAGE_ID = 'todos-angularjs';
9 |
10 | return {
11 | get: function () {
12 | return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]');
13 | },
14 |
15 | put: function (todos) {
16 | localStorage.setItem(STORAGE_ID, JSON.stringify(todos));
17 | }
18 | };
19 | });
20 |
--------------------------------------------------------------------------------
/js/translations.js:
--------------------------------------------------------------------------------
1 | angular.module('gettext').run(['gettextCatalog', function (gettextCatalog) {
2 | /* jshint -W100 */
3 | gettextCatalog.setStrings('nl', {"Mark all as complete":"Markeer als afgewerkt","{{$count}} item left":["{{$count}} item te gaan","{{$count}} items te gaan"],"All":"Alle","Active":"Actief","Completed":"Afgewerkt","Clear completed ({{completedCount}})":"Wis afgewerkte taken ({{completedCount}})","Double-click to edit a todo":"Dubbelklik om een todo te bewerken","What needs to be done?":"Wat moet gedaan worden?"});
4 | /* jshint +W100 */
5 | }]);
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todomvc-angular-gettext-example",
3 | "version": "0.0.0",
4 | "description": "This is an example of how to use angular-gettext, based on TodoMVC.",
5 | "main": "index.js",
6 | "directories": {
7 | "test": "test"
8 | },
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git://github.com/rubenv/angular-gettext-example.git"
15 | },
16 | "author": "Ruben Vermeersch ",
17 | "license": "MIT",
18 | "bugs": {
19 | "url": "https://github.com/rubenv/angular-gettext-example/issues"
20 | },
21 | "devDependencies": {
22 | "grunt": "~0.4.1",
23 | "grunt-angular-gettext": "~2.1.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/po/nl.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "Project-Id-Version: TodoMVC\n"
4 | "POT-Creation-Date: \n"
5 | "PO-Revision-Date: \n"
6 | "Last-Translator: Ruben Vermeersch \n"
7 | "Language-Team: \n"
8 | "Language: nl\n"
9 | "MIME-Version: 1.0\n"
10 | "Content-Type: text/plain; charset=UTF-8\n"
11 | "Content-Transfer-Encoding: 8bit\n"
12 | "X-Generator: Poedit 1.6.7\n"
13 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
14 |
15 | #: index.html:44
16 | msgid "Active"
17 | msgstr "Actief"
18 |
19 | #: index.html:41
20 | msgid "All"
21 | msgstr "Alle"
22 |
23 | #: index.html:50
24 | msgid "Clear completed ({{completedCount}})"
25 | msgstr "Wis afgewerkte taken ({{completedCount}})"
26 |
27 | #: index.html:47
28 | msgid "Completed"
29 | msgstr "Afgewerkt"
30 |
31 | #: index.html:54
32 | msgid "Double-click to edit a todo"
33 | msgstr "Dubbelklik om een todo te bewerken"
34 |
35 | #: index.html:23
36 | msgid "Mark all as complete"
37 | msgstr "Markeer als afgewerkt"
38 |
39 | #: index.html:18
40 | msgid "What needs to be done?"
41 | msgstr "Wat moet gedaan worden?"
42 |
43 | #: index.html:38
44 | msgid "{{$count}} item left"
45 | msgid_plural "{{$count}} items left"
46 | msgstr[0] "{{$count}} item te gaan"
47 | msgstr[1] "{{$count}} items te gaan"
48 |
49 | #~ msgid "{{remainingCount}} item left"
50 | #~ msgid_plural "{{remainingCount}} items left"
51 | #~ msgstr[0] "{{remainingCount}} todo te gaan"
52 | #~ msgstr[1] "{{remainingCount}} todos te gaan"
53 |
--------------------------------------------------------------------------------
/po/template.pot:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "Content-Type: text/plain; charset=UTF-8\n"
4 | "Content-Transfer-Encoding: 8bit\n"
5 | "Project-Id-Version: \n"
6 |
7 | #: index.html:44
8 | msgid "Active"
9 | msgstr ""
10 |
11 | #: index.html:41
12 | msgid "All"
13 | msgstr ""
14 |
15 | #: index.html:50
16 | msgid "Clear completed ({{completedCount}})"
17 | msgstr ""
18 |
19 | #: index.html:47
20 | msgid "Completed"
21 | msgstr ""
22 |
23 | #: index.html:54
24 | msgid "Double-click to edit a todo"
25 | msgstr ""
26 |
27 | #: index.html:23
28 | msgid "Mark all as complete"
29 | msgstr ""
30 |
31 | #: index.html:18
32 | msgid "What needs to be done?"
33 | msgstr ""
34 |
35 | #: index.html:38
36 | msgid "{{$count}} item left"
37 | msgid_plural "{{$count}} items left"
38 | msgstr[0] ""
39 | msgstr[1] ""
40 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Angular-gettext TodoMVC Example
2 |
3 | > This is an example of how to use [angular-gettext](http://angular-gettext.rocketeer.be/), based on [TodoMVC](http://todomvc.com/).
4 |
5 | Things to watch out for:
6 |
7 | * Added `angular-gettext` to `bower.json`.
8 | * Added a `Gruntfile` to extract and compile translations.
9 | * Added a language switcher.
10 | * Annotated the views to add translation support.
11 | * Added translations in the `po` folder.
12 |
13 | Full usage instructions can be found at [http://angular-gettext.rocketeer.be/](http://angular-gettext.rocketeer.be/).
14 |
15 | ---
16 |
17 | Original README below:
18 |
19 | # AngularJS TodoMVC Example
20 |
21 | > HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web-applications. AngularJS lets you extend HTML vocabulary for your application. The resulting environment is extraordinarily expressive, readable, and quick to develop.
22 |
23 | > _[AngularJS - angularjs.org](http://angularjs.org)_
24 |
25 |
26 | ## Learning AngularJS
27 | The [AngularJS website](http://angularjs.org) is a great resource for getting started.
28 |
29 | Here are some links you may find helpful:
30 |
31 | * [Tutorial](http://docs.angularjs.org/tutorial)
32 | * [API Reference](http://docs.angularjs.org/api)
33 | * [Developer Guide](http://docs.angularjs.org/guide)
34 | * [Applications built with AngularJS](http://builtwith.angularjs.org)
35 | * [Blog](http://blog.angularjs.org)
36 | * [FAQ](http://docs.angularjs.org/misc/faq)
37 | * [AngularJS Meetups](http://www.youtube.com/angularjs)
38 |
39 | Articles and guides from the community:
40 |
41 | * [Code School AngularJS course](http://www.codeschool.com/code_tv/angularjs-part-1)
42 | * [5 Awesome AngularJS Features](http://net.tutsplus.com/tutorials/javascript-ajax/5-awesome-angularjs-features)
43 | * [Using Yeoman with AngularJS](http://briantford.com/blog/angular-yeoman.html)
44 | * [me&ngular - an introduction to MVW](http://stephenplusplus.github.io/meangular)
45 |
46 | Get help from other AngularJS users:
47 |
48 | * [Walkthroughs and Tutorials on YouTube](http://www.youtube.com/playlist?list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz)
49 | * [Google Groups mailing list](https://groups.google.com/forum/?fromgroups#!forum/angular)
50 | * [angularjs on Stack Overflow](http://stackoverflow.com/questions/tagged/angularjs)
51 | * [AngularJS on Twitter](https://twitter.com/angularjs)
52 | * [AngularjS on Google +](https://plus.google.com/+AngularJS/posts)
53 |
54 | _If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
55 |
--------------------------------------------------------------------------------
/test/config/testacular.conf.js:
--------------------------------------------------------------------------------
1 | basePath = '../../';
2 |
3 | files = [
4 | JASMINE,
5 | JASMINE_ADAPTER,
6 | 'bower_components/jquery/jquery.js',
7 | 'bower_components/angular/angular.js',
8 | 'bower_components/angular-mocks/angular-mocks.js',
9 | 'bower_components/angular-gettext/dist/angular-gettext.js',
10 | 'js/**/*.js',
11 | 'test/unit/**/*.js'
12 | ];
13 |
14 | autoWatch = true;
15 |
16 | browsers = ['Chrome'];
17 |
--------------------------------------------------------------------------------
/test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todomvc-angular-tests",
3 | "description": "Unit tests for the AngularJS example of TodoMVC",
4 | "author": "Pascal Hartig ",
5 | "version": "1.0.0",
6 | "devDependencies": {
7 | "karma": "~0.8.5"
8 | },
9 | "scripts": {
10 | "test": "karma start config/testacular.conf.js"
11 | },
12 | "dependencies": {}
13 | }
14 |
--------------------------------------------------------------------------------
/test/readme.md:
--------------------------------------------------------------------------------
1 | Angular Unit Tests
2 | ==================
3 |
4 | To run the test suite, run these commands:
5 |
6 | npm install
7 | npm test
8 |
--------------------------------------------------------------------------------
/test/unit/directivesSpec.js:
--------------------------------------------------------------------------------
1 | /*global describe, it, beforeEach, inject, expect, angular*/
2 | (function () {
3 | 'use strict';
4 |
5 | beforeEach(module('todomvc'));
6 |
7 | describe('todoBlur directive', function () {
8 | var scope, compile;
9 |
10 | beforeEach(inject(function ($rootScope, $compile) {
11 | scope = $rootScope.$new();
12 | compile = $compile;
13 | }));
14 |
15 | it('should $apply on blur', function () {
16 | var el,
17 | mock = {
18 | called: false,
19 | call: function () { this.called = true; }
20 | };
21 |
22 | scope.mock = mock;
23 | el = angular.element('');
24 | compile(el)(scope);
25 |
26 | el.triggerHandler('blur');
27 | scope.$digest();
28 |
29 | expect(mock.called).toBeTruthy();
30 | });
31 | });
32 |
33 | describe('todoFocus directive', function () {
34 | var scope, compile, browser;
35 |
36 | beforeEach(inject(function ($rootScope, $compile, $browser) {
37 | scope = $rootScope.$new();
38 | compile = $compile;
39 | browser = $browser;
40 | }));
41 |
42 | it('should focus on truthy expression', function () {
43 | var el = angular.element('');
44 | scope.focus = false;
45 |
46 | compile(el)(scope);
47 | expect(browser.deferredFns.length).toBe(0);
48 |
49 | scope.$apply(function () {
50 | scope.focus = true;
51 | });
52 |
53 | expect(browser.deferredFns.length).toBe(1);
54 | });
55 | });
56 | }());
57 |
--------------------------------------------------------------------------------
/test/unit/todoCtrlSpec.js:
--------------------------------------------------------------------------------
1 | /*global describe, it, beforeEach, inject, expect*/
2 | (function () {
3 | 'use strict';
4 |
5 | describe('Todo Controller', function () {
6 | var ctrl, scope;
7 | var todoList;
8 | var todoStorage = {
9 | storage: {},
10 | get: function () {
11 | return this.storage;
12 | },
13 | put: function (value) {
14 | this.storage = value;
15 | }
16 | };
17 |
18 | // Load the module containing the app, only 'ng' is loaded by default.
19 | beforeEach(module('todomvc'));
20 |
21 | beforeEach(inject(function ($controller, $rootScope) {
22 | scope = $rootScope.$new();
23 | ctrl = $controller('TodoCtrl', { $scope: scope });
24 | }));
25 |
26 | it('should not have an edited Todo on start', function () {
27 | expect(scope.editedTodo).toBeNull();
28 | });
29 |
30 | it('should not have any Todos on start', function () {
31 | expect(scope.todos.length).toBe(0);
32 | });
33 |
34 | it('should have all Todos completed', function () {
35 | scope.$digest();
36 | expect(scope.allChecked).toBeTruthy();
37 | });
38 |
39 | describe('the path', function () {
40 | it('should default to "/"', function () {
41 | expect(scope.location.path()).toBe('/');
42 | });
43 |
44 | describe('being at /active', function () {
45 | it('should filter non-completed', inject(function ($controller) {
46 | ctrl = $controller('TodoCtrl', {
47 | $scope: scope,
48 | $location: {
49 | path: function () { return '/active'; }
50 | }
51 | });
52 |
53 | scope.$digest();
54 | expect(scope.statusFilter.completed).toBeFalsy();
55 | }));
56 | });
57 |
58 | describe('being at /completed', function () {
59 | it('should filter completed', inject(function ($controller) {
60 | ctrl = $controller('TodoCtrl', {
61 | $scope: scope,
62 | $location: {
63 | path: function () { return '/completed'; }
64 | }
65 | });
66 |
67 | scope.$digest();
68 | expect(scope.statusFilter.completed).toBeTruthy();
69 | }));
70 | });
71 | });
72 |
73 | describe('having no Todos', function () {
74 | var ctrl;
75 |
76 | beforeEach(inject(function ($controller) {
77 | todoStorage.storage = [];
78 | ctrl = $controller('TodoCtrl', {
79 | $scope: scope,
80 | todoStorage: todoStorage
81 | });
82 | scope.$digest();
83 | }));
84 |
85 | it('should not add empty Todos', function () {
86 | scope.newTodo = '';
87 | scope.addTodo();
88 | scope.$digest();
89 | expect(scope.todos.length).toBe(0);
90 | });
91 |
92 | it('should not add items consisting only of whitespaces', function () {
93 | scope.newTodo = ' ';
94 | scope.addTodo();
95 | scope.$digest();
96 | expect(scope.todos.length).toBe(0);
97 | });
98 |
99 |
100 | it('should trim whitespace from new Todos', function () {
101 | scope.newTodo = ' buy some unicorns ';
102 | scope.addTodo();
103 | scope.$digest();
104 | expect(scope.todos.length).toBe(1);
105 | expect(scope.todos[0].title).toBe('buy some unicorns');
106 | });
107 | });
108 |
109 | describe('having some saved Todos', function () {
110 | var ctrl;
111 |
112 | beforeEach(inject(function ($controller) {
113 | todoList = [{
114 | 'title': 'Uncompleted Item 0',
115 | 'completed': false
116 | }, {
117 | 'title': 'Uncompleted Item 1',
118 | 'completed': false
119 | }, {
120 | 'title': 'Uncompleted Item 2',
121 | 'completed': false
122 | }, {
123 | 'title': 'Completed Item 0',
124 | 'completed': true
125 | }, {
126 | 'title': 'Completed Item 1',
127 | 'completed': true
128 | }];
129 |
130 | todoStorage.storage = todoList;
131 | ctrl = $controller('TodoCtrl', {
132 | $scope: scope,
133 | todoStorage: todoStorage
134 | });
135 | scope.$digest();
136 | }));
137 |
138 | it('should count Todos correctly', function () {
139 | expect(scope.todos.length).toBe(5);
140 | expect(scope.remainingCount).toBe(3);
141 | expect(scope.completedCount).toBe(2);
142 | expect(scope.allChecked).toBeFalsy();
143 | });
144 |
145 | it('should save Todos to local storage', function () {
146 | expect(todoStorage.storage.length).toBe(5);
147 | });
148 |
149 | it('should remove Todos w/o title on saving', function () {
150 | var todo = todoList[2];
151 | todo.title = '';
152 |
153 | scope.doneEditing(todo);
154 | expect(scope.todos.length).toBe(4);
155 | });
156 |
157 | it('should trim Todos on saving', function () {
158 | var todo = todoList[0];
159 | todo.title = ' buy moar unicorns ';
160 |
161 | scope.doneEditing(todo);
162 | expect(scope.todos[0].title).toBe('buy moar unicorns');
163 | });
164 |
165 | it('clearCompletedTodos() should clear completed Todos', function () {
166 | scope.clearCompletedTodos();
167 | expect(scope.todos.length).toBe(3);
168 | });
169 |
170 | it('markAll() should mark all Todos completed', function () {
171 | scope.markAll();
172 | scope.$digest();
173 | expect(scope.completedCount).toBe(5);
174 | });
175 |
176 | it('revertTodo() get a Todo to its previous state', function () {
177 | var todo = todoList[0];
178 | scope.editTodo(todo);
179 | todo.title = 'Unicorn sparkly skypuffles.';
180 | scope.revertEditing(todo);
181 | scope.$digest();
182 | expect(scope.todos[0].title).toBe('Uncompleted Item 0');
183 | });
184 | });
185 | });
186 | }());
187 |
--------------------------------------------------------------------------------