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_orchestra.renderkit.html;
    20
    21  import org.apache.commons.logging.Log;
    22  import org.apache.commons.logging.LogFactory;
    23  import org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable;
    24  import org.apache.myfaces.shared_orchestra.component.EscapeCapable;
    25  import org.apache.myfaces.shared_orchestra.renderkit.JSFAttr;
    26  import org.apache.myfaces.shared_orchestra.renderkit.RendererUtils;
    27  import org.apache.myfaces.shared_orchestra.renderkit.html.util.HTMLEncoder;
    28  import org.apache.myfaces.shared_orchestra.renderkit.html.util.JavascriptUtils;
    29  import org.apache.myfaces.shared_orchestra.renderkit.html.util.FormInfo;
    30  import org.apache.myfaces.shared_orchestra.config.MyfacesConfig;
    31
    32  import javax.faces.FacesException;
    33  import javax.faces.component.*;
    34  import javax.faces.context.FacesContext;
    35  import javax.faces.context.ResponseWriter;
    36  import javax.faces.context.ExternalContext;
    37  import javax.faces.convert.Converter;
    38  import javax.faces.model.SelectItem;
    39  import javax.faces.model.SelectItemGroup;
    40  import java.io.IOException;
    41  import java.util.*;
    42
    43  /**
    44   * @author Manfred Geiler (latest modification by $Author: skitching $)
    45   * @version $Revision: 613572 $ $Date: 2008-01-20 10:07:27 -0500 (Sun, 20 Jan 2008) $
    46   */
    47  public final class HtmlRendererUtils {
    48      private static final Log log = LogFactory.getLog(HtmlRendererUtils.class);
    49
    50      //private static final String[] EMPTY_STRING_ARRAY = new String[0];
    51      private static final String LINE_SEPARATOR = System.getProperty(
    52          "line.separator", "\r\n");
    53      private static final char TABULATOR = '\t';
    54
    55      public static final String HIDDEN_COMMANDLINK_FIELD_NAME = "_idcl";
    56      public static final String HIDDEN_COMMANDLINK_FIELD_NAME_MYFACES_OLD = "_link_hidden_";
    57      public static final String HIDDEN_COMMANDLINK_FIELD_NAME_TRINIDAD = "source";
    58
    59      public static final String CLEAR_HIDDEN_FIELD_FN_NAME =
    60          "clearFormHiddenParams";
    61      public static final String SUBMIT_FORM_FN_NAME = "oamSubmitForm";
    62      public static final String ALLOW_CDATA_SECTION_ON = "org.apache.myfaces.ResponseWriter.CdataSectionOn";
    63
    64      private static final String SET_HIDDEN_INPUT_FN_NAME = "oamSetHiddenInput";
    65      private static final String CLEAR_HIDDEN_INPUT_FN_NAME = "oamClearHiddenInput";
    66
    67      private static final String AUTO_SCROLL_PARAM = "autoScroll";
    68      private static final String AUTO_SCROLL_FUNCTION = "getScrolling";
    69
    70      private static final String FIRST_SUBMIT_SCRIPT_ON_PAGE = "org.apache.MyFaces.FIRST_SUBMIT_SCRIPT_ON_PAGE";
    71
    72      public static final String NON_SUBMITTED_VALUE_WARNING
    73      = "There should always be a submitted value for an input if it is rendered,"
    74      + " its form is submitted, and it was not originally rendered disabled or read-only."
    75      + "  You cannot submit a form after disabling an input element via javascript."
    76      + "  Consider setting read-only to true instead"
    77      + " or resetting the disabled value back to false prior to form submission.";
    78
    79      private HtmlRendererUtils() {
    80          // utility class, do not instantiate
    81      }
    82
    83      /**
    84       * Utility to set the submitted value of the provided component from the
    85       * data in the current request object.
    86       * <p/>
    87       * Param component is required to be an EditableValueHolder. On return
    88       * from this method, the component's submittedValue property will be
    89       * set if the submitted form contained that component.
    90       */
    91      public static void decodeUIInput(FacesContext facesContext,
    92                                       UIComponent component) {
    93          if (!(component instanceof EditableValueHolder)) {
    94              throw new IllegalArgumentException("Component "
    95                  + component.getClientId(facesContext)
    96                  + " is not an EditableValueHolder");
    97          }
    98          Map paramMap = facesContext.getExternalContext()
    99              .getRequestParameterMap();
    100         String clientId = component.getClientId(facesContext);
    101
    102         if (isDisabledOrReadOnly(component))
    103             return;
    104
    105         if (paramMap.containsKey(clientId)) {
    106             ((EditableValueHolder) component).setSubmittedValue(paramMap
    107                 .get(clientId));
    108         }
    109         else {
    110             log.warn(NON_SUBMITTED_VALUE_WARNING +
    111                 " Component : " +
    112                     RendererUtils.getPathToComponent(component));
    113         }
    114     }
    115
    116     /**
    117      * X-CHECKED: tlddoc h:selectBooleanCheckbox
    118      *
    119      * @param facesContext
    120      * @param component
    121      */
    122     public static void decodeUISelectBoolean(FacesContext facesContext,
    123                                              UIComponent component) {
    124         if (!(component instanceof EditableValueHolder)) {
    125             throw new IllegalArgumentException("Component "
    126                 + component.getClientId(facesContext)
    127                 + " is not an EditableValueHolder");
    128         }
    129
    130         if (isDisabledOrReadOnly(component))
    131             return;
    132
    133         Map paramMap = facesContext.getExternalContext()
    134             .getRequestParameterMap();
    135         String clientId = component.getClientId(facesContext);
    136         if (paramMap.containsKey(clientId)) {
    137             String reqValue = (String) paramMap.get(clientId);
    138             if ((reqValue.equalsIgnoreCase("on")
    139                 || reqValue.equalsIgnoreCase("yes") || reqValue
    140                 .equalsIgnoreCase("true"))) {
    141                 ((EditableValueHolder) component)
    142                     .setSubmittedValue(Boolean.TRUE);
    143             }
    144             else {
    145                 ((EditableValueHolder) component)
    146                     .setSubmittedValue(Boolean.FALSE);
    147             }
    148         }
    149         else {
    150             ((EditableValueHolder) component)
    151                 .setSubmittedValue(Boolean.FALSE);
    152         }
    153     }
    154
    155     public static boolean isDisabledOrReadOnly(UIComponent component) {
    156         return isDisplayValueOnly(component) ||
    157             isTrue(component.getAttributes().get("disabled")) ||
    158             isTrue(component.getAttributes().get("readonly"));
    159     }
    160
    161     private static boolean isTrue(Object obj) {
    162         if (!(obj instanceof Boolean))
    163             return false;
    164
    165         return ((Boolean) obj).booleanValue();
    166     }
    167
    168     /**
    169      * X-CHECKED: tlddoc h:selectManyListbox
    170      *
    171      * @param facesContext
    172      * @param component
    173      */
    174     public static void decodeUISelectMany(FacesContext facesContext,
    175                                           UIComponent component) {
    176         if (!(component instanceof EditableValueHolder)) {
    177             throw new IllegalArgumentException("Component "
    178                 + component.getClientId(facesContext)
    179                 + " is not an EditableValueHolder");
    180         }
    181         Map paramValuesMap = facesContext.getExternalContext()
    182             .getRequestParameterValuesMap();
    183         String clientId = component.getClientId(facesContext);
    184
    185         if (isDisabledOrReadOnly(component))
    186             return;
    187
    188         if (paramValuesMap.containsKey(clientId)) {
    189             String[] reqValues = (String[]) paramValuesMap.get(clientId);
    190             ((EditableValueHolder) component).setSubmittedValue(reqValues);
    191         }
    192         else {
    193             /* request parameter not found, nothing to decode - set submitted value to an empty array
    194                as we should get here only if the component is on a submitted form, is rendered
    195                and if the component is not readonly or has not been disabled.
    196
    197                So in fact, there must be component value at this location, but for listboxes, comboboxes etc.
    198                the submitted value is not posted if no item is selected. */
    199             ((EditableValueHolder) component).setSubmittedValue(new String[]{});
    200         }
    201     }
    202
    203     /**
    204      * X-CHECKED: tlddoc h:selectManyListbox
    205      *
    206      * @param facesContext
    207      * @param component
    208      */
    209     public static void decodeUISelectOne(FacesContext facesContext,
    210                                          UIComponent component) {
    211         if (!(component instanceof EditableValueHolder)) {
    212             throw new IllegalArgumentException("Component "
    213                 + component.getClientId(facesContext)
    214                 + " is not an EditableValueHolder");
    215         }
    216
    217         if (isDisabledOrReadOnly(component))
    218             return;
    219
    220         Map paramMap = facesContext.getExternalContext()
    221             .getRequestParameterMap();
    222         String clientId = component.getClientId(facesContext);
    223         if (paramMap.containsKey(clientId)) {
    224             //request parameter found, set submitted value
    225             ((EditableValueHolder) component).setSubmittedValue(paramMap
    226                 .get(clientId));
    227         }
    228         else {
    229             //see reason for this action at decodeUISelectMany
    230             ((EditableValueHolder) component).setSubmittedValue(RendererUtils.NOTHING);
    231         }
    232     }
    233
    234     /*
    235      * public static void renderCheckbox(FacesContext facesContext, UIComponent
    236      * uiComponent, String value, String label, boolean checked) throws
    237      * IOException { String clientId = uiComponent.getClientId(facesContext);
    238      *
    239      * ResponseWriter writer = facesContext.getResponseWriter();
    240      *
    241      * writer.startElement(HTML.INPUT_ELEM, uiComponent);
    242      * writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_CHECKBOX, null);
    243      * writer.writeAttribute(HTML.NAME_ATTR, clientId, null);
    244      * writer.writeAttribute(HTML.ID_ATTR, clientId, null);
    245      *
    246      * if (checked) { writer.writeAttribute(HTML.CHECKED_ATTR,
    247      * HTML.CHECKED_ATTR, null); }
    248      *
    249      * if ((value != null) && (value.length() > 0)) {
    250      * writer.writeAttribute(HTML.VALUE_ATTR, value, null); }
    251      *
    252      * renderHTMLAttributes(writer, uiComponent,
    253      * HTML.INPUT_PASSTHROUGH_ATTRIBUTES); renderDisabledOnUserRole(writer,
    254      * uiComponent, facesContext);
    255      *
    256      * if ((label != null) && (label.length() > 0)) {
    257      * writer.write(HTML.NBSP_ENTITY); writer.writeText(label, null); }
    258      *
    259      * writer.endElement(HTML.INPUT_ELEM); }
    260      */
    261
    262     public static void renderListbox(FacesContext facesContext,
    263                                      UISelectOne selectOne, boolean disabled, int size)
    264         throws IOException {
    265         internalRenderSelect(facesContext, selectOne, disabled, size, false);
    266     }
    267
    268     public static void renderListbox(FacesContext facesContext,
    269                                      UISelectMany selectMany, boolean disabled, int size)
    270         throws IOException {
    271         internalRenderSelect(facesContext, selectMany, disabled, size, true);
    272     }
    273
    274     public static void renderMenu(FacesContext facesContext,
    275                                   UISelectOne selectOne, boolean disabled) throws IOException {
    276         internalRenderSelect(facesContext, selectOne, disabled, 1, false);
    277     }
    278
    279     public static void renderMenu(FacesContext facesContext,
    280                                   UISelectMany selectMany, boolean disabled) throws IOException {
    281         internalRenderSelect(facesContext, selectMany, disabled, 1, true);
    282     }
    283
    284     private static void internalRenderSelect(FacesContext facesContext,
    285                                              UIComponent uiComponent, boolean disabled, int size,
    286                                              boolean selectMany) throws IOException {
    287         ResponseWriter writer = facesContext.getResponseWriter();
    288
    289         writer.startElement(HTML.SELECT_ELEM, uiComponent);
    290         HtmlRendererUtils.writeIdIfNecessary(writer, uiComponent, facesContext);
    291         writer.writeAttribute(HTML.NAME_ATTR, uiComponent
    292             .getClientId(facesContext), null);
    293
    294         List selectItemList;
    295         Converter converter;
    296         if (selectMany) {
    297             writer.writeAttribute(HTML.MULTIPLE_ATTR, HTML.MULTIPLE_ATTR, null);
    298             selectItemList = org.apache.myfaces.shared_orchestra.renderkit.RendererUtils
    299                 .getSelectItemList((UISelectMany) uiComponent);
    300             converter = findUISelectManyConverterFailsafe(facesContext, uiComponent);
    301         }
    302         else {
    303             selectItemList = RendererUtils
    304                 .getSelectItemList((UISelectOne) uiComponent);
    305             converter = findUIOutputConverterFailSafe(facesContext, uiComponent);
    306         }
    307
    308         if (size == 0) {
    309             //No size given (Listbox) --> size is number of select items
    310             writer.writeAttribute(HTML.SIZE_ATTR, Integer
    311                 .toString(selectItemList.size()), null);
    312         }
    313         else {
    314             writer.writeAttribute(HTML.SIZE_ATTR, Integer.toString(size), null);
    315         }
    316         renderHTMLAttributes(writer, uiComponent,
    317                              HTML.SELECT_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED);
    318         if (disabled) {
    319             writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE, null);
    320         }
    321
    322         Set lookupSet = getSubmittedOrSelectedValuesAsSet(selectMany, uiComponent, facesContext, converter);
    323
    324         renderSelectOptions(facesContext, uiComponent, converter, lookupSet,
    325                             selectItemList);
    326         // bug #970747: force separate end tag
    327         writer.writeText("", null);
    328         writer.endElement(HTML.SELECT_ELEM);
    329     }
    330
    331     public static Set getSubmittedOrSelectedValuesAsSet(boolean selectMany, UIComponent uiComponent, FacesContext facesContext, Converter converter) {
    332         Set lookupSet;
    333
    334         if (selectMany) {
    335             UISelectMany uiSelectMany = (UISelectMany) uiComponent;
    336             lookupSet = RendererUtils.getSubmittedValuesAsSet(facesContext, uiComponent, converter, uiSelectMany);
    337             if (lookupSet == null) {
    338                 lookupSet = RendererUtils.getSelectedValuesAsSet(facesContext, uiComponent, converter, uiSelectMany);
    339             }
    340         }
    341         else {
    342             UISelectOne uiSelectOne = (UISelectOne) uiComponent;
    343             Object lookup = uiSelectOne.getSubmittedValue();
    344             if (lookup == null) {
    345                 lookup = uiSelectOne.getValue();
    346                 String lookupString = RendererUtils.getConvertedStringValue(facesContext, uiComponent, converter, lookup);
    347                 lookupSet = Collections.singleton(lookupString);
    348             }
    349             else if (org.apache.myfaces.shared_orchestra.renderkit.RendererUtils.NOTHING.equals(lookup)) {
    350                 lookupSet = Collections.EMPTY_SET;
    351             }
    352             else {
    353                 lookupSet = Collections.singleton(lookup);
    354             }
    355         }
    356         return lookupSet;
    357     }
    358
    359     public static Converter findUISelectManyConverterFailsafe(FacesContext facesContext, UIComponent uiComponent) {
    360         Converter converter;
    361         try {
    362             converter = RendererUtils.findUISelectManyConverter(
    363                 facesContext, (UISelectMany) uiComponent);
    364         }
    365         catch (FacesException e) {
    366             log.error("Error finding Converter for component with id "
    367                 + uiComponent.getClientId(facesContext), e);
    368             converter = null;
    369         }
    370         return converter;
    371     }
    372
    373     public static Converter findUIOutputConverterFailSafe(FacesContext facesContext, UIComponent uiComponent) {
    374         Converter converter;
    375         try {
    376             converter = RendererUtils.findUIOutputConverter(facesContext,
    377                                                             (UIOutput) uiComponent);
    378         }
    379         catch (FacesException e) {
    380             log.error("Error finding Converter for component with id "
    381                 + uiComponent.getClientId(facesContext), e);
    382             converter = null;
    383         }
    384         return converter;
    385     }
    386
    387     /**
    388      * Renders the select options for a <code>UIComponent</code> that is
    389      * rendered as an HTML select element.
    390      *
    391      * @param context        the current <code>FacesContext</code>.
    392      * @param component      the <code>UIComponent</code> whose options need to be
    393      *                       rendered.
    394      * @param converter      <code>component</code>'s converter
    395      * @param lookupSet      the <code>Set</code> to use to look up selected options
    396      * @param selectItemList the <code>List</code> of <code>SelectItem</code> s to be
    397      *                       rendered as HTML option elements.
    398      * @throws IOException
    399      */
    400     public static void renderSelectOptions(FacesContext context,
    401                                            UIComponent component, Converter converter, Set lookupSet,
    402                                            List selectItemList) throws IOException {
    403         ResponseWriter writer = context.getResponseWriter();
    404
    405         for (Iterator it = selectItemList.iterator(); it.hasNext();) {
    406             SelectItem selectItem = (SelectItem) it.next();
    407
    408             if (selectItem instanceof SelectItemGroup) {
    409                 writer.startElement(HTML.OPTGROUP_ELEM, component);
    410                 writer.writeAttribute(HTML.LABEL_ATTR, selectItem.getLabel(),
    411                                       null);
    412                 SelectItem[] selectItems = ((SelectItemGroup) selectItem)
    413                     .getSelectItems();
    414                 renderSelectOptions(context, component, converter, lookupSet,
    415                                     Arrays.asList(selectItems));
    416                 writer.endElement(HTML.OPTGROUP_ELEM);
    417             }
    418             else {
    419                 String itemStrValue = org.apache.myfaces.shared_orchestra.renderkit.RendererUtils.getConvertedStringValue(context, component,
    420                                                                                                                 converter, selectItem);
    421
    422                 writer.write(TABULATOR);
    423                 writer.startElement(HTML.OPTION_ELEM, component);
    424                 if (itemStrValue != null) {
    425                     writer.writeAttribute(HTML.VALUE_ATTR, itemStrValue, null);
    426                 }
    427
    428                 if (lookupSet.contains(itemStrValue))
    429                 {  //TODO/FIX: we always compare the String vales, better fill lookupSet with Strings only when useSubmittedValue==true, else use the real item value Objects
    430                     writer.writeAttribute(HTML.SELECTED_ATTR,
    431                                           HTML.SELECTED_ATTR, null);
    432                 }
    433
    434                 boolean disabled = selectItem.isDisabled();
    435                 if (disabled) {
    436                     writer.writeAttribute(HTML.DISABLED_ATTR,
    437                                           HTML.DISABLED_ATTR, null);
    438                 }
    439
    440                 String labelClass;
    441                 boolean componentDisabled = isTrue(component.getAttributes().get("disabled"));
    442
    443                 if (componentDisabled || disabled) {
    444                     labelClass = (String) component.getAttributes().get(JSFAttr.DISABLED_CLASS_ATTR);
    445                 }
    446                 else {
    447                     labelClass = (String) component.getAttributes().get(JSFAttr.ENABLED_CLASS_ATTR);
    448                 }
    449                 if (labelClass != null) {
    450                     writer.writeAttribute("class", labelClass, "labelClass");
    451                 }
    452
    453                 boolean escape;
    454                 if (component instanceof EscapeCapable) {
    455                     escape = ((EscapeCapable) component).isEscape();
    456                 }
    457                 else {
    458                     escape = RendererUtils.getBooleanAttribute(component, JSFAttr.ESCAPE_ATTR,
    459                                                                true); //default is to escape
    460                 }
    461
    462                 if (escape) {
    463                     writer.writeText(selectItem.getLabel(), null);
    464                 }
    465                 else {
    466                     writer.write(selectItem.getLabel());
    467                 }
    468
    469                 writer.endElement(HTML.OPTION_ELEM);
    470             }
    471         }
    472     }
    473
    474     /*
    475      * public static void renderRadio(FacesContext facesContext, UIInput
    476      * uiComponent, String value, String label, boolean checked) throws
    477      * IOException { String clientId = uiComponent.getClientId(facesContext);
    478      *
    479      * ResponseWriter writer = facesContext.getResponseWriter();
    480      *
    481      * writer.startElement(HTML.INPUT_ELEM, uiComponent);
    482      * writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_RADIO, null);
    483      * writer.writeAttribute(HTML.NAME_ATTR, clientId, null);
    484      * writer.writeAttribute(HTML.ID_ATTR, clientId, null);
    485      *
    486      * if (checked) { writer.writeAttribute(HTML.CHECKED_ATTR,
    487      * HTML.CHECKED_ATTR, null); }
    488      *
    489      * if ((value != null) && (value.length() > 0)) {
    490      * writer.writeAttribute(HTML.VALUE_ATTR, value, null); }
    491      *
    492      * renderHTMLAttributes(writer, uiComponent,
    493      * HTML.INPUT_PASSTHROUGH_ATTRIBUTES); renderDisabledOnUserRole(writer,
    494      * uiComponent, facesContext);
    495      *
    496      * if ((label != null) && (label.length() > 0)) {
    497      * writer.write(HTML.NBSP_ENTITY); writer.writeText(label, null); }
    498      *
    499      * writer.endElement(HTML.INPUT_ELEM); }
    500      */
    501
    502     public static void writePrettyLineSeparator(FacesContext facesContext)
    503         throws IOException {
    504         if (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext())
    505             .isPrettyHtml()) {
    506             facesContext.getResponseWriter().write(LINE_SEPARATOR);
    507         }
    508     }
    509
    510     public static void writePrettyIndent(FacesContext facesContext)
    511         throws IOException {
    512         if (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext())
    513             .isPrettyHtml()) {
    514             facesContext.getResponseWriter().write(TABULATOR);
    515         }
    516     }
    517
    518     /**
    519      * @return true, if the attribute was written
    520      * @throws java.io.IOException
    521      */
    522     public static boolean renderHTMLAttribute(ResponseWriter writer,
    523                                               String componentProperty, String attrName, Object value)
    524         throws IOException {
    525         if (!RendererUtils.isDefaultAttributeValue(value)) {
    526             // render JSF "styleClass" and "itemStyleClass" attributes as "class"
    527             String htmlAttrName =
    528                 attrName.equals(HTML.STYLE_CLASS_ATTR) ?
    529                     HTML.CLASS_ATTR : attrName;
    530             writer.writeAttribute(htmlAttrName, value, componentProperty);
    531             return true;
    532         }
    533
    534         return false;
    535     }
    536
    537     /**
    538      * @return true, if the attribute was written
    539      * @throws java.io.IOException
    540      */
    541     public static boolean renderHTMLAttribute(ResponseWriter writer,
    542                                               UIComponent component, String componentProperty, String htmlAttrName)
    543         throws IOException {
    544         Object value = component.getAttributes().get(componentProperty);
    545         return renderHTMLAttribute(writer, componentProperty, htmlAttrName,
    546                                    value);
    547     }
    548
    549     /**
    550      * @return true, if an attribute was written
    551      * @throws java.io.IOException
    552      */
    553     public static boolean renderHTMLAttributes(ResponseWriter writer,
    554                                                UIComponent component, String[] attributes) throws IOException {
    555         boolean somethingDone = false;
    556         for (int i = 0, len = attributes.length; i < len; i++) {
    557             String attrName = attributes[i];
    558             if (renderHTMLAttribute(writer, component, attrName, attrName)) {
    559                 somethingDone = true;
    560             }
    561         }
    562         return somethingDone;
    563     }
    564
    565     public static boolean renderHTMLAttributeWithOptionalStartElement(
    566         ResponseWriter writer, UIComponent component, String elementName,
    567         String attrName, Object value, boolean startElementWritten)
    568         throws IOException {
    569         if (!org.apache.myfaces.shared_orchestra.renderkit.RendererUtils.isDefaultAttributeValue(value)) {
    570             if (!startElementWritten) {
    571                 writer.startElement(elementName, component);
    572                 startElementWritten = true;
    573             }
    574             renderHTMLAttribute(writer, attrName, attrName, value);
    575         }
    576         return startElementWritten;
    577     }
    578
    579     public static boolean renderHTMLAttributesWithOptionalStartElement(
    580         ResponseWriter writer, UIComponent component, String elementName,
    581         String[] attributes) throws IOException {
    582         boolean startElementWritten = false;
    583         for (int i = 0, len = attributes.length; i < len; i++) {
    584             String attrName = attributes[i];
    585             Object value = component.getAttributes().get(attrName);
    586             if (!RendererUtils.isDefaultAttributeValue(value)) {
    587                 if (!startElementWritten) {
    588                     writer.startElement(elementName, component);
    589                     startElementWritten = true;
    590                 }
    591                 renderHTMLAttribute(writer, attrName, attrName, value);
    592             }
    593         }
    594         return startElementWritten;
    595     }
    596
    597     public static boolean renderOptionalEndElement(ResponseWriter writer,
    598                                                    UIComponent component, String elementName, String[] attributes)
    599         throws IOException {
    600         boolean endElementNeeded = false;
    601         for (int i = 0, len = attributes.length; i < len; i++) {
    602             String attrName = attributes[i];
    603             Object value = component.getAttributes().get(attrName);
    604             if (!RendererUtils.isDefaultAttributeValue(value)) {
    605                 endElementNeeded = true;
    606                 break;
    607             }
    608         }
    609         if (endElementNeeded) {
    610             writer.endElement(elementName);
    611             return true;
    612         }
    613
    614         return false;
    615     }
    616
    617     public static void writeIdIfNecessary(ResponseWriter writer, UIComponent component,
    618                                           FacesContext facesContext)
    619         throws IOException {
    620         if (component.getId() != null && !component.getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX)) {
    621             writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext), null);
    622         }
    623     }
    624
    625     public static void renderDisplayValueOnlyForSelects(FacesContext facesContext, UIComponent
    626         uiComponent)
    627         throws IOException {
    628         ResponseWriter writer = facesContext.getResponseWriter();
    629
    630         List selectItemList = null;
    631         Converter converter = null;
    632         boolean isSelectOne = false;
    633
    634         if (uiComponent instanceof UISelectBoolean) {
    635             converter = findUIOutputConverterFailSafe(facesContext, uiComponent);
    636
    637             writer.startElement(HTML.SPAN_ELEM, uiComponent);
    638             writeIdIfNecessary(writer, uiComponent, facesContext);
    639             renderDisplayValueOnlyAttributes(uiComponent, writer);
    640             writer.writeText(RendererUtils.getConvertedStringValue(facesContext, uiComponent,
    641                                                                    converter, ((UISelectBoolean) uiComponent).getValue()), JSFAttr.VALUE_ATTR);
    642             writer.endElement(HTML.SPAN_ELEM);
    643
    644         }
    645         else {
    646             if (uiComponent instanceof UISelectMany) {
    647                 isSelectOne = false;
    648                 selectItemList = RendererUtils
    649                     .getSelectItemList((UISelectMany) uiComponent);
    650                 converter = findUISelectManyConverterFailsafe(facesContext, uiComponent);
    651             }
    652             else if (uiComponent instanceof UISelectOne) {
    653                 isSelectOne = true;
    654                 selectItemList = RendererUtils
    655                     .getSelectItemList((UISelectOne) uiComponent);
    656                 converter = findUIOutputConverterFailSafe(facesContext, uiComponent);
    657             }
    658
    659             writer.startElement(isSelectOne ? HTML.SPAN_ELEM : HTML.UL_ELEM, uiComponent);
    660             writeIdIfNecessary(writer, uiComponent, facesContext);
    661
    662             renderDisplayValueOnlyAttributes(uiComponent, writer);
    663
    664             Set lookupSet = getSubmittedOrSelectedValuesAsSet(
    665                 uiComponent instanceof UISelectMany,
    666                 uiComponent, facesContext, converter);
    667
    668             renderSelectOptionsAsText(facesContext, uiComponent, converter, lookupSet,
    669                                       selectItemList, isSelectOne);
    670
    671             // bug #970747: force separate end tag
    672             writer.writeText("", null);
    673             writer.endElement(isSelectOne ? HTML.SPAN_ELEM : HTML.UL_ELEM);
    674         }
    675
    676     }
    677
    678     public static void renderDisplayValueOnlyAttributes(UIComponent uiComponent, ResponseWriter writer) throws IOException {
    679         if (!(uiComponent instanceof org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable)) {
    680             log.error("Wrong type of uiComponent. needs DisplayValueOnlyCapable.");
    681             renderHTMLAttributes(writer, uiComponent,
    682                                  HTML.COMMON_PASSTROUGH_ATTRIBUTES);
    683
    684             return;
    685         }
    686
    687         if (getDisplayValueOnlyStyle(uiComponent) != null || getDisplayValueOnlyStyleClass(uiComponent) != null) {
    688             if (getDisplayValueOnlyStyle(uiComponent) != null) {
    689                 writer.writeAttribute(HTML.STYLE_ATTR, getDisplayValueOnlyStyle(uiComponent), null);
    690             }
    691             else if (uiComponent.getAttributes().get("style") != null) {
    692                 writer.writeAttribute(HTML.STYLE_ATTR, uiComponent.getAttributes().get("style"), null);
    693             }
    694
    695             if (getDisplayValueOnlyStyleClass(uiComponent) != null) {
    696                 writer.writeAttribute(HTML.CLASS_ATTR, getDisplayValueOnlyStyleClass(uiComponent), null);
    697             }
    698             else if (uiComponent.getAttributes().get("styleClass") != null) {
    699                 writer.writeAttribute(HTML.CLASS_ATTR, uiComponent.getAttributes().get("styleClass"), null);
    700             }
    701
    702             renderHTMLAttributes(writer, uiComponent,
    703                                  HTML.COMMON_PASSTROUGH_ATTRIBUTES_WITHOUT_STYLE);
    704         }
    705         else {
    706             renderHTMLAttributes(writer, uiComponent,
    707                                  HTML.COMMON_PASSTROUGH_ATTRIBUTES);
    708         }
    709     }
    710
    711     private static void renderSelectOptionsAsText(FacesContext context,
    712                                                   UIComponent component, Converter converter, Set lookupSet,
    713                                                   List selectItemList, boolean isSelectOne) throws IOException {
    714         ResponseWriter writer = context.getResponseWriter();
    715
    716         for (Iterator it = selectItemList.iterator(); it.hasNext();) {
    717             SelectItem selectItem = (SelectItem) it.next();
    718
    719             if (selectItem instanceof SelectItemGroup) {
    720                 SelectItem[] selectItems = ((SelectItemGroup) selectItem)
    721                     .getSelectItems();
    722                 renderSelectOptionsAsText(context, component, converter, lookupSet,
    723                                           Arrays.asList(selectItems), isSelectOne);
    724             }
    725             else {
    726                 String itemStrValue = RendererUtils.getConvertedStringValue(context, component,
    727                                                                             converter, selectItem);
    728
    729                 if (lookupSet.contains(itemStrValue))
    730                 {  //TODO/FIX: we always compare the String vales, better fill lookupSet with Strings only when useSubmittedValue==true, else use the real item value Objects
    731
    732                     if (! isSelectOne)
    733                         writer.startElement(HTML.LI_ELEM, component);
    734                     writer.writeText(selectItem.getLabel(), null);
    735                     if (! isSelectOne)
    736                         writer.endElement(HTML.LI_ELEM);
    737
    738                     if (isSelectOne) {
    739                         //take care of several choices with the same value; use only the first one
    740                         return;
    741                     }
    742                 }
    743             }
    744         }
    745     }
    746
    747     public static String getDisplayValueOnlyStyleClass(UIComponent component) {
    748
    749         if (component instanceof org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable) {
    750             if (((org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable) component).getDisplayValueOnlyStyleClass() != null)
    751                 return ((org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable) component).getDisplayValueOnlyStyleClass();
    752
    753             UIComponent parent = component;
    754
    755             while ((parent = parent.getParent()) != null) {
    756                 if (parent instanceof org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable &&
    757                     ((org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable) parent).getDisplayValueOnlyStyleClass() != null)
    758                 {
    759                     return ((org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable) parent).getDisplayValueOnlyStyleClass();
    760                 }
    761             }
    762         }
    763
    764         return null;
    765     }
    766
    767     public static String getDisplayValueOnlyStyle(UIComponent component) {
    768
    769         if (component instanceof DisplayValueOnlyCapable) {
    770             if (((org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable) component).getDisplayValueOnlyStyle() != null)
    771                 return ((org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable) component).getDisplayValueOnlyStyle();
    772
    773             UIComponent parent = component;
    774
    775             while ((parent = parent.getParent()) != null) {
    776                 if (parent instanceof org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable &&
    777                     ((DisplayValueOnlyCapable) parent).getDisplayValueOnlyStyle() != null) {
    778                     return ((DisplayValueOnlyCapable) parent).getDisplayValueOnlyStyle();
    779                 }
    780             }
    781         }
    782
    783         return null;
    784     }
    785
    786     public static boolean isDisplayValueOnly(UIComponent component) {
    787
    788         if (component instanceof DisplayValueOnlyCapable) {
    789             if (((DisplayValueOnlyCapable) component).isSetDisplayValueOnly())
    790                 return ((org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable) component).isDisplayValueOnly();
    791
    792             UIComponent parent = component;
    793
    794             while ((parent = parent.getParent()) != null) {
    795                 if (parent instanceof DisplayValueOnlyCapable &&
    796                     ((DisplayValueOnlyCapable) parent).isSetDisplayValueOnly()) {
    797                     return ((org.apache.myfaces.shared_orchestra.component.DisplayValueOnlyCapable) parent).isDisplayValueOnly();
    798                 }
    799             }
    800         }
    801
    802         return false;
    803     }
    804
    805     public static void renderDisplayValueOnly(FacesContext facesContext, UIComponent input) throws IOException {
    806         ResponseWriter writer = facesContext.getResponseWriter();
    807         writer.startElement(org.apache.myfaces.shared_orchestra.renderkit.html.HTML.SPAN_ELEM, input);
    808
    809         writeIdIfNecessary(writer, input, facesContext);
    810
    811         renderDisplayValueOnlyAttributes(input, writer);
    812
    813         String strValue = RendererUtils.getStringValue(facesContext, input);
    814         writer.write(HTMLEncoder.encode(strValue, true, true));
    815
    816         writer.endElement(HTML.SPAN_ELEM);
    817     }
    818
    819     public static void appendClearHiddenCommandFormParamsFunctionCall(StringBuffer buf, String formName) {
    820         appendClearHiddenCommandFormParamsFunctionCall(new ScriptContext(buf,false), formName);
    821     }
    822
    823     private static void appendClearHiddenCommandFormParamsFunctionCall(ScriptContext context, String formName) {
    824
    825         String functionName = HtmlRendererUtils.getClearHiddenCommandFormParamsFunctionName(formName);
    826
    827         if(formName == null)
    828         {
    829             context.prettyLine();
    830             context.append("var clearFn = ");
    831             context.append(functionName);
    832             context.append(";");
    833             context.prettyLine();
    834             context.append("if(typeof eval('window.'+clearFn)!='undefined')");
    835             context.append("{");
    836             context.append("eval('window.'+clearFn+'(formName)');");
    837             context.append("}");
    838         }
    839         else
    840         {
    841             context.prettyLine();
    842             context.append("if(typeof window.");
    843             context.append(functionName);
    844             context.append("!='undefined')");
    845             context.append("{");
    846             context.append(functionName).append("('").append(formName).append("');");
    847             context.append("}");
    848         }
    849     }
    850
    851
    852     public static void renderFormSubmitScript(FacesContext facesContext)
    853             throws IOException
    854     {
    855
    856         Map map = facesContext.getExternalContext().getRequestMap();
    857         Boolean firstScript = (Boolean) map.get(FIRST_SUBMIT_SCRIPT_ON_PAGE);
    858
    859         if (firstScript == null || firstScript.equals(Boolean.TRUE)) {
    860             map.put(FIRST_SUBMIT_SCRIPT_ON_PAGE, Boolean.FALSE);
    861             HtmlRendererUtils.renderFormSubmitScriptIfNecessary(facesContext);
    862
    863         }
    864     }
    865
    866     private static void renderFormSubmitScriptIfNecessary(FacesContext facesContext) throws IOException {
    867         ResponseWriter writer = facesContext.getResponseWriter();
    868
    869         writer.startElement(HTML.SCRIPT_ELEM, null);
    870         writer.writeAttribute(HTML.TYPE_ATTR, "text/javascript", null);
    871
    872         final ExternalContext externalContext = facesContext.getExternalContext();
    873         final MyfacesConfig currentInstance = MyfacesConfig.getCurrentInstance(externalContext);
    874         boolean autoScroll = currentInstance.isAutoScroll();
    875
    876         ScriptContext context = new ScriptContext(currentInstance
    877             .isPrettyHtml());
    878         context.prettyLine();
    879         context.increaseIndent();
    880
    881         prepareScript(context, autoScroll);
    882
    883         writer.writeText(context.toString(),null);
    884
    885         writer.endElement(HTML.SCRIPT_ELEM);
    886     }
    887
    888     private static void prepareScript(ScriptContext context, boolean autoScroll)
    889     {
    890
    891         context.prettyLine();
    892
    893         //render a function to create a hidden input, if it doesn't exist
    894         context.append("function ");
    895         context.append(SET_HIDDEN_INPUT_FN_NAME).append("(formname, name, value)");
    896         context.append("{");
    897         context.append("var form = document.forms[formname];");
    898         context.prettyLine();
    899         context.append("if(typeof form.elements[name]=='undefined')");
    900         context.append("{");
    901         context.append("var newInput = document.createElement('input');");
    902         context.prettyLine();
    903         context.append("newInput.setAttribute('type','hidden');");
    904         context.prettyLine();
    905         context.append("newInput.setAttribute('id',name);"); //  // IE hack; See MYFACES-1805
    906         context.prettyLine();
    907         context.append("newInput.setAttribute('name',name);");
    908         context.prettyLine();
    909         context.append("newInput.setAttribute('value',value);");
    910         context.prettyLine();
    911         context.append("form.appendChild(newInput);");
    912         context.append("}");
    913         context.append("else");
    914         context.append("{");
    915         context.append("form.elements[name].value=value;");
    916         context.append("}");
    917
    918         context.append("}");
    919
    920         context.prettyLine();
    921
    922         context.prettyLine();
    923
    924         //render a function to clear a hidden input, if it exists
    925         context.append("function ");
    926         context.append(CLEAR_HIDDEN_INPUT_FN_NAME).append("(formname, name, value)");
    927         context.append("{");
    928         context.append("var form = document.forms[formname];");
    929         context.prettyLine();
    930         context.append("if(typeof form.elements[name]!='undefined')");
    931         context.append("{");
    932         context.append("form.elements[name].value=null;");
    933         context.append("}");
    934
    935         context.append("}");
    936
    937         context.prettyLine();
    938
    939         context.append("function ");
    940         context.append(SUBMIT_FORM_FN_NAME).append("(formName, linkId, target, params)");
    941         context.append("{");
    942
    943         //call the script to clear the form (clearFormHiddenParams_<formName>) method - optionally, only necessary for IE5.5.
    944         //todo: if IE5.5. is ever desupported, we can get rid of this and instead rely on the last part of this script to
    945         //clear the parameters
    946         HtmlRendererUtils.appendClearHiddenCommandFormParamsFunctionCall(context, null);
    947
    948         if (autoScroll)
    949         {
    950             appendAutoScrollAssignment(context, null);
    951         }
    952
    953         context.prettyLine();
    954
    955         //set the target (and save it)
    956         context.append("var oldTarget = '';");
    957         context.prettyLine();
    958         context.append("if((typeof target!='undefined') && target != null)");
    959         context.append("{");
    960         context.append("oldTarget=document.forms[formName].target;");
    961         context.prettyLine();
    962         context.append("document.forms[formName].target=target;");
    963         context.append("}");
    964
    965         //set the submit parameters
    966
    967         context.append("if((typeof params!='undefined') && params != null)");
    968         context.append("{");
    969         context.append("for(var i=0; i<params.length; i++)");
    970         context.append("{");
    971         context.append(SET_HIDDEN_INPUT_FN_NAME).append("(formName,params[i][0], params[i][1]);");
    972         context.append("}");
    973         context.append("}");
    974
    975         context.prettyLine();
    976
    977         context.append(SET_HIDDEN_INPUT_FN_NAME);
    978         context.append("(formName,formName +'"+NamingContainer.SEPARATOR_CHAR+
    979                 "'+'"+HtmlRendererUtils.HIDDEN_COMMANDLINK_FIELD_NAME+"',linkId);");
    980
    981         context.prettyLine();
    982         context.prettyLine();
    983
    984         //do the actual submit calls
    985
    986         context.append("if(document.forms[formName].onsubmit)");
    987         context.append("{");
    988         context.append("var result=document.forms[formName].onsubmit();");
    989         context.prettyLine();
    990         context.append("if((typeof result=='undefined')||result)");
    991         context.append("{");
    992         context.append("document.forms[formName].submit();");
    993         context.append("}");
    994         context.append("}");
    995         context.append("else ");
    996         context.append("{");
    997         context.append("document.forms[formName].submit();");
    998         context.append("}");
    999
    1000         //reset the target
    1001         context.append("if(oldTarget==null) oldTarget='';");
    1002         context.prettyLine();
    1003         context.append("document.forms[formName].target=oldTarget;");
    1004         context.prettyLine();
    1005
    1006         //clear the individual parameters - to make sure that even if the clear-function isn't called,
    1007         // the back button/resubmit functionality will still work in all browsers except IE 5.5.
    1008
    1009         context.append("if((typeof params!='undefined') && params != null)");
    1010         context.append("{");
    1011         context.append("for(var i=0; i<params.length; i++)");
    1012         context.append("{");
    1013         context.append(CLEAR_HIDDEN_INPUT_FN_NAME).append("(formName,params[i][0], params[i][1]);");
    1014         context.append("}");
    1015         context.append("}");
    1016
    1017         context.prettyLine();
    1018
    1019         context.append(CLEAR_HIDDEN_INPUT_FN_NAME);
    1020         context.append("(formName,formName +'"+NamingContainer.SEPARATOR_CHAR+
    1021                 "'+'"+HtmlRendererUtils.HIDDEN_COMMANDLINK_FIELD_NAME+"',linkId);");
    1022
    1023
    1024         //return false, so that browser does not handle the click
    1025         context.append("return false;");
    1026         context.append("}");
    1027
    1028         context.prettyLineDecreaseIndent();
    1029     }
    1030
    1031     /**
    1032      * Adds the hidden form input value assignment that is necessary for the autoscroll
    1033      * feature to an html link or button onclick attribute.
    1034      */
    1035     public static void appendAutoScrollAssignment(StringBuffer onClickValue, String formName)
    1036     {
    1037         appendAutoScrollAssignment(new ScriptContext(onClickValue,false),formName);
    1038     }
    1039
    1040     private static void appendAutoScrollAssignment(ScriptContext scriptContext, String formName)
    1041     {
    1042         String formNameStr = formName == null? "formName" : (new StringBuffer("'").append(formName).append("'").toString());
    1043         String paramName = new StringBuffer().append("'").
    1044                 append(AUTO_SCROLL_PARAM).append("'").toString();
    1045         String value = new StringBuffer().append(AUTO_SCROLL_FUNCTION).append("()").toString();
    1046
    1047         scriptContext.prettyLine();
    1048         scriptContext.append("if(typeof window."+AUTO_SCROLL_FUNCTION+"!='undefined')");
    1049         scriptContext.append("{");
    1050         scriptContext.append(SET_HIDDEN_INPUT_FN_NAME);
    1051         scriptContext.append("(").append(formNameStr).append(",").append(paramName).append(",").append(value).append(");");
    1052         scriptContext.append("}");
    1053
    1054     }
    1055
    1056     /**
    1057      * Renders the hidden form input that is necessary for the autoscroll feature.
    1058      */
    1059     public static void renderAutoScrollHiddenInput(FacesContext facesContext, ResponseWriter writer) throws IOException
    1060     {
    1061         writePrettyLineSeparator(facesContext);
    1062         writer.startElement(HTML.INPUT_ELEM, null);
    1063         writer.writeAttribute(HTML.TYPE_ATTR, "hidden", null);
    1064         writer.writeAttribute(HTML.NAME_ATTR, AUTO_SCROLL_PARAM, null);
    1065         writer.endElement(HTML.INPUT_ELEM);
    1066         writePrettyLineSeparator(facesContext);
    1067     }
    1068
    1069     /**
    1070      * Renders the autoscroll javascript function.
    1071      */
    1072     public static void renderAutoScrollFunction(FacesContext facesContext,
    1073                                                 ResponseWriter writer) throws IOException
    1074     {
    1075         writePrettyLineSeparator(facesContext);
    1076         writer.startElement(HTML.SCRIPT_ELEM,null);
    1077         writer.writeAttribute(HTML.SCRIPT_TYPE_ATTR, HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT,null);
    1078
    1079         ScriptContext script = new ScriptContext(
    1080                 MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isPrettyHtml());
    1081
    1082         script.prettyLineIncreaseIndent();
    1083
    1084         script.append("function ");
    1085         script.append(AUTO_SCROLL_FUNCTION);
    1086         script.append("()");
    1087         script.append("{");
    1088         script.append("var x = 0; var y = 0;");
    1089         script.append( "if (self.pageXOffset || self.pageYOffset)");
    1090         script.append("{");
    1091         script.append("x = self.pageXOffset;");
    1092         script.prettyLine();
    1093         script.append("y = self.pageYOffset;");
    1094         script.append("}");
    1095         script.append(" else if ((document.documentElement && document.documentElement.scrollLeft)||(document.documentElement && document.documentElement.scrollTop))");
    1096         script.append("{");
    1097         script.append("x = document.documentElement.scrollLeft;");
    1098         script.prettyLine();
    1099         script.append("y = document.documentElement.scrollTop;");
    1100         script.append("}");
    1101         script.append(" else if (document.body) ");
    1102         script.append("{");
    1103         script.append("x = document.body.scrollLeft;");
    1104         script.prettyLine();
    1105         script.append("y = document.body.scrollTop;");
    1106         script.append("}");
    1107         script.append("return x + \",\" + y;");
    1108         script.append("}");
    1109
    1110         ExternalContext externalContext = facesContext.getExternalContext();
    1111         String oldViewId = JavascriptUtils.getOldViewId(externalContext);
    1112         if (oldViewId != null && oldViewId.equals(facesContext.getViewRoot().getViewId()))
    1113         {
    1114             //ok, we stayed on the same page, so let's scroll it to the former place
    1115             String scrolling = (String)externalContext.getRequestParameterMap().get(AUTO_SCROLL_PARAM);
    1116             if (scrolling != null && scrolling.length() > 0)
    1117             {
    1118                 int x = 0;
    1119                 int y = 0;
    1120                 int comma = scrolling.indexOf(',');
    1121                 if (comma == -1)
    1122                 {
    1123                     log.warn("Illegal autoscroll request parameter: " + scrolling);
    1124                 }
    1125                 else
    1126                 {
    1127                     try {
    1128                         //we convert to int against XSS vulnerability
    1129                         x = Integer.parseInt(scrolling.substring(0, comma));
    1130                     } catch (NumberFormatException e) {
    1131                         log.warn("Error getting x offset for autoscroll feature. Bad param value: " + scrolling);
    1132                         x = 0; //ignore false numbers
    1133                     }
    1134
    1135                     try {
    1136                         //we convert to int against XSS vulnerability
    1137                         y = Integer.parseInt(scrolling.substring(comma + 1));
    1138                     } catch (NumberFormatException e) {
    1139                         log.warn("Error getting y offset for autoscroll feature. Bad param value: " + scrolling);
    1140                         y = 0; //ignore false numbers
    1141                     }
    1142                 }
    1143                 script.append("window.scrollTo(").append(x).append(",").append(y).append(");\n");
    1144             }
    1145         }
    1146
    1147         writer.writeText(script.toString(),null);
    1148
    1149         writer.endElement(HTML.SCRIPT_ELEM);
    1150         writePrettyLineSeparator(facesContext);
    1151     }
    1152
    1153     public static boolean isAllowedCdataSection(FacesContext fc) {
    1154         Boolean value = null;
    1155
    1156         if (fc != null) {
    1157             value = (Boolean) fc.getExternalContext().getRequestMap().get(ALLOW_CDATA_SECTION_ON);
    1158         }
    1159
    1160         return value != null && ((Boolean) value).booleanValue();
    1161     }
    1162
    1163     public static void allowCdataSection(FacesContext fc, boolean cdataSectionAllowed)
    1164     {
    1165           fc.getExternalContext().getRequestMap().put(ALLOW_CDATA_SECTION_ON,Boolean.valueOf(cdataSectionAllowed));
    1166     }
    1167
    1168     public static class LinkParameter {
    1169         private String _name;
    1170
    1171         private Object _value;
    1172
    1173         public String getName() {
    1174             return _name;
    1175         }
    1176
    1177         public void setName(String name) {
    1178             _name = name;
    1179         }
    1180
    1181         public Object getValue() {
    1182             return _value;
    1183         }
    1184
    1185         public void setValue(Object value) {
    1186             _value = value;
    1187         }
    1188
    1189     }
    1190
    1191     public static void renderHiddenCommandFormParams(ResponseWriter writer,
    1192                                                      Set dummyFormParams) throws IOException {
    1193         for (Iterator it = dummyFormParams.iterator(); it.hasNext();) {
    1194             Object name = it.next();
    1195             renderHiddenInputField(writer, name, null);
    1196         }
    1197     }
    1198
    1199     public static void renderHiddenInputField(ResponseWriter writer, Object name, Object value)
    1200         throws IOException {
    1201         writer.startElement(HTML.INPUT_ELEM, null);
    1202         writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_HIDDEN, JSFAttr.TYPE_ATTR);
    1203         writer.writeAttribute(HTML.NAME_ATTR, name, HTML.NAME_ATTR);
    1204         if (value != null) {
    1205             writer.writeAttribute(HTML.VALUE_ATTR, value, JSFAttr.VALUE_ATTR);
    1206         }
    1207         writer.endElement(HTML.INPUT_ELEM);
    1208     }
    1209
    1210     /**
    1211      * Render the javascript function that is called on a click on a commandLink
    1212      * to clear the hidden inputs. This is necessary because on a browser back,
    1213      * each hidden input still has it's old value (browser cache!) and therefore
    1214      * a new submit would fire the according action once more!
    1215      *
    1216      * @param writer
    1217      * @param formName
    1218      * @param dummyFormParams
    1219      * @param formTarget
    1220      * @throws IOException
    1221      */
    1222     public static void renderClearHiddenCommandFormParamsFunction(
    1223         ResponseWriter writer, String formName, Set dummyFormParams,
    1224         String formTarget) throws IOException {
    1225         //render the clear hidden inputs javascript function
    1226
    1227         String functionName = getClearHiddenCommandFormParamsFunctionName(formName);
    1228         String myfacesFunctionName = getClearHiddenCommandFormParamsFunctionNameMyfacesLegacy(formName);
    1229
    1230         writer.startElement(HTML.SCRIPT_ELEM, null);
    1231         writer.writeAttribute(HTML.TYPE_ATTR, "text/javascript", null);
    1232
    1233         ScriptContext script = new ScriptContext(MyfacesConfig.getCurrentInstance(
    1234                 FacesContext.getCurrentInstance().getExternalContext()).isPrettyHtml());
    1235
    1236         script.prettyLineIncreaseIndent();
    1237
    1238         script.append("function ").append(myfacesFunctionName).append("()");
    1239         script.append("{");
    1240         script.append(functionName).append("('").append(formName).append("');");
    1241         script.append("}");
    1242         script.prettyLine();
    1243         //the parameter in the following parameter list is added for compatibility to the RI
    1244         //of course, it isn't necessary - the current form is defined
    1245         //already by the formName passed as a parameter to this function, and included in the name of the function
    1246         script.append("function ").append(functionName).append("(currFormName)");
    1247         script.append("{");
    1248         if (dummyFormParams != null) {
    1249             script.append("var f = document.forms[");
    1250             script.append("'").append(formName).append("'");
    1251             script.append("];");
    1252             for (Iterator it = dummyFormParams.iterator(); it.hasNext();) {
    1253                 script.prettyLine();
    1254                 script.append("f.elements['");
    1255                 script.append((String) it.next());
    1256                 script.append("'].value='';");
    1257             }
    1258             script.prettyLine();
    1259         }
    1260         // clear form target
    1261         script.append("f.target=");
    1262         if (formTarget == null || formTarget.length() == 0) {
    1263             //Normally one would think that setting target to null has the
    1264             //desired effect, but once again IE is different...
    1265             //Setting target to null causes IE to open a new window!
    1266             script.append("'';");
    1267         }
    1268         else {
    1269             script.append("'");
    1270             script.append(formTarget);
    1271             script.append("';");
    1272         }
    1273         script.append("}");
    1274
    1275         //To be sure, we call this clear method on each load.
    1276         //If we don't do this and someone submits a form by pressing Enter
    1277         //within a text input, the hidden inputs won't be cleared!
    1278         script.prettyLine();
    1279         script.append(functionName);
    1280         script.append("();");
    1281
    1282         writer.writeText(script.toString(), null);
    1283         writer.endElement(HTML.SCRIPT_ELEM);
    1284     }
    1285
    1286     /**
    1287      * Prefixes the given String with CLEAR_HIDDEN_FIELD_FN_NAME and removes special characters
    1288      *
    1289      * @param formName
    1290      * @return String
    1291      */
    1292     public static String getClearHiddenCommandFormParamsFunctionName(
    1293         String formName) {
    1294         if(formName == null)
    1295         {
    1296             return "'" +CLEAR_HIDDEN_FIELD_FN_NAME
    1297                 + "_'+formName.replace(/-/g, '\\$"+NamingContainer.SEPARATOR_CHAR+"').replace(/"+NamingContainer.SEPARATOR_CHAR+"/g,'_')";
    1298         }
    1299
    1300         return JavascriptUtils.getValidJavascriptNameAsInRI(CLEAR_HIDDEN_FIELD_FN_NAME
    1301                 + "_"
    1302                 + formName
    1303                 .replace(NamingContainer.SEPARATOR_CHAR, '_'));
    1304     }
    1305
    1306     public static String getClearHiddenCommandFormParamsFunctionNameMyfacesLegacy(
    1307             String formName) {
    1308         return "clear_"
    1309                + JavascriptUtils.getValidJavascriptName(formName, false);
    1310     }
    1311
    1312     /**
    1313      * Get the name of the request parameter that holds the id of the
    1314      * link-type component that caused the form to be submitted.
    1315      * <p/>
    1316      * Within each page there may be multiple "link" type components that
    1317      * cause page submission. On the server it is necessary to know which
    1318      * of these actually caused the submit, in order to invoke the correct
    1319      * listeners. Such components therefore store their id into the
    1320      * "hidden command link field" in their associated form before
    1321      * submitting it.
    1322      * <p/>
    1323      * The field is always a direct child of each form, and has the same
    1324      * <i>name</i> in each form. The id of the form component is therefore
    1325      * both necessary and sufficient to determine the full name of the
    1326      * field.
    1327      */
    1328     public static String getHiddenCommandLinkFieldName(FormInfo formInfo) {
    1329         if (RendererUtils.isAdfOrTrinidadForm(formInfo.getForm())) {
    1330             return HIDDEN_COMMANDLINK_FIELD_NAME_TRINIDAD;
    1331         }
    1332         return formInfo.getFormName() + NamingContainer.SEPARATOR_CHAR
    1333             + HIDDEN_COMMANDLINK_FIELD_NAME;
    1334     }
    1335
    1336     public static String getHiddenCommandLinkFieldNameMyfacesOld(FormInfo formInfo) {
    1337         return formInfo.getFormName() + NamingContainer.SEPARATOR_CHAR
    1338             + HIDDEN_COMMANDLINK_FIELD_NAME_MYFACES_OLD;
    1339     }
    1340
    1341
    1342     private static String HTML_CONTENT_TYPE = "text/html";
    1343     private static String TEXT_ANY_CONTENT_TYPE = "text/*";
    1344     private static String ANY_CONTENT_TYPE = "*/*";
    1345
    1346     public static String DEFAULT_CHAR_ENCODING = "ISO-8859-1";
    1347     private static String XHTML_CONTENT_TYPE = "application/xhtml+xml";
    1348     private static String APPLICATION_XML_CONTENT_TYPE = "application/xml";
    1349     private static String TEXT_XML_CONTENT_TYPE = "text/xml";
    1350
    1351
    1352     public static String selectContentType(String contentTypeListString) {
    1353         if (contentTypeListString == null) {
    1354             FacesContext context = FacesContext.getCurrentInstance();
    1355             if (context != null) {
    1356                 contentTypeListString = (String)
    1357                     context.getExternalContext().getRequestHeaderMap().get("Accept");
    1358             }
    1359
    1360             if (contentTypeListString == null) {
    1361                 if (log.isDebugEnabled())
    1362                     log.debug("No content type list given, creating HtmlResponseWriterImpl with default content type.");
    1363
    1364                 contentTypeListString = HTML_CONTENT_TYPE;
    1365             }
    1366         }
    1367
    1368         List contentTypeList = splitContentTypeListString(contentTypeListString);
    1369         String[] supportedContentTypeArray = getSupportedContentTypes();
    1370
    1371         String selectedContentType = null;
    1372
    1373         for (int i = 0; i < supportedContentTypeArray.length; i++) {
    1374             String supportedContentType = supportedContentTypeArray[i].trim();
    1375
    1376             for (int j = 0; j < contentTypeList.size(); j++) {
    1377                 String contentType = (String) contentTypeList.get(j);
    1378
    1379                 if (contentType.indexOf(supportedContentType) != -1) {
    1380                     if (isHTMLContentType(contentType)) {
    1381                         selectedContentType = HTML_CONTENT_TYPE;
    1382                     }
    1383
    1384                     else if (isXHTMLContentType(contentType)) {
    1385                         selectedContentType = XHTML_CONTENT_TYPE;
    1386                     }
    1387                     break;
    1388                 }
    1389             }
    1390             if (selectedContentType != null) {
    1391                 break;
    1392             }
    1393         }
    1394
    1395         if (selectedContentType == null) {
    1396             throw new IllegalArgumentException("ContentTypeList does not contain a supported content type: " +
    1397                 contentTypeListString);
    1398         }
    1399         return selectedContentType;
    1400     }
    1401
    1402     public static String[] getSupportedContentTypes() {
    1403         //noinspection UnnecessaryLocalVariable
    1404         String[] supportedContentTypeArray = new String[]{HTML_CONTENT_TYPE, TEXT_ANY_CONTENT_TYPE, ANY_CONTENT_TYPE,
    1405                                                           XHTML_CONTENT_TYPE, APPLICATION_XML_CONTENT_TYPE, TEXT_XML_CONTENT_TYPE};
    1406         return supportedContentTypeArray;
    1407     }
    1408
    1409     private static boolean isHTMLContentType(String contentType) {
    1410         return contentType.indexOf(HTML_CONTENT_TYPE) != -1 ||
    1411             contentType.indexOf(ANY_CONTENT_TYPE) != -1 ||
    1412             contentType.indexOf(TEXT_ANY_CONTENT_TYPE) != -1 ;
    1413     }
    1414
    1415     public static boolean isXHTMLContentType(String contentType) {
    1416         return contentType.indexOf(XHTML_CONTENT_TYPE) != -1 ||
    1417             contentType.indexOf(APPLICATION_XML_CONTENT_TYPE) != -1 ||
    1418             contentType.indexOf(TEXT_XML_CONTENT_TYPE) != -1;
    1419     }
    1420
    1421     private static List splitContentTypeListString(String contentTypeListString) {
    1422         List contentTypeList = new ArrayList();
    1423
    1424         StringTokenizer st = new StringTokenizer(contentTypeListString, ",");
    1425         while (st.hasMoreTokens()) {
    1426             String contentType = st.nextToken().trim();
    1427
    1428             int semicolonIndex = contentType.indexOf(";");
    1429
    1430             if (semicolonIndex != -1) {
    1431                 contentType = contentType.substring(0, semicolonIndex);
    1432             }
    1433
    1434             contentTypeList.add(contentType);
    1435         }
    1436
    1437         return contentTypeList;
    1438     }
    1439
    1440     public static String getJavascriptLocation(UIComponent component) {
    1441         if (component == null)
    1442             return null;
    1443
    1444         return (String) component.getAttributes().get(JSFAttr.JAVASCRIPT_LOCATION);
    1445     }
    1446
    1447     public static String getImageLocation(UIComponent component) {
    1448         if (component == null)
    1449             return null;
    1450
    1451         return (String) component.getAttributes().get(JSFAttr.IMAGE_LOCATION);
    1452     }
    1453
    1454     public static String getStyleLocation(UIComponent component) {
    1455         if (component == null)
    1456             return null;
    1457
    1458         return (String) component.getAttributes().get(JSFAttr.STYLE_LOCATION);
    1459     }
    1460
    1461     /**
    1462      * The ScriptContext offers methods and fields
    1463      * to help with rendering out a script and keeping a
    1464      * proper formatting.
    1465      */
    1466     public static class ScriptContext
    1467     {
    1468         private long currentIndentationLevel;
    1469         private StringBuffer buffer = new StringBuffer();
    1470         private boolean prettyPrint = false;
    1471         /**
    1472          *  automatic formatting will render
    1473          *  new-lines and indents if blocks are opened
    1474          *  and closed - attention: you need to append
    1475          *  opening and closing brackets of blocks separately in this case!
    1476          */
    1477         private boolean automaticFormatting = true;
    1478
    1479         public ScriptContext()
    1480         {
    1481
    1482         }
    1483
    1484         public ScriptContext(boolean prettyPrint)
    1485         {
    1486             this.prettyPrint = prettyPrint;
    1487         }
    1488
    1489         public ScriptContext(StringBuffer buf, boolean prettyPrint)
    1490         {
    1491             this.prettyPrint = prettyPrint;
    1492             this.buffer = buf;
    1493         }
    1494
    1495         public void increaseIndent()
    1496         {
    1497             currentIndentationLevel++;
    1498         }
    1499
    1500         public void decreaseIndent()
    1501         {
    1502             currentIndentationLevel--;
    1503
    1504             if(currentIndentationLevel<0)
    1505                 currentIndentationLevel=0;
    1506         }
    1507
    1508         public void prettyLine()
    1509         {
    1510             if(prettyPrint)
    1511             {
    1512                 append(LINE_SEPARATOR);
    1513
    1514                 for(int i=0; i<getCurrentIndentationLevel(); i++)
    1515                     append(TABULATOR);
    1516             }
    1517         }
    1518
    1519         public void prettyLineIncreaseIndent()
    1520         {
    1521             increaseIndent();
    1522             prettyLine();
    1523         }
    1524
    1525         public void prettyLineDecreaseIndent()
    1526         {
    1527             decreaseIndent();
    1528             prettyLine();
    1529         }
    1530
    1531         public long getCurrentIndentationLevel()
    1532         {
    1533             return currentIndentationLevel;
    1534         }
    1535
    1536         public void setCurrentIndentationLevel(long currentIndentationLevel)
    1537         {
    1538             this.currentIndentationLevel = currentIndentationLevel;
    1539         }
    1540
    1541         public ScriptContext append(String str)
    1542         {
    1543
    1544             if(automaticFormatting && str.length()==1)
    1545             {
    1546                 boolean openBlock = str.equals("{");
    1547                 boolean closeBlock = str.equals("}");
    1548
    1549                 if(openBlock)
    1550                 {
    1551                     prettyLine();
    1552                 }
    1553                 else if(closeBlock)
    1554                 {
    1555                     prettyLineDecreaseIndent();
    1556                 }
    1557
    1558                 buffer.append(str);
    1559
    1560                 if(openBlock)
    1561                 {
    1562                     prettyLineIncreaseIndent();
    1563                 }
    1564                 else if(closeBlock)
    1565                 {
    1566                     prettyLine();
    1567                 }
    1568             }
    1569             else
    1570             {
    1571                 buffer.append(str);
    1572             }
    1573             return this;
    1574         }
    1575
    1576         public ScriptContext append(char c)
    1577         {
    1578             buffer.append(c);
    1579             return this;
    1580         }
    1581
    1582         public ScriptContext append(int i) {
    1583             buffer.append(i);
    1584             return this;
    1585         }
    1586
    1587         public String toString()
    1588         {
    1589             return buffer.toString();
    1590         }
    1591     }
    1592 }