001    package org.apache.myfaces.tobago.renderkit.html;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one or more
005     * contributor license agreements.  See the NOTICE file distributed with
006     * this work for additional information regarding copyright ownership.
007     * The ASF licenses this file to You under the Apache License, Version 2.0
008     * (the "License"); you may not use this file except in compliance with
009     * the License.  You may obtain a copy of the License at
010     *
011     *      http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing, software
014     * distributed under the License is distributed on an "AS IS" BASIS,
015     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    import org.apache.commons.lang.StringUtils;
021    import org.apache.commons.logging.Log;
022    import org.apache.commons.logging.LogFactory;
023    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_FOCUS;
024    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_INLINE;
025    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_INNER_HEIGHT;
026    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_INNER_WIDTH;
027    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_LAYOUT_HEIGHT;
028    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_LAYOUT_WIDTH;
029    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_STYLE;
030    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_STYLE_BODY;
031    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_STYLE_HEADER;
032    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_TIP;
033    import static org.apache.myfaces.tobago.TobagoConstants.FACET_LAYOUT;
034    import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_OUT;
035    import org.apache.myfaces.tobago.component.ComponentUtil;
036    import org.apache.myfaces.tobago.component.UIPage;
037    import org.apache.myfaces.tobago.component.UIData;
038    import org.apache.myfaces.tobago.context.ResourceManagerUtil;
039    import org.apache.myfaces.tobago.renderkit.LabelWithAccessKey;
040    import org.apache.myfaces.tobago.renderkit.LayoutInformationProvider;
041    import org.apache.myfaces.tobago.renderkit.LayoutableRendererBase;
042    import org.apache.myfaces.tobago.renderkit.RenderUtil;
043    import org.apache.myfaces.tobago.renderkit.RendererBaseWrapper;
044    import org.apache.myfaces.tobago.util.LayoutUtil;
045    import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
046    import org.apache.myfaces.tobago.webapp.TobagoResponseWriterWrapper;
047    
048    import javax.faces.component.UIComponent;
049    import javax.faces.component.UIInput;
050    import javax.faces.component.NamingContainer;
051    import javax.faces.context.FacesContext;
052    import javax.faces.context.ResponseWriter;
053    import javax.faces.model.SelectItem;
054    import javax.faces.model.SelectItemGroup;
055    import java.io.IOException;
056    import java.util.Arrays;
057    import java.util.List;
058    import java.util.Map;
059    import java.util.StringTokenizer;
060    
061    /*
062     * User: weber
063     * Date: Jan 11, 2005
064     * Time: 4:59:36 PM
065     */
066    public final class HtmlRendererUtil {
067    
068      private static final Log LOG = LogFactory.getLog(HtmlRendererUtil.class);
069    
070      private HtmlRendererUtil() {
071        // to prevent instantiation
072      }
073    
074      public static void renderFocusId(FacesContext facesContext, UIComponent component)
075          throws IOException {
076    
077        if (ComponentUtil.getBooleanAttribute(component, ATTR_FOCUS)) {
078          UIPage page = ComponentUtil.findPage(facesContext, component);
079          String id = component.getClientId(facesContext);
080          if (!StringUtils.isBlank(page.getFocusId()) && !page.getFocusId().equals(id)) {
081            LOG.warn("page focusId = \"" + page.getFocusId() + "\" ignoring new value \""
082                + id + "\"");
083          } else {
084            TobagoResponseWriter writer = HtmlRendererUtil.getTobagoResponseWriter(facesContext);
085            writer.writeJavascript("Tobago.focusId = '" + id + "';");
086          }
087        }
088      }
089    
090      public static void prepareRender(FacesContext facesContext, UIComponent component) {
091        // xxx find a better way for this question: isTobago or isLayoutable something like that.
092        LayoutableRendererBase layoutRendererBase = ComponentUtil.getRenderer(facesContext, component);
093        if (layoutRendererBase != null && !(layoutRendererBase instanceof RendererBaseWrapper)) {
094          createCssClass(facesContext, component);
095          layoutWidth(facesContext, component);
096          layoutHeight(facesContext, component);
097        }
098      }
099    
100      public static HtmlStyleMap prepareInnerStyle(UIComponent component) {
101        HtmlStyleMap htmlStyleMap = new HtmlStyleMap();
102        Integer innerSpaceInteger = (Integer)
103            component.getAttributes().get(ATTR_INNER_WIDTH);
104        if (innerSpaceInteger != null && innerSpaceInteger != -1) {
105          htmlStyleMap.put("width", innerSpaceInteger);
106        }
107        innerSpaceInteger = (Integer)
108            component.getAttributes().get(ATTR_INNER_HEIGHT);
109        if (innerSpaceInteger != null && innerSpaceInteger != -1) {
110          htmlStyleMap.put("height", innerSpaceInteger);
111        }
112        return htmlStyleMap;
113      }
114    
115    
116      public static void createCssClass(FacesContext facesContext, UIComponent component) {
117        String rendererName = getRendererName(facesContext, component);
118        if (rendererName != null) {
119          StyleClasses classes = StyleClasses.ensureStyleClasses(component);
120          classes.updateClassAttributeAndMarkup(component, rendererName);
121        }
122      }
123    
124      public static String getRendererName(FacesContext facesContext, UIComponent component) {
125        final String rendererType = component.getRendererType();
126        //final String family = component.getFamily();
127        if (rendererType != null//&& !"facelets".equals(family)
128           ) {
129          LayoutableRendererBase layoutableRendererBase = ComponentUtil.getRenderer(facesContext, component);
130          if (layoutableRendererBase != null) {
131            return layoutableRendererBase.getRendererName(rendererType);
132          }
133        }
134        return null;
135      }
136    
137      public static void writeLabelWithAccessKey(TobagoResponseWriter writer, LabelWithAccessKey label)
138          throws IOException {
139        int pos = label.getPos();
140        String text = label.getText();
141        if (pos == -1) {
142          writer.writeText(text);
143        } else {
144          writer.writeText(text.substring(0, pos));
145          writer.startElement(HtmlConstants.U, null);
146          writer.writeText(Character.toString(text.charAt(pos)));
147          writer.endElement(HtmlConstants.U);
148          writer.writeText(text.substring(pos + 1));
149        }
150      }
151    
152      public static void setDefaultTransition(FacesContext facesContext, boolean transition)
153          throws IOException {
154        writeScriptLoader(facesContext, null, new String[]{"Tobago.transition = " + transition + ";"});
155      }
156    
157      public static void addClickAcceleratorKey(
158          FacesContext facesContext, String clientId, char key)
159          throws IOException {
160        addClickAcceleratorKey(facesContext, clientId, key, null);
161      }
162    
163      public static void addClickAcceleratorKey(
164          FacesContext facesContext, String clientId, char key, String modifier)
165          throws IOException {
166        String str
167            = createOnclickAcceleratorKeyJsStatement(clientId, key, modifier);
168        writeScriptLoader(facesContext, null, new String[]{str});
169      }
170    
171      public static void addAcceleratorKey(
172          FacesContext facesContext, String func, char key) throws IOException {
173        addAcceleratorKey(facesContext, func, key, null);
174      }
175    
176      public static void addAcceleratorKey(
177          FacesContext facesContext, String func, char key, String modifier)
178          throws IOException {
179        String str = createAcceleratorKeyJsStatement(func, key, modifier);
180        writeScriptLoader(facesContext, null, new String[]{str});
181      }
182    
183      public static String createOnclickAcceleratorKeyJsStatement(
184          String clientId, char key, String modifier) {
185        String func = "Tobago.clickOnElement('" + clientId + "');";
186        return createAcceleratorKeyJsStatement(func, key, modifier);
187      }
188    
189      public static String createAcceleratorKeyJsStatement(
190          String func, char key, String modifier) {
191        StringBuilder buffer = new StringBuilder();
192        buffer.append("new Tobago.AcceleratorKey(function() {");
193        buffer.append(func);
194        if (!func.endsWith(";")) {
195          buffer.append(';');
196        }
197        buffer.append("}, \"");
198        buffer.append(key);
199        if (modifier != null) {
200          buffer.append("\", \"");
201          buffer.append(modifier);
202        }
203        buffer.append("\");");
204        return buffer.toString();
205      }
206    
207      public static String getLayoutSpaceStyle(UIComponent component) {
208        StringBuilder sb = new StringBuilder();
209        Integer space = LayoutUtil.getLayoutSpace(component, ATTR_LAYOUT_WIDTH, ATTR_LAYOUT_WIDTH);
210        if (space != null) {
211          sb.append(" width: ");
212          sb.append(space);
213          sb.append("px;");
214        }
215        space = LayoutUtil.getLayoutSpace(component, ATTR_LAYOUT_HEIGHT, ATTR_LAYOUT_HEIGHT);
216        if (space != null) {
217          sb.append(" height: ");
218          sb.append(space);
219          sb.append("px;");
220        }
221        return sb.toString();
222      }
223    
224      public static Integer getStyleAttributeIntValue(HtmlStyleMap style, String name) {
225        if (style == null) {
226          return null;
227        }
228        return style.getInt(name);
229      }
230    
231      public static String getStyleAttributeValue(String style, String name) {
232        if (style == null) {
233          return null;
234        }
235        String value = null;
236        StringTokenizer st = new StringTokenizer(style, ";");
237        while (st.hasMoreTokens()) {
238          String attribute = st.nextToken().trim();
239          if (attribute.startsWith(name)) {
240            value = attribute.substring(attribute.indexOf(':') + 1).trim();
241          }
242        }
243        return value;
244      }
245    
246    
247      public static void replaceStyleAttribute(UIComponent component, String styleAttribute, String value) {
248        HtmlStyleMap style = ensureStyleAttributeMap(component);
249        style.put(styleAttribute, value);
250      }
251    
252      public static void replaceStyleAttribute(UIComponent component, String attribute,
253          String styleAttribute, String value) {
254        HtmlStyleMap style = ensureStyleAttributeMap(component, attribute);
255        style.put(styleAttribute, value);
256      }
257    
258      public static void replaceStyleAttribute(UIComponent component, String styleAttribute, int value) {
259        HtmlStyleMap style = ensureStyleAttributeMap(component);
260        style.put(styleAttribute, value);
261      }
262    
263      public static void replaceStyleAttribute(UIComponent component, String attribute,
264          String styleAttribute, int value) {
265        HtmlStyleMap style = ensureStyleAttributeMap(component, attribute);
266        style.put(styleAttribute, value);
267    
268      }
269    
270      private static HtmlStyleMap ensureStyleAttributeMap(UIComponent component) {
271        return ensureStyleAttributeMap(component, ATTR_STYLE);
272      }
273    
274      private static HtmlStyleMap ensureStyleAttributeMap(UIComponent component, String attribute) {
275        final Map attributes = component.getAttributes();
276        HtmlStyleMap style = (HtmlStyleMap) attributes.get(attribute);
277        if (style == null) {
278          style = new HtmlStyleMap();
279          attributes.put(attribute, style);
280        }
281        return style;
282      }
283    
284      public static String replaceStyleAttribute(String style, String name,
285          String value) {
286        style = removeStyleAttribute(style != null ? style : "", name);
287        return style + " " + name + ": " + value + ";";
288      }
289    
290      public static String removeStyleAttribute(String style, String name) {
291        if (style == null) {
292          return null;
293        }
294        String pattern = name + "\\s*?:[^;]*?;";
295        return style.replaceAll(pattern, "").trim();
296      }
297    
298      public static void removeStyleAttribute(UIComponent component, String name) {
299        ensureStyleAttributeMap(component).remove(name);
300      }
301    
302      /**
303       * @deprecated Please use StyleClasses.ensureStyleClasses(component).add(clazz);
304       */
305      @Deprecated
306      public static void addCssClass(UIComponent component, String clazz) {
307        StyleClasses.ensureStyleClasses(component).addFullQualifiedClass(clazz);
308      }
309    
310      public static void layoutWidth(FacesContext facesContext, UIComponent component) {
311        layoutSpace(facesContext, component, true);
312      }
313    
314      public static void layoutHeight(FacesContext facesContext, UIComponent component) {
315        layoutSpace(facesContext, component, false);
316      }
317    
318      public static void layoutSpace(FacesContext facesContext, UIComponent component,
319          boolean width) {
320    
321        // prepare html 'style' attribute
322        Integer layoutSpace;
323        String layoutAttribute;
324        String styleAttribute;
325        if (width) {
326          layoutSpace = LayoutUtil.getLayoutWidth(component);
327          layoutAttribute = ATTR_LAYOUT_WIDTH;
328          styleAttribute = HtmlAttributes.WIDTH;
329        } else {
330          layoutSpace = LayoutUtil.getLayoutHeight(component);
331          layoutAttribute = ATTR_LAYOUT_HEIGHT;
332          styleAttribute = HtmlAttributes.HEIGHT;
333        }
334        int space = -1;
335        if (layoutSpace != null) {
336          space = layoutSpace.intValue();
337        }
338        if (space == -1 && (!RENDERER_TYPE_OUT.equals(component.getRendererType()))) {
339          UIComponent parent = component.getParent();
340          space = LayoutUtil.getInnerSpace(facesContext, parent, width);
341          if (space > 0 && !ComponentUtil.isFacetOf(component, parent)) {
342            component.getAttributes().put(layoutAttribute, Integer.valueOf(space));
343            if (width) {
344              component.getAttributes().remove(ATTR_INNER_WIDTH);
345            } else {
346              component.getAttributes().remove(ATTR_INNER_HEIGHT);
347            }
348          }
349        }
350        if (space > 0) {
351          LayoutInformationProvider renderer = ComponentUtil.getRenderer(facesContext, component);
352          if (layoutSpace != null
353              || !ComponentUtil.getBooleanAttribute(component, ATTR_INLINE)) {
354            int styleSpace = space;
355            if (renderer != null) {
356              if (width) {
357                styleSpace -= renderer.getComponentExtraWidth(facesContext, component);
358              } else {
359                styleSpace -= renderer.getComponentExtraHeight(facesContext, component);
360              }
361            }
362    
363            replaceStyleAttribute(component, styleAttribute, styleSpace);
364    
365          }
366          UIComponent layout = component.getFacet(FACET_LAYOUT);
367          if (layout != null) {
368            int layoutSpace2 = LayoutUtil.getInnerSpace(facesContext, component,
369                width);
370            if (layoutSpace2 > 0) {
371              layout.getAttributes().put(layoutAttribute, Integer.valueOf(layoutSpace2));
372            }
373          }
374        }
375      }
376    
377      public static void createHeaderAndBodyStyles(FacesContext facesContext, UIComponent component) {
378        createHeaderAndBodyStyles(facesContext, component, true);
379        createHeaderAndBodyStyles(facesContext, component, false);
380      }
381    
382      public static void createHeaderAndBodyStyles(FacesContext facesContext, UIComponent component, boolean width) {
383        LayoutInformationProvider renderer = ComponentUtil.getRenderer(facesContext, component);
384        HtmlStyleMap style = (HtmlStyleMap) component.getAttributes().get(ATTR_STYLE);
385        Integer styleSpace = null;
386        try {
387          styleSpace = style.getInt(width ? "width" : "height");
388        } catch (Exception e) {
389          /* ignore */
390        }
391        if (styleSpace != null) {
392          int bodySpace = 0;
393          int headerSpace = 0;
394          if (!width) {
395            if (renderer != null) {
396              headerSpace = renderer.getHeaderHeight(facesContext, component);
397            }
398            bodySpace = styleSpace - headerSpace;
399          }
400          HtmlStyleMap headerStyle = ensureStyleAttributeMap(component, ATTR_STYLE_HEADER);
401          HtmlStyleMap bodyStyle = ensureStyleAttributeMap(component, ATTR_STYLE_BODY);
402          if (width) {
403            headerStyle.put("width", styleSpace);
404            bodyStyle.put("width", styleSpace);
405          } else {
406            headerStyle.put("height", headerSpace);
407            bodyStyle.put("height", bodySpace);
408          }
409        }
410      }
411    
412      /**
413       * @deprecated Please use StyleClasses.ensureStyleClasses(component).updateClassAttribute(renderer, component);
414       */
415      @Deprecated
416      public static void updateClassAttribute(String cssClass, String rendererName, UIComponent component) {
417        throw new UnsupportedOperationException(
418            "Please use StyleClasses.ensureStyleClasses(component).updateClassAttribute(renderer, component)");
419      }
420    
421      /**
422       * @deprecated Please use StyleClasses.addMarkupClass()
423       */
424      @Deprecated
425      public static void addMarkupClass(UIComponent component, String rendererName,
426          String subComponent, StringBuilder tobagoClass) {
427        throw new UnsupportedOperationException("Please use StyleClasses.addMarkupClass()");
428      }
429    
430      /**
431       * @deprecated Please use StyleClasses.addMarkupClass()
432       */
433      @Deprecated
434      public static void addMarkupClass(UIComponent component, String rendererName, StyleClasses classes) {
435        classes.addMarkupClass(component, rendererName);
436      }
437    
438      public static void addImageSources(FacesContext facesContext, TobagoResponseWriter writer, String src, String id)
439          throws IOException {
440        StringBuilder buffer = new StringBuilder();
441        buffer.append("new Tobago.Image('");
442        buffer.append(id);
443        buffer.append("','");
444        buffer.append(ResourceManagerUtil.getImageWithPath(facesContext, src, false));
445        buffer.append("','");
446        buffer.append(ResourceManagerUtil.getImageWithPath(facesContext, createSrc(src, "Disabled"), true));
447        buffer.append("','");
448        buffer.append(ResourceManagerUtil.getImageWithPath(facesContext, createSrc(src, "Hover"), true));
449        buffer.append("');");
450        writer.writeJavascript(buffer.toString());
451      }
452    
453      public static String createSrc(String src, String ext) {
454        int dot = src.lastIndexOf('.');
455        if (dot == -1) {
456          LOG.warn("Image src without extension: '" + src + "'");
457          return src;
458        } else {
459          return src.substring(0, dot) + ext + src.substring(dot);
460        }
461      }
462    
463      public static TobagoResponseWriter getTobagoResponseWriter(FacesContext facesContext) {
464    
465        ResponseWriter writer = facesContext.getResponseWriter();
466        if (writer instanceof TobagoResponseWriter) {
467          return (TobagoResponseWriter) writer;
468        } else {
469          return new TobagoResponseWriterWrapper(writer);
470        }
471      }
472    
473      /** @deprecated use TobagoResponseWriter.writeJavascript() */
474      @Deprecated
475      public static void writeJavascript(ResponseWriter writer, String script) throws IOException {
476        startJavascript(writer);
477        writer.write(script);
478        endJavascript(writer);
479      }
480    
481      /** @deprecated use TobagoResponseWriter.writeJavascript() */
482      @Deprecated
483      public static void startJavascript(ResponseWriter writer) throws IOException {
484        writer.startElement(HtmlConstants.SCRIPT, null);
485        writer.writeAttribute(HtmlAttributes.TYPE, "text/javascript", null);
486        writer.write("\n<!--\n");
487      }
488    
489      /** @deprecated use TobagoResponseWriter.writeJavascript() */
490      @Deprecated
491      public static void endJavascript(ResponseWriter writer) throws IOException {
492        writer.write("\n// -->\n");
493        writer.endElement(HtmlConstants.SCRIPT);
494      }
495    
496      public static void writeScriptLoader(FacesContext facesContext, String script)
497          throws IOException {
498        writeScriptLoader(facesContext, new String[]{script}, null);
499      }
500    
501      public static void writeScriptLoader(FacesContext facesContext, String[] scripts, String[] afterLoadCmds)
502          throws IOException {
503        TobagoResponseWriter writer = HtmlRendererUtil.getTobagoResponseWriter(facesContext);
504    
505        String allScripts = "[]";
506        if (scripts != null) {
507          allScripts = ResourceManagerUtil.getScriptsAsJSArray(facesContext, scripts);
508        }
509    
510        StringBuilder script = new StringBuilder();
511        script.append("new Tobago.ScriptLoader(\n    ");
512        script.append(allScripts);
513    
514        if (afterLoadCmds != null && afterLoadCmds.length > 0) {
515          script.append(", \n");
516          boolean first = true;
517          for (String afterLoadCmd : afterLoadCmds) {
518            String[] splittedStrings = StringUtils.split(afterLoadCmd, '\n'); // split on <CR> to have nicer JS
519            for (String splitted : splittedStrings) {
520              String cmd = StringUtils.replace(splitted, "\\", "\\\\");
521              cmd = StringUtils.replace(cmd, "\"", "\\\"");
522              script.append(first ? "          " : "        + ");
523              script.append("\"");
524              script.append(cmd);
525              script.append("\"\n");
526              first = false;
527            }
528          }
529        }
530        script.append(");");
531    
532        writer.writeJavascript(script.toString());
533      }
534    
535      public static void writeStyleLoader(
536          FacesContext facesContext, String[] styles) throws IOException {
537        TobagoResponseWriter writer = HtmlRendererUtil.getTobagoResponseWriter(facesContext);
538    
539        StringBuilder builder = new StringBuilder();
540        builder.append("Tobago.ensureStyleFiles(\n    ");
541        builder.append(ResourceManagerUtil.getStylesAsJSArray(facesContext, styles));
542        builder.append(");");
543        writer.writeJavascript(builder.toString());
544      }
545    
546      public static String getTitleFromTipAndMessages(FacesContext facesContext, UIComponent component) {
547        String messages = ComponentUtil.getFacesMessageAsString(facesContext, component);
548        return HtmlRendererUtil.addTip(messages, (String) component.getAttributes().get(ATTR_TIP));
549      }
550    
551      public static String addTip(String title, String tip) {
552        if (tip != null) {
553          if (title != null && title.length() > 0) {
554            title += " :: ";
555          } else {
556            title = "";
557          }
558          title += tip;
559        }
560        return title;
561      }
562    
563      public static void renderSelectItems(UIInput component, List<SelectItem> items, Object[] values,
564          TobagoResponseWriter writer, FacesContext facesContext) throws IOException {
565    
566        if (LOG.isDebugEnabled()) {
567          LOG.debug("value = '" + Arrays.toString(values) + "'");
568        }
569        for (SelectItem item : items) {
570          if (item instanceof SelectItemGroup) {
571            writer.startElement(HtmlConstants.OPTGROUP, null);
572            writer.writeAttribute(HtmlAttributes.LABEL, item.getLabel(), true);
573            SelectItem[] selectItems = ((SelectItemGroup) item).getSelectItems();
574            renderSelectItems(component, Arrays.asList(selectItems), values, writer, facesContext);
575            writer.endElement(HtmlConstants.OPTGROUP);
576          } else {
577            writer.startElement(HtmlConstants.OPTION, null);
578            final Object itemValue = item.getValue();
579            String formattedValue
580                = RenderUtil.getFormattedValue(facesContext, component, itemValue);
581            writer.writeAttribute(HtmlAttributes.VALUE, formattedValue, true);
582            if (RenderUtil.contains(values, item.getValue())) {
583              writer.writeAttribute(HtmlAttributes.SELECTED, true);
584            }
585            writer.writeText(item.getLabel());
586            writer.endElement(HtmlConstants.OPTION);
587          }
588        }
589      }
590    
591      public static String getComponentId(FacesContext context, UIComponent component, String componentId) {
592        UIComponent partiallyComponent = ComponentUtil.findComponent(component, componentId);
593        if (partiallyComponent != null) {
594          String clientId = partiallyComponent.getClientId(context);
595          if (partiallyComponent instanceof UIData)  {
596            int rowIndex = ((UIData) partiallyComponent).getRowIndex();
597            if (rowIndex >= 0 && clientId.endsWith(Integer.toString(rowIndex))) {
598              return clientId.substring(0, clientId.lastIndexOf(NamingContainer.SEPARATOR_CHAR));
599            }
600          }
601          return clientId;
602        }
603        LOG.error("No Component found for id " + componentId);
604        return null;
605      }
606    
607      public static String toStyleString(String key, Integer value) {
608        StringBuilder buf = new StringBuilder();
609        buf.append(key);
610        buf.append(":");
611        buf.append(value);
612        buf.append("px; ");
613        return buf.toString();
614      }
615    
616      public static String toStyleString(String key, String value) {
617        StringBuilder buf = new StringBuilder();
618        buf.append(key);
619        buf.append(":");
620        buf.append(value);
621        buf.append("; ");
622        return buf.toString();
623      }
624    
625    }