forked from nakajima/better-edit-in-place
/
editable.js
124 lines (112 loc) · 4.21 KB
/
editable.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Editable: Better in-place-editing
// http://github.com/nakajima/nakatype/wikis/better-edit-in-place-editable-js
var Editable = Class.create({
editFieldTag: 'input',
initialize: function(element, options) {
Object.extend(this, options);
this.element = $(element);
this.elementID = this.element.identify();
this.field = this.parseField();
this.value = this.element.innerHTML;
this.setupForm();
this.setupBehaviors();
},
// In order to parse the field correctly, it's necessary that the element
// you want to edit in place for have an id of (model_name)_(id)_(field_name).
// For example, if you want to edit the "caption" field in a "Photo" model,
// your id should be something like "photo_#{@photo.id}_caption".
// If you want to edit the "comment_body" field in a "MemberBlogPost" model,
// it would be: "member_blog_post_#{@member_blog_post.id}_comment_body"
parseField: function() {
var matches = this.elementID.match(/(.*)_(\d*)_(.*)/);
var fieldString = matches[1] + '[' + matches[3] + ']';
return fieldString;
},
// Create the editing form for the editable and inserts it after the element.
// If window._token is defined, then we add a hidden element that contains the
// authenticity_token for the AJAX request.
setupForm: function() {
this.editForm = new Element('form', { 'action': this.element.readAttribute('rel'), 'style':'display:none', 'class':'editor' });
this.editInput = new Element(this.editFieldTag, { 'name':this.field, 'id':('edit_' + this.element.identify()) });
this.editInput.value = this.element.innerHTML;
var saveInput = new Element('input', { type:'submit', value: Editable.options.saveText });
this.cancelLink = new Element('a', { href:'#' }); this.cancelLink.update(Editable.options.cancelText);
var methodInput = new Element('input', { type:'hidden', value:'put', name:'_method' });
if (typeof(window._token) != 'undefined') {
this.editForm.insert(new Element('input', {
type: 'hidden',
value: window._token,
name: 'authenticity_token'
}));
}
this.editForm.insert(this.editInput);
this.editForm.insert(saveInput);
this.editForm.insert(this.cancelLink);
this.editForm.insert(methodInput);
this.element.insert({after: this.editForm });
},
// Sets up event handles for editable.
setupBehaviors: function() {
this.element.observe('click', this.edit.bindAsEventListener(this));
this.editForm.observe('submit', this.save.bindAsEventListener(this));
this.cancelLink.observe('click', this.cancel.bindAsEventListener(this));
},
// Event Handler that activates form and hides element
edit: function(event) {
this.element.hide();
this.editForm.show();
this.editInput.activate();
event.stop();
},
// Event handler that makes request to server, then handles a JSON response.
save: function(event) {
var form = event.element();
var pars = form.serialize();
var url = form.readAttribute('action');
form.disable();
new Ajax.Request(url, {
method: 'put',
parameters: pars,
onSuccess: function(transport) {
var json = transport.responseText.evalJSON();
var attr = this.field.replace(/\w+\[(\w+)\]/, '$1');
this.value = json[attr];
this.editInput.value = json[attr];
this.element.update(json[attr]);
form.enable();
this.cancel();
}.bind(this),
onFailure: function(transport) {
this.cancel();
alert("Your change could not be saved.");
}.bind(this)
});
event.stop();
},
// Event handler that restores original editable value and hides form.
cancel: function(event) {
this.element.show();
this.editInput.value = this.value;
this.editForm.hide();
event.stop();
},
// Removes editable behavior from an element.
clobber: function() {
this.editForm.remove();
this.element.stopObserving('click');
delete(this);
}
});
Object.extend(Editable, {
options: {
cancelText: 'Cancel',
saveText: 'Save'
},
create: function(element) {
new Editable(element);
},
setupAll: function() {
$$('.editable').each(Editable.create);
}
});
Event.observe(document, 'dom:loaded', Editable.setupAll);