My Scriptaculous Local.InPlaceEditor extension

Published:
Reading time:
About 2 min

I really like the script.aculo.us Ajax.InPlaceEditor, but it’s missing two things that I need.

One, it only edits a single field at a time. It would be much nicer IMHO to edit an entire form at once.

Two, it requires Ajax to submit the form and display the result. Nice and all, but sometimes I want to submit the form old-school style with a POST or GET and have the server generate the result. I tackled this today and have called it the Local.InPlaceEditor.

Local.InPlaceEditor requires that a form already is wrapping your text. When creating it the ‘url’ param is needed but ignored, and you need to supply two new options: externalFormId:‘reportGroupsEdit’,formFieldName:‘reportGroupName’

It would be nice if someone rewrote these two with a nice InPlaceEditor.Base like the AutoComplete classes. This extension is a bit of a hack, since it makes a handful of assumptions.

Here’s the code that I have placed in our extensions.js file. Post any questions below and I’ll try to answer them.


var InPlaceEditor = {}
InPlaceEditor.Local = Class.create();
Object.extend(InPlaceEditor.Local.prototype, Ajax.InPlaceEditor.prototype);
Object.extend(InPlaceEditor.Local.prototype, {
enterEditMode: function(evt) {
if (this.saving) return;
if (this.editing) return;
this.editing = true;
this.onEnterEditMode();
if (this.options.externalControl) {
Element.hide(this.options.externalControl);
}
Element.hide(this.element);
this.createForm();
this.element.parentNode.insertBefore(this.form, this.element);
Field.scrollFreeActivate(this.editField);
// stop the event to avoid a page refresh in Safari
if (evt) {
Event.stop(evt);
}
return false;
},
createForm: function() {
if (this.options.externalFormId) {
this.form = document.createElement(“span”);
// No bound onSubmit, so the ajax part won’t kick off
} else {
this.form = document.createElement(“form”);
Element.addClassName(this.form, this.options.formClassName)
this.form.onsubmit = this.onSubmit.bind(this);
}
this.form.id = this.options.formId;

this.createEditField();

if (this.options.textarea) {
var br = document.createElement(“br”);
this.form.appendChild(br);
}

if (this.options.okButton) {
okButton = document.createElement(“input”);
okButton.type = “submit”;
okButton.value = this.options.okText;
okButton.className = ‘editor_ok_button’;
this.form.appendChild(okButton);
}

if (this.options.cancelLink) {
cancelLink = document.createElement(“a”);
cancelLink.href = “#”;
cancelLink.appendChild(document.createTextNode(this.options.cancelText));
cancelLink.onclick = this.onclickCancel.bind(this);
cancelLink.className = ‘editor_cancel’;
this.form.appendChild(cancelLink);
}
},
createEditField: function() {
var text;
if(this.options.loadTextURL) {
text = this.options.loadingText;
} else {
text = this.getText();
}

var obj = this;

if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
this.options.textarea = false;
var textField = document.createElement(“input”);
textField.obj = this;
textField.type = “text”;
textField.name = this.options.formFieldName || “value”;
textField.value = text;
textField.style.backgroundColor = this.options.highlightcolor;
textField.className = ‘editor_field’;
var size = this.options.size || this.options.cols || 0;
if (size != 0) textField.size = size;
if (this.options.submitOnBlur)
textField.onblur = this.onSubmit.bind(this);
this.editField = textField;
} else {
this.options.textarea = true;
var textArea = document.createElement(“textarea”);
textArea.obj = this;
textArea.name = this.options.formFieldName || “value”;
textArea.value = this.convertHTMLLineBreaks(text);
textArea.rows = this.options.rows;
textArea.cols = this.options.cols || 40;
textArea.className = ‘editor_field’;
if (this.options.submitOnBlur)
textArea.onblur = this.onSubmit.bind(this);
this.editField = textArea;
}

if(this.options.loadTextURL) {
this.loadExternalText();
}
this.form.appendChild(this.editField);
}
});