// 一个backbone的实例,作者:
// [Jérôme Gravel-Niquet](http://jgn.me/). 这个demo使用了
// [LocalStorage adapter](backbone-localstorage.js)
// 你可以在浏览器中演示它.
//当DOM载入完之后加载应用:
$(function() {
// Todo Model
// 基础 **Todo** model 拥有 `title`, `order`, 和 `done` 属性.
var Todo = Backbone.Model.extend({
// todo的默认属性.
defaults : {
title : "empty todo...",
done : false
},
// 保证每个model创建的时候都有`title`.
initialize : function() {
if(!this.get("title")) {
this.set({
"title" : this.defaults.title
});
}
},
// 切换`done`状态.
toggle : function() {
this.save({
done : !this.get("done")
});
},
// 将Todo从*localStorage*和视图中删除.
clear : function() {
this.destroy();
}
});
// Todo 列表
// ---------------
// 列表存储在*localStorage*中,代替存储在服务器中
var TodoList = Backbone.Collection.extend({
// 关联列表的 model.
model : Todo,
// 以`"todos"`名字空间保存所有Todo.
localStorage : new Store("todos-backbone"),
// 过滤已完成的Todo.
done : function() {
return this.filter(function(todo) {
return todo.get('done');
});
},
// 过滤列表,保留未完成的Todo.
remaining : function() {
return this.without.apply(this, this.done());
},
// 尽管我们在localStorage中是无序存储的,但是我们还是按顺序读取和保存的
nextOrder : function() {
if(!this.length)
return 1;
return this.last().get('order') + 1;
},
// 按照原来的顺序保存.
comparator : function(todo) {
return todo.get('order');
}
});
// 创建一个全局列表 **Todos**.
var Todos = new TodoList;
// Todo Item View
// --------------
// todo item的DOM元素
var TodoView = Backbone.View.extend({
//列表标签.
tagName : "li",
// 为单个元素缓存模板.
template : _.template($('#item-template').html()),
// 单个元素的DOM事件.
events : {
"click .toggle" : "toggleDone",
"dblclick .view" : "edit",
"click a.destroy" : "clear",
"keypress .edit" : "updateOnEnter",
"blur .edit" : "close"
},
// TodoView视图监听 model的事件变化,重新渲染, **Todo** 和 **TodoView** 成一一对应的关系.
initialize : function() {
this.model.bind('change', this.render, this);
this.model.bind('destroy', this.remove, this);
},
// 重新渲染单条todo的title.
render : function() {
var $el = $(this.el);
$el.html(this.template(this.model.toJSON()));
$el.toggleClass('done', this.model.get('done'));
this.input = this.$('.edit');
return this;
},
// 切换model的`"done"`状态.
toggleDone : function() {
this.model.toggle();
},
// 切换视图为`"editing"`,显示输入框.
edit : function() {
$(this.el).addClass("editing");
this.input.focus();
},
// 关闭`"editing"`视图, 保存改变数据到Todo.
close : function() {
var value = this.input.val().trim();
if(!value)
this.clear();
this.model.save({
title : value
});
$(this.el).removeClass("editing");
},
// 如果输入 `enter`回车键, 保存编辑项目.
updateOnEnter : function(e) {
if(e.keyCode == 13)
this.close();
},
// 移除单条Todo,销毁model.
clear : function() {
this.model.clear();
}
});
// The Application
// ---------------
// **AppView**是最外层层UI.
var AppView = Backbone.View.extend({
// 使用页面上已有的HTML结构.
el : $("#todoapp"),
// app底部统计的模板.
statsTemplate : _.template($('#stats-template').html()),
// 为新建Todo和清除已完成Todo创建事件代理.
events : {
"keypress #new-todo" : "createOnEnter",
"click #clear-completed" : "clearCompleted",
"click #toggle-all" : "toggleAllComplete"
},
// 初始化的时候绑定 `Todos`列表的事件,add事件会添加到 *localStorage*.
initialize : function() {
this.input = this.$("#new-todo");
this.allCheckbox = this.$("#toggle-all")[0];
Todos.bind('add', this.addOne, this);
Todos.bind('reset', this.addAll, this);
Todos.bind('all', this.render, this);
this.$footer = this.$('footer');
this.$main = $('#main');
Todos.fetch();
},
// 重新渲染只是刷新统计,其他不变.
render : function() {
var done = Todos.done().length;
var remaining = Todos.remaining().length;
if(Todos.length) {
this.$main.show();
this.$footer.show();
this.$footer.html(this.statsTemplate({
done : done,
remaining : remaining
}));
} else {
this.$main.hide();
this.$footer.hide();
}
this.allCheckbox.checked = !remaining;
},
// 添加一个Todo项,并插入到`<ul>`中.
addOne : function(todo) {
var view = new TodoView({
model : todo
});
this.$("#todo-list").append(view.render().el);
},
// 一次把所有的Todo添加到 **Todos** 列表中.
addAll : function() {
Todos.each(this.addOne);
},
// 新建一个Todo赋予属性.
newAttributes : function() {
return {
title : this.input.val().trim(),
order : Todos.nextOrder(),
done : false
};
},
// 在input中按回车键会新建一个**Todo** model并且保存到*localStorage*.
createOnEnter : function(e) {
if(e.keyCode != 13)
return;
if(!this.input.val().trim())
return;
Todos.create(this.newAttributes());
this.input.val('');
},
// 清除所有已完成Todo models.
clearCompleted : function() {
_.each(Todos.done(), function(todo) {
todo.clear();
});
return false;
},
toggleAllComplete : function() {
var done = this.allCheckbox.checked;
Todos.each(function(todo) {
todo.save({
'done' : done
});
});
}
});
// 创建一个 **App**.
var App = new AppView;
});