Caution, long reply! Sorry...
Sounds like maybe IPE isn''t for you. First of all, I prefer generating
forms client-side using helpful tools such as Builder.node, and more
specialized wrappers that I write myself, and leaving the server to
handle only data. I think it is a much cleaner design philosophy, and
assuming your site is one that will take advantage of user cache, is
much quicker and less demanding of your server and makes debugging a
hell of a lot easier. Secondly, you may want to look at my Ajax.Tree
class at http://colin.mollenhour.com/ajaxtree if you are dealing with
hierarchical data a lot. That code is not the latest as I''ve been
working on implementing sorting into it as well so let me know if it
looks like something you''re interested in. I''ve used it in
many
different ways so far and the class/constructor design has proven itself
every time. It handles dynamic addition, deletion of data of multiple
types in any place very well, including proper event cleanup to prevent
memory leaks.
Back to InPlaceEditor... IMO it badly needs to be rewritten. It is so..
non-extensible. To do anything beyond a single text field requires you
to Object.extend and override a bunch of functions, many of which will
only have one or two lines of code that are different from the original.
There needs to be hooks for such actions as onCreate[Form|Field],
onSubmit, onComplete that make proper usage of bind and pass useful
variables. The loadExternalText feature is VERY specific and also needs
more customization ability (i.e. user created insertion handlers). I''m
not really talking about adding many lines of code, just rearranging
placement of hooks to where they make sense, make functions overridden
by the options parameter rather than having to override
Ajax.IPE.prototype.blah, using bind so that this. properties are
accessible, and for god''s sake, please do not use ajaxOptions for both
the loadExternalText AND the onSubmit! If you use an
ajaxOptions.onComplete for loadExternalText it will use it for onSubmit
as well, forcing you to use the same parameters for both loading text
and saving text! I wrestled IPE for hours the other day and all I
wanted was to add two select boxes to the form and fill them with a
loadExternalText hook. I think when IPE was written, there were great
ideas for making it extensible, just lots of oversights that you
wouldn''t notice until you actually tried to extend it. As it is,
extending IPE requires way too many lines of code that are redundant and
confusing as hell. I will post one of my several extensions as an
example. It is not clean at all since I had to study the IPE code
forever to make it work. If anyone can point out an easier way to do
something in it I am all ears. Maybe it will give you some ideas as
well, but be prepared for some confusing code!
Thanks,
Colin
It creates a form that looks like this:
clickable text:
<span>textarea contents <i>Assigned Task:</i> slave selected
innerHTML"</span>
when clicked becomes:
<form><textarea><select[master]><select[slave]><ok><cancel></form>
where master is a parent in a heirarchy that is used to drill down to
the value in slave, these select boxes are filled by onEnterEditMode
(the master select options will practically always be cached so it loads
really fast)
what is ugly here is that I had to assign a true value to loadTextUrl
and then override loadExternalText with an empty function. Also, to make
this work I overrode Ajax.InPlaceEditor.prototype.enterEditMode with a
modified function that will call this.options.onEnterEditMode after the
form has been created. Yes, if IPE is updated I will have to make sure
this function stays compatible with the updates. :(
----------CODE---------
....
Tree.makeNode.bind(this)(element,
[ Tree.addInPlaceEditor.bind(this)(data.text ||
''---'',this.page,{
size:90,
loadTextURL: true, /* prevent error */
onEnterEditMode: function(){
var masterSelect =
Builder.node(''select'',{name:''trade_id''});
var slaveSelect =
Builder.node(''select'',{name:''task_id''});
this.doubleCombo = new
Ajax.DoubleCombo(masterSelect, slaveSelect, QCCAdmin.tradesTasksPage,
QCCAdmin.taskComboOptions);
this.form.insertBefore(slaveSelect,this.editField.nextSibling);
this.form.insertBefore(masterSelect,this.editField.nextSibling);
this.form.insertBefore(Builder.node(''br''),this.editField.nextSibling);
this.doubleCombo.master.disabled = true;
this.editField.disabled = true;
new Ajax.Request( QCCAdmin.page, {
parameters:
''action=getInfo&id=''+this.element.id,
onComplete: function(xhr,json){
if(!json) json =
json_decode(xhr.responseText);
if(json && json.error){
alert(json.error); return; }
Element.removeClassName(this.form,
this.options.loadingClassName);
this.editField.disabled = false;
this.doubleCombo.master.disabled
= false;
this.editField.value =
json.template_name;
fillSelectCached(this.doubleCombo.master,''trades'',QCCAdmin.tradesTasksPage,{
onComplete:function(xhr2,json2){
if(json2 &&
json2.error){ alert(json2.error); return; }
if(json.trade_id){
selectValue(this.doubleCombo.master,json.trade_id);
this.doubleCombo.options.onComplete = function(xhr3,json3){
if(json3 &&
json3.error){ alert(json3.error); return; }
if(json.task_id){
selectValue(this.doubleCombo.slave,json.task_id);
}
this.doubleCombo.doHighlight(this.doubleCombo.slave);
Field.scrollFreeActivate(this.editField);
}.bind(this);
this.doubleCombo.onChange();
}
}.bind(this)
});
}.bind(this)
});
}
}) ],
[
Tree.addClickLink.bind(this)(''../images/icons/add.png'','''',this.options.showForm.bindAsEventListener(this,data)),
Tree.addClickLink.bind(this)(''../images/icons/delete.png'',''Delete'',Tree.deleteNode.bind(this))
]
);
this.disposables[this.disposables.length-1].loadExternalText = function(){};
.....
/* and the permanently modified onEnterEditMode function */
/* Changes:
made hiding of external control an option ("hideExternalControl")
relocated useless hook for onEnterEditMode to after createForm, now uses
options
do not scrollFreeActivate if loadTextURL is called
*/
Ajax.InPlaceEditor.prototype.enterEditMode = function(evt) {
if (this.saving || this.editing) return;
this.editing = true;
if(this.options.externalControl &&
this.options.hideExternalControl){
Element.hide(this.options.externalControl);
}
Element.hide(this.element);
this.createForm();
this.element.parentNode.insertBefore(this.form, this.element);
if(this.options.onEnterEditMode)
this.options.onEnterEditMode.bind(this)();
if(!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
// stop the event to avoid a page refresh in Safari
if(evt){ Event.stop(evt); }
return false;
}
Michael Schuerig wrote:>
>
> I''m trying to edit a hierarchical structure in-place. I''m
not using
> the Ajax.InPlaceEditor directly, but rather have derived a form editor
> from it that retrieves forms from the (rails) server. This stuff works
> mostly, but still needs some serious cleanup and generalization.
>
> What''s excluded from "works mostly" and is a real
bummer, is adding
> new objects. The UI is simply made of nested UL elements where the
> lowest list item in each list is an "Add Foo" link. When it is
> clicked, my InPlaceFormEditor retrieves a suitable edit form from the
> server and inserts it into the second but last position. As this item
> doesn''t have a persistent id yet, I set a special one. Then, when
the
> new item is saved, the ajax response contains a snippet of JavaScript
> that sets the id properly.
>
> Somewhere around this point, things are breaking down for me. Handling
> of ids, and wiring up newly inserted items with an in-place editor of
> their own, is getting just too messy. There must be a nice and clean
> solution, or so I hope.
> Michael
>
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Spinoffs" group.
To post to this group, send email to
rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-spinoffs?hl=en
-~----------~----~----~----~------~----~------~--~---