Okay, I have yet another approach that I thought of while walking my
dogs that is much more JSF-ish and goes along with Christi's email on
sub-renderers.
Instead creating a whole bloody wrapper API framework that would make
the API hard to change, what about breaking the renderers down even
more into subclasses.
Take the tr:panelPopup for example again. It has:
Outer container
Trigger
Popup
Title bar
Close button
Body
So lets say this is how the renderer could be built:
First, create a bunch of renderer types:
org.apache.myfaces.trinidad.Popup
org.apache.myfaces.trinidad.Popup.Trigger
org.apache.myfaces.trinidad.Popup.PopupShell
org.apache.myfaces.trinidad.Popup.TitleBar
org.apache.myfaces.trinidad.Popup.ButtonArea
org.apache.myfaces.trinidad.Popup.Body
Then register a default renderer for each of these types.
Then the PanelPopupRenderer would in encodeAll:
render outer DIV (ppr stuff)
call a render utils method to get the renderer for the trigger and encode it
call a render utils method to get the renderer for the popup shell and encode it
in the popup shell renderer:
encode the outer HTML
call a render utils method to get the renderer for the title bar and encode it
call a render utils method to get the renderer for the popup body and encode it
in the title bar renderer:
encode the outer HTML
encode the title
call a render utils method to get the renderer for the button area and encode it
in the body renderer:
encode the outer HTML
encode the children components
This way there are many renderers to one component. The renderers
would be registered in the faces-config.xml just like any ordinary
renderers. Since the FacesBean allows renderers to encode any
component that has certain property keys, this is ideal.
Take for example the close button on the popup, we could have a faces
bean alias wrapper. What I mean by this is something like this:
public class PopupTitleBarRenderer extends XhtmlRenderer {
protected void encodeAll(FacesContext context, RenderingContext rc,
UIComponent component, FacesBean bean) throws IOException {
FacesBean wrapped = new AliasedFacesBean(bean);
wrapped.map("text", "title");
...
This way a command button renderer could be used to render the close
button using the title from the dialog as the text of the button.
Using this way, the only exposed API are the sub-renderer types that
can be defined in the faces config. New types can be added and old
ones removed without breaking Java interfaces or abstract class APIs
(although it would have to be controlled to not break custom code too
badly).
-Andrew