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  
20  package org.apache.myfaces.tobago.internal.util;
21  
22  import org.apache.myfaces.tobago.component.Attributes;
23  import org.apache.myfaces.tobago.component.RendererTypes;
24  import org.apache.myfaces.tobago.component.Tags;
25  import org.apache.myfaces.tobago.component.Visual;
26  import org.apache.myfaces.tobago.context.Markup;
27  import org.apache.myfaces.tobago.internal.component.AbstractUIStyle;
28  import org.apache.myfaces.tobago.renderkit.LabelWithAccessKey;
29  import org.apache.myfaces.tobago.renderkit.css.Icons;
30  import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
31  import org.apache.myfaces.tobago.renderkit.html.DataAttributes;
32  import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
33  import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
34  import org.apache.myfaces.tobago.util.ComponentUtils;
35  import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
36  import org.slf4j.Logger;
37  import org.slf4j.LoggerFactory;
38  
39  import javax.el.ELContext;
40  import javax.el.ValueExpression;
41  import javax.faces.component.UIComponent;
42  import javax.faces.component.UIInput;
43  import javax.faces.context.FacesContext;
44  import javax.faces.model.SelectItem;
45  import javax.faces.model.SelectItemGroup;
46  import java.io.IOException;
47  import java.lang.invoke.MethodHandles;
48  import java.util.Arrays;
49  import java.util.Locale;
50  import java.util.Map;
51  
52  public final class HtmlRendererUtils {
53  
54    private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
55  
56    private HtmlRendererUtils() {
57      // to prevent instantiation
58    }
59  
60    public static String getRendererName(final FacesContext facesContext, final UIComponent component) {
61      final String rendererType = component.getRendererType();
62      return rendererType.substring(0, 1).toLowerCase(Locale.ENGLISH) + rendererType.substring(1);
63    }
64  
65    public static void writeLabelWithAccessKey(final TobagoResponseWriter writer, final LabelWithAccessKey label)
66        throws IOException {
67      final int pos = label.getPos();
68      final String text = label.getLabel();
69      if (text != null) {
70        if (pos == -1) {
71          writer.writeText(text);
72        } else {
73          writer.writeText(text.substring(0, pos));
74          writer.startElement(HtmlElements.U);
75          writer.writeText(Character.toString(text.charAt(pos)));
76          writer.endElement(HtmlElements.U);
77          writer.writeText(text.substring(pos + 1));
78        }
79      }
80    }
81  
82    public static void encodeIconOrImage(final TobagoResponseWriter writer, final String image) throws IOException {
83      if (image != null) {
84        if (image.startsWith("fa-")) {
85          writer.startElement(HtmlElements.I);
86          writer.writeClassAttribute(Icons.FA, Icons.custom(image));
87          writer.endElement(HtmlElements.I);
88        } else {
89          writer.startElement(HtmlElements.IMG);
90          writer.writeAttribute(HtmlAttributes.SRC, image, true);
91          writer.writeAttribute(HtmlAttributes.ALT, "", false);
92          writer.endElement(HtmlElements.IMG);
93        }
94      }
95    }
96  
97    public static String getTitleFromTipAndMessages(final FacesContext facesContext, final UIComponent component) {
98      final String messages = ComponentUtils.getFacesMessageAsString(facesContext, component);
99      return HtmlRendererUtils.addTip(messages, ComponentUtils.getAttribute(component, Attributes.tip));
100   }
101 
102   public static String addTip(final String title, final Object tip) {
103     String result = title;
104     if (tip != null) {
105       if (result != null && result.length() > 0) {
106         result += " :: ";
107       } else {
108         result = "";
109       }
110       result += tip;
111     }
112     return result;
113   }
114 
115   public static void renderSelectItems(final UIInput component, final TobagoClass optionClass,
116       final Iterable<SelectItem> items, final Object[] values, final String[] submittedValues,
117       final TobagoResponseWriter writer, final FacesContext facesContext) throws IOException {
118     renderSelectItems(component, optionClass, items, values, submittedValues, null, writer, facesContext);
119   }
120 
121   public static void renderSelectItems(final UIInput component, final TobagoClass optionClass,
122       final Iterable<SelectItem> items, final Object value, final String submittedValue,
123       final TobagoResponseWriter writer, final FacesContext facesContext) throws IOException {
124     renderSelectItems(component, optionClass, items, value != null ? new Object[]{value} : null,
125         submittedValue != null ? new String[]{submittedValue} : null, null, writer, facesContext);
126   }
127 
128   public static void renderSelectItems(final UIInput component, final TobagoClass optionClass,
129       final Iterable<SelectItem> items, final Object[] values, final String[] submittedValues,
130       final Boolean onlySelected, final TobagoResponseWriter writer, final FacesContext facesContext)
131       throws IOException {
132 
133     if (LOG.isDebugEnabled()) {
134       LOG.debug("component id = '{}'", component.getId());
135       LOG.debug("values = '{}'", Arrays.toString(values));
136       LOG.debug("submittedValues = '{}'", Arrays.toString(submittedValues));
137     }
138     for (final SelectItem item : items) {
139       if (item instanceof SelectItemGroup) {
140         writer.startElement(HtmlElements.OPTGROUP);
141         writer.writeAttribute(HtmlAttributes.LABEL, item.getLabel(), true);
142         if (item.isDisabled()) {
143           writer.writeAttribute(HtmlAttributes.DISABLED, true);
144         }
145         final SelectItem[] selectItems = ((SelectItemGroup) item).getSelectItems();
146         renderSelectItems(component, optionClass, Arrays.asList(selectItems), values, submittedValues,
147             onlySelected, writer, facesContext);
148         writer.endElement(HtmlElements.OPTGROUP);
149       } else {
150 
151         Object itemValue = item.getValue();
152         // when using selectItem tag with a literal value: use the converted value
153         if (itemValue instanceof String && values != null && values.length > 0 && !(values[0] instanceof String)) {
154           itemValue = ComponentUtils.getConvertedValue(facesContext, component, (String) itemValue);
155         }
156         final String formattedValue = ComponentUtils.getFormattedValue(facesContext, component, itemValue);
157         final boolean contains;
158         if (submittedValues == null) {
159           contains = ArrayUtils.contains(values, itemValue);
160         } else {
161           contains = ArrayUtils.contains(submittedValues, formattedValue);
162         }
163         if (onlySelected != null) {
164           if (onlySelected) {
165             if (!contains) {
166               continue;
167             }
168           } else {
169             if (contains) {
170               continue;
171             }
172           }
173         }
174         writer.startElement(HtmlElements.OPTION);
175         writer.writeAttribute(HtmlAttributes.VALUE, formattedValue, true);
176         if (item instanceof org.apache.myfaces.tobago.model.SelectItem) {
177           final String image = ((org.apache.myfaces.tobago.model.SelectItem) item).getImage();
178           if (image != null) {
179             final AbstractUIStyle style = (AbstractUIStyle) facesContext.getApplication()
180                 .createComponent(facesContext, Tags.style.componentType(), RendererTypes.Style.name());
181             style.setTransient(true);
182             style.setBackgroundImage(image);
183             style.setSelector(
184                 StyleRenderUtils.encodeIdSelector(component.getClientId(facesContext))
185                     + " option[value=" + formattedValue + "]");
186             // XXX This works not in common browsers...
187             component.getChildren().add(style);
188           }
189         }
190         Markup markup = item instanceof Visual ? ((Visual) item).getMarkup() : Markup.NULL;
191         if (onlySelected == null && contains) {
192           writer.writeAttribute(HtmlAttributes.SELECTED, true);
193           markup = Markup.SELECTED.add(markup);
194         }
195         if (item.isDisabled()) {
196           writer.writeAttribute(HtmlAttributes.DISABLED, true);
197           markup = Markup.DISABLED.add(markup);
198         }
199         writer.writeClassAttribute(optionClass, optionClass.createMarkup(markup));
200 
201         writer.writeText(item.getLabel());
202         writer.endElement(HtmlElements.OPTION);
203       }
204     }
205   }
206 
207   public static void writeDataAttributes(
208       final FacesContext context, final TobagoResponseWriter writer, final UIComponent component)
209       throws IOException {
210 
211     final Map<Object, Object> dataAttributes = ComponentUtils.getDataAttributes(component);
212     if (dataAttributes == null) {
213       return;
214     }
215 
216     final ELContext elContext = context.getELContext();
217 
218     for (final Map.Entry<Object, Object> entry : dataAttributes.entrySet()) {
219       final Object mapKey = entry.getKey();
220       final String name = mapKey instanceof ValueExpression
221           ? ((ValueExpression) mapKey).getValue(elContext).toString() : mapKey.toString();
222       final Object mapValue = entry.getValue();
223       final String value = mapValue instanceof ValueExpression
224           ? ((ValueExpression) mapValue).getValue(elContext).toString() : mapValue.toString();
225       writer.writeAttribute(DataAttributes.dynamic(name), value, true);
226     }
227   }
228 }