+1 also.

Matt Cooper wrote:
+1 on supporting an iterator around form items, I feel that would be quite a powerful enhancement

On 6/5/07, *Adam Winer* < [EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>> wrote:

    On 6/4/07, * Matt Cooper* <[EMAIL PROTECTED]
    <mailto:[EMAIL PROTECTED]>> 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* <[EMAIL PROTECTED]
        <mailto:[EMAIL PROTECTED]>> 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










Reply via email to