In-Place Editing: The Summer 2007 Rewrite
July 17th, 2007 by Thomas Fuchs, 9 comments »Christophe rewrote In-Place Editing from scratch, seeking to eliminate all the corner-case quirks, smoothe the API, clean up the options, and add several much-requested features. The result is now part of script.aculo.us (as of changeset 7191)!
Does this break anything?
Well, mostly no. The only feature we know about that changed in a non-compatible manner is multiple-line management in the edited contents. Aside from that, existing options and behaviors remain.
Feedback welcome! I’d encourage trying out script.aculo.us trunk—if you have any bugs or general feedback, please don’t hesitate to discuss this on the mailing list!
However…
Many, many users monkey-patched the classes (that is, hacked internal methods directly, such as createEditField or createForm). This was never a safe practice, as it relies on undocumented, generally internal, and essentially unsupported aspects of the code. Note that you can of course continue to use the old version if anything blows, but I’d recommend to port the code over.
Because the code was heavily refactored in this rewrite, it is very much possible that some methods you used to monkey-patch are not there anymore, or that they still exist but do not have the exact same set of responsibilities as their previous version, or occur at the exact same moment in the in-place editor’s lifecycle. So you should beware, and when installing the latest script.aculo.us, test your tweaks like crazy.
What’s changed
Aside from plenty of internal cleanup and performance boosts, there are essentially two changes to existing behavior: multiple-line management and a few options that morphed to something else. The sequence of AJAX calls used by such features as alternate text loading and final persistence have also been cleaned up, along with AJAX-related form disabling/enabling.
Multiple-line management
In the previous version, if the markup being edited contained any notion of multiple-line once rendered (e.g. it featured a <br/> or a <p>), you’d get a multi-line editor (a textarea). This behavior could be disabled by setting the handleLineBreaks option to false. The only way to get a single-line editor was to not feature such markup in the edited text (or disable its detection) and have the rows option set to 1 (one). The markup itself would be converted on-the-fly to multiple lines with no markup before being edited, but would not get converted back when being saved. Also, if the editor was configured to load alternate text from the server side, this conversion and detection would not occur on the loaded text, but on the loading… message cough.
We discussed this in length, and decided to change that a bit for better consistency. There’s no more implicit, one-way HTML conversion or what-not. If you want a multiple-line editor, just set the rows option to a value greater than 1 (as before), or just feature line breaks (actual line breaks, not specific markup) in the element’s contents. That’s it. If you want to make that content editable using an alternate syntax, use the alternative text options (loadTextURL and loadingText), which serve exactly that purpose.
There’s also a new option, called autoRows, which determines how many lines are used when rows uses its default value of 1 (one), but the element’s contents features line breaks. This option defaults to 3 (three).
Option changes you should migrate to
Several options changed their names and value sets with this rewrite. Here’s a rundown:
okLinkandokButtonbecameokControl. The accepted values are'button'(default),'link'andfalse.- The same goes for
cancelLinkandcancelButtontowardscancelControl, except the default value is'link'here. highlightcolorandhighlightendcolorwere re-cased tohighlightColorandhighlightEndColor.evalScriptswas a source of confusion, was improperly used internally, and has been replaced byhtmlResponse(see below, “New options”).
Yes, you can’t have a button and a link for the same action anymore. But then, nobody used that configuration (and frankly, who would?!).
Currently, a deprecation layer lets you still use the former option names and values, but that won’t be kept in eternally, so migrate your scripts now!
What’s new
Plenty of stuff!
New options
- As stated earlier,
okControlandcancelControlgovern OK/cancel controls in the form now. fieldPostCreationdetermines what to do after the editing form gets ready. It can be'activate'(default),'focus'orfalse.htmlResponsedetermines what kind of request to perform when the editing form gets submitted to the server:- If set to
true(default), anAjax.Updateris used internally, with itsevalScriptsoption defaulting totrue(you can change that using theajaxOptionsoption). Only successful requests will update the element: failures will trigger theonFailurecallback. - If set to
false, anAjax.Requestwill be used, as we assume the server will not return an updated version of the contents for our element: we’re just notifying it. However, as always withAjax.Request, defaulting togetmethod (once again,ajaxOptionscan change that), returning a JavaScript-typed response will trigger automatic evaluation. Failed requests trigger theonFailurecallback, as always.
This essentially replaces the formerevalScriptsoption, whose named introduced confusion.
- If set to
rowsis now complemented byautoRows, as mentioned earlier: ifrowsis 1 and the value has line breaks, a multiple-line editor withautoRowsrows (defaults to 3) will be used.stripLoadedTextTagsdetermines whether to strip the tags from the alternate, AJAX-loaded contents (defaults tofalse).
New/changed callbacks
In-place editors feature a variety of callbacks, some of which existed in the previous version. Their exact triggering moment in the lifecycle may have changed, though. Here’s a full rundown so there’s no doubt left.
callbackis called when the form is about to be submitted to the server. At this point in time, the form was taken out of the DOM already, and the saving text was displayed. This takes the form and the editor’s value as its arguments, and defaults to serializing the form usingForm.serialize(which makes it easier for you to customize the form’s contents).onEnterEditModetriggers right before in-place editing begins, basically as soon as the editable element is clicked. The external control, if any, is not hidden yet, nor is the element, and the editing form hasn’t yet been created. It takes the in-place editor object as its single argument. Along with a few others, this was previously not a proper callback (passed through the options hash), but a method you had to override in your own version of the class. Ugh.onLeaveEditModeis symmetrical, and triggers once the whole editing process is over and every part of it is out of the page’s DOM. Same argument asonEnterEditMode.onEnterHovertriggers when the mouse enter the surface of the editable element. This takes the in-place editor object as its single argument, and defaults to setting the background’s color to thehighlightColoroption.onLeaveHoveris symmetrical, triggering when the mouse leaves the element’s surface, and fading the background color back to its original value (keeping the background image, too).onCompletetriggers when the editor form is done with, either through cancellation or successful submission to the server, and reacts by performing a highlight (keeping the background image). It takes two arguments: theXMLHttpRequestobject (orundefinedif it’s a cancellation) and the editable element.onFailuretriggers whenever an internal AJAX request fails (including HTTP responses with non-2xx codes). It takes theXMLHttpRequestand the in-place editor object as arguments, and defaults to displaying a message box with the details of the response’s body.onFormCustomizationis a brand-new callback that aims to make it easier to customize the editor form. It is triggered right after the editor field was created, and before any controls (OK/Cancel) are in. As it gets passed the in-place editor object and the form as its arguments, it’s pretty simple to useappendChildin order to add a few custom controls in there.
Support for multiple in-place editors
Every single AJAX request made by an in-place editor guarantees a new editorId parameter, that contains the edited element’s id attribute. This lets you factor the code for multiple in-place editors in a single server-side resource.
A better collection editor
The previous version of Ajax.InPlaceCollectionEditor required that you provide the collection of items as an array in the collection parameter at construction time. What’s more, it did not integrate well at all with alternate text loading.
The new version plays nice with alternate text loading, and also lets you dynamically load the collection through AJAX, every time the editing form is created (as always, the collection query will feature a editorId parameter, as described earlier). The two allowed formats for the collection are retained: either an array of values, which will serve as both value and text, or an array of two-item arrays, the first one being the value, the second one being the text.
When loading an alternate text (which will be used to match against item values in the collection), the loading text is featured as the sole option in the temporarily disabled dropdown list. The same kind of display is used while the collection is dynamically loaded. Note that the collection is loaded before the alternate text is.
The value option, which could force a given item in the dropdown list to be selected regardless of the current contents of the editable element, is still featured (however seldom it is used).
So, start your In-Place Editor engines!
Tweet This Post
Digg This Post
Share on Facebook









Any chance of a demopage pointing out the changes, it would be nice to see the new stuff in action.
Yeah, demos/examples would be very helpful.
A followup, in the interest of completeness.
I must have misunderstood what th0fu said about the implementation of ‘htmlResponse’ …
In order for JavaScript instructions from RJS files kicked off automatically by Rails to be executed properly, I found it was necessary to set ‘htmlResponse: false’. When set to true, the script would be rendered in the modified element (wrong!!), and also executed (altering the other elements on the page properly). Set to false, everything works as it did before in IPE, and finally also allows for execution of scripts after editing is finished in an IPCE.
This has been a very confusing process for me. Thus far, Rails has only been 50% effective or less at hiding the complexity and fragility of JS. But keep up the good work!
I am looking forward to seeing the new InPlaceCollectionEditor at work tomorrow! Today was such a struggle with the former one.
I use the "value" option!
I usually find it necessary to update other interface elements when a dropdown list is changed, so I hope there will be support for doing so.
Thank you to everyone who has worked on this!
It’s me again.
With regard to demos: please demonstrate the ‘paramName’ and ‘htmlResponse’ functionality — I can find no evidence that it functions as advertised.
I’m using prototype 1.5.1.1 and the very newest controls.js w/ Christophe’s changes. I am not certain whether there are other (undocumented) dependencies on other elements of script.aculo.us 1.7.1b3 … If so, it’d be nice to know that.
As it stands now, IPCE ignores "paramName" and neither it nor the basic IPE (text field) will allow execution of JS sent back to the browser (say, to update other fields on the page). Previously (yesterday, before I upgraded), the IPE would allow JS to execute, but the IPCE would not. I have now -lost- functionality as a result of upgrading.
According to this post, I expected that JS would be executed as if I had set ‘evalScripts’ even without explicitly setting it, since what you say is that it is ‘true’ by default.
If I could find any documentation about how these mysterious features are supposed to work, that would be excellent. If anyone knows of any, please tell me!
Thanks in advance!
Caleb: it’s the old dichotomy of Ajax.Request vs. Ajax.Updater: if you expect an HTML response, say so with htmlResponse: true (default). Then scripts in the markup (stuff surrounded by <script> elements) will be processed, and the rest of the markup will replace your recent edition. This is nominal.
The evalScripts option is NOT supported anymore.
If you expect a pure-JS response (as RJS would provide), set htmlResponse: false, and that’s it: because Ajax.Request is used internally, it’ll auto-eval JS-typed responses (i.e. HTTP responses featuring a JS MIME type, see http://prototypejs.org/api/ajax/request for details).
Also, do note that the latest controls.js assumes you’re using the latest trunk, which means the prototype.js version in its lib/ directory (which I believe is more recent than 1.5.1.1, but I might be wrong).
All: I’m working on a full doc/demo page that will describe and demo all options for both InPlaceEditor and InPlaceCollectionEditor. I can’t say when it will be released (I’m pretty overbooked), but it’ll definitely get out before August is over.
staticnullvoid: the dev space you’re referring to is huge and a hodge-podge of stuff ranging from despicable to excellent. Prototype will put up a 3rd-party lib page that will be carefully screened and monitored. Af for Scripty, every other developer writes some stuff he/she thinks is worthy of attention, but then who can say whether it’s great stuff or absolute crap? Still, Scripty’s current site is a wiki, indeed, so anyone can tweak it: if you’re so enclined, go ahead!
First, thank you very much for the great work – espacially the loadCollection-Option was a feature I really missed in the past.
Now – while I try the work with the new controls.js I’ve got some errors with InternetExplorer and the CollectionEditor. Looks like there are JS-Errors while dynamicalyy building the option-list for the edit-field.
Is the InPlaceCollectionEditor working for you in InternetExplorer?
Micha
Hi there,
Prototype recommends using a Hash for Ajax.[Request/Updater] calls.
I think that could be easily done with few changes like:
Rewrite the default callback:
callback: function(form,value) {
return Form.serialize(form, true);
}
Lines like 709:
params = (params ? params + ‘&’ : ‘?’) + ‘editorId=’ + this.element.id;
… should be:
params.editorId = this.element.id;
Which leads to also support a much needed ‘parameters’ option for the IPE. You just need to rewrite 708-710 from controls.js
var params = $H(this.options.callback(form, value));
params.editorId = this.element.id;
params.merge(this.options.parameters);
But, just a suggestion.