todomvc
Version:
> Helping you select an MV\* framework
140 lines (113 loc) • 3.05 kB
JavaScript
/*global TodoMVC */
'use strict';
TodoMVC.module('TodoList.Views', function (Views, App, Backbone, Marionette) {
// Todo List Item View
// -------------------
//
// Display an individual todo item, and respond to changes
// that are made to the item, including marking completed.
Views.ItemView = Marionette.ItemView.extend({
tagName: 'li',
template: '#template-todoItemView',
ui: {
edit: '.edit',
destroy: '.destroy',
label: 'label',
toggle: '.toggle'
},
events: {
'click @ui.destroy': 'deleteModel',
'dblclick @ui.label': 'onEditClick',
'keydown @ui.edit': 'onEditKeypress',
'focusout @ui.edit': 'onEditFocusout',
'click @ui.toggle': 'toggle'
},
modelEvents: {
'change': 'render'
},
onRender: function () {
this.$el.removeClass('active completed');
if (this.model.get('completed')) {
this.$el.addClass('completed');
} else {
this.$el.addClass('active');
}
},
deleteModel: function () {
this.model.destroy();
},
toggle: function () {
this.model.toggle().save();
},
onEditClick: function () {
this.$el.addClass('editing');
this.ui.edit.focus();
this.ui.edit.val(this.ui.edit.val());
},
onEditFocusout: function () {
var todoText = this.ui.edit.val().trim();
if (todoText) {
this.model.set('title', todoText).save();
this.$el.removeClass('editing');
} else {
this.destroy();
}
},
onEditKeypress: function (e) {
var ENTER_KEY = 13, ESC_KEY = 27;
if (e.which === ENTER_KEY) {
this.onEditFocusout();
return;
}
if (e.which === ESC_KEY) {
this.ui.edit.val(this.model.get('title'));
this.$el.removeClass('editing');
}
}
});
// Item List View
// --------------
//
// Controls the rendering of the list of items, including the
// filtering of activs vs completed items for display.
Views.ListView = Backbone.Marionette.CompositeView.extend({
template: '#template-todoListCompositeView',
childView: Views.ItemView,
childViewContainer: '#todo-list',
ui: {
toggle: '#toggle-all'
},
events: {
'click @ui.toggle': 'onToggleAllClick'
},
collectionEvents: {
'all': 'update'
},
initialize: function () {
this.listenTo(App.request('filterState'), 'change:filter', this.render, this);
},
addChild: function (child) {
var filteredOn = App.request('filterState').get('filter');
if (child.matchesFilter(filteredOn)) {
Backbone.Marionette.CompositeView.prototype.addChild.apply(this, arguments);
}
},
onRender: function () {
this.update();
},
update: function () {
function reduceCompleted(left, right) {
return left && right.get('completed');
}
var allCompleted = this.collection.reduce(reduceCompleted, true);
this.ui.toggle.prop('checked', allCompleted);
this.$el.parent().toggle(!!this.collection.length);
},
onToggleAllClick: function (e) {
var isChecked = e.currentTarget.checked;
this.collection.each(function (todo) {
todo.save({ 'completed': isChecked });
});
}
});
});