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: 1230370 $ $Date: 2012-01-11 21:07:58 -0500 (Wed, 11 Jan 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             writer.write(selectItem.getLabel());
198             writer.endElement(HTML.TD_ELEM);
199 
200             if (pageDirectionLayout)
201             {
202                 writer.endElement(HTML.TR_ELEM);
203                 writer.startElement(HTML.TR_ELEM, selectOne);
204             }
205             writer.startElement(HTML.TD_ELEM, selectOne);
206 
207             writer.startElement(HTML.TABLE_ELEM, selectOne);
208             writer.writeAttribute(HTML.BORDER_ATTR, "0", null);
209             
210             if(!pageDirectionLayout)
211             {
212                 writer.startElement(HTML.TR_ELEM, selectOne);
213             }
214 
215             SelectItemGroup group = (SelectItemGroup) selectItem;
216             SelectItem[] selectItems = group.getSelectItems();
217 
218             for (SelectItem groupSelectItem : selectItems)
219             { 
220                 itemNum = renderGroupOrItemRadio(facesContext, selectOne, groupSelectItem, currentValue, 
221                                                  converter, pageDirectionLayout, itemNum);
222             }
223 
224             if(!pageDirectionLayout)
225             {
226                 writer.endElement(HTML.TR_ELEM);
227             }
228             writer.endElement(HTML.TABLE_ELEM);
229             writer.endElement(HTML.TD_ELEM);
230 
231             if (pageDirectionLayout)
232             {
233                 writer.endElement(HTML.TR_ELEM);
234             }
235 
236         } 
237         else 
238         {
239             String itemStrValue = org.apache.myfaces.shared.renderkit.RendererUtils.getConvertedStringValue(
240                     facesContext, selectOne, converter, selectItem.getValue());
241             boolean itemChecked = (itemStrValue == null) ? 
242                     itemStrValue == currentValue : 
243                     "".equals(itemStrValue) ? 
244                             (currentValue == null || itemStrValue.equals(currentValue)) : 
245                             itemStrValue.equals(currentValue);
246             
247             // IF the hideNoSelectionOption attribute of the component is true
248             // AND this selectItem is the "no selection option"
249             // AND there are currently selected items
250             // AND this item (the "no selection option") is not selected
251             if (HtmlRendererUtils.isHideNoSelectionOption(uiComponent) && selectItem.isNoSelectionOption() 
252                     && currentValue != null && !"".equals(currentValue) && !itemChecked)
253             {
254                 // do not render this selectItem
255                 return itemNum;
256             }
257             
258             writer.write("\t\t");
259             if (pageDirectionLayout)
260             {
261                 writer.startElement(HTML.TR_ELEM, selectOne);
262             }
263             writer.startElement(HTML.TD_ELEM, selectOne);
264     
265             boolean itemDisabled = selectItem.isDisabled();
266     
267             String itemId = renderRadio(facesContext, selectOne, itemStrValue, itemDisabled, 
268                     itemChecked, false, itemNum);
269     
270             // label element after the input
271             boolean componentDisabled = isDisabled(facesContext, selectOne);
272             boolean disabled = (componentDisabled || itemDisabled);
273     
274             HtmlRendererUtils.renderLabel(writer, selectOne, itemId, selectItem, disabled);
275     
276             writer.endElement(HTML.TD_ELEM);
277             if (pageDirectionLayout)
278             {
279                 writer.endElement(HTML.TR_ELEM);
280             }
281             
282             // we rendered one radio --> increment itemNum
283             itemNum++;
284         }
285         return itemNum;
286     }
287 
288     @Deprecated
289     protected void renderRadio(FacesContext facesContext,
290                                UIComponent uiComponent,
291                                String value,
292                                String label,
293                                boolean disabled,
294                                boolean checked, boolean renderId)
295             throws IOException
296     {
297         renderRadio(facesContext, (UIInput) uiComponent, value, disabled, checked, renderId, 0);
298     }
299 
300     /**
301      * Renders the input item
302      * @return the 'id' value of the rendered element
303      */
304     protected String renderRadio(FacesContext facesContext,
305                                UIInput uiComponent,
306                                String value,
307                                boolean disabled,
308                                boolean checked,
309                                boolean renderId,
310                                Integer itemNum)
311             throws IOException
312     {
313         String clientId = uiComponent.getClientId(facesContext);
314 
315         String itemId = (itemNum == null)? null : clientId + 
316                 UINamingContainer.getSeparatorChar(facesContext) + itemNum;
317 
318         ResponseWriter writer = facesContext.getResponseWriter();
319 
320         writer.startElement(HTML.INPUT_ELEM, uiComponent);
321 
322         if (itemId != null)
323         {
324             writer.writeAttribute(HTML.ID_ATTR, itemId, null);
325         }
326         else if (renderId)
327         {
328             writer.writeAttribute(HTML.ID_ATTR, clientId, null);
329         }
330         writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_RADIO, null);
331         writer.writeAttribute(HTML.NAME_ATTR, clientId, null);
332 
333         if (disabled)
334         {
335             writer.writeAttribute(HTML.DISABLED_ATTR, HTML.DISABLED_ATTR, null);
336         }
337 
338         if (checked)
339         {
340             writer.writeAttribute(HTML.CHECKED_ATTR, HTML.CHECKED_ATTR, null);
341         }
342 
343         if (value != null)
344         {
345             writer.writeAttribute(HTML.VALUE_ATTR, value, null);
346         }
347         else
348         {
349             writer.writeAttribute(HTML.VALUE_ATTR, "", null);
350         }
351         
352         Map<String, List<ClientBehavior>> behaviors = null;
353         if (uiComponent instanceof ClientBehaviorHolder && JavascriptUtils.isJavascriptAllowed(
354                 facesContext.getExternalContext()))
355         {
356             behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
357             
358             long commonPropertiesMarked = 0L;
359             if (isCommonPropertiesOptimizationEnabled(facesContext))
360             {
361                 commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(uiComponent);
362             }
363             if (behaviors.isEmpty() && isCommonPropertiesOptimizationEnabled(facesContext))
364             {
365                 CommonPropertyUtils.renderChangeEventProperty(writer, 
366                         commonPropertiesMarked, uiComponent);
367                 CommonPropertyUtils.renderEventProperties(writer, 
368                         commonPropertiesMarked, uiComponent);
369                 CommonPropertyUtils.renderFieldEventPropertiesWithoutOnchange(writer, 
370                         commonPropertiesMarked, uiComponent);
371             }
372             else
373             {
374                 HtmlRendererUtils.renderBehaviorizedOnchangeEventHandler(facesContext, writer, uiComponent, behaviors);
375                 if (isCommonEventsOptimizationEnabled(facesContext))
376                 {
377                     Long commonEventsMarked = CommonEventUtils.getCommonEventsMarked(uiComponent);
378                     CommonEventUtils.renderBehaviorizedEventHandlers(facesContext, writer, 
379                             commonPropertiesMarked, commonEventsMarked, uiComponent, behaviors);
380                     CommonEventUtils.renderBehaviorizedFieldEventHandlersWithoutOnchange(
381                         facesContext, writer, commonPropertiesMarked, commonEventsMarked, uiComponent, behaviors);
382                 }
383                 else
384                 {
385                     HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, uiComponent, behaviors);
386                     HtmlRendererUtils.renderBehaviorizedFieldEventHandlersWithoutOnchange(
387                             facesContext, writer, uiComponent, behaviors);
388                 }
389             }
390             HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, 
391                     HTML.INPUT_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED_AND_STYLE_AND_EVENTS);
392         }
393         else
394         {
395             HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, 
396                     HTML.INPUT_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED_AND_STYLE);
397         }
398 
399         if (isDisabled(facesContext, uiComponent))
400         {
401             writer.writeAttribute(org.apache.myfaces.shared.renderkit.html.HTML.DISABLED_ATTR, Boolean.TRUE, null);
402         }
403 
404         writer.endElement(HTML.INPUT_ELEM);
405 
406         return itemId;
407     }
408 
409 
410     protected boolean isDisabled(FacesContext facesContext, UIComponent uiComponent)
411     {
412         //TODO: overwrite in extended HtmlRadioRenderer and check for enabledOnUserRole
413         if (uiComponent instanceof HtmlSelectOneRadio)
414         {
415             return ((HtmlSelectOneRadio)uiComponent).isDisabled();
416         }
417 
418         return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(
419                 uiComponent, HTML.DISABLED_ATTR, false);
420     }
421 
422 
423     public void decode(FacesContext facesContext, UIComponent uiComponent)
424     {
425         org.apache.myfaces.shared.renderkit.RendererUtils.checkParamValidity(facesContext, uiComponent, null);
426         if (uiComponent instanceof UIInput)
427         {
428             HtmlRendererUtils.decodeUISelectOne(facesContext, uiComponent);
429         }
430         if (uiComponent instanceof ClientBehaviorHolder &&
431                 !HtmlRendererUtils.isDisabled(uiComponent))
432         {
433             HtmlRendererUtils.decodeClientBehaviors(facesContext, uiComponent);
434         }
435     }
436 
437 
438     public Object getConvertedValue(FacesContext facesContext, UIComponent uiComponent, Object submittedValue)
439         throws ConverterException
440     {
441         RendererUtils.checkParamValidity(facesContext, uiComponent, UISelectOne.class);
442         return org.apache.myfaces.shared.renderkit.RendererUtils.getConvertedUISelectOneValue(facesContext,
443                                                                                                (UISelectOne)uiComponent,
444                                                                                                submittedValue);
445     }
446 
447 }