View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.tobago.internal.renderkit.renderer;
21  
22  import org.apache.myfaces.tobago.context.Markup;
23  import org.apache.myfaces.tobago.internal.component.AbstractUISelectOneRadio;
24  import org.apache.myfaces.tobago.internal.component.AbstractUISelectReference;
25  import org.apache.myfaces.tobago.internal.util.ArrayUtils;
26  import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
27  import org.apache.myfaces.tobago.internal.util.ObjectUtils;
28  import org.apache.myfaces.tobago.internal.util.SelectItemUtils;
29  import org.apache.myfaces.tobago.internal.util.StringUtils;
30  import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
31  import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
32  import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
33  import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
34  import org.apache.myfaces.tobago.util.ComponentUtils;
35  import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
36  
37  import javax.faces.context.FacesContext;
38  import javax.faces.model.SelectItem;
39  import java.io.IOException;
40  
41  public class SelectOneRadioRenderer<T extends AbstractUISelectOneRadio> extends SelectOneRendererBase<T> {
42  
43    @Override
44    public HtmlElements getComponentTag() {
45      return HtmlElements.TOBAGO_SELECT_ONE_RADIO;
46    }
47  
48    @Override
49    protected void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
50      final AbstractUISelectReference reference = component.getRenderRangeReference();
51      final TobagoResponseWriter writer = getResponseWriter(facesContext);
52  
53      final String id = component.getClientId(facesContext);
54  //    final String referenceId = reference != null ? reference.getClientId(facesContext) : id;
55      final Iterable<SelectItem> items = SelectItemUtils.getItemIterator(facesContext, component);
56      final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
57      final boolean disabled = component.isDisabled();
58      final boolean readonly = component.isReadonly();
59      final boolean required = component.isRequired();
60      final boolean inline = component.isInline();
61      final Markup markup = component.getMarkup();
62      final boolean isInsideCommand = isInside(facesContext, HtmlElements.COMMAND);
63  
64      writer.startElement(getTag(facesContext));
65      writer.writeClassAttribute(
66          inline ? BootstrapClass.FORM_CHECK_INLINE : null,
67          component.getCustomClass());
68      HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
69      writer.writeAttribute(HtmlAttributes.TITLE, title, true);
70      boolean first = true;
71      final Object value = component.getValue();
72      final String submittedValue = (String) component.getSubmittedValue();
73      int i = 0;
74      final int[] renderRange = getRenderRangeList(component, reference);
75      for (final SelectItem item : items) {
76        if (renderRange == null || ArrayUtils.contains(renderRange, i)) {
77          final boolean itemDisabled = item.isDisabled() || disabled;
78          final String itemId = id + ComponentUtils.SUB_SEPARATOR + i;
79          writer.startElement(HtmlElements.DIV);
80          writer.writeClassAttribute(
81              BootstrapClass.FORM_CHECK,
82              inline ? BootstrapClass.FORM_CHECK_INLINE : null,
83              isInsideCommand ? BootstrapClass.DROPDOWN_ITEM : null);
84          writer.startElement(HtmlElements.INPUT);
85          writer.writeClassAttribute(BootstrapClass.FORM_CHECK_INPUT);
86          writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.RADIO);
87          final String formattedValue = ComponentUtils.getFormattedValue(facesContext, component, item.getValue());
88          final boolean checked;
89          if (submittedValue == null) {
90            checked = ObjectUtils.equals(item.getValue(), value);
91          } else {
92            checked = ObjectUtils.equals(formattedValue, submittedValue);
93          }
94          writer.writeAttribute(HtmlAttributes.CHECKED, checked);
95          writer.writeNameAttribute(id);
96          writer.writeIdAttribute(itemId);
97          writer.writeAttribute(HtmlAttributes.VALUE, formattedValue, true);
98          writer.writeAttribute(HtmlAttributes.DISABLED, itemDisabled);
99          writer.writeAttribute(HtmlAttributes.READONLY, readonly);
100         writer.writeAttribute(HtmlAttributes.REQUIRED, required);
101         if (first) {
102           renderFocus(id, component.isFocus(), component.isError(), facesContext, writer);
103           first = false;
104         }
105         writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
106         writer.endElement(HtmlElements.INPUT);
107 
108         writer.startElement(HtmlElements.LABEL);
109         writer.writeClassAttribute(BootstrapClass.FORM_CHECK_LABEL);
110         writer.writeAttribute(HtmlAttributes.FOR, itemId, false);
111         if (item instanceof org.apache.myfaces.tobago.model.SelectItem) {
112           final org.apache.myfaces.tobago.model.SelectItem tobagoItem =
113               (org.apache.myfaces.tobago.model.SelectItem) item;
114           final String image = tobagoItem.getImage();
115           if (image != null) {
116             writer.startElement(HtmlElements.IMG);
117             writer.writeAttribute(HtmlAttributes.SRC, image, true);
118             writer.writeAttribute(HtmlAttributes.ALT, "", false);
119             writer.endElement(HtmlElements.IMG);
120           }
121         }
122 
123         final String label = item.getLabel();
124         if (label != null) {
125           writer.writeText(label);
126         }
127 
128         writer.endElement(HtmlElements.LABEL);
129         writer.endElement(HtmlElements.DIV);
130       }
131       i++;
132     }
133   }
134 
135   private int[] getRenderRangeList(AbstractUISelectOneRadio select, AbstractUISelectReference reference) {
136     final int[] indices
137         = StringUtils.getIndices(reference != null ? reference.getRenderRange() : select.getRenderRange());
138     return indices.length > 0 ? indices : null;
139   }
140 
141   @Override
142   protected void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
143     final TobagoResponseWriter writer = getResponseWriter(facesContext);
144 
145     writer.endElement(getTag(facesContext));
146 
147     encodeBehavior(writer, facesContext, component);
148   }
149 
150   private HtmlElements getTag(final FacesContext facesContext) {
151     if (isInside(facesContext, HtmlElements.COMMAND)) {
152       return HtmlElements.TOBAGO_SELECT_ONE_RADIO;
153     } else {
154       return HtmlElements.DIV;
155     }
156   }
157 
158   @Override
159   protected String getFieldId(final FacesContext facesContext, final T component) {
160     return null; // there is not a single input element in the type=radio case.
161   }
162 }