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.
184 lines
4.5 KiB
184 lines
4.5 KiB
/*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(); |
|
});
|
|
|