├── .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 |
12 | 21 |
22 | 23 | 24 | 36 |
37 | 52 |
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 | --------------------------------------------------------------------------------