Skip to content

Instantly share code, notes, and snippets.

@jbenet
Created February 9, 2012 04:29
Show Gist options
  • Save jbenet/1777302 to your computer and use it in GitHub Desktop.
Save jbenet/1777302 to your computer and use it in GitHub Desktop.
Backbone EditableText Component
define([
'jquery',
'underscore',
'backbone',
'handlebars',
'ich',
'util/resource',
'order!libs/bootstrap/bootstrap-twipsy',
'order!libs/bootstrap/bootstrap-popover',
], function($, _, Backbone, Handlebars, ich, Res) {
var random_id = function() {
return 'editabletext' + Math.round(Math.random() * 100000000);
}
var EditableTextComponent = {};
// Setup template.
EditableTextComponent.html = " \
<div class='editabletext' id='{{id}}'> \
<div id='{{id}}_text'> \
{{{html}}} \
{{#if addToggle}}<small id='toggle'>edit</small>{{/if}} \
</div> \
{{#if multiline}} \
<textarea id='{{id}}_edit' style='display: none;'>{{text}}</textarea> \
{{else}} \
<input type='text' id='{{id}}_edit' \
style='display: none;' value='{{text}}' /> \
{{/if}} \
</div> \
";
ich.addTemplate('editabletext', EditableTextComponent.html);
EditableTextComponent.template = ich.editabletext;
// Setup view.
EditableTextComponent.View = Backbone.View.extend({
template: EditableTextComponent.template,
// Delegated events for creating new items, and clearing completed ones.
events: {
"keypress textarea": "saveOnEnter",
"keypress input": "saveOnEnter",
"click #toggle": "toggle"
},
initialize: function() {
_.bindAll(this, 'saveOnEnter', 'toggle');
if (!this.options.textFn) {
throw new Error("EditableTextComponent requires option textFn.");
}
this.options.html = this.options.html || function(_) { return _; }
this.options.multiline = !!this.options.multiline;
this.options.addToggle = !!this.options.addToggle;
},
render: function() {
var text_ = this.options.textFn();
$(this.el).html(this.template({
id: this.options.id || random_id(),
text: text_,
html: this.html(text_),
multiline: this.options.multiline,
addToggle: this.options.addToggle
}));
if (this.options.help) {
this.find(".editabletext > #edit").popover(this.options.help);
}
Res.rendered(this.find(".editabletext > #text"));
},
find: function(sel) {
// add the randomly generated id in between.
var id = $(this.el).find('.editabletext').attr('id');
return $(this.el).find(sel.replace(/#/g, '#' + id + '_'));
},
// add any transforms from text to display html.
html: function(text) {
return this.options.html(text);
},
is_editing: false,
edit: function() {
var field = this.find(".editabletext > #edit");
var text = this.find(".editabletext > #text");
field.css("width", text.css("width") || '10');
field.css("height", text.css("height") || '10');
field.css("font", text.css("font"));
field.css("margin-left", parseInt(text.css("margin-left")) - 5);
field.css("margin-top", parseInt(text.css("margin-top")) - 5);
text.hide();
field.show();
field.focus();
field.value = field.value; // to move cursor to end.
this.is_editing = true;
if (this.options.onEdit)
this.options.onEdit();
},
saveText: function() {
return this.find(".editabletext > #edit").val()
},
save: function() {
var text = this.saveText();
// close popover
this.find(".editabletext > #edit").popover('hide');
// Attempt to validate
if (this.options.validate) {
var result = this.options.validate(text);
if (result) {
// validation failed. show help, and return
this.find(".editabletext > #edit").popover(result);
this.find(".editabletext > #edit").popover('show');
return;
}
}
// save and render
this.options.textFn(text);
this.render();
this.is_editing = false;
if (this.options.onSave)
this.options.onSave();
},
toggle: function() {
this.is_editing ? this.save() : this.edit();
},
saveOnEnter: function(e) {
if (e.keyCode == 13 && this.is_editing) {
this.save();
return false;
}
},
alert: function(text) {
this.find('.editabletext > #edit').css("class", "error");
this.find('.editabletext > #edit').popover({
title: "Error: invalid text.",
body: text,
trigger: 'manual',
});
}
});
return EditableTextComponent;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment