You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@myfaces.apache.org by "glynn leininiger (Jira)" <de...@myfaces.apache.org> on 2022/03/09 21:40:00 UTC

[jira] [Created] (MYFACES-4430) Separate "begin tag" code from "end tag" code for HtmlCheckboxRendererBase

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)