001/* 002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a> 018 * 019 * $Id: FaceletHandlerHelper.java 30553 2008-02-24 15:51:31Z atchertchian $ 020 */ 021 022package org.nuxeo.ecm.platform.forms.layout.facelets; 023 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.Collections; 028import java.util.HashMap; 029import java.util.List; 030import java.util.Map; 031import java.util.regex.Matcher; 032import java.util.regex.Pattern; 033 034import javax.el.ExpressionFactory; 035import javax.el.ValueExpression; 036import javax.faces.component.html.HtmlMessage; 037import javax.faces.component.html.HtmlOutputText; 038import javax.faces.context.FacesContext; 039import javax.faces.convert.Converter; 040import javax.faces.validator.Validator; 041import javax.faces.view.facelets.ComponentConfig; 042import javax.faces.view.facelets.ComponentHandler; 043import javax.faces.view.facelets.ConverterConfig; 044import javax.faces.view.facelets.ConverterHandler; 045import javax.faces.view.facelets.FaceletContext; 046import javax.faces.view.facelets.FaceletHandler; 047import javax.faces.view.facelets.TagAttribute; 048import javax.faces.view.facelets.TagAttributes; 049import javax.faces.view.facelets.TagConfig; 050import javax.faces.view.facelets.TagHandler; 051import javax.faces.view.facelets.ValidatorConfig; 052import javax.faces.view.facelets.ValidatorHandler; 053 054import org.apache.commons.logging.Log; 055import org.apache.commons.logging.LogFactory; 056import org.nuxeo.ecm.platform.forms.layout.actions.NuxeoLayoutManagerBean; 057import org.nuxeo.ecm.platform.forms.layout.api.FieldDefinition; 058import org.nuxeo.ecm.platform.forms.layout.api.Widget; 059import org.nuxeo.ecm.platform.forms.layout.api.WidgetSelectOption; 060import org.nuxeo.ecm.platform.forms.layout.api.WidgetSelectOptions; 061import org.nuxeo.ecm.platform.forms.layout.service.WebLayoutManager; 062import org.nuxeo.ecm.platform.ui.web.binding.alias.AliasTagHandler; 063import org.nuxeo.ecm.platform.ui.web.tag.fn.Functions; 064import org.nuxeo.ecm.platform.ui.web.tag.handler.GenericHtmlComponentHandler; 065import org.nuxeo.ecm.platform.ui.web.tag.handler.SetTagHandler; 066import org.nuxeo.ecm.platform.ui.web.tag.handler.TagConfigFactory; 067import org.nuxeo.ecm.platform.ui.web.util.ComponentTagUtils; 068import org.nuxeo.runtime.api.Framework; 069 070import com.sun.faces.facelets.tag.TagAttributeImpl; 071import com.sun.faces.facelets.tag.TagAttributesImpl; 072import com.sun.faces.facelets.tag.ui.ComponentRef; 073import com.sun.faces.facelets.tag.ui.ComponentRefHandler; 074 075/** 076 * Helpers for layout/widget handlers. 077 * <p> 078 * Helps generating custom tag handlers and custom tag attributes. 079 * 080 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a> 081 */ 082public final class FaceletHandlerHelper { 083 084 private static final Log log = LogFactory.getLog(FaceletHandlerHelper.class); 085 086 public static final String LAYOUT_ID_PREFIX = "nxl_"; 087 088 public static final String WIDGET_ID_PREFIX = "nxw_"; 089 090 public static final String MESSAGE_ID_SUFFIX = "_message"; 091 092 /** 093 * @since 6.0 094 */ 095 public static final String DEV_CONTAINER_ID_SUFFIX = "_dev_container"; 096 097 /** 098 * @since 6.0 099 */ 100 public static final String DEV_REGION_ID_SUFFIX = "_dev_region"; 101 102 /** 103 * @since 6.0 104 */ 105 public static String DEV_MODE_DISABLED_VARIABLE = "nuxeoLayoutDevModeDisabled"; 106 107 private static final Pattern UNIQUE_ID_STRIP_PATTERN = Pattern.compile("(.*)(_[0-9]+)"); 108 109 /** 110 * @since 5.7 111 */ 112 public static final String DIR_PROPERTY = "dir"; 113 114 /** 115 * @since 5.7 116 */ 117 public static final String DIR_AUTO = "auto"; 118 119 final TagConfig tagConfig; 120 121 public FaceletHandlerHelper(TagConfig tagConfig) { 122 this.tagConfig = tagConfig; 123 } 124 125 /** 126 * Returns a id unique within the facelet context. 127 */ 128 public String generateUniqueId(FaceletContext context) { 129 String id; 130 TagAttribute idAttr = tagConfig.getTag().getAttributes().get("id"); 131 if (idAttr != null) { 132 id = idAttr.getValue(context); 133 } else { 134 id = context.getFacesContext().getViewRoot().createUniqueId(); 135 } 136 return generateUniqueId(context, id); 137 } 138 139 /** 140 * Returns a id unique within the facelet context using given id as base. 141 */ 142 public static String generateUniqueId(FaceletContext context, String base) { 143 return generateUniqueId(context.getFacesContext(), base); 144 } 145 146 /** 147 * Returns a id unique within the faces context using given id as base. 148 * 149 * @since 8.1 150 */ 151 public static String generateUniqueId(FacesContext faces, String base) { 152 NuxeoLayoutIdManagerBean bean = lookupIdBean(faces); 153 return bean.generateUniqueId(base); 154 } 155 156 protected static NuxeoLayoutIdManagerBean lookupIdBean(FacesContext ctx) { 157 String expr = "#{" + NuxeoLayoutIdManagerBean.NAME + "}"; 158 NuxeoLayoutIdManagerBean bean = (NuxeoLayoutIdManagerBean) ctx.getApplication().evaluateExpressionGet(ctx, expr, 159 Object.class); 160 if (bean == null) { 161 throw new RuntimeException("Managed bean not found: " + expr); 162 } 163 return bean; 164 } 165 166 /** 167 * Strips given base of any ending counter that would conflict with potential already generated unique ids 168 * 169 * @since 5.7 170 */ 171 protected static String stripUniqueIdBase(String base) { 172 if (base != null) { 173 Matcher m = UNIQUE_ID_STRIP_PATTERN.matcher(base); 174 if (m.matches()) { 175 base = m.group(1); 176 return stripUniqueIdBase(base); 177 } 178 } 179 return base; 180 } 181 182 /** 183 * @throws IllegalArgumentException if the given string is null or empty. 184 */ 185 protected static String generateValidIdString(String base) { 186 if (base == null) { 187 throw new IllegalArgumentException(base); 188 } 189 int n = base.length(); 190 if (n < 1) { 191 throw new IllegalArgumentException(base); 192 } 193 return Functions.jsfTagIdEscape(base); 194 } 195 196 public static String generateWidgetId(FaceletContext context, String widgetName) { 197 return generateUniqueId(context, WIDGET_ID_PREFIX + widgetName); 198 } 199 200 public static String generateLayoutId(FaceletContext context, String layoutName) { 201 return generateUniqueId(context, LAYOUT_ID_PREFIX + layoutName); 202 } 203 204 public static String generateMessageId(FaceletContext context, String widgetName) { 205 return generateUniqueId(context, WIDGET_ID_PREFIX + widgetName + MESSAGE_ID_SUFFIX); 206 } 207 208 /** 209 * @since 6.0 210 */ 211 public static String generateDevRegionId(FaceletContext context, String widgetName) { 212 return generateUniqueId(context, WIDGET_ID_PREFIX + widgetName + DEV_REGION_ID_SUFFIX); 213 } 214 215 /** 216 * @since 6.0 217 */ 218 public static String generateDevContainerId(FaceletContext context, String widgetName) { 219 return generateUniqueId(context, WIDGET_ID_PREFIX + widgetName + DEV_CONTAINER_ID_SUFFIX); 220 } 221 222 /** 223 * Creates a unique id and returns corresponding attribute, using given string id as base. 224 */ 225 public TagAttribute createIdAttribute(FaceletContext context, String base) { 226 String value = generateUniqueId(context, base); 227 return new TagAttributeImpl(tagConfig.getTag().getLocation(), "", "id", "id", value); 228 } 229 230 /** 231 * Creates an attribute with given name and value. 232 * <p> 233 * The attribute namespace is assumed to be empty. 234 */ 235 public TagAttribute createAttribute(String name, String value) { 236 if (value == null || value instanceof String) { 237 return new TagAttributeImpl(tagConfig.getTag().getLocation(), "", name, name, value); 238 } 239 return null; 240 } 241 242 /** 243 * Returns true if a reference tag attribute should be created for given property value. 244 * <p> 245 * Reference tag attributes are using a non-literal EL expression so that this property value is not kept (cached) 246 * in the component on ajax refresh. 247 * <p> 248 * Of course property values already representing an expression cannot be mapped as is because they would need to be 249 * resolved twice. 250 * <p> 251 * Converters and validators cannot be referenced either because components expect corresponding value expressions 252 * to resolve to a {@link Converter} or {@link Validator} instance (instead of the converter of validator id). 253 */ 254 public boolean shouldCreateReferenceAttribute(String key, Serializable value) { 255 // FIXME: NXP-7004: make this configurable per widget type and mode or 256 // JSF component 257 if ((value instanceof String) 258 && (ComponentTagUtils.isValueReference((String) value) || "converter".equals(key) 259 || "validator".equals(key) 260 // size is mistaken for the properties map size because 261 // of jboss el resolvers 262 || "size".equals(key) 263 // richfaces calendar does not resolve EL expressions 264 // correctly 265 || "showApplyButton".equals(key) || "defaultTime".equals(key))) { 266 return false; 267 } 268 return true; 269 } 270 271 public static TagAttributes getTagAttributes(TagAttribute... attributes) { 272 if (attributes == null || attributes.length == 0) { 273 return new TagAttributesImpl(new TagAttribute[0]); 274 } 275 return new TagAttributesImpl(attributes); 276 } 277 278 public static TagAttributes getTagAttributes(List<TagAttribute> attributes) { 279 return getTagAttributes(attributes.toArray(new TagAttribute[0])); 280 } 281 282 public static TagAttributes addTagAttribute(TagAttributes orig, TagAttribute newAttr) { 283 if (orig == null) { 284 return new TagAttributesImpl(new TagAttribute[] { newAttr }); 285 } 286 List<TagAttribute> allAttrs = new ArrayList<TagAttribute>(Arrays.asList(orig.getAll())); 287 allAttrs.add(newAttr); 288 return getTagAttributes(allAttrs); 289 } 290 291 /** 292 * Copies tag attributes with given names from the tag config, using given id as base for the id attribute. 293 */ 294 public TagAttributes copyTagAttributes(FaceletContext context, String id, String... names) { 295 List<TagAttribute> list = new ArrayList<TagAttribute>(); 296 list.add(createIdAttribute(context, id)); 297 for (String name : names) { 298 if ("id".equals(name)) { 299 // ignore 300 continue; 301 } 302 TagAttribute attr = tagConfig.getTag().getAttributes().get(name); 303 if (attr != null) { 304 list.add(attr); 305 } 306 } 307 TagAttribute[] attrs = list.toArray(new TagAttribute[list.size()]); 308 return new TagAttributesImpl(attrs); 309 } 310 311 /** 312 * Creates tag attributes using given widget properties and field definitions. 313 * <p> 314 * Assumes the "value" attribute has to be computed from the first field definition, using the "value" expression 315 * (see widget type tag handler exposed values). 316 */ 317 public TagAttributes getTagAttributes(String id, Widget widget) { 318 // add id and value computed from fields 319 TagAttributes widgetAttrs = getTagAttributes(widget); 320 return addTagAttribute(widgetAttrs, createAttribute("id", id)); 321 } 322 323 public TagAttributes getTagAttributes(Widget widget) { 324 return getTagAttributes(widget, null, true); 325 } 326 327 /** 328 * @since 5.5 329 */ 330 public TagAttributes getTagAttributes(Widget widget, List<String> excludedProperties, 331 boolean bindFirstFieldDefinition) { 332 return getTagAttributes(widget, excludedProperties, bindFirstFieldDefinition, false); 333 } 334 335 /** 336 * Return tag attributes for this widget, including value mapping from field definitions and properties 337 * 338 * @since 5.6 339 * @param widget the widget to generate tag attributes for 340 * @param excludedProperties the properties to exclude from tag attributes 341 * @param bindFirstFieldDefinition if true, the first field definition will be bound to the tag attribute named 342 * "value" 343 * @param defaultToValue if true, and there are no field definitions, tag attribute named "value" will be mapped to 344 * the current widget value name (e.g the layout value in most cases, or the parent widget value if 345 * widget is a sub widget) 346 */ 347 public TagAttributes getTagAttributes(Widget widget, List<String> excludedProperties, 348 boolean bindFirstFieldDefinition, boolean defaultToValue) { 349 List<TagAttribute> attrs = new ArrayList<TagAttribute>(); 350 if (bindFirstFieldDefinition) { 351 FieldDefinition field = null; 352 FieldDefinition[] fields = widget.getFieldDefinitions(); 353 if (fields != null && fields.length > 0) { 354 field = fields[0]; 355 } 356 if (field != null || defaultToValue) { 357 // bind value to first field definition or current value name 358 TagAttribute valueAttr = createAttribute("value", 359 ValueExpressionHelper.createExpressionString(widget.getValueName(), field)); 360 attrs.add(valueAttr); 361 } 362 } 363 // fill with widget properties 364 List<TagAttribute> propertyAttrs = getTagAttributes(widget.getProperties(), excludedProperties, true, 365 widget.getType(), widget.getTypeCategory(), widget.getMode()); 366 if (propertyAttrs != null) { 367 attrs.addAll(propertyAttrs); 368 } 369 return getTagAttributes(attrs); 370 } 371 372 /** 373 * @since 5.5, signature changed on 5.6 to include parameters widgetType and widgetMode. 374 */ 375 public List<TagAttribute> getTagAttributes(Map<String, Serializable> properties, List<String> excludedProperties, 376 boolean useReferenceProperties, String widgetType, String widgetTypeCategory, String widgetMode) { 377 WebLayoutManager service = Framework.getService(WebLayoutManager.class); 378 List<TagAttribute> attrs = new ArrayList<TagAttribute>(); 379 if (properties != null) { 380 for (Map.Entry<String, Serializable> prop : properties.entrySet()) { 381 TagAttribute attr; 382 String key = prop.getKey(); 383 if (excludedProperties != null && excludedProperties.contains(key)) { 384 continue; 385 } 386 Serializable valueInstance = prop.getValue(); 387 if (!useReferenceProperties 388 || !service.referencePropertyAsExpression(key, valueInstance, widgetType, widgetTypeCategory, 389 widgetMode, null)) { 390 if (valueInstance == null || valueInstance instanceof String) { 391 // FIXME: this will not be updated correctly using ajax 392 attr = createAttribute(key, (String) valueInstance); 393 } else { 394 attr = createAttribute(key, valueInstance.toString()); 395 } 396 } else { 397 // create a reference so that it's a real expression 398 // and it's not kept (cached) in a component value on 399 // ajax refresh 400 attr = createAttribute(key, 401 "#{" + RenderVariables.widgetVariables.widget.name() + ".properties." + key + "}"); 402 } 403 attrs.add(attr); 404 } 405 } 406 return attrs; 407 } 408 409 /** 410 * @since 6.0 411 */ 412 public TagAttributes getTagAttributes(WidgetSelectOption selectOption, Map<String, Serializable> additionalProps) { 413 Map<String, Serializable> props = getSelectOptionProperties(selectOption); 414 if (additionalProps != null) { 415 props.putAll(additionalProps); 416 } 417 List<TagAttribute> attrs = getTagAttributes(props, null, false, null, null, null); 418 if (attrs == null) { 419 attrs = Collections.emptyList(); 420 } 421 return getTagAttributes(attrs); 422 } 423 424 public TagAttributes getTagAttributes(WidgetSelectOption selectOption) { 425 return getTagAttributes(selectOption, null); 426 } 427 428 public Map<String, Serializable> getSelectOptionProperties(WidgetSelectOption selectOption) { 429 Map<String, Serializable> map = new HashMap<String, Serializable>(); 430 if (selectOption != null) { 431 Serializable value = selectOption.getValue(); 432 if (value != null) { 433 map.put("value", value); 434 } 435 String var = selectOption.getVar(); 436 if (var != null) { 437 map.put("var", var); 438 } 439 String itemLabel = selectOption.getItemLabel(); 440 if (itemLabel != null) { 441 map.put("itemLabel", itemLabel); 442 } 443 String itemValue = selectOption.getItemValue(); 444 if (itemValue != null) { 445 map.put("itemValue", itemValue); 446 } 447 Serializable itemDisabled = selectOption.getItemDisabled(); 448 if (itemDisabled != null) { 449 map.put("itemDisabled", itemDisabled); 450 } 451 Serializable itemRendered = selectOption.getItemRendered(); 452 if (itemRendered != null) { 453 map.put("itemRendered", itemRendered); 454 } 455 if (selectOption instanceof WidgetSelectOptions) { 456 WidgetSelectOptions selectOptions = (WidgetSelectOptions) selectOption; 457 Boolean caseSensitive = selectOptions.getCaseSensitive(); 458 if (caseSensitive != null) { 459 map.put("caseSensitive", caseSensitive); 460 } 461 String ordering = selectOptions.getOrdering(); 462 if (ordering != null) { 463 map.put("ordering", ordering); 464 } 465 } 466 } 467 return map; 468 } 469 470 /** 471 * @deprecated since 5.4.2, use 472 * {@link FaceletHandlerHelper#getHtmlComponentHandler(String, TagAttributes, FaceletHandler, String, String)} 473 * instead. 474 */ 475 @Deprecated 476 public ComponentHandler getHtmlComponentHandler(TagAttributes attributes, FaceletHandler nextHandler, 477 String componentType, String rendererType) { 478 return getHtmlComponentHandler(null, attributes, nextHandler, componentType, rendererType); 479 } 480 481 /** 482 * Returns an html component handler for this configuration. 483 * <p> 484 * Next handler cannot be null, use {@link org.nuxeo.ecm.platform.ui.web.tag.handler.LeafFaceletHandler} if no next 485 * handler is needed. 486 */ 487 public ComponentHandler getHtmlComponentHandler(String tagConfigId, TagAttributes attributes, 488 FaceletHandler nextHandler, String componentType, String rendererType) { 489 ComponentConfig config = TagConfigFactory.createComponentConfig(tagConfig, tagConfigId, attributes, 490 nextHandler, componentType, rendererType); 491 return new GenericHtmlComponentHandler(config); 492 } 493 494 /** 495 * @deprecated since 5.4.2, use {@link FaceletHandlerHelper#getErrorComponentHandler(String, String)} instead. 496 */ 497 @Deprecated 498 public ComponentHandler getErrorComponentHandler(String errorMessage) { 499 return getErrorComponentHandler(null, errorMessage); 500 } 501 502 /** 503 * Component handler that displays an error on interface 504 */ 505 public ComponentHandler getErrorComponentHandler(String tagConfigId, String errorMessage) { 506 FaceletHandler leaf = new org.nuxeo.ecm.platform.ui.web.tag.handler.LeafFaceletHandler(); 507 TagAttribute valueAttr = createAttribute("value", 508 "<span style=\"color:red;font-weight:bold;\">ERROR: " + errorMessage + "</span><br />"); 509 TagAttribute escapeAttr = createAttribute("escape", "false"); 510 ComponentHandler output = getHtmlComponentHandler(tagConfigId, 511 FaceletHandlerHelper.getTagAttributes(valueAttr, escapeAttr), leaf, HtmlOutputText.COMPONENT_TYPE, null); 512 return output; 513 } 514 515 /** 516 * @deprecated since 5.4.2, use 517 * {@link FaceletHandlerHelper#getConvertHandler(String, TagAttributes, FaceletHandler, String)} 518 * instead. 519 */ 520 @Deprecated 521 public ConverterHandler getConvertHandler(TagAttributes attributes, FaceletHandler nextHandler, String converterId) { 522 return getConvertHandler(null, attributes, nextHandler, converterId); 523 } 524 525 /** 526 * Returns a convert handler for this configuration. 527 * <p> 528 * Next handler cannot be null, use {@link org.nuxeo.ecm.platform.ui.web.tag.handler.LeafFaceletHandler} if no next 529 * handler is needed. 530 */ 531 public ConverterHandler getConvertHandler(String tagConfigId, TagAttributes attributes, FaceletHandler nextHandler, 532 String converterId) { 533 ConverterConfig config = TagConfigFactory.createConverterConfig(tagConfig, tagConfigId, attributes, 534 nextHandler, converterId); 535 return new ConverterHandler(config); 536 } 537 538 /** 539 * @deprecated since 5.4.2, use 540 * {@link FaceletHandlerHelper#getValidateHandler(String, TagAttributes, FaceletHandler, String)} 541 * instead. 542 */ 543 @Deprecated 544 public ValidatorHandler getValidateHandler(TagAttributes attributes, FaceletHandler nextHandler, String validatorId) { 545 return getValidateHandler(null, attributes, nextHandler, validatorId); 546 } 547 548 /** 549 * Returns a validate handler for this configuration. 550 * <p> 551 * Next handler cannot be null, use {@link org.nuxeo.ecm.platform.ui.web.tag.handler.LeafFaceletHandler} if no next 552 * handler is needed. 553 */ 554 public ValidatorHandler getValidateHandler(String tagConfigId, TagAttributes attributes, 555 FaceletHandler nextHandler, String validatorId) { 556 ValidatorConfig config = TagConfigFactory.createValidatorConfig(tagConfig, tagConfigId, attributes, 557 nextHandler, validatorId); 558 return new ValidatorHandler(config); 559 } 560 561 /** 562 * @deprecated since 5.4.2, use 563 * {@link FaceletHandlerHelper#getMessageComponentHandler(String, String, String, String)} instead. 564 */ 565 @Deprecated 566 public ComponentHandler getMessageComponentHandler(String id, String forId, String styleClass) { 567 return getMessageComponentHandler(null, id, forId, styleClass); 568 } 569 570 /** 571 * Returns a message component handler with given attributes. 572 * <p> 573 * Uses component type "javax.faces.HtmlMessage" and renderer type "javax.faces.Message". 574 */ 575 public ComponentHandler getMessageComponentHandler(String tagConfigId, String id, String forId, String styleClass) { 576 TagAttribute forAttr = createAttribute("for", forId); 577 TagAttribute idAttr = createAttribute("id", id); 578 if (styleClass == null) { 579 // default style class 580 styleClass = "errorMessage"; 581 } 582 TagAttribute styleAttr = createAttribute("styleClass", styleClass); 583 TagAttributes attributes = getTagAttributes(forAttr, idAttr, styleAttr); 584 ComponentConfig config = TagConfigFactory.createComponentConfig(tagConfig, tagConfigId, attributes, 585 new org.nuxeo.ecm.platform.ui.web.tag.handler.LeafFaceletHandler(), HtmlMessage.COMPONENT_TYPE, null); 586 return new ComponentHandler(config); 587 } 588 589 /** 590 * @since 5.6 591 */ 592 public FaceletHandler getAliasFaceletHandler(String tagConfigId, Map<String, ValueExpression> variables, 593 List<String> blockedPatterns, FaceletHandler nextHandler) { 594 FaceletHandler currentHandler = nextHandler; 595 if (variables != null) { 596 currentHandler = getBareAliasTagHandler(tagConfigId, variables, blockedPatterns, nextHandler); 597 } 598 return currentHandler; 599 } 600 601 /** 602 * @since 8.1 603 */ 604 public TagHandler getAliasTagHandler(String tagConfigId, Map<String, ValueExpression> variables, 605 List<String> blockedPatterns, TagHandler nextHandler) { 606 TagHandler currentHandler = nextHandler; 607 if (variables != null) { 608 currentHandler = getBareAliasTagHandler(tagConfigId, variables, blockedPatterns, nextHandler); 609 } 610 return currentHandler; 611 } 612 613 protected TagHandler getBareAliasTagHandler(String tagConfigId, Map<String, ValueExpression> variables, 614 List<String> blockedPatterns, FaceletHandler nextHandler) { 615 // XXX also set id? cache? anchor? 616 ComponentConfig config = TagConfigFactory.createAliasTagConfig(tagConfig, tagConfigId, getTagAttributes(), 617 nextHandler); 618 AliasTagHandler alias = new AliasTagHandler(config, variables, blockedPatterns); 619 // NXP-18639: always wrap next alias handler in a component ref for tagConfigId to be taken into account and 620 // anchored in the view with this id. 621 ComponentConfig ref = TagConfigFactory.createComponentConfig(tagConfig, tagConfigId, getTagAttributes(), alias, 622 ComponentRef.COMPONENT_TYPE, null); 623 return new ComponentRefHandler(ref); 624 } 625 626 /** 627 * @since 6.0 628 */ 629 public static boolean isDevModeEnabled(FaceletContext ctx) { 630 // avoid stack overflow when using layout tags within the dev 631 // handler 632 if (Framework.isDevModeSet()) { 633 NuxeoLayoutManagerBean bean = lookupBean(ctx.getFacesContext()); 634 if (bean.isDevModeSet()) { 635 ExpressionFactory eFactory = ctx.getExpressionFactory(); 636 ValueExpression disableDevAttr = eFactory.createValueExpression(ctx, 637 "#{" + DEV_MODE_DISABLED_VARIABLE + "}", Boolean.class); 638 if (!Boolean.TRUE.equals(disableDevAttr.getValue(ctx))) { 639 return true; 640 } 641 } 642 } 643 return false; 644 } 645 646 protected static NuxeoLayoutManagerBean lookupBean(FacesContext ctx) { 647 String expr = "#{" + NuxeoLayoutManagerBean.NAME + "}"; 648 NuxeoLayoutManagerBean bean = (NuxeoLayoutManagerBean) ctx.getApplication().evaluateExpressionGet(ctx, expr, 649 Object.class); 650 if (bean == null) { 651 log.error("Managed bean not found: " + expr); 652 return null; 653 } 654 return bean; 655 } 656 657 /** 658 * @since 6.0 659 */ 660 public FaceletHandler getDisableDevModeTagHandler(String tagConfigId, FaceletHandler nextHandler) { 661 ComponentConfig config = TagConfigFactory.createAliasTagConfig(tagConfig, tagConfigId, 662 DEV_MODE_DISABLED_VARIABLE, "true", "true", "false", nextHandler); 663 return new SetTagHandler(config); 664 } 665}