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.UISelectOne;
30  import javax.faces.component.behavior.ClientBehavior;
31  import javax.faces.component.behavior.ClientBehaviorHolder;
32  import javax.faces.component.html.HtmlSelectOneRadio;
33  import javax.faces.context.FacesContext;
34  import javax.faces.context.ResponseWriter;
35  import javax.faces.convert.Converter;
36  import javax.faces.convert.ConverterException;
37  import javax.faces.model.SelectItem;
38  import javax.faces.model.SelectItemGroup;
39  
40  import org.apache.myfaces.shared.renderkit.JSFAttr;
41  import org.apache.myfaces.shared.renderkit.RendererUtils;
42  import org.apache.myfaces.shared.renderkit.html.util.ResourceUtils;
43  
44  public class HtmlRadioRendererBase
45          extends HtmlRenderer
46  {
47      //private static final Log log = LogFactory.getLog(HtmlRadioRendererBase.class);
48      private static final Logger log = Logger.getLogger(HtmlRadioRendererBase.class.getName());
49  
50      private static final String PAGE_DIRECTION = "pageDirection";
51      private static final String LINE_DIRECTION = "lineDirection";
52  
53      public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException
54      {
55          org.apache.myfaces.shared.renderkit.RendererUtils.checkParamValidity(
56                  facesContext, uiComponent, UISelectOne.class);
57  
58          UISelectOne selectOne = (UISelectOne)uiComponent;
59  
60          String layout = getLayout(selectOne);
61  
62          boolean pageDirectionLayout = false; // Defaults to LINE_DIRECTION
63          if (layout != null)
64          {
65              if (layout.equals(PAGE_DIRECTION))
66              {
67                  pageDirectionLayout = true;
68              }
69              else if (layout.equals(LINE_DIRECTION))
70              {
71                  pageDirectionLayout = false;
72              }
73              else
74              {
75                  log.severe("Wrong layout attribute for component " + 
76                          selectOne.getClientId(facesContext) + ": " + layout);
77              }
78          }
79  
80          ResponseWriter writer = facesContext.getResponseWriter();
81  
82          Map<String, List<ClientBehavior>> behaviors = null;
83  
84          if (uiComponent instanceof ClientBehaviorHolder)
85          {
86              behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
87              if (!behaviors.isEmpty())
88              {
89                  ResourceUtils.renderDefaultJsfJsInlineIfNecessary(facesContext, writer);
90              }
91          }
92          
93          writer.startElement(HTML.TABLE_ELEM, selectOne);
94          HtmlRendererUtils.renderHTMLAttributes(writer, selectOne,
95                                                 HTML.SELECT_TABLE_PASSTHROUGH_ATTRIBUTES);
96          
97          if (behaviors != null && !behaviors.isEmpty())
98          {
99              writer.writeAttribute(HTML.ID_ATTR, selectOne.getClientId(facesContext), null);
100         }
101         else
102         {
103             HtmlRendererUtils.writeIdIfNecessary(writer, selectOne, facesContext); 
104         }        
105 
106         if (!pageDirectionLayout)
107         {
108             writer.startElement(HTML.TR_ELEM, null); // selectOne);
109         }
110 
111         Converter converter;
112         List selectItemList = org.apache.myfaces.shared.renderkit.RendererUtils.getSelectItemList(
113                 selectOne, facesContext);
114         converter = HtmlRendererUtils.findUIOutputConverterFailSafe(facesContext, selectOne);
115         
116         Object currentValue = 
117             org.apache.myfaces.shared.renderkit.RendererUtils.getStringFromSubmittedValueOrLocalValueReturnNull(
118                     facesContext, selectOne);
119 
120         int itemNum = 0;
121 
122         for (Iterator it = selectItemList.iterator(); it.hasNext(); )
123         {
124             SelectItem selectItem = (SelectItem)it.next();
125 
126             itemNum = renderGroupOrItemRadio(facesContext, selectOne,
127                                              selectItem, currentValue,
128                                              converter, pageDirectionLayout, itemNum);
129         }
130 
131         if (!pageDirectionLayout)
132         {
133             writer.endElement(HTML.TR_ELEM);
134         }
135         writer.endElement(HTML.TABLE_ELEM);
136     }
137 
138 
139     protected String getLayout(UIComponent selectOne)
140     {
141         if (selectOne instanceof HtmlSelectOneRadio)
142         {
143             return ((HtmlSelectOneRadio)selectOne).getLayout();
144         }
145 
146         return (String)selectOne.getAttributes().get(JSFAttr.LAYOUT_ATTR);
147     }
148 
149 
150     protected String getStyleClass(UISelectOne selectOne)
151      {
152          if (selectOne instanceof HtmlSelectOneRadio)
153          {
154              return ((HtmlSelectOneRadio)selectOne).getStyleClass();
155          }
156 
157          return (String)selectOne.getAttributes().get(JSFAttr.STYLE_CLASS_ATTR);
158      }
159 
160 
161     /**
162      * Renders the given SelectItem(Group)
163      * @return the itemNum for the next item
164      */
165     protected int renderGroupOrItemRadio(FacesContext facesContext,
166                                          UIComponent uiComponent, SelectItem selectItem,
167                                          Object currentValue,
168                                          Converter converter, boolean pageDirectionLayout,
169                                          Integer itemNum) throws IOException
170     {
171 
172         ResponseWriter writer = facesContext.getResponseWriter();
173 
174         boolean isSelectItemGroup = (selectItem instanceof SelectItemGroup);
175 
176         // TODO : Check here for getSubmittedValue. Look at RendererUtils.getValue
177         // this is useless object creation
178 //        Object itemValue = selectItem.getValue();
179 
180         UISelectOne selectOne = (UISelectOne)uiComponent;
181 
182         if (isSelectItemGroup) 
183         {
184             if (pageDirectionLayout)
185             {
186                 writer.startElement(HTML.TR_ELEM, null); // selectOne);
187             }
188 
189             writer.startElement(HTML.TD_ELEM, null); // selectOne);
190             if (selectItem.isEscape())
191             {
192                 writer.writeText(selectItem.getLabel(),HTML.LABEL_ATTR);
193             }
194             else
195             {
196                 writer.write(selectItem.getLabel());
197             }
198             writer.endElement(HTML.TD_ELEM);
199 
200             if (pageDirectionLayout)
201             {
202                 writer.endElement(HTML.TR_ELEM);
203                 writer.startElement(HTML.TR_ELEM, null); // selectOne);
204             }
205             writer.startElement(HTML.TD_ELEM, null); // selectOne);
206 
207             writer.startElement(HTML.TABLE_ELEM, null); // selectOne);
208             writer.writeAttribute(HTML.BORDER_ATTR, "0", null);
209             
210             if(!pageDirectionLayout)
211             {
212                 writer.startElement(HTML.TR_ELEM, null); // 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, null); // selectOne);
262             }
263             writer.startElement(HTML.TD_ELEM, null); // 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                 facesContext.getNamingContainerSeparatorChar() + 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)
354         {
355             behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
356             
357             long commonPropertiesMarked = 0L;
358             if (isCommonPropertiesOptimizationEnabled(facesContext))
359             {
360                 commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(uiComponent);
361             }
362             if (behaviors.isEmpty() && isCommonPropertiesOptimizationEnabled(facesContext))
363             {
364                 CommonPropertyUtils.renderChangeEventProperty(writer, 
365                         commonPropertiesMarked, uiComponent);
366                 CommonPropertyUtils.renderEventProperties(writer, 
367                         commonPropertiesMarked, uiComponent);
368                 CommonPropertyUtils.renderFieldEventPropertiesWithoutOnchange(writer, 
369                         commonPropertiesMarked, uiComponent);
370             }
371             else
372             {
373                 HtmlRendererUtils.renderBehaviorizedOnchangeEventHandler(facesContext, writer, uiComponent, 
374                         itemId != null ? itemId : clientId, behaviors);
375                 if (isCommonEventsOptimizationEnabled(facesContext))
376                 {
377                     Long commonEventsMarked = CommonEventUtils.getCommonEventsMarked(uiComponent);
378                     CommonEventUtils.renderBehaviorizedEventHandlers(facesContext, writer, 
379                             commonPropertiesMarked, commonEventsMarked, uiComponent,
380                             itemId != null ? itemId : clientId, behaviors);
381                     CommonEventUtils.renderBehaviorizedFieldEventHandlersWithoutOnchange(
382                         facesContext, writer, commonPropertiesMarked, commonEventsMarked, uiComponent,
383                             itemId != null ? itemId : clientId, behaviors);
384                 }
385                 else
386                 {
387                     HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, uiComponent,
388                             itemId != null ? itemId : clientId, behaviors);
389                     HtmlRendererUtils.renderBehaviorizedFieldEventHandlersWithoutOnchange(
390                             facesContext, writer, uiComponent,
391                             itemId != null ? itemId : clientId, behaviors);
392                 }
393             }
394             HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, 
395                     HTML.INPUT_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED_AND_STYLE_AND_EVENTS);
396         }
397         else
398         {
399             HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, 
400                     HTML.INPUT_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED_AND_STYLE);
401         }
402 
403         if (isDisabled(facesContext, uiComponent))
404         {
405             writer.writeAttribute(org.apache.myfaces.shared.renderkit.html.HTML.DISABLED_ATTR, Boolean.TRUE, null);
406         }
407 
408         writer.endElement(HTML.INPUT_ELEM);
409 
410         return itemId;
411     }
412 
413 
414     protected boolean isDisabled(FacesContext facesContext, UIComponent uiComponent)
415     {
416         //TODO: overwrite in extended HtmlRadioRenderer and check for enabledOnUserRole
417         if (uiComponent instanceof HtmlSelectOneRadio)
418         {
419             return ((HtmlSelectOneRadio)uiComponent).isDisabled();
420         }
421 
422         return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(
423                 uiComponent, HTML.DISABLED_ATTR, false);
424     }
425 
426 
427     public void decode(FacesContext facesContext, UIComponent uiComponent)
428     {
429         org.apache.myfaces.shared.renderkit.RendererUtils.checkParamValidity(facesContext, uiComponent, null);
430         if (uiComponent instanceof UIInput)
431         {
432             HtmlRendererUtils.decodeUISelectOne(facesContext, uiComponent);
433         }
434         if (uiComponent instanceof ClientBehaviorHolder &&
435                 !HtmlRendererUtils.isDisabled(uiComponent))
436         {
437             HtmlRendererUtils.decodeClientBehaviors(facesContext, uiComponent);
438         }
439     }
440 
441 
442     public Object getConvertedValue(FacesContext facesContext, UIComponent uiComponent, Object submittedValue)
443         throws ConverterException
444     {
445         RendererUtils.checkParamValidity(facesContext, uiComponent, UISelectOne.class);
446         return org.apache.myfaces.shared.renderkit.RendererUtils.getConvertedUISelectOneValue(facesContext,
447                                                                                                (UISelectOne)uiComponent,
448                                                                                                submittedValue);
449     }
450 
451 }