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 protected])
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]

Reply via email to