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.SupportsMarkup; 037 import org.apache.myfaces.tobago.component.UICommand; 038 import org.apache.myfaces.tobago.component.UIData; 039 import org.apache.myfaces.tobago.component.UIPage; 040 import org.apache.myfaces.tobago.context.ResourceManagerUtil; 041 import org.apache.myfaces.tobago.renderkit.LabelWithAccessKey; 042 import org.apache.myfaces.tobago.renderkit.LayoutInformationProvider; 043 import org.apache.myfaces.tobago.renderkit.LayoutableRendererBase; 044 import org.apache.myfaces.tobago.renderkit.RenderUtil; 045 import org.apache.myfaces.tobago.renderkit.RendererBaseWrapper; 046 import org.apache.myfaces.tobago.util.LayoutUtil; 047 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter; 048 import org.apache.myfaces.tobago.webapp.TobagoResponseWriterWrapper; 049 050 import javax.faces.component.NamingContainer; 051 import javax.faces.component.UIComponent; 052 import javax.faces.component.UIInput; 053 import javax.faces.context.FacesContext; 054 import javax.faces.context.ResponseWriter; 055 import javax.faces.model.SelectItem; 056 import javax.faces.model.SelectItemGroup; 057 import java.io.IOException; 058 import java.util.Arrays; 059 import java.util.List; 060 import java.util.Locale; 061 import java.util.Map; 062 import java.util.StringTokenizer; 063 064 /* 065 * Date: Jan 11, 2005 066 * Time: 4:59:36 PM 067 */ 068 public final class HtmlRendererUtil { 069 070 private static final Log LOG = LogFactory.getLog(HtmlRendererUtil.class); 071 private static final String ERROR_FOCUS_KEY = HtmlRendererUtil.class.getName() + ".ErrorFocusId"; 072 073 private HtmlRendererUtil() { 074 // to prevent instantiation 075 } 076 077 private static boolean renderErrorFocusId(final FacesContext facesContext, final UIInput input) throws IOException { 078 if (ComponentUtil.isError(input)) { 079 if (!FacesContext.getCurrentInstance().getExternalContext().getRequestMap().containsKey(ERROR_FOCUS_KEY)) { 080 FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put(ERROR_FOCUS_KEY, Boolean.TRUE); 081 TobagoResponseWriter writer = HtmlRendererUtil.getTobagoResponseWriter(facesContext); 082 String id = input.getClientId(facesContext); 083 writer.writeJavascript("Tobago.errorFocusId = '" + id + "';"); 084 return true; 085 } else { 086 return true; 087 } 088 } 089 return FacesContext.getCurrentInstance().getExternalContext().getRequestMap().containsKey(ERROR_FOCUS_KEY); 090 } 091 092 public static void renderFocusId(final FacesContext facesContext, final UIComponent component) 093 throws IOException { 094 if (component instanceof UIInput) { 095 renderFocusId(facesContext, (UIInput) component); 096 } 097 } 098 099 public static void renderFocusId(final FacesContext facesContext, final UIInput component) 100 throws IOException { 101 if (renderErrorFocusId(facesContext, component)) { 102 return; 103 } 104 if (ComponentUtil.getBooleanAttribute(component, ATTR_FOCUS)) { 105 UIPage page = ComponentUtil.findPage(facesContext, component); 106 String id = component.getClientId(facesContext); 107 if (!StringUtils.isBlank(page.getFocusId()) && !page.getFocusId().equals(id)) { 108 LOG.warn("page focusId = \"" + page.getFocusId() + "\" ignoring new value \"" 109 + id + "\""); 110 } else { 111 TobagoResponseWriter writer = HtmlRendererUtil.getTobagoResponseWriter(facesContext); 112 writer.writeJavascript("Tobago.focusId = '" + id + "';"); 113 } 114 } 115 } 116 117 public static void prepareRender(FacesContext facesContext, UIComponent component) { 118 // xxx find a better way for this question: isTobago or isLayoutable something like that. 119 LayoutableRendererBase layoutRendererBase = ComponentUtil.getRenderer(facesContext, component); 120 if (layoutRendererBase != null && !(layoutRendererBase instanceof RendererBaseWrapper)) { 121 createCssClass(facesContext, component); 122 layoutWidth(facesContext, component); 123 layoutHeight(facesContext, component); 124 } 125 } 126 127 public static HtmlStyleMap prepareInnerStyle(UIComponent component) { 128 HtmlStyleMap htmlStyleMap = new HtmlStyleMap(); 129 Integer innerSpaceInteger = (Integer) 130 component.getAttributes().get(ATTR_INNER_WIDTH); 131 if (innerSpaceInteger != null && innerSpaceInteger != -1) { 132 htmlStyleMap.put("width", innerSpaceInteger); 133 } 134 innerSpaceInteger = (Integer) 135 component.getAttributes().get(ATTR_INNER_HEIGHT); 136 if (innerSpaceInteger != null && innerSpaceInteger != -1) { 137 htmlStyleMap.put("height", innerSpaceInteger); 138 } 139 return htmlStyleMap; 140 } 141 142 143 public static void createCssClass(FacesContext facesContext, UIComponent component) { 144 String rendererName = getRendererName(facesContext, component); 145 if (rendererName != null) { 146 StyleClasses classes = StyleClasses.ensureStyleClasses(component); 147 classes.updateClassAttributeAndMarkup(component, rendererName); 148 } 149 } 150 151 public static String getRendererName(FacesContext facesContext, UIComponent component) { 152 final String rendererType = component.getRendererType(); 153 //final String family = component.getFamily(); 154 if (rendererType != null//&& !"facelets".equals(family) 155 ) { 156 LayoutableRendererBase layoutableRendererBase = ComponentUtil.getRenderer(facesContext, component); 157 if (layoutableRendererBase != null) { 158 return layoutableRendererBase.getRendererName(rendererType); 159 } 160 } 161 return null; 162 } 163 164 public static void writeLabelWithAccessKey(TobagoResponseWriter writer, LabelWithAccessKey label) 165 throws IOException { 166 int pos = label.getPos(); 167 String text = label.getText(); 168 if (pos == -1) { 169 writer.writeText(text); 170 } else { 171 writer.writeText(text.substring(0, pos)); 172 writer.startElement(HtmlConstants.U, null); 173 writer.writeText(Character.toString(text.charAt(pos))); 174 writer.endElement(HtmlConstants.U); 175 writer.writeText(text.substring(pos + 1)); 176 } 177 } 178 179 public static void setDefaultTransition(FacesContext facesContext, boolean transition) 180 throws IOException { 181 writeScriptLoader(facesContext, null, new String[]{"Tobago.transition = " + transition + ";"}); 182 } 183 184 public static void addClickAcceleratorKey( 185 FacesContext facesContext, String clientId, char key) 186 throws IOException { 187 addClickAcceleratorKey(facesContext, clientId, key, null); 188 } 189 190 public static void addClickAcceleratorKey( 191 FacesContext facesContext, String clientId, char key, String modifier) 192 throws IOException { 193 String str 194 = createOnclickAcceleratorKeyJsStatement(clientId, key, modifier); 195 writeScriptLoader(facesContext, null, new String[]{str}); 196 } 197 198 public static void addAcceleratorKey( 199 FacesContext facesContext, String func, char key) throws IOException { 200 addAcceleratorKey(facesContext, func, key, null); 201 } 202 203 public static void addAcceleratorKey( 204 FacesContext facesContext, String func, char key, String modifier) 205 throws IOException { 206 String str = createAcceleratorKeyJsStatement(func, key, modifier); 207 writeScriptLoader(facesContext, null, new String[]{str}); 208 } 209 210 public static String createOnclickAcceleratorKeyJsStatement( 211 String clientId, char key, String modifier) { 212 String func = "Tobago.clickOnElement('" + clientId + "');"; 213 return createAcceleratorKeyJsStatement(func, key, modifier); 214 } 215 216 public static String createAcceleratorKeyJsStatement( 217 String func, char key, String modifier) { 218 StringBuilder buffer = new StringBuilder(); 219 buffer.append("new Tobago.AcceleratorKey(function() {"); 220 buffer.append(func); 221 if (!func.endsWith(";")) { 222 buffer.append(';'); 223 } 224 buffer.append("}, \""); 225 buffer.append(key); 226 if (modifier != null) { 227 buffer.append("\", \""); 228 buffer.append(modifier); 229 } 230 buffer.append("\");"); 231 return buffer.toString(); 232 } 233 234 public static String getLayoutSpaceStyle(UIComponent component) { 235 StringBuilder sb = new StringBuilder(); 236 Integer space = LayoutUtil.getLayoutSpace(component, ATTR_LAYOUT_WIDTH, ATTR_LAYOUT_WIDTH); 237 if (space != null) { 238 sb.append(" width: "); 239 sb.append(space); 240 sb.append("px;"); 241 } 242 space = LayoutUtil.getLayoutSpace(component, ATTR_LAYOUT_HEIGHT, ATTR_LAYOUT_HEIGHT); 243 if (space != null) { 244 sb.append(" height: "); 245 sb.append(space); 246 sb.append("px;"); 247 } 248 return sb.toString(); 249 } 250 251 public static Integer getStyleAttributeIntValue(HtmlStyleMap style, String name) { 252 if (style == null) { 253 return null; 254 } 255 return style.getInt(name); 256 } 257 258 public static String getStyleAttributeValue(String style, String name) { 259 if (style == null) { 260 return null; 261 } 262 String value = null; 263 StringTokenizer st = new StringTokenizer(style, ";"); 264 while (st.hasMoreTokens()) { 265 String attribute = st.nextToken().trim(); 266 if (attribute.startsWith(name)) { 267 value = attribute.substring(attribute.indexOf(':') + 1).trim(); 268 } 269 } 270 return value; 271 } 272 273 274 public static void replaceStyleAttribute(UIComponent component, String styleAttribute, String value) { 275 HtmlStyleMap style = ensureStyleAttributeMap(component); 276 style.put(styleAttribute, value); 277 } 278 279 public static void replaceStyleAttribute(UIComponent component, String attribute, 280 String styleAttribute, String value) { 281 HtmlStyleMap style = ensureStyleAttributeMap(component, attribute); 282 style.put(styleAttribute, value); 283 } 284 285 public static void replaceStyleAttribute(UIComponent component, String styleAttribute, int value) { 286 HtmlStyleMap style = ensureStyleAttributeMap(component); 287 style.put(styleAttribute, value); 288 } 289 290 public static void replaceStyleAttribute(UIComponent component, String attribute, 291 String styleAttribute, int value) { 292 HtmlStyleMap style = ensureStyleAttributeMap(component, attribute); 293 style.put(styleAttribute, value); 294 295 } 296 297 private static HtmlStyleMap ensureStyleAttributeMap(UIComponent component) { 298 return ensureStyleAttributeMap(component, ATTR_STYLE); 299 } 300 301 private static HtmlStyleMap ensureStyleAttributeMap(UIComponent component, String attribute) { 302 final Map attributes = component.getAttributes(); 303 HtmlStyleMap style = (HtmlStyleMap) attributes.get(attribute); 304 if (style == null) { 305 style = new HtmlStyleMap(); 306 attributes.put(attribute, style); 307 } 308 return style; 309 } 310 311 /** 312 * @deprecated 313 */ 314 public static String replaceStyleAttribute(String style, String name, 315 String value) { 316 style = removeStyleAttribute(style != null ? style : "", name); 317 return style + " " + name + ": " + value + ";"; 318 } 319 320 /** 321 * @deprecated 322 */ 323 public static String removeStyleAttribute(String style, String name) { 324 if (style == null) { 325 return null; 326 } 327 String pattern = name + "\\s*?:[^;]*?;"; 328 return style.replaceAll(pattern, "").trim(); 329 } 330 331 public static void removeStyleAttribute(UIComponent component, String name) { 332 ensureStyleAttributeMap(component).remove(name); 333 } 334 335 /** 336 * @deprecated Please use StyleClasses.ensureStyleClasses(component).add(clazz); 337 */ 338 @Deprecated 339 public static void addCssClass(UIComponent component, String clazz) { 340 StyleClasses.ensureStyleClasses(component).addFullQualifiedClass(clazz); 341 } 342 343 public static void layoutWidth(FacesContext facesContext, UIComponent component) { 344 layoutSpace(facesContext, component, true); 345 } 346 347 public static void layoutHeight(FacesContext facesContext, UIComponent component) { 348 layoutSpace(facesContext, component, false); 349 } 350 351 public static void layoutSpace(FacesContext facesContext, UIComponent component, 352 boolean width) { 353 354 // prepare html 'style' attribute 355 Integer layoutSpace; 356 String layoutAttribute; 357 String styleAttribute; 358 if (width) { 359 layoutSpace = LayoutUtil.getLayoutWidth(component); 360 layoutAttribute = ATTR_LAYOUT_WIDTH; 361 styleAttribute = HtmlAttributes.WIDTH; 362 } else { 363 layoutSpace = LayoutUtil.getLayoutHeight(component); 364 layoutAttribute = ATTR_LAYOUT_HEIGHT; 365 styleAttribute = HtmlAttributes.HEIGHT; 366 } 367 int space = -1; 368 if (layoutSpace != null) { 369 space = layoutSpace.intValue(); 370 } 371 if (space == -1 && (!RENDERER_TYPE_OUT.equals(component.getRendererType()))) { 372 UIComponent parent = component.getParent(); 373 space = LayoutUtil.getInnerSpace(facesContext, parent, width); 374 if (space > 0 && !ComponentUtil.isFacetOf(component, parent)) { 375 component.getAttributes().put(layoutAttribute, Integer.valueOf(space)); 376 if (width) { 377 component.getAttributes().remove(ATTR_INNER_WIDTH); 378 } else { 379 component.getAttributes().remove(ATTR_INNER_HEIGHT); 380 } 381 } 382 } 383 if (space > 0) { 384 LayoutInformationProvider renderer = ComponentUtil.getRenderer(facesContext, component); 385 if (layoutSpace != null 386 || !ComponentUtil.getBooleanAttribute(component, ATTR_INLINE)) { 387 int styleSpace = space; 388 if (renderer != null) { 389 if (width) { 390 styleSpace -= renderer.getComponentExtraWidth(facesContext, component); 391 } else { 392 styleSpace -= renderer.getComponentExtraHeight(facesContext, component); 393 } 394 } 395 396 replaceStyleAttribute(component, styleAttribute, styleSpace); 397 398 } 399 UIComponent layout = component.getFacet(FACET_LAYOUT); 400 if (layout != null) { 401 int layoutSpace2 = LayoutUtil.getInnerSpace(facesContext, component, 402 width); 403 if (layoutSpace2 > 0) { 404 layout.getAttributes().put(layoutAttribute, Integer.valueOf(layoutSpace2)); 405 } 406 } 407 } 408 } 409 410 public static void createHeaderAndBodyStyles(FacesContext facesContext, UIComponent component) { 411 createHeaderAndBodyStyles(facesContext, component, true); 412 createHeaderAndBodyStyles(facesContext, component, false); 413 } 414 415 public static void createHeaderAndBodyStyles(FacesContext facesContext, UIComponent component, boolean width) { 416 LayoutInformationProvider renderer = ComponentUtil.getRenderer(facesContext, component); 417 HtmlStyleMap style = (HtmlStyleMap) component.getAttributes().get(ATTR_STYLE); 418 Integer styleSpace = null; 419 try { 420 styleSpace = style.getInt(width ? "width" : "height"); 421 } catch (Exception e) { 422 /* ignore */ 423 } 424 if (styleSpace != null) { 425 int bodySpace = 0; 426 int headerSpace = 0; 427 if (!width) { 428 if (renderer != null) { 429 headerSpace = renderer.getHeaderHeight(facesContext, component); 430 } 431 bodySpace = styleSpace - headerSpace; 432 } 433 HtmlStyleMap headerStyle = ensureStyleAttributeMap(component, ATTR_STYLE_HEADER); 434 HtmlStyleMap bodyStyle = ensureStyleAttributeMap(component, ATTR_STYLE_BODY); 435 if (width) { 436 headerStyle.put("width", styleSpace); 437 bodyStyle.put("width", styleSpace); 438 } else { 439 headerStyle.put("height", headerSpace); 440 bodyStyle.put("height", bodySpace); 441 } 442 } 443 } 444 445 /** 446 * @deprecated Please use StyleClasses.ensureStyleClasses(component).updateClassAttribute(renderer, component); 447 */ 448 @Deprecated 449 public static void updateClassAttribute(String cssClass, String rendererName, UIComponent component) { 450 throw new UnsupportedOperationException( 451 "Please use StyleClasses.ensureStyleClasses(component).updateClassAttribute(renderer, component)"); 452 } 453 454 /** 455 * @deprecated Please use StyleClasses.addMarkupClass() 456 */ 457 @Deprecated 458 public static void addMarkupClass(UIComponent component, String rendererName, 459 String subComponent, StringBuilder tobagoClass) { 460 throw new UnsupportedOperationException("Please use StyleClasses.addMarkupClass()"); 461 } 462 463 /** 464 * @deprecated Please use StyleClasses.addMarkupClass() 465 */ 466 @Deprecated 467 public static void addMarkupClass(UIComponent component, String rendererName, StyleClasses classes) { 468 classes.addMarkupClass(component, rendererName); 469 } 470 471 public static void addImageSources(FacesContext facesContext, TobagoResponseWriter writer, String src, String id) 472 throws IOException { 473 StringBuilder buffer = new StringBuilder(); 474 buffer.append("new Tobago.Image('"); 475 buffer.append(id); 476 buffer.append("','"); 477 buffer.append(ResourceManagerUtil.getImageWithPath(facesContext, src, false)); 478 buffer.append("','"); 479 buffer.append(ResourceManagerUtil.getImageWithPath(facesContext, createSrc(src, "Disabled"), true)); 480 buffer.append("','"); 481 buffer.append(ResourceManagerUtil.getImageWithPath(facesContext, createSrc(src, "Hover"), true)); 482 buffer.append("');"); 483 writer.writeJavascript(buffer.toString()); 484 } 485 486 public static String createSrc(String src, String ext) { 487 int dot = src.lastIndexOf('.'); 488 if (dot == -1) { 489 LOG.warn("Image src without extension: '" + src + "'"); 490 return src; 491 } else { 492 return src.substring(0, dot) + ext + src.substring(dot); 493 } 494 } 495 496 public static TobagoResponseWriter getTobagoResponseWriter(FacesContext facesContext) { 497 498 ResponseWriter writer = facesContext.getResponseWriter(); 499 if (writer instanceof TobagoResponseWriter) { 500 return (TobagoResponseWriter) writer; 501 } else { 502 return new TobagoResponseWriterWrapper(writer); 503 } 504 } 505 506 /** 507 * @deprecated use TobagoResponseWriter.writeJavascript() 508 */ 509 @Deprecated 510 public static void writeJavascript(ResponseWriter writer, String script) throws IOException { 511 startJavascript(writer); 512 writer.write(script); 513 endJavascript(writer); 514 } 515 516 /** 517 * @deprecated use TobagoResponseWriter.writeJavascript() 518 */ 519 @Deprecated 520 public static void startJavascript(ResponseWriter writer) throws IOException { 521 writer.startElement(HtmlConstants.SCRIPT, null); 522 writer.writeAttribute(HtmlAttributes.TYPE, "text/javascript", null); 523 writer.write("\n<!--\n"); 524 } 525 526 /** 527 * @deprecated use TobagoResponseWriter.writeJavascript() 528 */ 529 @Deprecated 530 public static void endJavascript(ResponseWriter writer) throws IOException { 531 writer.write("\n// -->\n"); 532 writer.endElement(HtmlConstants.SCRIPT); 533 } 534 535 public static void writeScriptLoader(FacesContext facesContext, String script) 536 throws IOException { 537 writeScriptLoader(facesContext, new String[]{script}, null); 538 } 539 540 public static void writeScriptLoader(FacesContext facesContext, String[] scripts, String[] afterLoadCmds) 541 throws IOException { 542 TobagoResponseWriter writer = HtmlRendererUtil.getTobagoResponseWriter(facesContext); 543 544 String allScripts = "[]"; 545 if (scripts != null) { 546 allScripts = ResourceManagerUtil.getScriptsAsJSArray(facesContext, scripts); 547 } 548 549 StringBuilder script = new StringBuilder(); 550 script.append("new Tobago.ScriptLoader(\n "); 551 script.append(allScripts); 552 553 if (afterLoadCmds != null && afterLoadCmds.length > 0) { 554 script.append(", \n"); 555 boolean first = true; 556 for (String afterLoadCmd : afterLoadCmds) { 557 String[] splittedStrings = StringUtils.split(afterLoadCmd, '\n'); // split on <CR> to have nicer JS 558 for (String splitted : splittedStrings) { 559 String cmd = StringUtils.replace(splitted, "\\", "\\\\"); 560 cmd = StringUtils.replace(cmd, "\"", "\\\""); 561 script.append(first ? " " : " + "); 562 script.append("\""); 563 script.append(cmd); 564 script.append("\"\n"); 565 first = false; 566 } 567 } 568 } 569 script.append(");"); 570 571 writer.writeJavascript(script.toString()); 572 } 573 574 public static void writeStyleLoader( 575 FacesContext facesContext, String[] styles) throws IOException { 576 TobagoResponseWriter writer = HtmlRendererUtil.getTobagoResponseWriter(facesContext); 577 578 StringBuilder builder = new StringBuilder(); 579 builder.append("Tobago.ensureStyleFiles(\n "); 580 builder.append(ResourceManagerUtil.getStylesAsJSArray(facesContext, styles)); 581 builder.append(");"); 582 writer.writeJavascript(builder.toString()); 583 } 584 585 public static String getTitleFromTipAndMessages(FacesContext facesContext, UIComponent component) { 586 String messages = ComponentUtil.getFacesMessageAsString(facesContext, component); 587 return HtmlRendererUtil.addTip(messages, component.getAttributes().get(ATTR_TIP)); 588 } 589 590 public static String addTip(String title, Object tip) { 591 if (tip != null) { 592 if (title != null && title.length() > 0) { 593 title += " :: "; 594 } else { 595 title = ""; 596 } 597 title += tip; 598 } 599 return title; 600 } 601 602 public static void renderSelectItems(UIInput component, List<SelectItem> items, Object[] values, 603 TobagoResponseWriter writer, FacesContext facesContext) throws IOException { 604 605 if (LOG.isDebugEnabled()) { 606 LOG.debug("value = '" + Arrays.toString(values) + "'"); 607 } 608 for (SelectItem item : items) { 609 if (item instanceof SelectItemGroup) { 610 writer.startElement(HtmlConstants.OPTGROUP, null); 611 writer.writeAttribute(HtmlAttributes.LABEL, item.getLabel(), true); 612 if (item.isDisabled()) { 613 writer.writeAttribute(HtmlAttributes.DISABLED, true); 614 } 615 SelectItem[] selectItems = ((SelectItemGroup) item).getSelectItems(); 616 renderSelectItems(component, Arrays.asList(selectItems), values, writer, facesContext); 617 writer.endElement(HtmlConstants.OPTGROUP); 618 } else { 619 writer.startElement(HtmlConstants.OPTION, null); 620 final Object itemValue = item.getValue(); 621 String formattedValue = RenderUtil.getFormattedValue(facesContext, component, itemValue); 622 writer.writeAttribute(HtmlAttributes.VALUE, formattedValue, true); 623 if (item instanceof org.apache.myfaces.tobago.model.SelectItem) { 624 String image = ((org.apache.myfaces.tobago.model.SelectItem) item).getImage(); 625 if (image != null) { 626 String imagePath = ResourceManagerUtil.getImageWithPath(facesContext, image); 627 writer.writeStyleAttribute("background-image: url('" + imagePath + "')"); 628 } 629 } 630 if (item instanceof SupportsMarkup) { 631 StyleClasses optionStyle = new StyleClasses(); 632 optionStyle.addMarkupClass((SupportsMarkup) item, getRendererName(facesContext, component), "option"); 633 writer.writeClassAttribute(optionStyle); 634 } 635 if (RenderUtil.contains(values, item.getValue())) { 636 writer.writeAttribute(HtmlAttributes.SELECTED, true); 637 } 638 if (item.isDisabled()) { 639 writer.writeAttribute(HtmlAttributes.DISABLED, true); 640 } 641 writer.writeText(item.getLabel()); 642 writer.endElement(HtmlConstants.OPTION); 643 } 644 } 645 } 646 647 public static String getComponentId(FacesContext context, UIComponent component, String componentId) { 648 UIComponent partiallyComponent = ComponentUtil.findComponent(component, componentId); 649 if (partiallyComponent != null) { 650 String clientId = partiallyComponent.getClientId(context); 651 if (partiallyComponent instanceof UIData) { 652 int rowIndex = ((UIData) partiallyComponent).getRowIndex(); 653 if (rowIndex >= 0 && clientId.endsWith(Integer.toString(rowIndex))) { 654 return clientId.substring(0, clientId.lastIndexOf(NamingContainer.SEPARATOR_CHAR)); 655 } 656 } 657 return clientId; 658 } 659 LOG.error("No Component found for id " + componentId + " search base component " + component.getClientId(context)); 660 return null; 661 } 662 663 public static String toStyleString(String key, Integer value) { 664 StringBuilder buf = new StringBuilder(); 665 buf.append(key); 666 buf.append(":"); 667 buf.append(value); 668 buf.append("px; "); 669 return buf.toString(); 670 } 671 672 public static String toStyleString(String key, String value) { 673 StringBuilder buf = new StringBuilder(); 674 buf.append(key); 675 buf.append(":"); 676 buf.append(value); 677 buf.append("; "); 678 return buf.toString(); 679 } 680 681 public static void renderTip(UIComponent component, TobagoResponseWriter writer) throws IOException { 682 Object objTip = component.getAttributes().get(ATTR_TIP); 683 if (objTip != null) { 684 writer.writeAttribute(HtmlAttributes.TITLE, String.valueOf(objTip), true); 685 } 686 } 687 688 public static void renderImageTip(UIComponent component, TobagoResponseWriter writer) throws IOException { 689 Object objTip = component.getAttributes().get(ATTR_TIP); 690 if (objTip != null) { 691 writer.writeAttribute(HtmlAttributes.ALT, String.valueOf(objTip), true); 692 } else { 693 writer.writeAttribute(HtmlAttributes.ALT, "", false); 694 } 695 } 696 697 public static String getJavascriptString(String str) { 698 if (str != null) { 699 return "\"" + str + "\""; 700 } 701 return null; 702 } 703 704 public static String getRenderedPartiallyJavascriptArray(FacesContext facesContext, UICommand command) { 705 if (command == null) { 706 return null; 707 } 708 String[] list = command.getRenderedPartially(); 709 StringBuilder strBuilder = new StringBuilder(); 710 strBuilder.append("["); 711 for (int i = 0; i < list.length; i++) { 712 if (i != 0) { 713 strBuilder.append(","); 714 } 715 strBuilder.append("\""); 716 strBuilder.append(HtmlRendererUtil.getComponentId(facesContext, command, list[i])); 717 strBuilder.append("\""); 718 } 719 strBuilder.append("]"); 720 return strBuilder.toString(); 721 } 722 723 public static String getJavascriptArray(String[] list) { 724 StringBuilder strBuilder = new StringBuilder(); 725 strBuilder.append("["); 726 for (int i = 0; i < list.length; i++) { 727 if (i != 0) { 728 strBuilder.append(","); 729 } 730 strBuilder.append("\""); 731 strBuilder.append(list[i]); 732 strBuilder.append("\""); 733 } 734 strBuilder.append("]"); 735 return strBuilder.toString(); 736 } 737 738 public static void removeStyleClasses(UIComponent cell) { 739 Object obj = cell.getAttributes().get(org.apache.myfaces.tobago.TobagoConstants.ATTR_STYLE_CLASS); 740 if (obj != null && obj instanceof StyleClasses && cell.getRendererType() != null) { 741 StyleClasses styleClasses = (StyleClasses) obj; 742 if (!styleClasses.isEmpty()) { 743 String rendererName = cell.getRendererType().substring(0, 1).toLowerCase(Locale.ENGLISH) 744 + cell.getRendererType().substring(1); 745 styleClasses.removeTobagoClasses(rendererName); 746 } 747 if (styleClasses.isEmpty()) { 748 cell.getAttributes().remove(org.apache.myfaces.tobago.TobagoConstants.ATTR_STYLE_CLASS); 749 } 750 } 751 } 752 }