AEM 6420 - Add Sort by Name, Type in Assets Card, List, Column views, set Default Sort to Name

Goal


In all 3 views (Card, List, Column) of Assets UI, set Default Sort by column to Name. Configure the Name and Type columns to be sortable in List View

Use sling.filter.scope=COMPONENT and the following regex for sling.filter.pattern to apply default name sort when browsing folders or bookmarked urls (eg. /assets.html/content/dam/experience-aem)
"^((\\/assets\\.html\\/content\\/dam)|(\\/mnt\\/overlay\\/dam\\/gui\\/content\\/assets\\/jcr:content\\/views\\/)).*$"

For Sites Console check this post

Demo | Source Code | Package Install | Github


Extension



List view Sort by Name




Solution


1) Login to CRXDe Lite, overlay the name and type nodes of /libs/dam/gui/content/commons/availablecolumns, set the property sortable=true

                                  /apps/dam/gui/content/commons/availablecolumns/name
                                  /apps/dam/gui/content/commons/availablecolumns/type

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
    jcr:primaryType="nt:unstructured">
    <name
        jcr:primaryType="nt:unstructured"
        jcr:title="Name"
        configurable="{Boolean}false"
        default="{Boolean}true"
        sortable="{Boolean}true"/>
    <type
        jcr:primaryType="nt:unstructured"
        jcr:title="Type"
        columnGroup="metadata"
        default="{Boolean}true"
        sortable="{Boolean}true"/>
</jcr:root>


2) Create a Sling Filter to intercept request URIs starting with /mnt/overlay/dam/gui/content/assets/jcr:content/views, set the sort property to name if sortName parameter is empty (overriding the default orderby=@jcr:created with orderby=nodename). NameSortSlingServletRequestWrapper, a sling request wrapper in the filter returns name if sortName parameter value is empty

package apps.experienceaem.assets;

import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import java.io.IOException;

@Component(
        metatype = true,
        description = "Experience AEM Request filter for AssetsDataSourceServlet",
        label = "EAEM Datasource Sort Filter")
@Service({Filter.class})
@Properties({
        @Property(name = "sling.filter.scope",value = {"REQUEST"},propertyPrivate = true),
        @Property(  name = "sling.filter.pattern",
                    value = {"/mnt/overlay/dam/gui/content/assets/jcr:content/views/.*"},
                    propertyPrivate = true),
        @Property(name = "service.ranking",intValue = {-99},propertyPrivate = true)})
public class EAEMAssetDataSourceFilter implements Filter {
    private static Logger log = LoggerFactory.getLogger(EAEMAssetDataSourceFilter.class);

    public static String SORT_NAME = "sortName";

    public static String SORT_NAME_NAME = "name";


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        SlingHttpServletRequest slingRequest = (SlingHttpServletRequest)request;

        String orderBy = slingRequest.getParameter(SORT_NAME);

        if(StringUtils.isNotEmpty(orderBy)){
            chain.doFilter(request, response);
            return;
        }

        SlingHttpServletRequest nameSortRequest = new NameSortSlingServletRequestWrapper(slingRequest);
        chain.doFilter(nameSortRequest, response);
    }

    @Override
    public void destroy() {
    }

    private class NameSortSlingServletRequestWrapper extends SlingHttpServletRequestWrapper {
        public NameSortSlingServletRequestWrapper(final SlingHttpServletRequest request) {
            super(request);
        }

        @Override
        public String getParameter(String paramName) {
            if(!EAEMAssetDataSourceFilter.SORT_NAME.equals(paramName)){
                return super.getParameter(paramName);
            }

            return EAEMAssetDataSourceFilter.SORT_NAME_NAME;
        }
    }
}

3) To sort by case ignored extend predicate com.day.cq.search.eval.NodenamePredicateEvaluator

import com.day.cq.search.Predicate;
import com.day.cq.search.eval.EvaluationContext;
import com.day.cq.search.eval.NodenamePredicateEvaluator;
import org.apache.jackrabbit.util.Text;
import org.osgi.service.component.annotations.Component;

import javax.jcr.query.Row;
import java.util.Comparator;

@Component(
        factory = "com.day.cq.search.eval.PredicateEvaluator/nodename"
)
public class IgnoreCasePedicateEvaluator extends NodenamePredicateEvaluator {

    /*public String[] getOrderByProperties(Predicate p, EvaluationContext context) {
        // com.day.cq.search.eval.XPath.getPropertyPath() converts fn:upper-case(@jcr:path) to @fn:upper-case_x0028__x0040_jcr:path_x0029_ 
        // making this piece unusable
  
        List<String> orderProps = new ArrayList<String>();

        orderProps.add("fn:upper-case(@jcr:path)");

        return orderProps.toArray(new String[0]);
    }*/

    public Comparator<Row> getOrderByComparator(Predicate predicate, final EvaluationContext context) {
        return new Comparator<Row>() {
            public int compare(Row r1, Row r2) {
                String path1 = context.getPath(r1);

                if(path1 == null) {
                    return 0;
                }

                String path2 = context.getPath(r2);

                if(path2 == null){
                    return 0;
                }

                return Text.getName(path1).compareToIgnoreCase(Text.getName(path2));
            }
        };
    }
}

1 comment: