/* * � Copyright IBM Corp. 2014 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ /* * Author: Brian Gleeson (brian.gleeson@ie.ibm.com) * Date: 19 Aug 2014 * CheckboxRenderer.java */ package com.ibm.xsp.theme.bootstrap.renderkit.html.extlib.form; import java.io.IOException; import javax.faces.component.UIComponent; import javax.faces.component.UIInput; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import com.ibm.commons.util.StringUtil; import com.ibm.xsp.ajax.AjaxUtil; import com.ibm.xsp.application.XspPropertyConstants; import com.ibm.xsp.component.FacesAttrsObject; import com.ibm.xsp.component.FacesOutputFiltering; import com.ibm.xsp.component.UIInputCheckbox; import com.ibm.xsp.component.xp.XspInputCheckbox; import com.ibm.xsp.context.FacesContextEx; import com.ibm.xsp.renderkit.ReadOnlyAdapterRenderer; import com.ibm.xsp.renderkit.dojo.DojoUtil; import com.ibm.xsp.renderkit.html_basic.AttrsUtil; import com.ibm.xsp.renderkit.html_basic.InputRendererUtil; /** * * @author Brian Gleeson (brian.gleeson@ie.ibm.com) */ public class CheckboxRenderer extends com.ibm.xsp.renderkit.html_extended.CheckboxRenderer { static final String CHECKBOX = "checkbox"; //$NON-NLS-1$ static final String[] ATTRS = { "tabindex", "accesskey" }; // $NON-NLS-1$ $NON-NLS-2$ static final String DIR = "dir"; //$NON-NLS-1$ /* * (non-Javadoc) * * @see javax.faces.render.Renderer#encodeEnd(javax.faces.context.FacesContext, * javax.faces.component.UIComponent) */ @Override public void encodeEnd(FacesContext context, UIComponent component) throws IOException { // validate the context and component if (context == null || component == null) { throw new NullPointerException(); } ResponseWriter writer = context.getResponseWriter(); if (writer == null) { throw new NullPointerException(); } // should this component be rendered if (!component.isRendered()) { return; } // SPR# YSAI8RVAJB - do not render a checkbox for non-existent entries (e.g. deleted parent docs) String customHtmlValue = null; XspInputCheckbox checkbox = (component instanceof XspInputCheckbox) ? (XspInputCheckbox)component : null; if(null != checkbox && checkbox.useCustomHtmlValue()) { customHtmlValue = checkbox.getCustomHtmlValue(); if (StringUtil.isEmpty(customHtmlValue)) { return; // we need a custom value and we don't have it - return } // if non-null, the customHtmlValue is rendered further down // but we need to check here first in case we need to bale... } // start the label String text = (String)component.getAttributes().get(TEXT); if(text!=null && component instanceof FacesOutputFiltering) { String filter = ((FacesOutputFiltering)component).getHtmlFilterName(); if(filter!=null) { text = ((FacesContextEx)context).filterHtml(filter, text); } } boolean writeLabel = StringUtil.isNotEmpty(text); if(AjaxUtil.isAjaxPartialRefresh(context) && AjaxUtil.isRendered(context, component)) { //then this is a 'partial refresh' targetted on the component //the JS will replace the <INPUT> element, so don't render the <LABEL> or we'll get nested labels //don't move the ID to the <LABEL> element as this will affect other functionality writeLabel = false; } // start the wrapping div tag writer.startElement("div", component); // $NON-NLS-1$ if(checkbox.getDojoType()==null) { writer.writeAttribute("class", CHECKBOX, "class"); // $NON-NLS-1$ $NON-NLS-2$ }else{ writer.writeAttribute("style", "display: inline;", "style"); // $NON-NLS-1$ $NON-NLS-2$ $NON-NLS-3$ } encodeHtmlStyleAttributes(writer, component); if (writeLabel) { writer.startElement(LABEL, component); String clientId = component.getClientId(context); writer.writeAttribute(FOR, clientId, CLIENTID); String dir = (String)component.getAttributes().get(DIR); if (!StringUtil.isEmpty(dir)) writer.writeAttribute(DIR, dir, DIR); encodeHtmlStyleAttributes(writer, component); } // encode the input tag writer.startElement(INPUT, component); //dojoType and dojoAttributes if they are present boolean forceId = false; if(checkbox!=null) { //Only force the Id if dojoType is set if(DojoUtil.addDojoAttributes(context, checkbox)!=null){ forceId = true; } } writeId(writer, context, component, forceId); writer.writeAttribute(TYPE, CHECKBOX, TYPE); writer.writeAttribute(NAME, component.getClientId(context), NAME); // readonly boolean readonly = ReadOnlyAdapterRenderer.isReadOnly(context,component); if(readonly) { writer.writeAttribute("readonly", "readonly", "readonly"); // $NON-NLS-1$ $NON-NLS-2$ $NON-NLS-3$ // TODO when showReadonlyAsDisabled, writing the disabled attribute. // would it be OK to only write the readonly attribute? writer.writeAttribute("disabled", "disabled", "disabled"); // $NON-NLS-1$ $NON-NLS-2$ $NON-NLS-3$ } // Add ARIA role attribute if (null != checkbox) { String role = checkbox.getRole(); if (StringUtil.isNotEmpty(role)) { writer.writeAttribute("role", role, "role"); // $NON-NLS-1$ $NON-NLS-2$ } if (checkbox.isRequired()) { writer.writeAttribute("aria-required", "true", null); // $NON-NLS-1$ $NON-NLS-2$ } if (!checkbox.isValid()) { writer.writeAttribute("aria-invalid", "true", null); // $NON-NLS-1$ $NON-NLS-2$ } } // encode the attributes listed in ATTRS... for(int i = 0; i < ATTRS.length; i++) writeAttribute(writer, component, ATTRS[i]); //encodeHtmlStyleAttributes(writer, component); // add the customHtmlValue if non-null (typically the note id) if (StringUtil.isNotEmpty(customHtmlValue)) { writer.writeAttribute(VALUE, customHtmlValue, VALUE); } writer.writeAttribute(CHECKED, UIInputCheckbox.isChecked(context, component)? Boolean.TRUE : Boolean.FALSE, VALUE); if( !readonly ){ // when readonly will have written disabled above. // check if disabled, and if so, write the disabled attribute writeBooleanAttribute(writer, component, "disabled"); // //$NON-NLS-1$ } encodeHtmlAttributes(writer, component, false); String onchangeTrigger = null; if( context instanceof FacesContextEx ){ FacesContextEx contextEx = (FacesContextEx)context; //xsp.client.script.radioCheckbox.ie.onchange.trigger= early-onclick | late-onblur[default] onchangeTrigger = contextEx.getProperty(XspPropertyConstants.XSP_RADIO_ONCHANGE_TRIGGER); } if( null != onchangeTrigger && !"late-onblur".equals(onchangeTrigger) ){ //$NON-NLS-1$ writer.writeAttribute("onchangeTrigger", onchangeTrigger, null); //$NON-NLS-1$ } if (component instanceof FacesAttrsObject) { FacesAttrsObject attrsHolder = (FacesAttrsObject) component; AttrsUtil.encodeAttrs(context, writer, attrsHolder); } writer.endElement(INPUT); // end the label if (writeLabel) { writer.writeText(text, TEXT); writer.endElement(LABEL); } //end the div writer.endElement("div"); // $NON-NLS-1$ InputRendererUtil.encodeValidation(context, context.getResponseWriter(), (UIInput)component); InputRendererUtil.encodeDirtyState(context, context.getResponseWriter(), (UIInput)component); } }