todomvc
Version:
> Helping you select an MV\* framework
115 lines (95 loc) • 3.12 kB
JavaScript
/*global define*/
define([
'jquery',
'underscore',
'backbone',
'text!templates/todos.html',
'common'
], function ($, _, Backbone, todosTemplate, Common) {
'use strict';
var TodoView = Backbone.View.extend({
tagName: 'li',
template: _.template(todosTemplate),
// The DOM events specific to an item.
events: {
'click .toggle': 'toggleCompleted',
'dblclick label': 'edit',
'click .destroy': 'clear',
'keypress .edit': 'updateOnEnter',
'keydown .edit': 'revertOnEscape',
'blur .edit': 'close'
},
// The TodoView listens for changes to its model, re-rendering. Since there's
// a one-to-one correspondence between a **Todo** and a **TodoView** in this
// app, we set a direct reference on the model for convenience.
initialize: function () {
this.listenTo(this.model, 'change', this.render);
this.listenTo(this.model, 'destroy', this.remove);
this.listenTo(this.model, 'visible', this.toggleVisible);
},
// Re-render the titles of the todo item.
render: function () {
this.$el.html(this.template(this.model.toJSON()));
this.$el.toggleClass('completed', this.model.get('completed'));
this.toggleVisible();
this.$input = this.$('.edit');
return this;
},
toggleVisible: function () {
this.$el.toggleClass('hidden', this.isHidden());
},
isHidden: function () {
var isCompleted = this.model.get('completed');
return (// hidden cases only
(!isCompleted && Common.TodoFilter === 'completed') ||
(isCompleted && Common.TodoFilter === 'active')
);
},
// Toggle the `"completed"` state of the model.
toggleCompleted: function () {
this.model.toggle();
},
// Switch this view into `"editing"` mode, displaying the input field.
edit: function () {
this.$el.addClass('editing');
this.$input.focus();
},
// Close the `"editing"` mode, saving changes to the todo.
close: function () {
var value = this.$input.val();
var trimmedValue = value.trim();
if (trimmedValue) {
this.model.save({ title: trimmedValue });
if (value !== trimmedValue) {
// Model values changes consisting of whitespaces only are not causing change to be triggered
// Therefore we've to compare untrimmed version with a trimmed one to chech whether anything changed
// And if yes, we've to trigger change event ourselves
this.model.trigger('change');
}
} else {
this.clear();
}
this.$el.removeClass('editing');
},
// If you hit `enter`, we're through editing the item.
updateOnEnter: function (e) {
if (e.keyCode === Common.ENTER_KEY) {
this.close();
}
},
// If you're pressing `escape` we revert your change by simply leaving
// the `editing` state.
revertOnEscape: function (e) {
if (e.which === Common.ESCAPE_KEY) {
this.$el.removeClass('editing');
// Also reset the hidden input back to the original value.
this.$input.val(this.model.get('title'));
}
},
// Remove the item, destroy the model from *localStorage* and delete its view.
clear: function () {
this.model.destroy();
}
});
return TodoView;
});