glynn leininiger created MYFACES-4430:
-----------------------------------------

             Summary: Separate "begin tag" code from "end tag" code for 
HtmlCheckboxRendererBase
                 Key: MYFACES-4430
                 URL: https://issues.apache.org/jira/browse/MYFACES-4430
             Project: MyFaces Core
          Issue Type: Improvement
          Components: General
    Affects Versions: 2.3.9
            Reporter: glynn leininiger


This ticket is very similar to MYFACES-4428, except it applies to 
HtmlSelectBooleanCheckbox. 

We're trying to implement a few JSF components that extend from the generic JSF 
components/renderers. This particular component is extending 
javax.faces.component.html.HtmlSelectBooleanCheckbox.

On the renderer side, we're grabbing a handle to the default renderer of the 
component:
{code:java}
        private static final String PARENT_FAMILY = "javax.faces.Checkbox";
        private static final String PARENT_RENDERER = 
"javax.faces.SelectBoolean";
        static final Renderer getWrappedRenderer(FacesContext context) {
                Renderer baseRenderer = 
context.getRenderKit().getRenderer(PARENT_FAMILY, PARENT_RENDERER);
                return baseRenderer;
        }{code}
Then we're going to attempt to write out some new CSS classes for the component 
and leave the rest of everything alone:
{code:java}
        @Override
        public void encodeBegin(FacesContext context, UIComponent component) 
throws IOException {
                Renderer baseRenderer = getWrappedRenderer(context);
                baseRenderer.encodeBegin(context, component);
                XXFaces.writeClasses(context, null, SF_FORM_CONTROL, 
BS_FORM_CONTROL);
        }


        @Override
        public void encodeEnd(FacesContext context, UIComponent component) 
throws IOException {
                Renderer baseRenderer = getWrappedRenderer(context);
                baseRenderer.encodeEnd(context, component);
        } {code}
 

The problem is HtmlCheckboxRendererBase does not have an encodeBegin() method, 
instead it does all of the "Start tag" encoding in the encodeEnd() method. This 
makes it impossible to create custom components that wrap the functionality of 
the default render kit without extending myfaces renderers and breaks any 
chance cross-platform components.

I propose adding this method in HtmlCheckboxRendererBase:
{code:java}
    @Override    
 public void encodeBegin(FacesContext facesContext, UIComponent uiComponent)
        throws IOException
{
    
org.apache.myfaces.shared.renderkit.RendererUtils.checkParamValidity(facesContext,
 uiComponent, null);
    
    Map<String, List<ClientBehavior>> behaviors = null;
    if (uiComponent instanceof ClientBehaviorHolder)
    {
        behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
        if (!behaviors.isEmpty())
        {
            ResourceUtils.renderDefaultJsfJsInlineIfNecessary(facesContext, 
facesContext.getResponseWriter());
        }
    }
    
    if (uiComponent instanceof UISelectBoolean)
    {
        Boolean value = 
org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanValue( uiComponent 
);
        boolean isChecked = value != null ? value.booleanValue() : false;
        renderCheckbox(facesContext, uiComponent, EXTERNAL_TRUE_VALUE, 
false,isChecked, true, null); 
            //TODO: the selectBoolean is never disabled
    }
    else if (uiComponent instanceof UISelectMany)
    {
        // let the current impl do what it does in encodeEnd do nothing here 
just don't want exception
        // throw if it is this case
        log.finest("encodeBegin() doing nothing intentionally for 
UISelectMany");
    }
    else
    {
        throw new IllegalArgumentException("Unsupported component class "
                + uiComponent.getClass().getName());
    }
}{code}
and changing encodeEnd() to this following:
{code:keyword}
    public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) 
throws IOException
{
    if (uiComponent instanceof UISelectBoolean)
    {
        ResponseWriter writer = facesContext.getResponseWriter();
        writer.endElement(HTML.INPUT_ELEM);
    }
    else if (uiComponent instanceof UISelectMany)
    {
        renderCheckboxList(facesContext, (UISelectMany) uiComponent);
    }
    else
    {
        throw new IllegalArgumentException("Unsupported component class " + 
uiComponent.getClass().getName());
    }
}{code}
and add this to the end of renderCheckbox()
{code:java}
if (uiComponent instanceof UISelectMany)
{
    writer.endElement(HTML.INPUT_ELEM);
}{code}
These changes split the logic for encode end and begin for renderCheckbox() and 
leaves the rendering logic alone for renderCheckboxList(). Encode begin calls 
renderCheckbox and encodeEnd writes the end element. Encode begin does nothing 
for UISelectMany elements as it is implemented in encodeEnd.

Im open to any feedback on this proposed change. 



--
This message was sent by Atlassian Jira
(v8.20.1#820001)

Reply via email to