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  package org.apache.myfaces.shared.renderkit.html;
20  
21  import java.io.IOException;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.logging.Logger;
26  
27  import javax.faces.component.UIComponent;
28  import javax.faces.component.UIInput;
29  import javax.faces.component.UINamingContainer;
30  import javax.faces.component.UISelectOne;
31  import javax.faces.component.behavior.ClientBehavior;
32  import javax.faces.component.behavior.ClientBehaviorHolder;
33  import javax.faces.component.html.HtmlSelectOneRadio;
34  import javax.faces.context.FacesContext;
35  import javax.faces.context.ResponseWriter;
36  import javax.faces.convert.Converter;
37  import javax.faces.convert.ConverterException;
38  import javax.faces.model.SelectItem;
39  import javax.faces.model.SelectItemGroup;
40  
41  import org.apache.myfaces.shared.renderkit.JSFAttr;
42  import org.apache.myfaces.shared.renderkit.RendererUtils;
43  import org.apache.myfaces.shared.renderkit.html.util.JavascriptUtils;
44  import org.apache.myfaces.shared.renderkit.html.util.ResourceUtils;
45  
46  /**
47   * @author Manfred Geiler (latest modification by $Author: lu4242 $)
48   * @author Thomas Spiegl
49   * @version $Revision: 1393891 $ $Date: 2012-10-03 21:55:02 -0500 (Wed, 03 Oct 2012) $
50   */
51  public class HtmlRadioRendererBase
52          extends HtmlRenderer
53  {
54      //private static final Log log = LogFactory.getLog(HtmlRadioRendererBase.class);
55      private static final Logger log = Logger.getLogger(HtmlRadioRendererBase.class.getName());
56  
57      private static final String PAGE_DIRECTION = "pageDirection";
58      private static final String LINE_DIRECTION = "lineDirection";
59  
60      public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException
61      {
62          org.apache.myfaces.shared.renderkit.RendererUtils.checkParamValidity(
63                  facesContext, uiComponent, UISelectOne.class);
64  
65          UISelectOne selectOne = (UISelectOne)uiComponent;
66  
67          String layout = getLayout(selectOne);
68  
69          boolean pageDirectionLayout = false; // Defaults to LINE_DIRECTION
70          if (layout != null)
71          {
72              if (layout.equals(PAGE_DIRECTION))
73              {
74                  pageDirectionLayout = true;
75              }
76              else if (layout.equals(LINE_DIRECTION))
77              {
78                  pageDirectionLayout = false;
79              }
80              else
81              {
82                  log.severe("Wrong layout attribute for component " + 
83                          selectOne.getClientId(facesContext) + ": " + layout);
84              }
85          }
86  
87          ResponseWriter writer = facesContext.getResponseWriter();
88  
89          Map<String, List<ClientBehavior>> behaviors = null;
90  
91          if (uiComponent instanceof ClientBehaviorHolder)
92          {
93              behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
94              if (!behaviors.isEmpty())
95              {
96                  ResourceUtils.renderDefaultJsfJsInlineIfNecessary(facesContext, writer);
97              }
98          }
99          
100         writer.startElement(HTML.TABLE_ELEM, selectOne);
101         HtmlRendererUtils.renderHTMLAttributes(writer, selectOne,
102                                                HTML.SELECT_TABLE_PASSTHROUGH_ATTRIBUTES);
103         
104         if (behaviors != null && !behaviors.isEmpty())
105         {
106             writer.writeAttribute(HTML.ID_ATTR, selectOne.getClientId(facesContext), null);
107         }
108         else
109         {
110             HtmlRendererUtils.writeIdIfNecessary(writer, selectOne, facesContext); 
111         }        
112 
113         if (!pageDirectionLayout)
114         {
115             writer.startElement(HTML.TR_ELEM, selectOne);
116         }
117 
118         Converter converter;
119         List selectItemList = org.apache.myfaces.shared.renderkit.RendererUtils.getSelectItemList(
120                 selectOne, facesContext);
121         converter = HtmlRendererUtils.findUIOutputConverterFailSafe(facesContext, selectOne);
122         
123         Object currentValue = 
124             org.apache.myfaces.shared.renderkit.RendererUtils.getStringFromSubmittedValueOrLocalValueReturnNull(
125                     facesContext, selectOne);
126 
127         int itemNum = 0;
128 
129         for (Iterator it = selectItemList.iterator(); it.hasNext(); )
130         {
131             SelectItem selectItem = (SelectItem)it.next();
132 
133             itemNum = renderGroupOrItemRadio(facesContext, selectOne,
134                                              selectItem, currentValue,
135                                              converter, pageDirectionLayout, itemNum);
136         }
137 
138         if (!pageDirectionLayout)
139         {
140             writer.endElement(HTML.TR_ELEM);
141         }
142         writer.endElement(HTML.TABLE_ELEM);
143     }
144 
145 
146     protected String getLayout(UIComponent selectOne)
147     {
148         if (selectOne instanceof HtmlSelectOneRadio)
149         {
150             return ((HtmlSelectOneRadio)selectOne).getLayout();
151         }
152 
153         return (String)selectOne.getAttributes().get(JSFAttr.LAYOUT_ATTR);
154     }
155 
156 
157     protected String getStyleClass(UISelectOne selectOne)
158      {
159          if (selectOne instanceof HtmlSelectOneRadio)
160          {
161              return ((HtmlSelectOneRadio)selectOne).getStyleClass();
162          }
163 
164          return (String)selectOne.getAttributes().get(JSFAttr.STYLE_CLASS_ATTR);
165      }
166 
167 
168     /**
169      * Renders the given SelectItem(Group)
170      * @return the itemNum for the next item
171      */
172     protected int renderGroupOrItemRadio(FacesContext facesContext,
173                                          UIComponent uiComponent, SelectItem selectItem,
174                                          Object currentValue,
175                                          Converter converter, boolean pageDirectionLayout,
176                                          Integer itemNum) throws IOException
177     {
178 
179         ResponseWriter writer = facesContext.getResponseWriter();
180 
181         boolean isSelectItemGroup = (selectItem instanceof SelectItemGroup);
182 
183         // TODO : Check here for getSubmittedValue. Look at RendererUtils.getValue
184         // this is useless object creation
185 //        Object itemValue = selectItem.getValue();
186 
187         UISelectOne selectOne = (UISelectOne)uiComponent;
188 
189         if (isSelectItemGroup) 
190         {
191             if (pageDirectionLayout)
192             {
193                 writer.startElement(HTML.TR_ELEM, selectOne);
194             }
195 
196             writer.startElement(HTML.TD_ELEM, selectOne);
197             if (selectItem.isEscape())
198             {
199                 writer.writeText(selectItem.getLabel(),HTML.LABEL_ATTR);
200             }
201             else
202             {
203                 writer.write(selectItem.getLabel());
204             }
205             writer.endElement(HTML.TD_ELEM);
206 
207             if (pageDirectionLayout)
208             {
209                 writer.endElement(HTML.TR_ELEM);
210                 writer.startElement(HTML.TR_ELEM, selectOne);
211             }
212             writer.startElement(HTML.TD_ELEM, selectOne);
213 
214             writer.startElement(HTML.TABLE_ELEM, selectOne);
215             writer.writeAttribute(HTML.BORDER_ATTR, "0", null);
216             
217             if(!pageDirectionLayout)
218             {
219                 writer.startElement(HTML.TR_ELEM, selectOne);
220             }
221 
222             SelectItemGroup group = (SelectItemGroup) selectItem;
223             SelectItem[] selectItems = group.getSelectItems();
224 
225             for (SelectItem groupSelectItem : selectItems)
226             { 
227                 itemNum = renderGroupOrItemRadio(facesContext, selectOne, groupSelectItem, currentValue, 
228                                                  converter, pageDirectionLayout, itemNum);
229             }
230 
231             if(!pageDirectionLayout)
232             {
233                 writer.endElement(HTML.TR_ELEM);
234             }
235             writer.endElement(HTML.TABLE_ELEM);
236             writer.endElement(HTML.TD_ELEM);
237 
238             if (pageDirectionLayout)
239             {
240                 writer.endElement(HTML.TR_ELEM);
241             }
242 
243         } 
244         else 
245         {
246             String itemStrValue = org.apache.myfaces.shared.renderkit.RendererUtils.getConvertedStringValue(
247                     facesContext, selectOne, converter, selectItem.getValue());
248             boolean itemChecked = (itemStrValue == null) ? 
249                     itemStrValue == currentValue : 
250                     "".equals(itemStrValue) ? 
251                             (currentValue == null || itemStrValue.equals(currentValue)) : 
252                             itemStrValue.equals(currentValue);
253             
254             // IF the hideNoSelectionOption attribute of the component is true
255             // AND this selectItem is the "no selection option"
256             // AND there are currently selected items
257             // AND this item (the "no selection option") is not selected
258             if (HtmlRendererUtils.isHideNoSelectionOption(uiComponent) && selectItem.isNoSelectionOption() 
259                     && currentValue != null && !"".equals(currentValue) && !itemChecked)
260             {
261                 // do not render this selectItem
262                 return itemNum;
263             }
264             
265             writer.write("\t\t");
266             if (pageDirectionLayout)
267             {
268                 writer.startElement(HTML.TR_ELEM, selectOne);
269             }
270             writer.startElement(HTML.TD_ELEM, selectOne);
271     
272             boolean itemDisabled = selectItem.isDisabled();
273     
274             String itemId = renderRadio(facesContext, selectOne, itemStrValue, itemDisabled, 
275                     itemChecked, false, itemNum);
276     
277             // label element after the input
278             boolean componentDisabled = isDisabled(facesContext, selectOne);
279             boolean disabled = (componentDisabled || itemDisabled);
280     
281             HtmlRendererUtils.renderLabel(writer, selectOne, itemId, selectItem, disabled);
282     
283             writer.endElement(HTML.TD_ELEM);
284             if (pageDirectionLayout)
285             {
286                 writer.endElement(HTML.TR_ELEM);
287             }
288             
289             // we rendered one radio --> increment itemNum
290             itemNum++;
291         }
292         return itemNum;
293     }
294 
295     @Deprecated
296     protected void renderRadio(FacesContext facesContext,
297                                UIComponent uiComponent,
298                                String value,
299                                String label,
300                                boolean disabled,
301                                boolean checked, boolean renderId)
302             throws IOException
303     {
304         renderRadio(facesContext, (UIInput) uiComponent, value, disabled, checked, renderId, 0);
305     }
306 
307     /**
308      * Renders the input item
309      * @return the 'id' value of the rendered element
310      */
311     protected String renderRadio(FacesContext facesContext,
312                                UIInput uiComponent,
313                                String value,
314                                boolean disabled,
315                                boolean checked,
316                                boolean renderId,
317                                Integer itemNum)
318             throws IOException
319     {
320         String clientId = uiComponent.getClientId(facesContext);
321 
322         String itemId = (itemNum == null)? null : clientId + 
323                 UINamingContainer.getSeparatorChar(facesContext) + itemNum;
324 
325         ResponseWriter writer = facesContext.getResponseWriter();
326 
327         writer.startElement(HTML.INPUT_ELEM, uiComponent);
328 
329         if (itemId != null)
330         {
331             writer.writeAttribute(HTML.ID_ATTR, itemId, null);
332         }
333         else if (renderId)
334         {
335             writer.writeAttribute(HTML.ID_ATTR, clientId, null);
336         }
337         writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_RADIO, null);
338         writer.writeAttribute(HTML.NAME_ATTR, clientId, null);
339 
340         if (disabled)
341         {
342             writer.writeAttribute(HTML.DISABLED_ATTR, HTML.DISABLED_ATTR, null);
343         }
344 
345         if (checked)
346         {
347             writer.writeAttribute(HTML.CHECKED_ATTR, HTML.CHECKED_ATTR, null);
348         }
349 
350         if (value != null)
351         {
352             writer.writeAttribute(HTML.VALUE_ATTR, value, null);
353         }
354         else
355         {
356             writer.writeAttribute(HTML.VALUE_ATTR, "", null);
357         }
358         
359         Map<String, List<ClientBehavior>> behaviors = null;
360         if (uiComponent instanceof ClientBehaviorHolder && JavascriptUtils.isJavascriptAllowed(
361                 facesContext.getExternalContext()))
362         {
363             behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
364             
365             long commonPropertiesMarked = 0L;
366             if (isCommonPropertiesOptimizationEnabled(facesContext))
367             {
368                 commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(uiComponent);
369             }
370             if (behaviors.isEmpty() && isCommonPropertiesOptimizationEnabled(facesContext))
371             {
372                 CommonPropertyUtils.renderChangeEventProperty(writer, 
373                         commonPropertiesMarked, uiComponent);
374                 CommonPropertyUtils.renderEventProperties(writer, 
375                         commonPropertiesMarked, uiComponent);
376                 CommonPropertyUtils.renderFieldEventPropertiesWithoutOnchange(writer, 
377                         commonPropertiesMarked, uiComponent);
378             }
379             else
380             {
381                 HtmlRendererUtils.renderBehaviorizedOnchangeEventHandler(facesContext, writer, uiComponent, behaviors);
382                 if (isCommonEventsOptimizationEnabled(facesContext))
383                 {
384                     Long commonEventsMarked = CommonEventUtils.getCommonEventsMarked(uiComponent);
385                     CommonEventUtils.renderBehaviorizedEventHandlers(facesContext, writer, 
386                             commonPropertiesMarked, commonEventsMarked, uiComponent, behaviors);
387                     CommonEventUtils.renderBehaviorizedFieldEventHandlersWithoutOnchange(
388                         facesContext, writer, commonPropertiesMarked, commonEventsMarked, uiComponent, behaviors);
389                 }
390                 else
391                 {
392                     HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, uiComponent, behaviors);
393                     HtmlRendererUtils.renderBehaviorizedFieldEventHandlersWithoutOnchange(
394                             facesContext, writer, uiComponent, behaviors);
395                 }
396             }
397             HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, 
398                     HTML.INPUT_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED_AND_STYLE_AND_EVENTS);
399         }
400         else
401         {
402             HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, 
403                     HTML.INPUT_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED_AND_STYLE);
404         }
405 
406         if (isDisabled(facesContext, uiComponent))
407         {
408             writer.writeAttribute(org.apache.myfaces.shared.renderkit.html.HTML.DISABLED_ATTR, Boolean.TRUE, null);
409         }
410 
411         writer.endElement(HTML.INPUT_ELEM);
412 
413         return itemId;
414     }
415 
416 
417     protected boolean isDisabled(FacesContext facesContext, UIComponent uiComponent)
418     {
419         //TODO: overwrite in extended HtmlRadioRenderer and check for enabledOnUserRole
420         if (uiComponent instanceof HtmlSelectOneRadio)
421         {
422             return ((HtmlSelectOneRadio)uiComponent).isDisabled();
423         }
424 
425         return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(
426                 uiComponent, HTML.DISABLED_ATTR, false);
427     }
428 
429 
430     public void decode(FacesContext facesContext, UIComponent uiComponent)
431     {
432         org.apache.myfaces.shared.renderkit.RendererUtils.checkParamValidity(facesContext, uiComponent, null);
433         if (uiComponent instanceof UIInput)
434         {
435             HtmlRendererUtils.decodeUISelectOne(facesContext, uiComponent);
436         }
437         if (uiComponent instanceof ClientBehaviorHolder &&
438                 !HtmlRendererUtils.isDisabled(uiComponent))
439         {
440             HtmlRendererUtils.decodeClientBehaviors(facesContext, uiComponent);
441         }
442     }
443 
444 
445     public Object getConvertedValue(FacesContext facesContext, UIComponent uiComponent, Object submittedValue)
446         throws ConverterException
447     {
448         RendererUtils.checkParamValidity(facesContext, uiComponent, UISelectOne.class);
449         return org.apache.myfaces.shared.renderkit.RendererUtils.getConvertedUISelectOneValue(facesContext,
450                                                                                                (UISelectOne)uiComponent,
451                                                                                                submittedValue);
452     }
453 
454 }