Commit 0c52b217 authored by Sam Saccone's avatar Sam Saccone

Merge pull request #1561 from dmitriz/my-angular-perf-fixed

Removed globals, readability, simplified or removed components - replace PR #1559
parents 4026ef86 c705f8b8
...@@ -8,45 +8,51 @@ ...@@ -8,45 +8,51 @@
<style>[ng-cloak] { display: none; }</style> <style>[ng-cloak] { display: none; }</style>
</head> </head>
<body> <body>
<section id="todoapp" ng-controller="TodoCtrl"> <section id="todoapp" ng-controller="TodoCtrl as TC">
<header id="header"> <header id="header">
<h1>todos</h1> <h1>todos</h1>
<form id="todo-form" ng-submit="addTodo()"> <form id="todo-form" ng-submit="TC.addTodo()">
<input id="new-todo" placeholder="What needs to be done?" ng-model="newTodo" autofocus> <input id="new-todo" placeholder="What needs to be done?" ng-model="TC.newTodo.title" autofocus>
</form> </form>
</header> </header>
<section id="main" ng-show="todos.length" ng-cloak> <section id="main" ng-show="TC.todos.length" ng-cloak>
<input id="toggle-all" type="checkbox" ng-model="allChecked" ng-click="markAll(allChecked)"> <input id="toggle-all" type="checkbox" ng-model="TC.allChecked" ng-click="TC.markAll(TC.allChecked)">
<label for="toggle-all">Mark all as complete</label> <label for="toggle-all">Mark all as complete</label>
<ul id="todo-list"> <ul id="todo-list">
<li ng-repeat="todo in todos | filter:statusFilter track by $index" ng-class="{completed: todo.completed, editing: todo == editedTodo}"> <li ng-repeat="todo in TC.todos | filter:TC.statusFilter track by $index"
ng-class="{completed: todo.completed, editing: todo === TC.editedTodo}">
<div class="view"> <div class="view">
<input class="toggle" type="checkbox" ng-model="todo.completed" ng-change="todoCompleted(todo)"> <input class="toggle" type="checkbox" ng-model="todo.completed">
<label ng-dblclick="editTodo(todo)">{{todo.title}}</label> <label ng-dblclick="TC.editTodo(todo)">{{todo.title}}</label>
<button class="destroy" ng-click="removeTodo(todo)"></button> <button class="destroy" ng-click="TC.removeTodo($index)"></button>
</div> </div>
<form ng-submit="doneEditing(todo)"> <form ng-submit="TC.doneEditing(todo, $index)">
<input class="edit" ng-trim="false" ng-model="todo.title" ng-blur="doneEditing(todo)" todo-escape="revertEditing(todo)" todo-focus="todo == editedTodo"> <input class="edit"
ng-trim="false"
ng-model="todo.title"
ng-blur="TC.doneEditing(todo, $index)"
ng-keydown="($event.keyCode === TC.ESCAPE_KEY) && TC.revertEditing($index)"
todo-focus="todo === TC.editedTodo">
</form> </form>
</li> </li>
</ul> </ul>
</section> </section>
<footer id="footer" ng-show="todos.length" ng-cloak> <footer id="footer" ng-show="TC.todos.length" ng-cloak>
<span id="todo-count"><strong>{{remainingCount}}</strong> <span id="todo-count"><strong>{{TC.remainingCount}}</strong>
<ng-pluralize count="remainingCount" when="{ one: 'item left', other: 'items left' }"></ng-pluralize> <ng-pluralize count="TC.remainingCount" when="{ one: 'item left', other: 'items left' }"></ng-pluralize>
</span> </span>
<ul id="filters"> <ul id="filters">
<li> <li>
<a ng-class="{selected: location.path() == '/'} " href="#/">All</a> <a ng-class="{selected: TC.location.path() == '/'} " href="#/">All</a>
</li> </li>
<li> <li>
<a ng-class="{selected: location.path() == '/active'}" href="#/active">Active</a> <a ng-class="{selected: TC.location.path() == '/active'}" href="#/active">Active</a>
</li> </li>
<li> <li>
<a ng-class="{selected: location.path() == '/completed'}" href="#/completed">Completed</a> <a ng-class="{selected: TC.location.path() == '/completed'}" href="#/completed">Completed</a>
</li> </li>
</ul> </ul>
<button id="clear-completed" ng-click="clearCompletedTodos()" ng-show="remainingCount < todos.length">Clear completed</button> <button id="clear-completed" ng-click="TC.clearCompletedTodos()" ng-show="TC.remainingCount < TC.todos.length">Clear completed</button>
</footer> </footer>
</section> </section>
<footer id="info"> <footer id="info">
...@@ -65,6 +71,5 @@ ...@@ -65,6 +71,5 @@
<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/todoEscape.js"></script>
</body> </body>
</html> </html>
/* jshint undef: true, unused: true */
/*global angular */ /*global angular */
/*jshint unused:false */ (function () {
'use strict'; 'use strict';
/** /**
* The main TodoMVC app module * The main TodoMVC app module that pulls all dependency modules declared in same named files
* *
* @type {angular.Module} * @type {angular.Module}
*/ */
var todomvc = angular.module('todomvc', []); angular.module('todomvc', ['todoCtrl', 'todoFocus', 'todoStorage']);
})();
/*global todomvc, angular */ /* jshint undef: true, unused: true */
'use strict'; /*global angular */
/** /*
* The main controller for the app. The controller: * Line below lets us save `this` as `TC`
* - retrieves and persists the model via the todoStorage service * to make properties look exactly the same as in the template
* - exposes the model to the template and provides event handlers
*/ */
todomvc.controller('TodoCtrl', function TodoCtrl($scope, $location, $filter, todoStorage) { //jscs:disable safeContextKeyword
var todos = $scope.todos = todoStorage.get(); (function () {
'use strict';
$scope.newTodo = '';
$scope.remainingCount = $filter('filter')(todos, {completed: false}).length; angular.module('todoCtrl', [])
$scope.editedTodo = null;
/**
if ($location.path() === '') { * The main controller for the app. The controller:
$location.path('/'); * - retrieves and persists the model via the todoStorage service
} * - exposes the model to the template and provides event handlers
*/
$scope.location = $location; .controller('TodoCtrl', function TodoCtrl($scope, $location, todoStorage) {
var TC = this;
$scope.$watch('location.path()', function (path) { var todos = TC.todos = todoStorage.get();
$scope.statusFilter = { '/active': {completed: false}, '/completed': {completed: true} }[path];
}); TC.ESCAPE_KEY = 27;
TC.editedTodo = {};
$scope.$watch('remainingCount == 0', function (val) {
$scope.allChecked = val; function resetTodo() {
}); TC.newTodo = {title: '', completed: false};
$scope.addTodo = function () {
var newTodo = $scope.newTodo.trim();
if (newTodo.length === 0) {
return;
} }
todos.push({ resetTodo();
title: newTodo,
completed: false
});
todoStorage.put(todos);
$scope.newTodo = ''; if ($location.path() === '') {
$scope.remainingCount++; $location.path('/');
};
$scope.editTodo = function (todo) {
$scope.editedTodo = todo;
// Clone the original todo to restore it on demand.
$scope.originalTodo = angular.extend({}, todo);
};
$scope.doneEditing = function (todo) {
$scope.editedTodo = null;
todo.title = todo.title.trim();
if (!todo.title) {
$scope.removeTodo(todo);
} }
todoStorage.put(todos); TC.location = $location;
};
$scope.revertEditing = function (todo) {
todos[todos.indexOf(todo)] = $scope.originalTodo;
$scope.doneEditing($scope.originalTodo);
};
$scope.removeTodo = function (todo) { $scope.$watch('TC.location.path()', function (path) {
$scope.remainingCount -= todo.completed ? 0 : 1; TC.statusFilter = { '/active': {completed: false}, '/completed': {completed: true} }[path];
todos.splice(todos.indexOf(todo), 1);
todoStorage.put(todos);
};
$scope.todoCompleted = function (todo) {
$scope.remainingCount += todo.completed ? -1 : 1;
todoStorage.put(todos);
};
$scope.clearCompletedTodos = function () {
$scope.todos = todos = todos.filter(function (val) {
return !val.completed;
}); });
todoStorage.put(todos);
};
$scope.markAll = function (completed) { // 3rd argument `true` for deep object watching
todos.forEach(function (todo) { $scope.$watch('TC.todos', function () {
todo.completed = completed; TC.remainingCount = todos.filter(function (todo) { return !todo.completed; }).length;
}); TC.allChecked = (TC.remainingCount === 0);
$scope.remainingCount = completed ? 0 : todos.length;
todoStorage.put(todos); // Save any changes to localStorage
}; todoStorage.put(todos);
}); }, true);
TC.addTodo = function () {
var newTitle = TC.newTodo.title = TC.newTodo.title.trim();
if (newTitle.length === 0) {
return;
}
todos.push(TC.newTodo);
resetTodo();
};
TC.editTodo = function (todo) {
TC.editedTodo = todo;
// Clone the original todo to restore it on demand.
TC.originalTodo = angular.copy(todo);
};
TC.doneEditing = function (todo, index) {
TC.editedTodo = {};
todo.title = todo.title.trim();
if (!todo.title) {
TC.removeTodo(index);
}
};
TC.revertEditing = function (index) {
TC.editedTodo = {};
todos[index] = TC.originalTodo;
};
TC.removeTodo = function (index) {
todos.splice(index, 1);
};
TC.clearCompletedTodos = function () {
TC.todos = todos = todos.filter(function (val) {
return !val.completed;
});
};
TC.markAll = function (completed) {
todos.forEach(function (todo) {
todo.completed = completed;
});
};
});
})();
//jscs:enable
/*global todomvc */
'use strict';
/**
* Directive that executes an expression when the element it is applied to gets
* an `escape` keydown event.
*/
todomvc.directive('todoEscape', function () {
var ESCAPE_KEY = 27;
return function (scope, elem, attrs) {
elem.bind('keydown', function (event) {
if (event.keyCode === ESCAPE_KEY) {
scope.$apply(attrs.todoEscape);
}
});
scope.$on('$destroy', function () {
elem.unbind('keydown');
});
};
});
/*global todomvc */ /* jshint undef: true, unused: true */
'use strict'; /*global angular */
(function () {
'use strict';
/** angular.module('todoFocus', [])
* Directive that places focus on the element it is applied to when the expression it binds to evaluates to true
*/ /**
todomvc.directive('todoFocus', function ($timeout) { * Directive that places focus on the element it is applied to when the expression it binds to evaluates to true
return function (scope, elem, attrs) { */
scope.$watch(attrs.todoFocus, function (newVal) { .directive('todoFocus', function ($timeout) {
if (newVal) { return function (scope, elem, attrs) {
$timeout(function () { scope.$watch(attrs.todoFocus, function (newVal) {
elem[0].focus(); if (newVal) {
}, 0, false); $timeout(function () {
} elem[0].focus();
}); }, 0, false);
}; }
}); });
};
});
})();
/*global todomvc */ /* jshint undef: true, unused: true */
'use strict'; /*global angular */
(function () {
'use strict';
/** angular.module('todoStorage', [])
* Services that persists and retrieves TODOs from localStorage
*/
todomvc.factory('todoStorage', function () {
var STORAGE_ID = 'todos-angularjs-perf';
return { /**
get: function () { * Services that persists and retrieves TODOs from localStorage
return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]'); */
}, .factory('todoStorage', function () {
var STORAGE_ID = 'todos-angularjs-perf';
put: function (todos) { return {
localStorage.setItem(STORAGE_ID, JSON.stringify(todos)); get: function () {
} return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]');
}; },
});
put: function (todos) {
localStorage.setItem(STORAGE_ID, JSON.stringify(todos));
}
};
});
})();
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