blob: 12fb24d5025d3c85ce2035851779bb11a7e403b3 [file] [log] [blame]
/*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();
});
}
};
window.app = App;
Utils.store = function () { return []; }
App.init();
});