AEM 6510 - Extend Asset Share Commons Date Filter to provide Relative Date Lower Bound Entry

Goal


Just a simple component extending Asset Share Commons Date Filterhttps://adobe-marketing-cloud.github.io/asset-share-commons/pages/search/date-range/

Provides a text box to enter query builder relativedaterange lowerBoundhttps://helpx.adobe.com/experience-manager/6-5/sites/developing/using/querybuilder-predicate-reference.html#relativedaterange

Demo | Package Install | Github


Configuration



Rendering



Solution


1) Create component dialog /apps/eaem-asset-share-date-filter/date-range/cq:dialog by extending the Asset Share Commons Date Filter dialog asset-share-commons/components/search/date-range and use render conditions granite:rendercondition to not display unnecessary tabs

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
    jcr:primaryType="nt:unstructured"
    jcr:title="Date Range Filter"
    sling:resourceType="cq/gui/components/authoring/dialog"
    extraClientlibs="[core.wcm.components.form.options.v1.editor,asset-share-commons.author.dialog]">
    <content
        granite:class="cmp-options--editor-v1"
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/coral/foundation/container">
        <items jcr:primaryType="nt:unstructured">
            <options
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"
                margin="{Boolean}true">
                <items jcr:primaryType="nt:unstructured">
                    <columns
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="granite/ui/components/coral/foundation/container">
                        <items jcr:primaryType="nt:unstructured">
                            <dialog
                                granite:class="foundation-layout-util-vmargin"
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/container">
                                <items jcr:primaryType="nt:unstructured">
                                    <tabs
                                        jcr:primaryType="nt:unstructured"
                                        sling:resourceType="granite/ui/components/coral/foundation/tabs"
                                        maxmized="{Boolean}true">
                                        <items jcr:primaryType="nt:unstructured">
                                            <tab1
                                                jcr:primaryType="nt:unstructured"
                                                jcr:title="Filter"
                                                sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"
                                                margin="{Boolean}true">
                                                <items jcr:primaryType="nt:unstructured">
                                                    <column
                                                        jcr:primaryType="nt:unstructured"
                                                        sling:resourceType="granite/ui/components/coral/foundation/container">
                                                        <items jcr:primaryType="nt:unstructured">
                                                            <title
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                                                fieldDescription="Legend to describe the role of the field."
                                                                fieldLabel="Title"
                                                                name="./jcr:title"
                                                                required="{Boolean}true"/>
                                                            <property
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:orderBefore="name"
                                                                sling:resourceType="granite/ui/components/coral/foundation/form/select"
                                                                fieldDescription="The name of the field, which is submitted with the form data."
                                                                fieldLabel="Date Property"
                                                                metadataFieldTypes="[datetime]"
                                                                name="./property"
                                                                required="{Boolean}true">
                                                                <datasource
                                                                    jcr:primaryType="nt:unstructured"
                                                                    sling:resourceType="asset-share-commons/data-sources/filterable-properties"/>
                                                            </property>
                                                            <expanded
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:orderBefore="name"
                                                                sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
                                                                fieldDescription="Select if the field set should start in an expanded state (not applicable for drop down)"
                                                                name="./expanded"
                                                                text="Start expanded"
                                                                value="true"/>
                                                            <date-types
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:resourceType="granite/ui/components/coral/foundation/form/hidden"/>
                                                        </items>
                                                    </column>
                                                </items>
                                            </tab1>
                                            <search-behavior-tab
                                                jcr:primaryType="nt:unstructured"
                                                sling:resourceType="granite/ui/components/coral/foundation/form/hidden">
                                                <granite:rendercondition
                                                    jcr:primaryType="nt:unstructured"
                                                    sling:resourceType="granite/ui/components/coral/foundation/renderconditions/simple"
                                                    expression="false"/>
                                            </search-behavior-tab>
                                        </items>
                                    </tabs>
                                </items>
                            </dialog>
                        </items>
                    </columns>
                </items>
            </options>
        </items>
    </content>
</jcr:root>


2) Create a use api class apps.experienceaem.assets.EAEMDatePredicate for reading the dialog data in HTL file

package apps.experienceaem.assets;

import com.adobe.aem.commons.assetshare.util.PredicateUtil;
import com.adobe.cq.sightly.WCMUsePojo;
import com.day.cq.search.eval.DateRangePredicateEvaluator;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EAEMDatePredicate extends WCMUsePojo {
    private static final Logger log = LoggerFactory.getLogger(EAEMDatePredicate.class);

    private static final String REQUEST_ATTR_FORM_ID_TRACKER = "asset-share-commons__form-id";
    private static final String COMPONENT_NAME_IN_PAGE = "date_range";
    private static final int INITIAL_GROUP_NUM = 99999;

    private ValueMap resourceProps;
    private String property;
    private int group;

    @Override
    public void activate() {
        Resource resource = getResource();

        resourceProps = ResourceUtil.getValueMap(resource);
        property = resourceProps.get("property", "");
        group = INITIAL_GROUP_NUM;

        String compName = COMPONENT_NAME_IN_PAGE + "_";
        String resName = resource.getName();

        if(resName.contains(compName)) {
            group = Integer.parseInt(resName.substring(resName.lastIndexOf("_") + 1));
        }
    }

    public boolean isReady() {
        return StringUtils.isNotEmpty(property);
    }

    public String getTitle() {
        return resourceProps.get("jcr:title", "");
    }

    public String getGroup() {
        return group + "_group";
    }

    public String getName() {
        return "relativedaterange";
    }

    public String getProperty() {
        return property;
    }

    public boolean isExpanded() {
        return Boolean.valueOf(resourceProps.get("expanded", "false"));
    }

    public String getFormId() {
        SlingHttpServletRequest request = getRequest();

        if (request.getAttribute(REQUEST_ATTR_FORM_ID_TRACKER) == null) {
            request.setAttribute(REQUEST_ATTR_FORM_ID_TRACKER, 1);
        }

        return REQUEST_ATTR_FORM_ID_TRACKER + "__" + String.valueOf(request.getAttribute(REQUEST_ATTR_FORM_ID_TRACKER));
    }

    public String getLowerBoundName() {
        return getName() + "." + DateRangePredicateEvaluator.LOWER_BOUND;
    }

    public String getInitialLowerBound() {
        return PredicateUtil.getParamFromQueryParams(getRequest(), getGroup() + "." + getLowerBoundName());
    }

    public String getId() {
        SlingHttpServletRequest request = getRequest();
        return "cmp-date-filter" + "_" + String.valueOf(request.getResource().getPath().hashCode());
    }
}

3) Create the component rendering HTL script /apps/eaem-asset-share-date-filter/date-range/date-range.html with the following code

<sly data-sly-use.predicate="apps.experienceaem.assets.EAEMDatePredicate"
     data-sly-use.placeholderTemplate="core/wcm/components/commons/v1/templates.html"
     data-sly-test.ready="${predicate.ready}">

    <input type="hidden"
           form="${predicate.formId}"
           name="${predicate.group}.${predicate.name}.property"
           value="${predicate.property}"
           data-asset-share-predicate-id="${predicate.id}"/>

    <div class="ui form">
        <div class="ui fluid styled accordion field">

            <div class="${predicate.expanded ? 'active' : ''} title right">
                <i class="dropdown icon"></i>
                ${predicate.title}
            </div>

            <div class="${predicate.expanded ? 'active' : ''} content field"
                 data-asset-share-id="${predicate.id}__fields">

                Units of time

                <span style="margin-left: 10px ;font-size: 12px">
                    e.g. <b>-2m</b> = past 2 minutes | <b>-3h</b> = past 3 hours | <b>-4d</b> = past 4 days | <b>-5M</b> = past 5 months | <b>-6y</b> = past 6 years
                </span>

                <div style="margin-top: 10px">
                    <input type="text" style="width: 60%"
                           value="${predicate.initialLowerBound}"
                           form="${predicate.formId}"
                           maxlength="9"
                           for="${predicate.id}"
                           name="${predicate.group}.${predicate.name}.lowerBound"/>
                </div>
            </div>

            <div class="active content field">
            </div>
        </div>
    </div>

</sly>
<sly data-sly-call="${placeholderTemplate.placeholder @ isEmpty=!ready}"></sly>


Relative Date Range Predicate Extension


The following predicate creates XPath expression for days in the past (assuming user enters only a number eg. 30 = -30d = 30 days in the past) 0 means today (logic calculates hours from 00:00)

package com.experienceaem.assets;

import com.day.cq.search.Predicate;
import com.day.cq.search.eval.EvaluationContext;
import com.day.cq.search.eval.RelativeDateRangePredicateEvaluator;
import org.apache.commons.lang3.StringUtils;
import org.osgi.service.component.annotations.Component;

import java.util.Calendar;

@Component(
        factory = "com.day.cq.search.eval.PredicateEvaluator/eaemrelativedaterange"
)
public class LowerBoundPredicateEvaluator extends RelativeDateRangePredicateEvaluator {
    public String getXPathExpression(Predicate predicate, EvaluationContext context) {
        String value = predicate.get("lowerBound");

        if(StringUtils.isEmpty((value))){
            return super.getXPathExpression(predicate, context);
        }

        value = value.trim();

        if(value.equals("0")){//for today, get hours from midnight
            Calendar rightNow = Calendar.getInstance();
            predicate.set("lowerBound", "-" + rightNow.get(Calendar.HOUR_OF_DAY) + "h");
        }else{
            predicate.set("lowerBound", "-" + value + "d");
        }

        return super.getXPathExpression(predicate, context);
    }

}


No comments:

Post a Comment