Tuesday, May 30, 2006

My Scriptaculous Local.InPlaceEditor extension

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;
if (this.options.externalControl) {
this.element.parentNode.insertBefore(this.form, this.element);
// stop the event to avoid a page refresh in Safari
if (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;


if (this.options.textarea) {
var br = document.createElement("br");

if (this.options.okButton) {
okButton = document.createElement("input");
okButton.type = "submit";
okButton.value = this.options.okText;
okButton.className = 'editor_ok_button';

if (this.options.cancelLink) {
cancelLink = document.createElement("a");
cancelLink.href = "#";
cancelLink.onclick = this.onclickCancel.bind(this);
cancelLink.className = 'editor_cancel';
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) {


Anonymous said...

Can we show a demo ?
I think this fonction will be realy great for "edit in placer" :D


Jeff Sheets said...

I'll try to get a demo going in the next week or two.

Anonymous said...

Hello, very nice hack but do u know where to put this option externalFormId:'reportGroupsEdit',formFieldName:'reportGroupName' and what to fill in to use ur hack?

Anonymous said...

This might be of interest too http://www.archivesat.com/Rails_spinoffs/thread831288.htm