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