myfaces-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Adam Winer" <awi...@gmail.com>
Subject Re: [TRINIDAD] Decoupling Renderers (PanelFormLayoutRenderer and LabelAndMessageRenderer)
Date Tue, 05 Jun 2007 16:53:10 GMT
On 6/4/07, Matt Cooper <matt.faces@gmail.com> wrote:
>
> I think decoupling of these renderers would be a good thing.  The trick
> will be to make sure the form item renders properly when it is a direct
> child of the form layout component.  Let's say that you put a
> tr:panelGroupLayout (or some other non form layout component) inbetween the
> form layout component and the form item--I feel that that particular form
> item should render the same as if there was no form layout involved (this
> would be insulating the form item from the form layout).


One of the big questions to decide when decoupling is whether you want the
parent component to augment/enhance the rendering of the children or for the
child to be passed more information to render itself differently.  In this
case, I wonder if both might be desirable, and I could imagine:
- A generic mechanism whereby a parent renderer could say "on my children,
here's a CoreRendererDecorator that I'd like to have called for any child
CoreRenderer", akin to a servlet fil
- A generic mechanism whereby a parent could publish rendering information
and child could ask for it, decoupled from looking at the renderer and
component (so we don't have getParent() or getParent().getRenderer() and
"instanceof" calls), something like Object
RenderingContext.getDescriptor(UIComponent
parent)?  This'd let us have classes like FormLayoutData in the public API,
decoupling the renderers, without forcing us to move the renderers
themselves into the public API.


When considering a decoupling approach, you will also want consider cases
> where a developer wants to have one kind of a form layout component inside
> of another form layout component.  There will need to be some sort of
> mechanism to ensure the correct rendering path is taken for the each
> particular component hierarchy so a simple "am I contained, at any level, in
> a form layout" might not be sufficient but an "am I a direct child of a form
> layout" might.
>
> Today, I believe if you have a tr:panelFormLayout inside of another
> tr:panelFormLayout, the outer layout will have labels on the side of the
> contents and the inner layout will have the labels above the contents.  This
> is determined by a request attribute that is present only during the
> encodeAll of the PanelFormLayout's encoding.
>
> One final tip...  There is one particular case where a form item isn't a
> direct child of the form layout but will still render as a form item:  when
> it is contained in a tr:group component and that tr:group is a direct child
> of the form layout.  The tr:group component is used by the form layout
> renderer to draw separator lines between groups of form items.


And, in addition, I think a lot of people really wish that if you had a
tr:iterator inside of
a tr:panelFormLayout, that children of that iterator would render as a form
item.  I think
a CoreRendererDecorator approach might accomplish that...

-- Adam



Regards,
> Matt
>
> On 5/24/07, Leonardo Uribe <lu4242@gmail.com> wrote:
> >
> > Hi everybody.
> >
> > I'm working on a trinidad component for do layout (as part of a Google
> > Summer of Code) more easy and with less code than panelFormLayout
> > component.
> >
> > Checking the code, I found a strong coupling between the classes
> > PanelFormLayoutRenderer and LabelAndMessageRenderer.
> >
> > I found the following points:
> >
> > 1. LabelAndMessageRenderer has about 3 behaviors, depending what is his
> > parent components. In the code it checks in a method something like
> > that:
> >
> >   private boolean _isFormRendererType(String rendererType)
> >   {
> >     return "org.apache.myfaces.trinidad.Form".equals(rendererType) ||
> >         "org.apache.myfaces.trinidad.FormLayout".equals(rendererType) ||
> >
> >         "org.apache.myfaces.trinidad.rich.Form ".equals(rendererType) ;
> >   }
> >
> > Because my component is a new component, i have to add a line like this
> >
> >     return "org.apache.myfaces.trinidad.Form".equals(rendererType) ||
> >         "org.apache.myfaces.trinidad.FormLayout ".equals(rendererType)
> > ||
> >         "org.apache.myfaces.trinidad.rich.Form".equals(rendererType) ||
> >         "org.apache.myfaces. trinidad.TableLayout".equals(rendererType);
> >
> > But this is very hacky. I have to do this because i need that the method
> > in encodeAll of LabelAndMessageRenderer
> >
> > boolean needsPanelFormLayout = _isParentPanelForm(component);
> >
> > returns true, because my component layout a table like panelFormLayout.
> >
> > 2. In other part of the code, LabelAndMessageRenderer call this method
> > (in encodeAll)
> >
> >       if (needsPanelFormLayout)
> >       {
> >         if(PanelFormLayoutRenderer.encodeBetweenLabelAndFieldCells(context,
> > arc, rw))
> >         {
> >           renderRootDomElementStyles(context, arc, component, bean);
> >         }
> >       }
> >
> > What if my component has another behavior to this method?
> > PanelFormLayoutRenderer detects if this panelFormLayout is inside
> > another panelFormLayout and because if it is the case, it adds between
> > Label and Field Cells something like this
> >
> >       rw.endElement("tr"); // label row
> >       rw.startElement("tr", null); // field row
> >
> > So, the label is rendered on top of the field.
> >
> > 3. LabelAndMessageRenderer do this for render a Label an a field (please
> > look the parts in yellow)
> >
> >   private void _renderLabelCell(
> >     FacesContext        context,
> >     RenderingContext arc,
> >     UIComponent         component,
> >     FacesBean           bean,
> >     boolean             labelExists) throws IOException
> >   {
> >     ResponseWriter rw = context.getResponseWriter();
> >     rw.startElement("td", null);
> >
> >     // render labelStyleClass and defaultStyleClass.
> >     renderStyleClasses(context, arc, new String[]{
> >                        getLabelStyleClass(bean),
> >                        _getDefaultLabelStyleClass(arc,
> >                           SkinSelectors.AF_LABEL_TEXT_STYLE_CLASS )});
> >
> >     String labelInlineStyle = getLabelInlineStyleKey(bean);
> >     rw.writeAttribute("style", labelInlineStyle, null);
> >
> >     String valign = getDefaultLabelValign(bean);
> >
> >     rw.writeAttribute ("valign", valign, null);
> >     if (isDesktop(arc))
> >       rw.writeAttribute("nowrap", Boolean.TRUE, null);
> >
> >     if (labelExists)
> >     {
> >       rw.writeAttribute("width",
> >                         arc.getProperties().get(_LABEL_CELL_WIDTH_KEY),
> >                         null);
> >     }
> >
> >     delegateRenderer(context, arc, component, bean, _label);
> >     rw.endElement ("td");
> >   }
> >
> >   private void _renderFieldCell(
> >     FacesContext        context,
> >     RenderingContext arc,
> >     UIComponent         component,
> >     FacesBean           bean,
> >     boolean             labelExists,
> >     boolean             needsPanelFormLayout,
> >     boolean             isInline) throws IOException
> >   {
> >     ResponseWriter rw = context.getResponseWriter();
> >     rw.startElement("td", null);
> >
> >     rw.writeAttribute("valign", "top", null);
> >     rw.writeAttribute("nowrap", Boolean.TRUE, null);
> >
> >     renderStyleClass(context, arc,
> > SkinSelectors.AF_CONTENT_CELL_STYLE_CLASS );
> >
> >     if (labelExists)
> >       rw.writeAttribute("width",
> >                         arc.getProperties().get(_FIELD_CELL_WIDTH_KEY),
> >                         null);
> >
> >     renderFieldCellContents(context, arc, component, bean);
> >
> >     // The panelForm places messages below the fields, not on a separate
> >     // row:
> >     if (needsPanelFormLayout)
> >     {
> >       // =-= mcc PPR PROBLEM!!!  We should always be rendering the
> > "div",
> >       //     and always rendering an ID, if we ever want it to be PPR
> >       //     replaceable:
> >       if (isInline || hasMessage(context, arc, component, bean))
> >       {
> >         rw.startElement("div", null);
> >         renderStyleClass(context, arc,
> >
> > SkinSelectors.AF_COMPONENT_MESSAGE_CELL_STYLE_CLASS);
> >         _renderMessageCellContents(context, arc, component, bean);
> >         rw.endElement("div");
> >       }
> >     }
> >
> >     // bug 2484841: PDA: TOO MUCH WHITESPACE BETWEEN
> >     //                   INPUT ELEMENTS IN LABELEDFIELD
> >     // This is a browser bug workaround, hopefully we can remove it
> > eventually
> >     if (isPDA(arc) && isIE(arc))
> >     {
> >       rw.startElement("div", null);
> >       renderSpacer(context, arc, "1", "0");
> >       rw.endElement("div");
> >     }
> >
> >     rw.endElement("td");
> >   }
> >
> > I need to add an attribute in the td tag like <td colspan=2 rowspan=3
> > height=XXX width=XXX .........>, but if i want this, i need to
> > modify LabelAndMessageRenderer to recognize if the parent component is
> > my component, check if it has an attribute like this
> >
> >                     <mycomp:tableFormLayout labelWidth="100"
> > width="400" height="300"
> >                         fieldWidth="100" rows="100" columns="1*;1*;1*" >
> >                         <tr:selectOneChoice label="Salutation">
> >                             <f:selectItem itemLabel="1 Option"
> > itemValue="1" />
> >                             <f:attribute name="spanXItem" value="2"/>
> >                             <f:attribute name="spanYItem" value="3"/>
> >                         </tr:selectOneChoice>
> >                     </mycomp:tableFormLayout>
> >
> > and finally add a colspan or rowspan (height and width are optional).
> >
> > ---------
> > Conclusion?: It's necesary to decouple PanelFormLayoutRenderer and other
> > FormRenderers with LabelAndMessageRenderer in order to avoid
> > those hacks. I propose to create an interface that implements some
> > affected methods or create new ones, and delegate this rendering to the
> > parent
> > classes.
> >
> > I want to you what should be better to do in that case. If its necesary
> > to refactor the classes, how it can be done.
> >
> > Thanks for your attention
> >
> > regards
> >
> > Att: Leonardo Uribe
> > Ingeniero de Sistemas
> > Pontificia Universidad Javeriana
> > Ingeniero Electronico
> > Universidad Nacional de Colombia
> >
> >
> >
> >
> >
> >
> >
> >
>

Mime
View raw message