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