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);
  }
});