Re: WOComponent children
Re: WOComponent children
- Subject: Re: WOComponent children
- From: email@hidden
- Date: Tue, 15 Jan 2008 12:23:10 -0500
Thank you Paul Hertz, Lachlan Deck,
and Alexandar Spohr for your recent thoughts on the subject.
The ultimate goal is "resusability."
If you were to post to me and say "Aaron, those widgets you made are
cool, can I use them?" I would like to be able to just give you a
framework file and let you just link it into your project. All you should
have to worry about is dropping "CoolDateWidget" on a page and
it would just work. You shouldn't be concerned with the following three
points:
1) Don't worry that CoolDateWidget is
inside a WOConditional that is inside an AjaxUpdateContainer. When the
page loads you won't see the CoolDateWidget, but after selecting a choice
from a dependent popup (dropdown), it would appear. I don't want this widget
to break on you in this circumstance.
2) I shouldn't have to tell you to place
one or more _javascript_ and CSS resources in some static HTML web directory
and then add them to the head of your page wrapper. You might forget one
of them, you might place them out of order, the site admin might forget
to upload them, moreover... why should you care? The CoolDateWidget should
be a black box with exposed bindings that just works. You don't *have*
to know how it works.
3) I shouldn't have to tell you to extend
all of your page level components from MyGenericComponent in my framework
instead of WOComponent. Doing this might allow me to get things right with
some special logic but now you are in a bind. What if not only I did this
but some guy named Tom also did this in his framework. Now you have to
choose between Tom's framework and mine because you can't extend from both
MyGenericComponent and TomsGenericComponent at the same time. Bummer.
Those three points make it very clear.
It is presently impossible to develop effective reusable objects for the
Web 2.0 era in WebObjects. Mike's and Lachlan's ideas to manipulate the
DOM to load the required resources could work in the major browsers, but
it's tricky and appears to be the easiest way around a fatal flaw in the
WO component architecture. That fatal flaw is that the tree of components
that make up a page does not exist. Each node gets temporarily built piece
meal through a lot of pushing and popping in and out of woContext in each
phase of the request-response loop. Another way to say this is that there
is no notion of "children" and that is what is really needed.
The "parent" relationship should be considered optional and avoided
for reusable components.
Paul's method of building a tree of
WOComponents sounds like it could bare fruit, but he'll need to post some
code samples. Still, he is effectively building around a deficiency in
the WOComponent architecture by actually creating the desperately needed
tree structure. It also sounds like you'd have to do a bit of book keeping
to set up this node structure somewhat obviating the benefit for the purpose
at hand.
For the record, our current solution
works for us and is a reasonable compromise. It fails from item #3 outlined
above so it makes our code not easily used by others. But, if you find
yourself building lots of AJAX enabled reusable components in WebObjects,
this could work well for you across all browsers.
Summary:
Create a general WOComponent that will
be the ancestor for all your page level components, call it "GenericComponent.wo"
for this illustration. It could extend WOComponent, ERXWOComponent, or
something else. Every time you make a new AJAX reusable component, you'll
need to make GenericComponent.wo aware of it. Here's the source code to
GenericComponent.wo:
import com.webobjects.foundation.*;
import com.webobjects.appserver.*;
import com.webobjects.eocontrol.*;
import com.webobjects.eoaccess.*;
import er.ajax.AjaxUtils;
public class GenericComponent extends
WOComponent {
public GenericComponent(WOContext
context) {
super(context);
}
public
void appendToResponse(WOResponse response, WOContext context) {
super.appendToResponse(response, context);
// It's important that <html> and <head>
tags are already present so we call
// "addChildrenResourcesInHead"
after the appendToResponse cycle but right before that cycle ends.
addChildrenResourcesInHead(response, context);
}
protected
void addChildrenResourcesInHead(WOResponse response, WOContext context)
{
if (parent() == null) {
// Only
perform this logic if we are the outermost component (no parent)
// start
- General and WOnder related items
AjaxUtils.addScriptResourceInHead(context,
response, "Ajax", "prototype.js");
AjaxUtils.addScriptResourceInHead(context,
response, "Ajax", "scriptaculous.js");
AjaxUtils.addScriptResourceInHead(context,
response, "Ajax", "wonder.js");
// end
- General and WOnder related items
// your
app or framework specific
CoolDateWidget.addWebResourcesInHead(response,
context);
CoolValidatingTextField.addWebResourcesInHead(response,
context);
CoolBlockLayout.addWebResourcesInHead(response,
context);
...
}
}
}
Here's the relavent code for CoolBlockLayout.wo:
import com.webobjects.foundation.*;
import com.webobjects.appserver.*;
import com.webobjects.eocontrol.*;
import com.webobjects.eoaccess.*;
import er.ajax.AjaxUtils;
public abstract class CoolBlockLayout
extends WOComponent {
public CoolBlockLayout(WOContext
context) {
super(context);
}
public
static void addWebResourcesInHead(WOResponse response, WOContext context)
{
// Notice how we concentrate only on what
CoolBlockLayout needs to function.
// This is a nice abstraction so we never
have to worry about what is in the head
// because the next time we tweak this method
to add one more _javascript_ resource,
// the head tags will pick it up so long as
the GenericComponent calls the overall
// method here.
AjaxUtils.addStylesheetResourceInHead(context,
response, "MyFramework", "myBlocks.css");
AjaxUtils.addScriptResourceInHead(context,
response, "Ajax", "prototype.js");
AjaxUtils.addScriptResourceInHead(context,
response, "MyFramework", "myJavascriptUtilities.js");
AjaxUtils.addScriptResourceInHead(context,
response, "MyFramework", "myBlocks.js");
AjaxUtils.addScriptResourceInHead(context,
response, "MyFramework", "mySameHeight.js");
}
}
Again, this example is workable but
isn't perfect. At least it allows us to think about one reusable component
at a time. It also makes sure that all the needed resources are in the
head tag. You have to do a small amount of book keeping in the GenericComponent
(a drawback). You also have to make your page level components extend the
GenericComponent (bigger drawback). Finally, all your resources will be
in the head tag of every page (not so bad since they get cached).
The ideal solution is for "addWebResourcesInHead()"
to not be static and to be called automatically by the WO framework at
the right time so that it can put the proper values in the head. That way,
no other fiddling is necessary and "GenericComponent" is no longer
needed. Do I ask for too much? I think not.
"Seaside" does it right. Its
"WAComponent" knows how to find the "children" but
does not know how to find the "parent" (the exact opposite of
WOComponent). You can override #updateRoot in a WAComponent of your own
to do the equivalent of what I just called "the ideal solution".
This post by Ramon Leon is worth reading:
http://onsmalltalk.com/programming/smalltalk/pragmatic-css-and-_javascript_-in-seaside/
You know, I really don't mind Apple
holding the source code tight to WebObjects so long as they continue to
innovate. But I fear if they don't start innovating our beloved tool of
choice will begin evaporating. Presently we are in a configuration nightmare
and it's not so much fun to develop anymore. I really feel for Mike, Anjo
and others who continue to fight valiantly against all odds. The WOnder
team are the innovators right now. WOnder should be packaged together with
WebObjects... yea it should BE WebObjects. You should be free to fix the
problems with rapid-turn-around-mode parsing of updated resources without
having to sit and wait for Apple to incorporate them. I can go on... But
our champions can't do this so long as WebObjects is closed source. Apple,
if you love WO, set it free.
Additionally, please forgive my wandering
eye. Squeak did spring from Apple after all.
-- Aaron
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden