Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/myfaces/renderkit/html/HtmlRendererUtils.java


1   /*
2    * Copyright 2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.myfaces.renderkit.html;
17  
18  import java.io.IOException;
19  import java.util.*;
20  
21  import javax.faces.FacesException;
22  import javax.faces.component.*;
23  import javax.faces.context.FacesContext;
24  import javax.faces.context.ResponseWriter;
25  import javax.faces.convert.Converter;
26  import javax.faces.model.SelectItem;
27  import javax.faces.model.SelectItemGroup;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.myfaces.config.MyfacesConfig;
32  import org.apache.myfaces.renderkit.RendererUtils;
33  import org.apache.myfaces.renderkit.JSFAttr;
34  import org.apache.myfaces.renderkit.html.util.DummyFormUtils;
35  import org.apache.myfaces.renderkit.html.util.HTMLEncoder;
36  import org.apache.myfaces.renderkit.html.util.JavascriptUtils;
37  import org.apache.myfaces.component.DisplayValueOnlyCapable;
38  
39  /**
40   * @author Manfred Geiler (latest modification by $Author: mbr $)
41   * @version $Revision: 291881 $ $Date: 2005-09-27 05:59:11 -0400 (Tue, 27 Sep 2005) $
42   */
43  public final class HtmlRendererUtils {
44      private static final Log log = LogFactory.getLog(HtmlRendererUtils.class);
45  
46      //private static final String[] EMPTY_STRING_ARRAY = new String[0];
47      private static final String LINE_SEPARATOR = System.getProperty(
48              "line.separator", "\r\n");
49  
50      private static final String HIDDEN_COMMANDLINK_FIELD_NAME = "_link_hidden_";
51  
52  
53      private HtmlRendererUtils() {
54          // utility class, do not instantiate
55      }
56  
57      /**
58       * X-CHECKED: tlddoc h:inputText
59       *
60       * @param facesContext
61       * @param component
62       */
63      public static void decodeUIInput(FacesContext facesContext,
64              UIComponent component) {
65          if (!(component instanceof EditableValueHolder)) {
66              throw new IllegalArgumentException("Component "
67                      + component.getClientId(facesContext)
68                      + " is not an EditableValueHolder");
69          }
70          Map paramMap = facesContext.getExternalContext()
71                  .getRequestParameterMap();
72          String clientId = component.getClientId(facesContext);
73  
74          if(isDisabledOrReadOnly(component))
75              return;
76  
77          if(paramMap.containsKey(clientId))
78          {
79              ((EditableValueHolder) component).setSubmittedValue(paramMap
80                  .get(clientId));
81          }
82          else
83          {
84              log.warn("There should always be a submitted value for an input if it is rendered, its form is submitted, and it is not disabled or read-only.");
85          }
86      }
87  
88      /**
89       * X-CHECKED: tlddoc h:selectBooleanCheckbox
90       *
91       * @param facesContext
92       * @param component
93       */
94      public static void decodeUISelectBoolean(FacesContext facesContext,
95              UIComponent component) {
96          if (!(component instanceof EditableValueHolder)) {
97              throw new IllegalArgumentException("Component "
98                      + component.getClientId(facesContext)
99                      + " is not an EditableValueHolder");
100         }
101 
102         if(isDisabledOrReadOnly(component))
103             return;
104 
105         Map paramMap = facesContext.getExternalContext()
106                 .getRequestParameterMap();
107         String clientId = component.getClientId(facesContext);
108         if (paramMap.containsKey(clientId)) {
109             String reqValue = (String) paramMap.get(clientId);
110             if ((reqValue.equalsIgnoreCase("on")
111                             || reqValue.equalsIgnoreCase("yes") || reqValue
112                             .equalsIgnoreCase("true"))) {
113                 ((EditableValueHolder) component)
114                         .setSubmittedValue(Boolean.TRUE);
115             } else {
116                 ((EditableValueHolder) component)
117                         .setSubmittedValue(Boolean.FALSE);
118             }
119         } else {
120             ((EditableValueHolder) component)
121                     .setSubmittedValue(Boolean.FALSE);
122         }
123     }
124 
125     public static boolean isDisabledOrReadOnly(UIComponent component)
126     {
127         return isDisplayValueOnly(component) ||
128                 isTrue(component.getAttributes().get("disabled")) ||
129                     isTrue(component.getAttributes().get("readOnly"));
130     }
131 
132     private static boolean isTrue(Object obj)
133     {
134         if(!(obj instanceof Boolean))
135             return false;
136 
137         return ((Boolean) obj).booleanValue();
138     }
139 
140     /**
141      * X-CHECKED: tlddoc h:selectManyListbox
142      *
143      * @param facesContext
144      * @param component
145      */
146     public static void decodeUISelectMany(FacesContext facesContext,
147             UIComponent component) {
148         if (!(component instanceof EditableValueHolder)) {
149             throw new IllegalArgumentException("Component "
150                     + component.getClientId(facesContext)
151                     + " is not an EditableValueHolder");
152         }
153         Map paramValuesMap = facesContext.getExternalContext()
154                 .getRequestParameterValuesMap();
155         String clientId = component.getClientId(facesContext);
156 
157         if(isDisabledOrReadOnly(component))
158             return;
159 
160         if (paramValuesMap.containsKey(clientId)) {
161             String[] reqValues = (String[]) paramValuesMap.get(clientId);
162             ((EditableValueHolder) component).setSubmittedValue(reqValues);
163         } else {
164             /* request parameter not found, nothing to decode - set submitted value to an empty array
165                as we should get here only if the component is on a submitted form, is rendered
166                and if the component is not readonly or has not been disabled.
167 
168                So in fact, there must be component value at this location, but for listboxes, comboboxes etc.
169                the submitted value is not posted if no item is selected. */
170             ((EditableValueHolder) component).setSubmittedValue( new String[]{});
171         }
172     }
173 
174     /**
175      * X-CHECKED: tlddoc h:selectManyListbox
176      *
177      * @param facesContext
178      * @param component
179      */
180     public static void decodeUISelectOne(FacesContext facesContext,
181             UIComponent component) {
182         if (!(component instanceof EditableValueHolder)) {
183             throw new IllegalArgumentException("Component "
184                     + component.getClientId(facesContext)
185                     + " is not an EditableValueHolder");
186         }
187 
188         if(isDisabledOrReadOnly(component))
189             return;
190 
191         Map paramMap = facesContext.getExternalContext()
192                 .getRequestParameterMap();
193         String clientId = component.getClientId(facesContext);
194         if (paramMap.containsKey(clientId)) {
195             //request parameter found, set submitted value
196             ((EditableValueHolder) component).setSubmittedValue(paramMap
197                     .get(clientId));
198         } else {
199             //see reason for this action at decodeUISelectMany
200             ((EditableValueHolder) component).setSubmittedValue( RendererUtils.NOTHING );
201         }
202     }
203 
204     /*
205      * public static void renderCheckbox(FacesContext facesContext, UIComponent
206      * uiComponent, String value, String label, boolean checked) throws
207      * IOException { String clientId = uiComponent.getClientId(facesContext);
208      *
209      * ResponseWriter writer = facesContext.getResponseWriter();
210      *
211      * writer.startElement(HTML.INPUT_ELEM, uiComponent);
212      * writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_CHECKBOX, null);
213      * writer.writeAttribute(HTML.NAME_ATTR, clientId, null);
214      * writer.writeAttribute(HTML.ID_ATTR, clientId, null);
215      *
216      * if (checked) { writer.writeAttribute(HTML.CHECKED_ATTR,
217      * HTML.CHECKED_ATTR, null); }
218      *
219      * if ((value != null) && (value.length() > 0)) {
220      * writer.writeAttribute(HTML.VALUE_ATTR, value, null); }
221      *
222      * renderHTMLAttributes(writer, uiComponent,
223      * HTML.INPUT_PASSTHROUGH_ATTRIBUTES); renderDisabledOnUserRole(writer,
224      * uiComponent, facesContext);
225      *
226      * if ((label != null) && (label.length() > 0)) {
227      * writer.write(HTML.NBSP_ENTITY); writer.writeText(label, null); }
228      *
229      * writer.endElement(HTML.INPUT_ELEM); }
230      */
231 
232     public static void renderListbox(FacesContext facesContext,
233             UISelectOne selectOne, boolean disabled, int size)
234             throws IOException {
235         internalRenderSelect(facesContext, selectOne, disabled, size, false);
236     }
237 
238     public static void renderListbox(FacesContext facesContext,
239             UISelectMany selectMany, boolean disabled, int size)
240             throws IOException {
241         internalRenderSelect(facesContext, selectMany, disabled, size, true);
242     }
243 
244     public static void renderMenu(FacesContext facesContext,
245             UISelectOne selectOne, boolean disabled) throws IOException {
246         internalRenderSelect(facesContext, selectOne, disabled, 1, false);
247     }
248 
249     public static void renderMenu(FacesContext facesContext,
250             UISelectMany selectMany, boolean disabled) throws IOException {
251         internalRenderSelect(facesContext, selectMany, disabled, 1, true);
252     }
253 
254     private static void internalRenderSelect(FacesContext facesContext,
255             UIComponent uiComponent, boolean disabled, int size,
256             boolean selectMany) throws IOException {
257         ResponseWriter writer = facesContext.getResponseWriter();
258 
259         writer.startElement(HTML.SELECT_ELEM, uiComponent);
260         HtmlRendererUtils.writeIdIfNecessary(writer, uiComponent, facesContext);
261         writer.writeAttribute(HTML.NAME_ATTR, uiComponent
262                 .getClientId(facesContext), null);
263 
264         List selectItemList;
265         Converter converter;
266         if (selectMany) {
267             writer.writeAttribute(HTML.MULTIPLE_ATTR, "true", null);
268             selectItemList = RendererUtils
269                     .getSelectItemList((UISelectMany) uiComponent);
270             converter = findUISelectManyConverterFailsafe(facesContext, uiComponent);
271         } else {
272             selectItemList = RendererUtils
273                     .getSelectItemList((UISelectOne) uiComponent);
274             converter = findUIOutputConverterFailSafe(facesContext, uiComponent);
275         }
276 
277         if (size == 0) {
278             //No size given (Listbox) --> size is number of select items
279             writer.writeAttribute(HTML.SIZE_ATTR, Integer
280                     .toString(selectItemList.size()), null);
281         } else {
282             writer.writeAttribute(HTML.SIZE_ATTR, Integer.toString(size), null);
283         }
284         renderHTMLAttributes(writer, uiComponent,
285                 HTML.SELECT_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED);
286         if (disabled) {
287             writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE, null);
288         }
289 
290         Set lookupSet = getSubmittedOrSelectedValuesAsSet(selectMany, uiComponent, facesContext, converter);
291 
292         renderSelectOptions(facesContext, uiComponent, converter, lookupSet,
293                 selectItemList);
294         // bug #970747: force separate end tag
295         writer.writeText("", null);
296         writer.endElement(HTML.SELECT_ELEM);
297     }
298 
299     public static Set getSubmittedOrSelectedValuesAsSet(boolean selectMany, UIComponent uiComponent, FacesContext facesContext, Converter converter) {
300         Set lookupSet;
301 
302         if (selectMany) {
303             UISelectMany uiSelectMany = (UISelectMany) uiComponent;
304             lookupSet = RendererUtils.getSubmittedValuesAsSet(facesContext, uiComponent, converter, uiSelectMany);
305             if (lookupSet == null)
306             {
307                 lookupSet = RendererUtils.getSelectedValuesAsSet(facesContext, uiComponent, converter, uiSelectMany);
308             }
309         } else {
310             UISelectOne uiSelectOne = (UISelectOne) uiComponent;
311             Object lookup = uiSelectOne.getSubmittedValue();
312             if (lookup == null)
313             {
314                 lookup = uiSelectOne.getValue();
315                 String lookupString = RendererUtils.getConvertedStringValue(facesContext, uiComponent, converter, lookup);
316                 lookupSet = Collections.singleton(lookupString);
317             }
318             else if(RendererUtils.NOTHING.equals(lookup))
319             {
320                 lookupSet = Collections.EMPTY_SET;
321             }
322             else
323             {
324                 lookupSet = Collections.singleton(lookup);
325             }
326         }
327         return lookupSet;
328     }
329 
330     public static Converter findUISelectManyConverterFailsafe(FacesContext facesContext, UIComponent uiComponent) {
331         Converter converter;
332         try {
333             converter = RendererUtils.findUISelectManyConverter(
334                     facesContext, (UISelectMany) uiComponent);
335         } catch (FacesException e) {
336             log.error("Error finding Converter for component with id "
337                     + uiComponent.getClientId(facesContext));
338             converter = null;
339         }
340         return converter;
341     }
342 
343     public static Converter findUIOutputConverterFailSafe(FacesContext facesContext, UIComponent uiComponent) {
344         Converter converter;
345         try {
346             converter = RendererUtils.findUIOutputConverter(facesContext,
347                     (UISelectOne) uiComponent);
348         } catch (FacesException e) {
349             log.error("Error finding Converter for component with id "
350                     + uiComponent.getClientId(facesContext));
351             converter = null;
352         }
353         return converter;
354     }
355 
356     /**
357      * Renders the select options for a <code>UIComponent</code> that is
358      * rendered as an HTML select element.
359      *
360      * @param context
361      *            the current <code>FacesContext</code>.
362      * @param component
363      *            the <code>UIComponent</code> whose options need to be
364      *            rendered.
365      * @param converter
366      *            <code>component</code>'s converter
367      * @param lookupSet
368      *            the <code>Set</code> to use to look up selected options
369      * @param selectItemList
370      *            the <code>List</code> of <code>SelectItem</code> s to be
371      *            rendered as HTML option elements.
372      * @throws IOException
373      */
374     public static void renderSelectOptions(FacesContext context,
375                                             UIComponent component, Converter converter, Set lookupSet,
376                                             List selectItemList) throws IOException {
377         ResponseWriter writer = context.getResponseWriter();
378 
379         for (Iterator it = selectItemList.iterator(); it.hasNext();) {
380             SelectItem selectItem = (SelectItem) it.next();
381 
382             if (selectItem instanceof SelectItemGroup) {
383                 writer.startElement(HTML.OPTGROUP_ELEM, component);
384                 writer.writeAttribute(HTML.LABEL_ATTR, selectItem.getLabel(),
385                         null);
386                 SelectItem[] selectItems = ((SelectItemGroup) selectItem)
387                         .getSelectItems();
388                 renderSelectOptions(context, component, converter, lookupSet,
389                         Arrays.asList(selectItems));
390                 writer.endElement(HTML.OPTGROUP_ELEM);
391             } else {
392                 String itemStrValue = RendererUtils.getConvertedStringValue(context, component,
393                         converter, selectItem);
394 
395                 writer.write("\t");
396                 writer.startElement(HTML.OPTION_ELEM, component);
397                 if (itemStrValue != null) {
398                     writer.writeAttribute(HTML.VALUE_ATTR, itemStrValue, null);
399                 }
400 
401                 if (lookupSet.contains(itemStrValue)) {  //TODO/FIX: we always compare the String vales, better fill lookupSet with Strings only when useSubmittedValue==true, else use the real item value Objects
402                     writer.writeAttribute(HTML.SELECTED_ATTR,
403                             HTML.SELECTED_ATTR, null);
404                 }
405 
406                 boolean disabled = selectItem.isDisabled();
407                 if (disabled) {
408                     writer.writeAttribute(HTML.DISABLED_ATTR,
409                             HTML.DISABLED_ATTR, null);
410                 }
411 
412                 String labelClass = null;
413                 boolean componentDisabled = isTrue(component.getAttributes().get("disabled"));
414 
415                 if (componentDisabled || disabled) {
416                     labelClass = (String) component.getAttributes().get(JSFAttr.DISABLED_CLASS_ATTR);
417                 } else {
418                     labelClass = (String) component.getAttributes().get(JSFAttr.ENABLED_CLASS_ATTR);
419                 }
420                 if (labelClass != null) {
421                     writer.writeAttribute("class", labelClass, "labelClass");
422                 }
423 
424 
425                 writer.writeText(selectItem.getLabel(), null);
426 
427                 writer.endElement(HTML.OPTION_ELEM);
428             }
429         }
430     }
431 
432     /*
433      * public static void renderRadio(FacesContext facesContext, UIInput
434      * uiComponent, String value, String label, boolean checked) throws
435      * IOException { String clientId = uiComponent.getClientId(facesContext);
436      *
437      * ResponseWriter writer = facesContext.getResponseWriter();
438      *
439      * writer.startElement(HTML.INPUT_ELEM, uiComponent);
440      * writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_RADIO, null);
441      * writer.writeAttribute(HTML.NAME_ATTR, clientId, null);
442      * writer.writeAttribute(HTML.ID_ATTR, clientId, null);
443      *
444      * if (checked) { writer.writeAttribute(HTML.CHECKED_ATTR,
445      * HTML.CHECKED_ATTR, null); }
446      *
447      * if ((value != null) && (value.length() > 0)) {
448      * writer.writeAttribute(HTML.VALUE_ATTR, value, null); }
449      *
450      * renderHTMLAttributes(writer, uiComponent,
451      * HTML.INPUT_PASSTHROUGH_ATTRIBUTES); renderDisabledOnUserRole(writer,
452      * uiComponent, facesContext);
453      *
454      * if ((label != null) && (label.length() > 0)) {
455      * writer.write(HTML.NBSP_ENTITY); writer.writeText(label, null); }
456      *
457      * writer.endElement(HTML.INPUT_ELEM); }
458      */
459 
460     public static void writePrettyLineSeparator(FacesContext facesContext)
461             throws IOException {
462         if (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext())
463                 .isPrettyHtml()) {
464             facesContext.getResponseWriter().write(LINE_SEPARATOR);
465         }
466     }
467 
468     public static void writePrettyIndent(FacesContext facesContext)
469             throws IOException {
470         if (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext())
471                 .isPrettyHtml()) {
472             facesContext.getResponseWriter().write('\t');
473         }
474     }
475 
476     /**
477      * @return true, if the attribute was written
478      * @throws java.io.IOException
479      */
480     public static boolean renderHTMLAttribute(ResponseWriter writer,
481             String componentProperty, String attrName, Object value)
482             throws IOException {
483         if (!RendererUtils.isDefaultAttributeValue(value)) {
484             // render JSF "styleClass" attribute as "class"
485             String htmlAttrName = attrName.equals(HTML.STYLE_CLASS_ATTR) ? HTML.CLASS_ATTR
486                     : attrName;
487             writer.writeAttribute(htmlAttrName, value, componentProperty);
488             return true;
489         }
490 
491         return false;
492     }
493 
494     /**
495      * @return true, if the attribute was written
496      * @throws java.io.IOException
497      */
498     public static boolean renderHTMLAttribute(ResponseWriter writer,
499             UIComponent component, String componentProperty, String htmlAttrName)
500             throws IOException {
501         Object value = component.getAttributes().get(componentProperty);
502         return renderHTMLAttribute(writer, componentProperty, htmlAttrName,
503                 value);
504     }
505 
506     /**
507      * @return true, if an attribute was written
508      * @throws java.io.IOException
509      */
510     public static boolean renderHTMLAttributes(ResponseWriter writer,
511             UIComponent component, String[] attributes) throws IOException {
512         boolean somethingDone = false;
513         for (int i = 0, len = attributes.length; i < len; i++) {
514             String attrName = attributes[i];
515             if (renderHTMLAttribute(writer, component, attrName, attrName)) {
516                 somethingDone = true;
517             }
518         }
519         return somethingDone;
520     }
521 
522     public static boolean renderHTMLAttributeWithOptionalStartElement(
523             ResponseWriter writer, UIComponent component, String elementName,
524             String attrName, Object value, boolean startElementWritten)
525             throws IOException {
526         if (!RendererUtils.isDefaultAttributeValue(value)) {
527             if (!startElementWritten) {
528                 writer.startElement(elementName, component);
529                 startElementWritten = true;
530             }
531             renderHTMLAttribute(writer, attrName, attrName, value);
532         }
533         return startElementWritten;
534     }
535 
536     public static boolean renderHTMLAttributesWithOptionalStartElement(
537             ResponseWriter writer, UIComponent component, String elementName,
538             String[] attributes) throws IOException {
539         boolean startElementWritten = false;
540         for (int i = 0, len = attributes.length; i < len; i++) {
541             String attrName = attributes[i];
542             Object value = component.getAttributes().get(attrName);
543             if (!RendererUtils.isDefaultAttributeValue(value)) {
544                 if (!startElementWritten) {
545                     writer.startElement(elementName, component);
546                     startElementWritten = true;
547                 }
548                 renderHTMLAttribute(writer, attrName, attrName, value);
549             }
550         }
551         return startElementWritten;
552     }
553 
554     public static boolean renderOptionalEndElement(ResponseWriter writer,
555             UIComponent component, String elementName, String[] attributes)
556             throws IOException {
557         boolean endElementNeeded = false;
558         for (int i = 0, len = attributes.length; i < len; i++) {
559             String attrName = attributes[i];
560             Object value = component.getAttributes().get(attrName);
561             if (!RendererUtils.isDefaultAttributeValue(value)) {
562                 endElementNeeded = true;
563                 break;
564             }
565         }
566         if (endElementNeeded) {
567             writer.endElement(elementName);
568             return true;
569         }
570 
571         return false;
572     }
573 
574     public static void writeIdIfNecessary(ResponseWriter writer, UIComponent component,
575                                           FacesContext facesContext)
576         throws IOException
577     {
578         if(component.getId()!=null && !component.getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
579         {
580             writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext),null);
581         }
582     }
583 
584     public static void renderDisplayValueOnlyForSelects(FacesContext facesContext, UIComponent
585             uiComponent)
586         throws IOException
587     {
588         ResponseWriter writer = facesContext.getResponseWriter();
589 
590         List selectItemList;
591         Converter converter;
592         boolean isSelectOne;
593         if (uiComponent instanceof UISelectMany) {
594           isSelectOne = false;
595             selectItemList = RendererUtils
596                     .getSelectItemList((UISelectMany) uiComponent);
597             converter = findUISelectManyConverterFailsafe(facesContext, uiComponent);
598         } else {
599           isSelectOne = true;
600             selectItemList = RendererUtils
601                     .getSelectItemList((UISelectOne) uiComponent);
602             converter = findUIOutputConverterFailSafe(facesContext, uiComponent);
603         }
604 
605         writer.startElement(isSelectOne ? HTML.SPAN_ELEM : HTML.UL_ELEM, uiComponent);
606         writeIdIfNecessary(writer, uiComponent, facesContext);
607 
608         renderDisplayValueOnlyAttributes(uiComponent, writer);
609 
610         Set lookupSet = getSubmittedOrSelectedValuesAsSet(
611                 uiComponent instanceof UISelectMany,
612                 uiComponent, facesContext, converter);
613 
614         renderSelectOptionsAsText(facesContext, uiComponent, converter, lookupSet,
615                 selectItemList, isSelectOne);
616 
617         // bug #970747: force separate end tag
618         writer.writeText("", null);
619         writer.endElement(isSelectOne ? HTML.SPAN_ELEM : HTML.UL_ELEM);
620 
621     }
622 
623     public static void renderDisplayValueOnlyAttributes(UIComponent uiComponent, ResponseWriter writer) throws IOException {
624         if(!(uiComponent instanceof DisplayValueOnlyCapable))
625         {
626             log.error("Wrong type of uiComponent. needs DisplayValueOnlyCapable.");
627             renderHTMLAttributes(writer, uiComponent,
628                     HTML.COMMON_PASSTROUGH_ATTRIBUTES);
629 
630             return;
631         }
632 
633         if(getDisplayValueOnlyStyle(uiComponent) != null || getDisplayValueOnlyStyleClass(uiComponent)!=null)
634         {
635             if(getDisplayValueOnlyStyle(uiComponent) != null )
636             {
637                 writer.writeAttribute(HTML.STYLE_ATTR, getDisplayValueOnlyStyle(uiComponent), null);
638             }
639             else if(uiComponent.getAttributes().get("style")!=null)
640             {
641                 writer.writeAttribute(HTML.STYLE_ATTR, uiComponent.getAttributes().get("style"), null);
642             }
643 
644             if(getDisplayValueOnlyStyleClass(uiComponent) != null )
645             {
646                 writer.writeAttribute(HTML.CLASS_ATTR, getDisplayValueOnlyStyleClass(uiComponent), null);
647             }
648             else if(uiComponent.getAttributes().get("styleClass")!=null)
649             {
650                 writer.writeAttribute(HTML.CLASS_ATTR, uiComponent.getAttributes().get("styleClass"), null);
651             }
652 
653             renderHTMLAttributes(writer, uiComponent,
654                     HTML.COMMON_PASSTROUGH_ATTRIBUTES_WITHOUT_STYLE);
655         }
656         else
657         {
658             renderHTMLAttributes(writer, uiComponent,
659                     HTML.COMMON_PASSTROUGH_ATTRIBUTES);
660         }
661     }
662 
663     private static void renderSelectOptionsAsText(FacesContext context,
664                                             UIComponent component, Converter converter, Set lookupSet,
665                                             List selectItemList, boolean isSelectOne) throws IOException {
666         ResponseWriter writer = context.getResponseWriter();
667 
668         for (Iterator it = selectItemList.iterator(); it.hasNext();) {
669             SelectItem selectItem = (SelectItem) it.next();
670 
671             if (selectItem instanceof SelectItemGroup) {
672                 SelectItem[] selectItems = ((SelectItemGroup) selectItem)
673                         .getSelectItems();
674                 renderSelectOptionsAsText(context, component, converter, lookupSet,
675                         Arrays.asList(selectItems), isSelectOne);
676             } else {
677                 String itemStrValue = RendererUtils.getConvertedStringValue(context, component,
678                         converter, selectItem);
679 
680                 if (lookupSet.contains(itemStrValue)) {  //TODO/FIX: we always compare the String vales, better fill lookupSet with Strings only when useSubmittedValue==true, else use the real item value Objects
681 
682                     if( ! isSelectOne )
683                       writer.startElement(HTML.LI_ELEM, component);
684                     writer.writeText(selectItem.getLabel(), null);
685                     if( ! isSelectOne )
686                       writer.endElement(HTML.LI_ELEM);
687 
688                     if( isSelectOne )
689                     {
690                         //take care of several choices with the same value; use only the first one
691                         return;
692                     }
693                 }
694             }
695         }
696     }
697 
698     public static String getDisplayValueOnlyStyleClass(UIComponent component) {
699 
700         if(component instanceof DisplayValueOnlyCapable)
701         {
702             if(((DisplayValueOnlyCapable) component).getDisplayValueOnlyStyleClass()!=null)
703                 return ((DisplayValueOnlyCapable) component).getDisplayValueOnlyStyleClass();
704 
705             UIComponent parent=component;
706 
707             while((parent = parent.getParent())!=null)
708             {
709                 if(parent instanceof DisplayValueOnlyCapable &&
710                         ((DisplayValueOnlyCapable) parent).getDisplayValueOnlyStyleClass()!=null)
711                 {
712                     return ((DisplayValueOnlyCapable) parent).getDisplayValueOnlyStyleClass();
713                 }
714             }
715         }
716 
717         return null;
718     }
719 
720     public static String getDisplayValueOnlyStyle(UIComponent component) {
721 
722         if(component instanceof DisplayValueOnlyCapable)
723         {
724             if(((DisplayValueOnlyCapable) component).getDisplayValueOnlyStyle()!=null)
725                 return ((DisplayValueOnlyCapable) component).getDisplayValueOnlyStyle();
726 
727             UIComponent parent=component;
728 
729             while((parent = parent.getParent())!=null)
730             {
731                 if(parent instanceof DisplayValueOnlyCapable &&
732                         ((DisplayValueOnlyCapable) parent).getDisplayValueOnlyStyle()!=null)
733                 {
734                     return ((DisplayValueOnlyCapable) parent).getDisplayValueOnlyStyle();
735                 }
736             }
737         }
738 
739         return null;
740     }
741 
742     public static boolean isDisplayValueOnly(UIComponent component) {
743 
744         if(component instanceof DisplayValueOnlyCapable)
745         {
746             if(((DisplayValueOnlyCapable) component).isSetDisplayValueOnly())
747                 return ((DisplayValueOnlyCapable) component).isDisplayValueOnly();
748 
749             UIComponent parent=component;
750 
751             while((parent = parent.getParent())!=null)
752             {
753                 if(parent instanceof DisplayValueOnlyCapable &&
754                         ((DisplayValueOnlyCapable) parent).isSetDisplayValueOnly())
755                 {
756                     return ((DisplayValueOnlyCapable) parent).isDisplayValueOnly();
757                 }
758             }
759         }
760 
761         return false;
762     }
763 
764     public static void renderDisplayValueOnly(FacesContext facesContext, UIInput input) throws IOException {
765         ResponseWriter writer = facesContext.getResponseWriter();
766         writer.startElement(HTML.SPAN_ELEM, input);
767 
768         writeIdIfNecessary(writer, input, facesContext);
769 
770         renderDisplayValueOnlyAttributes(input, writer);
771 
772         String strValue = RendererUtils.getStringValue(facesContext, input);
773         writer.write( HTMLEncoder.encode(strValue, true, true) );
774 
775         writer.endElement(HTML.SPAN_ELEM);
776     }
777 
778     public static class LinkParameter {
779         private String _name;
780 
781         private Object _value;
782 
783         public String getName() {
784             return _name;
785         }
786 
787         public void setName(String name) {
788             _name = name;
789         }
790 
791         public Object getValue() {
792             return _value;
793         }
794 
795         public void setValue(Object value) {
796             _value = value;
797         }
798 
799     }
800 
801     public static void renderHiddenCommandFormParams(ResponseWriter writer,
802             Set dummyFormParams) throws IOException {
803         for (Iterator it = dummyFormParams.iterator(); it.hasNext();) {
804             writer.startElement(HTML.INPUT_ELEM, null);
805             writer.writeAttribute(HTML.TYPE_ATTR, "hidden", null);
806             writer.writeAttribute(HTML.NAME_ATTR, it.next(), null);
807             writer.endElement(HTML.INPUT_ELEM);
808         }
809     }
810 
811     /**
812      * Render the javascript function that is called on a click on a commandLink
813      * to clear the hidden inputs. This is necessary because on a browser back,
814      * each hidden input still has it's old value (browser cache!) and therefore
815      * a new submit would cause the according action once more!
816      *
817      * @param writer
818      * @param formName
819      * @param dummyFormParams
820      * @param formTarget
821      * @throws IOException
822      */
823     public static void renderClearHiddenCommandFormParamsFunction(
824             ResponseWriter writer, String formName, Set dummyFormParams,
825             String formTarget) throws IOException {
826         //render the clear hidden inputs javascript function
827         String functionName = getClearHiddenCommandFormParamsFunctionName(formName);
828         writer.startElement(HTML.SCRIPT_ELEM, null);
829         writer.writeAttribute(HTML.TYPE_ATTR, "text/javascript", null);
830 
831         // Using writeComment instead of write with <!-- tag
832         StringBuffer script = new StringBuffer();
833         script.append("function ");
834         script.append(functionName);
835         script.append("() {");
836         if (dummyFormParams != null) {
837             script.append("\n  var f = document.forms['");
838             script.append(formName);
839             script.append("'];");
840             for (Iterator it = dummyFormParams.iterator(); it.hasNext();) {
841                 script.append("\n  f.elements['");
842                 script.append((String) it.next());
843                 script.append("'].value='';");
844             }
845         }
846         // clear form target
847         script.append("\n  f.target=");
848         if (formTarget == null || formTarget.length() == 0) {
849             //Normally one would think that setting target to null has the
850             //desired effect, but once again IE is different...
851             //Setting target to null causes IE to open a new window!
852             script.append("'';");
853         } else {
854             script.append("'");
855             script.append(formTarget);
856             script.append("';");
857         }
858         script.append("\n}");
859 
860         //Just to be sure we call this clear method on each load.
861         //Otherwise in the case, that someone submits a form by pressing Enter
862         //within a text input, the hidden inputs won't be cleared!
863         script.append("\n");
864         script.append(functionName);
865         script.append("();");
866 
867         writer.writeText(script.toString(),null);
868         writer.endElement(HTML.SCRIPT_ELEM);
869     }
870 
871     /**
872      * Prefixes the given String with "clear_" and removes special characters
873      *
874      * @param formName
875      * @return String
876      */
877     public static String getClearHiddenCommandFormParamsFunctionName(
878             String formName) {
879         return "clear_"
880                 + JavascriptUtils.getValidJavascriptName(formName, false);
881     }
882 
883     public static String getFormName(UIComponent component, FacesContext context) {
884         //Find form
885         UIComponent parent = component.getParent();
886         while (parent != null && !(parent instanceof UIForm)) {
887             parent = parent.getParent();
888         }
889 
890         if (parent != null) {
891             //link is nested inside a form
892             return ((UIForm) parent).getClientId(context);
893         }
894         //not nested in form, we must add a dummy form at the end of the
895         // document
896         return DummyFormUtils.DUMMY_FORM_NAME;
897     }
898 
899     public static String getHiddenCommandLinkFieldName(String formName) {
900         return formName + NamingContainer.SEPARATOR_CHAR
901                 + HIDDEN_COMMANDLINK_FIELD_NAME;
902     }
903 
904     private static String HTML_CONTENT_TYPE = "text/html";
905     private static String ANY_CONTENT_TYPE = "*/*";
906 
907     public static String DEFAULT_CHAR_ENCODING = "ISO-8859-1";
908     private static String XHTML_CONTENT_TYPE = "application/xhtml+xml";
909     private static String APPLICATION_XML_CONTENT_TYPE = "application/xml";
910     private static String TEXT_XML_CONTENT_TYPE = "text/xml";
911 
912 
913     public static String selectContentType(String contentTypeListString)
914     {
915         if (contentTypeListString == null)
916         {
917             FacesContext context = FacesContext.getCurrentInstance();
918 
919             contentTypeListString = (String)
920                     context.getExternalContext().getRequestHeaderMap().get("Accept");
921 
922             if(contentTypeListString == null)
923             {
924                 if (log.isDebugEnabled())
925                     log.debug("No content type list given, creating HtmlResponseWriterImpl with default content type.");
926 
927                 contentTypeListString = HTML_CONTENT_TYPE;
928             }
929         }
930 
931         List contentTypeList = splitContentTypeListString(contentTypeListString);
932         String[] supportedContentTypeArray = getSupportedContentTypes();
933 
934         String selectedContentType = null;
935 
936         for (int i = 0; i < supportedContentTypeArray.length; i++)
937         {
938                 String supportedContentType = supportedContentTypeArray[i].trim();
939 
940                 for (int j = 0; j < contentTypeList.size(); j++)
941                 {
942                     String contentType = (String) contentTypeList.get(j);
943 
944                     if (contentType.indexOf(supportedContentType) != -1)
945                     {
946                         if (isHTMLContentType(contentType)) {
947                             selectedContentType = HTML_CONTENT_TYPE;
948                         }
949 
950                         else if (isXHTMLContentType(contentType)) {
951                             selectedContentType = XHTML_CONTENT_TYPE;
952                         }
953                         break;
954                     }
955                 }
956                 if (selectedContentType!=null)
957                 {
958                     break;
959                 }
960         }
961 
962         if(selectedContentType==null)
963         {
964             throw new IllegalArgumentException("ContentTypeList does not contain a supported content type: " +
965                     contentTypeListString);
966         }
967         return selectedContentType;
968     }
969 
970     public static String[] getSupportedContentTypes()
971     {
972         String[] supportedContentTypeArray = new String[]{HTML_CONTENT_TYPE,ANY_CONTENT_TYPE,
973                 XHTML_CONTENT_TYPE,APPLICATION_XML_CONTENT_TYPE,TEXT_XML_CONTENT_TYPE};
974         return supportedContentTypeArray;
975     }
976 
977     private static boolean isHTMLContentType(String contentType)
978     {
979         return contentType.indexOf(HTML_CONTENT_TYPE) != -1 ||
980                 contentType.indexOf(ANY_CONTENT_TYPE) != -1;
981     }
982 
983     public static boolean isXHTMLContentType(String contentType)
984     {
985         return contentType.indexOf(XHTML_CONTENT_TYPE) != -1 ||
986                  contentType.indexOf(APPLICATION_XML_CONTENT_TYPE) != -1 ||
987                  contentType.indexOf(TEXT_XML_CONTENT_TYPE) != -1;
988     }
989 
990     private static List splitContentTypeListString(String contentTypeListString)
991     {
992         List contentTypeList = new ArrayList();
993 
994         StringTokenizer st = new StringTokenizer(contentTypeListString, ",");
995         while (st.hasMoreTokens())
996         {
997             String contentType = st.nextToken().trim();
998 
999             int semicolonIndex = contentType.indexOf(";");
1000
1001            if (semicolonIndex!=-1)
1002            {
1003                contentType = contentType.substring(0,semicolonIndex);
1004            }
1005
1006            contentTypeList.add(contentType);
1007        }
1008
1009        return contentTypeList;
1010    }
1011
1012
1013}