Skip to content

Commit b228955

Browse files
committed
Init
0 parents  commit b228955

File tree

10 files changed

+577
-0
lines changed

10 files changed

+577
-0
lines changed

Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: node server.js

index.html

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<!doctype html>
2+
<html lang="en" data-framework="angularjs">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>AngularJS • TodoMVC</title>
6+
<link rel="stylesheet" href="node_modules/todomvc-common/base.css">
7+
<link rel="stylesheet" href="node_modules/todomvc-app-css/index.css">
8+
<style>[ng-cloak] { display: none; }</style>
9+
</head>
10+
<body ng-app="todomvc">
11+
<ng-view />
12+
13+
<script type="text/ng-template" id="todomvc-index.html">
14+
<section id="todoapp">
15+
<header id="header">
16+
<h1>todos</h1>
17+
<form id="todo-form" ng-submit="addTodo()">
18+
<input id="new-todo" placeholder="What needs to be done?" ng-model="newTodo" ng-disabled="saving" autofocus>
19+
</form>
20+
</header>
21+
<section id="main" ng-show="todos.length" ng-cloak>
22+
<input id="toggle-all" type="checkbox" ng-model="allChecked" ng-click="markAll(allChecked)">
23+
<label for="toggle-all">Mark all as complete</label>
24+
<ul id="todo-list">
25+
<li ng-repeat="todo in todos | filter:statusFilter track by $index" ng-class="{completed: todo.completed, editing: todo == editedTodo}">
26+
<div class="view">
27+
<input class="toggle" type="checkbox" ng-model="todo.completed" ng-change="toggleCompleted(todo)">
28+
<label ng-dblclick="editTodo(todo)">{{todo.title}}</label>
29+
<button class="destroy" ng-click="removeTodo(todo)"></button>
30+
</div>
31+
<form ng-submit="saveEdits(todo, 'submit')">
32+
<input class="edit" ng-trim="false" ng-model="todo.title" todo-escape="revertEdits(todo)" ng-blur="saveEdits(todo, 'blur')" todo-focus="todo == editedTodo">
33+
</form>
34+
</li>
35+
</ul>
36+
</section>
37+
<footer id="footer" ng-show="todos.length" ng-cloak>
38+
<span id="todo-count"><strong>{{remainingCount}}</strong>
39+
<ng-pluralize count="remainingCount" when="{ one: 'item left', other: 'items left' }"></ng-pluralize>
40+
</span>
41+
<ul id="filters">
42+
<li>
43+
<a ng-class="{selected: status == ''} " href="#/">All</a>
44+
</li>
45+
<li>
46+
<a ng-class="{selected: status == 'active'}" href="#/active">Active</a>
47+
</li>
48+
<li>
49+
<a ng-class="{selected: status == 'completed'}" href="#/completed">Completed</a>
50+
</li>
51+
</ul>
52+
<button id="clear-completed" ng-click="clearCompletedTodos()" ng-show="completedCount">Clear completed</button>
53+
</footer>
54+
</section>
55+
<footer id="info">
56+
<p>Double-click to edit a todo</p>
57+
<p>Credits:
58+
<a href="http://twitter.com/cburgdorf">Christoph Burgdorf</a>,
59+
<a href="http://ericbidelman.com">Eric Bidelman</a>,
60+
<a href="http://jacobmumm.com">Jacob Mumm</a> and
61+
<a href="http://igorminar.com">Igor Minar</a>
62+
</p>
63+
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
64+
</footer>
65+
</script>
66+
<script src="node_modules/todomvc-common/base.js"></script>
67+
<script src="node_modules/angular/angular.js"></script>
68+
<script src="node_modules/angular-route/angular-route.js"></script>
69+
<script src="js/app.js"></script>
70+
<script src="js/controllers/todoCtrl.js"></script>
71+
<script src="js/services/todoStorage.js"></script>
72+
<script src="js/directives/todoFocus.js"></script>
73+
<script src="js/directives/todoEscape.js"></script>
74+
</body>
75+
</html>

js/app.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*global angular */
2+
3+
/**
4+
* The main TodoMVC app module
5+
*
6+
* @type {angular.Module}
7+
*/
8+
angular.module('todomvc', ['ngRoute'])
9+
.config(function ($routeProvider) {
10+
'use strict';
11+
12+
var routeConfig = {
13+
controller: 'TodoCtrl',
14+
templateUrl: 'todomvc-index.html',
15+
resolve: {
16+
store: function (todoStorage) {
17+
// Get the correct module (API or localStorage).
18+
return todoStorage.then(function (module) {
19+
module.get(); // Fetch the todo records in the background.
20+
return module;
21+
});
22+
}
23+
}
24+
};
25+
26+
$routeProvider
27+
.when('/', routeConfig)
28+
.when('/:status', routeConfig)
29+
.otherwise({
30+
redirectTo: '/'
31+
});
32+
});

js/controllers/todoCtrl.js

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*global angular */
2+
3+
/**
4+
* The main controller for the app. The controller:
5+
* - retrieves and persists the model via the todoStorage service
6+
* - exposes the model to the template and provides event handlers
7+
*/
8+
angular.module('todomvc')
9+
.controller('TodoCtrl', function TodoCtrl($scope, $routeParams, $filter, store) {
10+
'use strict';
11+
12+
var todos = $scope.todos = store.todos;
13+
14+
$scope.newTodo = '';
15+
$scope.editedTodo = null;
16+
17+
$scope.$watch('todos', function () {
18+
$scope.remainingCount = $filter('filter')(todos, { completed: false }).length;
19+
$scope.completedCount = todos.length - $scope.remainingCount;
20+
$scope.allChecked = !$scope.remainingCount;
21+
}, true);
22+
23+
// Monitor the current route for changes and adjust the filter accordingly.
24+
$scope.$on('$routeChangeSuccess', function () {
25+
var status = $scope.status = $routeParams.status || '';
26+
27+
$scope.statusFilter = (status === 'active') ?
28+
{ completed: false } : (status === 'completed') ?
29+
{ completed: true } : '';
30+
});
31+
32+
$scope.addTodo = function () {
33+
var newTodo = {
34+
title: $scope.newTodo.trim(),
35+
completed: false
36+
};
37+
38+
if (!newTodo.title) {
39+
return;
40+
}
41+
42+
$scope.saving = true;
43+
store.insert(newTodo)
44+
.then(function success() {
45+
$scope.newTodo = '';
46+
})
47+
.finally(function () {
48+
$scope.saving = false;
49+
});
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.saveEdits = function (todo, event) {
59+
// Blur events are automatically triggered after the form submit event.
60+
// This does some unfortunate logic handling to prevent saving twice.
61+
if (event === 'blur' && $scope.saveEvent === 'submit') {
62+
$scope.saveEvent = null;
63+
return;
64+
}
65+
66+
$scope.saveEvent = event;
67+
68+
if ($scope.reverted) {
69+
// Todo edits were reverted-- don't save.
70+
$scope.reverted = null;
71+
return;
72+
}
73+
74+
todo.title = todo.title.trim();
75+
76+
if (todo.title === $scope.originalTodo.title) {
77+
$scope.editedTodo = null;
78+
return;
79+
}
80+
81+
store[todo.title ? 'put' : 'delete'](todo)
82+
.then(function success() {}, function error() {
83+
todo.title = $scope.originalTodo.title;
84+
})
85+
.finally(function () {
86+
$scope.editedTodo = null;
87+
});
88+
};
89+
90+
$scope.revertEdits = function (todo) {
91+
todos[todos.indexOf(todo)] = $scope.originalTodo;
92+
$scope.editedTodo = null;
93+
$scope.originalTodo = null;
94+
$scope.reverted = true;
95+
};
96+
97+
$scope.removeTodo = function (todo) {
98+
store.delete(todo);
99+
};
100+
101+
$scope.saveTodo = function (todo) {
102+
store.put(todo);
103+
};
104+
105+
$scope.toggleCompleted = function (todo, completed) {
106+
if (angular.isDefined(completed)) {
107+
todo.completed = completed;
108+
}
109+
store.put(todo, todos.indexOf(todo))
110+
.then(function success() {}, function error() {
111+
todo.completed = !todo.completed;
112+
});
113+
};
114+
115+
$scope.clearCompletedTodos = function () {
116+
store.clearCompleted();
117+
};
118+
119+
$scope.markAll = function (completed) {
120+
todos.forEach(function (todo) {
121+
if (todo.completed !== completed) {
122+
$scope.toggleCompleted(todo, completed);
123+
}
124+
});
125+
};
126+
});

js/directives/todoEscape.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*global angular */
2+
3+
/**
4+
* Directive that executes an expression when the element it is applied to gets
5+
* an `escape` keydown event.
6+
*/
7+
angular.module('todomvc')
8+
.directive('todoEscape', function () {
9+
'use strict';
10+
11+
var ESCAPE_KEY = 27;
12+
13+
return function (scope, elem, attrs) {
14+
elem.bind('keydown', function (event) {
15+
if (event.keyCode === ESCAPE_KEY) {
16+
scope.$apply(attrs.todoEscape);
17+
}
18+
});
19+
20+
scope.$on('$destroy', function () {
21+
elem.unbind('keydown');
22+
});
23+
};
24+
});

js/directives/todoFocus.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*global angular */
2+
3+
/**
4+
* Directive that places focus on the element it is applied to when the
5+
* expression it binds to evaluates to true
6+
*/
7+
angular.module('todomvc')
8+
.directive('todoFocus', function todoFocus($timeout) {
9+
'use strict';
10+
11+
return function (scope, elem, attrs) {
12+
scope.$watch(attrs.todoFocus, function (newVal) {
13+
if (newVal) {
14+
$timeout(function () {
15+
elem[0].focus();
16+
}, 0, false);
17+
}
18+
});
19+
};
20+
});

0 commit comments

Comments
 (0)