All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.granite.ui.components.ComponentHelper Maven / Gradle / Ivy

/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2013 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/
package com.adobe.granite.ui.components;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.jsp.PageContext;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.scripting.jsp.util.JspSlingHttpServletResponseWrapper;

import com.adobe.granite.ui.components.ds.DataSource;
import com.adobe.granite.ui.components.ds.EmptyDataSource;
import com.adobe.granite.ui.components.impl.BaseComponentHelper;
import com.adobe.granite.ui.components.impl.SlingIncludeObjectFactory;
import com.adobe.granite.ui.components.rendercondition.RenderCondition;
import com.adobe.granite.ui.components.rendercondition.RenderConditionHelper;
import com.adobe.granite.ui.components.rendercondition.SimpleRenderCondition;
import com.adobe.granite.xss.XSSAPI;
import com.day.cq.i18n.I18n;

/**
 * A convenient helper for development of Granite UI component.
 */
public class ComponentHelper {
    private static final String DEFAULT_LAYOUT_RT = "granite/ui/components/foundation/layouts/container";
    private final BaseComponentHelper base;
    private RenderConditionHelper renderConditionHelper;
    private SlingIncludeObjectFactory dataFetcher;

    public ComponentHelper(PageContext pageContext) {
        SlingBindings bindings = (SlingBindings) pageContext.getRequest().getAttribute(SlingBindings.class.getName());
        base = new BaseComponentHelper(bindings.getSling(), bindings.getRequest(), new JspSlingHttpServletResponseWrapper(pageContext));
    }

    /**
     * Returns I18n appropriate for the current page.
     * @return I18n appropriate for the current page
     */
    public I18n getI18n() {
        return base.getI18n();
    }

    /**
     * Returns XSSAPI based on the current request.
     * @return XSSAPI based on the current request
     */
    public XSSAPI getXss() {
        return base.getXss();
    }

    /**
     * Returns the config of current resource of the page.
     * @return the config of current resource of the page
     */
    public Config getConfig() {
        return base.getConfig();
    }

    /**
     * Returns the values that is applicable for the current page.
     * @return the values that is applicable for the current page
     */
    public Value getValue() {
        return base.getValue();
    }

    /**
     * Returns the ExpressionHelper appropriate for the current page.
     * @return the ExpressionHelper appropriate for the current page
     */
    public ExpressionHelper getExpressionHelper() {
        return base.getExpressionHelper();
    }

    /**
     * Returns the client state.
     * @return the client state
     */
    public State getState() {
        return base.getState();
    }

    private RenderConditionHelper getRenderConditionHelper() {
        if (renderConditionHelper == null) {
            renderConditionHelper = new RenderConditionHelper(base.getRequest(), base.getResponse());
        }
        return renderConditionHelper;
    }

    private SlingIncludeObjectFactory getSlingIncludeObjectFactory() {
        if (dataFetcher == null) {
            dataFetcher = new SlingIncludeObjectFactory(base.getRequest(), base.getResponse());
        }
        return dataFetcher;
    }

    /**
     * Consumes the current available tag for current page. If the request
     * doesn't have the tag applicable to the page, a new tag is created.
     * 

* There is a mechanism such that a tag can be passed to another page when * including that page. This method is intended as a way to consume the tag * passed by other page. Component developer can make use this method to get * the main tag of the component regardless if there is a tag passed by * other page or not. * * @return the tag * @see #include(Resource, Tag) * @see #include(Resource, String, Tag) */ public Tag consumeTag() { return base.consumeTag(); } /** * Consumes the current available layout resource for current page. This * method first attempts to return the layout resource from the options, * second it will attempt to return {@link Config#LAYOUT} child node, * otherwise null is returned. *

* This method is usually called by layout implementation to get the layout * resource that can be passed by the caller. * * @return the resource * @see #includeForLayout(Resource, Options) * @see #includeForLayout(Resource, Resource, Options) */ public Resource consumeLayoutResource() { Resource layout = getOptions().layoutResource(); return layout == null ? base.getRequest().getResource().getChild(Config.LAYOUT) : layout; } /** * The overload of {@link #populateCommonAttrs(AttrBuilder, Resource)} using the current request's resource as the source. * * @param attrs the attribute builder */ public void populateCommonAttrs(AttrBuilder attrs) { base.populateCommonAttrs(attrs); } /** * Populates the common attributes to the given {@link AttrBuilder}. * *

Currently the following common properties and nodes are read and processed from the given resource: * *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
NameTypeDescription
granite:idProperty: StringELThe id attribute.
granite:relProperty: StringELThe class attribute. This is used to indicate the semantic relationship of the component similar to rel attribute.
granite:classProperty: StringELThe class attribute.
granite:titleProperty: StringThe title attribute. This property is i18nable.
granite:hiddenProperty: BooleanThe hidden attribute.
granite:itemscopeProperty: BooleanThe itemscope attribute.
granite:itemtypeProperty: StringThe itemtype attribute.
granite:itempropProperty: StringThe itemprop attribute.
granite:dataNodeEach property of this node is converted into a data-* attribute. * If the property value is an instance of a String, it will be interpreted as StringEL. * The property having a prefixed name is ignored.
* * @param attrs The attribute builder to populate to * @param src The resource of the source of the config */ public void populateCommonAttrs(AttrBuilder attrs, Resource src) { base.populateCommonAttrs(attrs, src); } /** * Returns the options passed from another page. If no options is passed, * empty options is returned. *

* There is a mechanism such that options can be passed to another page when * including that page. * * @return the options passed from another page. if no options is passed, * empty options is returned. * @see #include(Resource, Options) * @see #include(Resource, String, Options) */ public Options getOptions() { com.adobe.granite.ui.components.Options baseOptions = base.getOptions(); if (Options.class.isAssignableFrom(baseOptions.getClass())) { return (Options)baseOptions; } return new Options().tag(baseOptions.tag()).rootField(baseOptions.rootField()); } /** * Returns the layout config of current resource of the page. This method is * setting the default resource type of the layout. * * @return the layout config of current resource of the page * @see LayoutBuilder#getResourceType() */ public LayoutBuilder getLayout() { return LayoutBuilder.from(consumeLayoutResource(), DEFAULT_LAYOUT_RT); } /** * Returns the associated resource type of current resource for the purpose rendering read only version. * First the granite:readOnlyResourceType property of the resource type of the current resource (the RT) is used. * Otherwise it is defaulted to readonly child resource of the RT. * * @return the associated resource type of current resource */ public String getReadOnlyResourceType() { return base.getReadOnlyResourceType(); } /** * Returns the associated resource type of the given content resource for the purpose rendering read only version. * First the granite:readOnlyResourceType property of the resource type of the content resource (the RT) is used. * Otherwise it is defaulted to readonly child resource of the RT. * * @param resource the resource * @return the associated resource type of the given content resource */ public String getReadOnlyResourceType(Resource resource) { return base.getReadOnlyResourceType(resource); } /** * Returns the datasource for items of the current resource. This is an * overload of {@link #getItemDataSource(Resource)} with resource is the * current request resource. * * @return the data source for items of the current resource * @throws ServletException in case there's a servlet error while fetching data * @throws IOException in case there's an i/o error while fetching data */ public DataSource getItemDataSource() throws ServletException, IOException { return base.getItemDataSource(); } /** * Returns the datasource for items of the given resource. * This method can be used to fetch the items that are specified literally * using {@link Config#ITEMS} subresource; or specified as datasource using {@link Config#DATASOURCE} subresource. * * If there is no {@link Config#ITEMS} or {@link Config#DATASOURCE} subresource, then {@link EmptyDataSource} is returned. * * In contrast with {@link #asDataSource(Resource, Resource)}, this method * looks for the datasource resource of the given resource. i.e. The given * resource is the parent of the items, not the datasource resource itself. * The given resource is also used as the context resource when calling * {@link #asDataSource(Resource, Resource)} internally. * * @param resource the resource * @return the data source for items of the given resource * @throws ServletException in case there's a servlet error while fetching data * @throws IOException in case there's an i/o error while fetching data */ public DataSource getItemDataSource(Resource resource) throws ServletException, IOException { return base.getItemDataSource(resource); } /** * Returns the datasource given its datasource resource. This method is an * overload of {@link #asDataSource(Resource, Resource)} with context is * null. * @param datasource the resource representing the datasource * @return the datasource given its datasource resource * @throws ServletException in case there's a servlet error while fetching data * @throws IOException in case there's an i/o error while fetching data */ public DataSource asDataSource(Resource datasource) throws ServletException, IOException { return base.asDataSource(datasource); } /** * Returns the datasource given its datasource resource. * * @param datasource The resource representing the datasource * @param context The context resource that is returned when calling * {@link SlingHttpServletRequest#getResource()} at the * datasource implementation. If this is null, the * given datasource is used. * @return null if the given datasource is null. * @throws ServletException in case there's a servlet error while fetching data * @throws IOException in case there's an i/o error while fetching data */ public DataSource asDataSource(Resource datasource, Resource context) throws ServletException, IOException { return base.asDataSource(datasource, context); } /** * Returns the render condition of the current resource. This method is an * overload of {@link #getRenderCondition(Resource)} using the current * resource. * * The render condition is specified by granite:rendercondition * or rendercondition subresource. * * Contrast this with {@link #getRenderCondition(Resource, boolean)}, where * only granite:rendercondition is checked. This method is * meant for backward compatibility; otherwise it is better to use * {@link #getRenderCondition(Resource, boolean)} for performance. Once the * transition is over, this method will have the same behaviour as * {@link #getRenderCondition(Resource, boolean)} with cache = * false. * * @return the render condition of the current resource * @throws ServletException * in case there's a servlet error * @throws IOException * in case there's an i/o error */ public RenderCondition getRenderCondition() throws ServletException, IOException { return getRenderCondition(base.getRequest().getResource()); } /** * Returns the render condition of the given resource. * * The render condition is specified by granite:rendercondition * or rendercondition subresource. * * Contrast this with {@link #getRenderCondition(Resource, boolean)}, where * only granite:rendercondition is checked. This method is * meant for backward compatibility; otherwise it is better to use * {@link #getRenderCondition(Resource, boolean)} for performance. Once the * transition is over, this method will have the same behaviour as * {@link #getRenderCondition(Resource, boolean)} with cache = * false. * * @param resource * the resource * @return the render condition of the given resource * @throws ServletException * in case there's a servlet error * @throws IOException * in case there's an i/o error */ public RenderCondition getRenderCondition(Resource resource) throws ServletException, IOException { RenderCondition rc = null; Resource condition = resource.getChild("granite:rendercondition"); if (condition == null) { condition = resource.getChild(Config.RENDERCONDITION); } if (condition != null) { String resourceType = getResourceType(condition, "granite/ui/components/foundation/renderconditions/simple"); rc = getSlingIncludeObjectFactory().get(condition, resourceType, RenderCondition.class); } if (rc == null) { rc = SimpleRenderCondition.TRUE; } return rc; } /** * Returns the render condition of the given resource. * * The render condition is specified by granite:rendercondition * subresource, unlike {@link #getRenderCondition(Resource)}. * * @param resource * The resource * @param cache * true to cache the result; Use it when checking * render condition of other resource (typically the item * resource) so that the render condition is only resolved once. * * @return The render condition of the given resource; never null. * * @throws ServletException * in case there's a servlet error * @throws IOException * in case there's an i/o error */ public RenderCondition getRenderCondition(Resource resource, boolean cache) throws ServletException, IOException { return getRenderConditionHelper().getRenderCondition(resource, cache); } /** * Returns the icon class(es) for the given icon string from the content property. * @param icon the icon string * @return the icon class(es) for the given icon string from the content property */ public String getIconClass(String icon) { // In the future we can make it pluggable using OSGi so that others can provide their own icons based on certain icon class pattern. if (icon == null) return null; if (!icon.startsWith("icon-")) return icon; return "coral-Icon--" + toCamel(icon.substring(5)); } private static String toCamel(String s) { String[] parts = s.split("-"); StringBuilder b = new StringBuilder(); b.append(parts[0]); for (int i = 1; i < parts.length; i++) { b.append(parts[i].substring(0, 1).toUpperCase()); b.append(parts[i].substring(1)); } return b.toString(); } private static String getResourceType(Resource resource) { return new Config(resource).get(ResourceResolver.PROPERTY_RESOURCE_TYPE, String.class); } private static String getResourceType(Resource resource, String defaultValue) { return new Config(resource).get(ResourceResolver.PROPERTY_RESOURCE_TYPE, defaultValue); } /** * Includes the given resource and passes the given tag to its renderer. * This method performs similarly to <sling:include resource="" />. * @param resource the resource to include * @param tag the tag * @throws ServletException in case there's a servlet error * @throws IOException in case there's an i/o error */ public void include(Resource resource, Tag tag) throws ServletException, IOException { include(resource, null, tag); } /** * Includes the given resource and passes the given options to its renderer. * This method performs similarly to <sling:include resource="" />. * @param resource the resource to include * @param options the options * @throws ServletException in case there's a servlet error * @throws IOException in case there's an i/o error */ public void include(Resource resource, Options options) throws ServletException, IOException { include(resource, null, options); } /** * Includes the given resource with the given resourceType and passes the * given tag to its renderer. This method performs similarly to * <sling:include resource="" resourceType="" />. * @param resource the resource to include * @param resourceType the resource type * @param tag the tag * @throws ServletException in case there's a servlet error * @throws IOException in case there's an i/o error */ public void include(Resource resource, String resourceType, Tag tag) throws ServletException, IOException { include(resource, resourceType, new Options().tag(tag)); } /** * Includes the given resource with the given resourceType and passes the * given options to its renderer. This method performs similarly to * <sling:include resource="" resourceType="" />. * @param resource the resource to include * @param resourceType the resource type * @param options the options * @throws ServletException in case there's a servlet error * @throws IOException in case there's an i/o error */ public void include(Resource resource, String resourceType, Options options) throws ServletException, IOException { include(resource, resourceType, null, options); } /** * Includes the given resource with the given resourceType and passes the * given options to its renderer. This method performs similarly to * <sling:include resource="" replaceSelectors="" resourceType="" />. * @param resource the resource to include * @param resourceType the resource type * @param selectors the selectors to be included as part of the request. * @param options the options * @throws ServletException in case there's a servlet error * @throws IOException in case there's an i/o error */ public void include(Resource resource, String resourceType, String selectors, Options options) throws ServletException, IOException { base.include(resource, resourceType, selectors, options); } /** * A convenient overload to * {@link #includeForLayout(Resource, Resource, Options)}, with * layoutResource as null. * @param resource the resource to include * @param options the options * @throws ServletException in case there's a servlet error * @throws IOException in case there's an i/o error */ public void includeForLayout(Resource resource, Options options) throws ServletException, IOException { includeForLayout(resource, null, options); } /** * Includes the given resource to be rendered by the given layoutResource. * This method is used by a component to delegate the rendering process to a * layout. *

* If layoutResource is not null, the * {@link Options#layoutResource(Resource)} is set. *

* This method will attempt to derive the resourceType to be passed to * {@link #include(Resource, String, Options)} based the following * priorities: *

    *
  1. layoutResource is not null, the resourceType is layoutResource's RT
  2. *
  3. layoutResource is null, the resourceType is {@link Config#LAYOUT} * child node's RT
  4. *
  5. the resourceType is default layout as a catch-all fallback
  6. *
* @param resource the resource to include * @param layoutResource the layout resource to render the given resource with * @param options the options * @throws ServletException in case there's a servlet error * @throws IOException in case there's an i/o error */ public void includeForLayout(Resource resource, Resource layoutResource, Options options) throws ServletException, IOException { String resourceType = null; if (layoutResource == null) { Resource r = resource.getChild(Config.LAYOUT); if (r != null) { resourceType = getResourceType(r); } } else { resourceType = getResourceType(layoutResource); options.layoutResource(layoutResource); } if (resourceType == null) { resourceType = DEFAULT_LAYOUT_RT; } include(resource, resourceType, options); } /** * Calls the given script and passes the given options to its renderer. This * method performs similarly to <sling:call script="" />. * @param script the script to be called * @param options the options * @throws ServletException in case there's a servlet error * @throws IOException in case there's an i/o error */ public void call(String script, Options options) throws ServletException, IOException { base.call(script, options); } /** * An options to be passed to the included resource's renderer. */ public static class Options extends com.adobe.granite.ui.components.Options { private Resource layout; /** * Creates a new instance. */ public Options() { } /** * Sets the tag. * @param tag the tag * @return the options */ @Override public Options tag(Tag tag) { super.tag(tag); return this; } /** * Sets true to make the renderer (the field) should render * itself as root field; false otherwise. *

* A root field is a field that acts in its own context, instead of as * part of a composite field. For example, sizing field consists of * weight and height fields. So sizing field is a composite field and * wants to leverage the existing number field for width and height. In * this case when sizing field is including ( * {@link ComponentHelper#include(Resource, Options)}) the number field, * it should set this option as false. *

* The field implementation is free to interpret the exact behaviour of * root/non-root field. Most likely scenario, the root field will handle * it own sizing state (e.g. inline-block/block state), while non root * field will not, where the parent composite field is managing it. * * @param flag the flag * @return this instance */ @Override public Options rootField(boolean flag) { super.rootField(flag); return this; } /** * Returns the layout resource. * @return the layout resource */ public Resource layoutResource() { return layout; } /** * Sets the layout resource. * @param r the layout resource to set * @return this instance */ public Options layoutResource(Resource r) { this.layout = r; return this; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy