You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
4.5 KiB
185 lines
4.5 KiB
11 years ago
|
/*global jQuery, Handlebars */
|
||
|
jQuery(function ($) {
|
||
|
'use strict';
|
||
|
|
||
|
var Utils = {
|
||
|
uuid: function () {
|
||
|
/*jshint bitwise:false */
|
||
|
var i, random;
|
||
|
var uuid = '';
|
||
|
|
||
|
for (i = 0; i < 32; i++) {
|
||
|
random = Math.random() * 16 | 0;
|
||
|
if (i === 8 || i === 12 || i === 16 || i === 20) {
|
||
|
uuid += '-';
|
||
|
}
|
||
|
uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16);
|
||
|
}
|
||
|
|
||
|
return uuid;
|
||
|
},
|
||
|
pluralize: function (count, word) {
|
||
|
return count === 1 ? word : word + 's';
|
||
|
},
|
||
|
store: function (namespace, data) {
|
||
|
if (arguments.length > 1) {
|
||
|
return localStorage.setItem(namespace, JSON.stringify(data));
|
||
|
} else {
|
||
|
var store = localStorage.getItem(namespace);
|
||
|
return (store && JSON.parse(store)) || [];
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var App = {
|
||
|
init: function () {
|
||
|
this.ENTER_KEY = 13;
|
||
|
this.todos = Utils.store('todos-jquery');
|
||
|
this.cacheElements();
|
||
|
this.bindEvents();
|
||
|
this.render();
|
||
|
},
|
||
|
cacheElements: function () {
|
||
|
this.todoTemplate = Handlebars.compile($('#todo-template').html());
|
||
|
this.footerTemplate = Handlebars.compile($('#footer-template').html());
|
||
|
this.$todoApp = $('#todoapp');
|
||
|
this.$header = this.$todoApp.find('#header');
|
||
|
this.$main = this.$todoApp.find('#main');
|
||
|
this.$footer = this.$todoApp.find('#footer');
|
||
|
this.$newTodo = this.$header.find('#new-todo');
|
||
|
this.$toggleAll = this.$main.find('#toggle-all');
|
||
|
this.$todoList = this.$main.find('#todo-list');
|
||
|
this.$count = this.$footer.find('#todo-count');
|
||
|
this.$clearBtn = this.$footer.find('#clear-completed');
|
||
|
},
|
||
|
bindEvents: function () {
|
||
|
var list = this.$todoList;
|
||
|
this.$newTodo.on('keyup', this.create);
|
||
|
this.$toggleAll.on('change', this.toggleAll);
|
||
|
this.$footer.on('click', '#clear-completed', this.destroyCompleted);
|
||
|
list.on('change', '.toggle', this.toggle);
|
||
|
list.on('dblclick', 'label', this.edit);
|
||
|
list.on('keypress', '.edit', this.blurOnEnter);
|
||
|
list.on('blur', '.edit', this.update);
|
||
|
list.on('click', '.destroy', this.destroy);
|
||
|
},
|
||
|
render: function () {
|
||
|
this.$todoList.html(this.todoTemplate(this.todos));
|
||
|
this.$main.toggle(!!this.todos.length);
|
||
|
this.$toggleAll.prop('checked', !this.activeTodoCount());
|
||
|
this.renderFooter();
|
||
|
Utils.store('todos-jquery', this.todos);
|
||
|
},
|
||
|
renderFooter: function () {
|
||
|
var todoCount = this.todos.length;
|
||
|
var activeTodoCount = this.activeTodoCount();
|
||
|
var footer = {
|
||
|
activeTodoCount: activeTodoCount,
|
||
|
activeTodoWord: Utils.pluralize(activeTodoCount, 'item'),
|
||
|
completedTodos: todoCount - activeTodoCount
|
||
|
};
|
||
|
|
||
|
this.$footer.toggle(!!todoCount);
|
||
|
this.$footer.html(this.footerTemplate(footer));
|
||
|
},
|
||
|
toggleAll: function () {
|
||
|
var isChecked = $(this).prop('checked');
|
||
|
|
||
|
$.each(App.todos, function (i, val) {
|
||
|
val.completed = isChecked;
|
||
|
});
|
||
|
|
||
|
App.render();
|
||
|
},
|
||
|
activeTodoCount: function () {
|
||
|
var count = 0;
|
||
|
|
||
|
$.each(this.todos, function (i, val) {
|
||
|
if (!val.completed) {
|
||
|
count++;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return count;
|
||
|
},
|
||
|
destroyCompleted: function () {
|
||
|
var todos = App.todos;
|
||
|
var l = todos.length;
|
||
|
|
||
|
while (l--) {
|
||
|
if (todos[l].completed) {
|
||
|
todos.splice(l, 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
App.render();
|
||
|
},
|
||
|
// accepts an element from inside the `.item` div and
|
||
|
// returns the corresponding todo in the todos array
|
||
|
getTodo: function (elem, callback) {
|
||
|
var id = $(elem).closest('li').data('id');
|
||
|
|
||
|
$.each(this.todos, function (i, val) {
|
||
|
if (val.id === id) {
|
||
|
callback.apply(App, arguments);
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
create: function (e) {
|
||
|
var $input = $(this);
|
||
|
var val = $.trim($input.val());
|
||
|
|
||
|
if (e.which !== App.ENTER_KEY || !val) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
App.todos.push({
|
||
|
id: Utils.uuid(),
|
||
|
title: val,
|
||
|
completed: false
|
||
|
});
|
||
|
|
||
|
$input.val('');
|
||
|
App.render();
|
||
|
},
|
||
|
toggle: function () {
|
||
|
App.getTodo(this, function (i, val) {
|
||
|
val.completed = !val.completed;
|
||
|
});
|
||
|
App.render();
|
||
|
},
|
||
|
edit: function () {
|
||
|
var $input = $(this).closest('li').addClass('editing').find('.edit');
|
||
|
var val = $input.val();
|
||
|
|
||
|
$input.val(val).focus();
|
||
|
},
|
||
|
blurOnEnter: function (e) {
|
||
|
if (e.which === App.ENTER_KEY) {
|
||
|
e.target.blur();
|
||
|
}
|
||
|
},
|
||
|
update: function () {
|
||
|
var val = $.trim($(this).removeClass('editing').val());
|
||
|
|
||
|
App.getTodo(this, function (i) {
|
||
|
if (val) {
|
||
|
this.todos[i].title = val;
|
||
|
} else {
|
||
|
this.todos.splice(i, 1);
|
||
|
}
|
||
|
this.render();
|
||
|
});
|
||
|
},
|
||
|
destroy: function () {
|
||
|
App.getTodo(this, function (i) {
|
||
|
this.todos.splice(i, 1);
|
||
|
this.render();
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
App.init();
|
||
|
});
|