AEM 61 - Touch UI Filtering Pages by Template in Asset Finder

Goal


Asset Finder in Touch UI is Content Finder of Classic UI. In AEM 61 ( not 60 ) we can search for pages in Asset Finder. In this extension we provide additional filtering of pages by providing Search by Template (Granite/TouchUI/Coral UI sample Select)

Demo | Source Code | Package Install

A similar extension for Classic UI is here



Solution


1) We need a servlet to return templates as json. So code one and install as OSGI bundle

package apps.experienceaem.pagefilters;

import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.commons.json.io.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Session;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.servlet.ServletException;
import java.io.IOException;

@SlingServlet(
        paths="/bin/experience-aem/touch-ui/page-filters/templates",
        methods = "GET",
        metatype = false,
        label = "Get Templates Servlet"
)
public class GetTemplates extends SlingAllMethodsServlet {
    private static final Logger log = LoggerFactory.getLogger(GetTemplates.class);

    @Override
    protected void doGet(final SlingHttpServletRequest request, final SlingHttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");

        JSONWriter jw = new JSONWriter(response.getWriter());

        try{
            ResourceResolver resolver = request.getResourceResolver();
            Session session = resolver.adaptTo(Session.class);
            QueryManager qm = session.getWorkspace().getQueryManager();

            String stmt = "//element(*,cq:Template)[jcr:like(@jcr:path, '/apps/%')] order by @jcr:title";

            Query q = qm.createQuery(stmt, Query.XPATH);

            NodeIterator results = q.execute().getNodes();
            Node node = null, tNode = null; String path = null;

            jw.array();

            while(results.hasNext()){
                node = results.nextNode();
                path = node.getProperty("jcr:content/sling:resourceType").getString();

                if(path.startsWith("/apps/")){
                    path = path.substring(6);//remove /apps/
                }

                jw.object();
                jw.key("id").value(path);
                jw.key("name").value(node.getProperty("jcr:title").getString());
                jw.endObject();
            }

            jw.endArray();
        }catch(Exception e){
            log.error("Error getting templates",e);
            throw new ServletException(e);
        }
    }
}

2) JS logic for showing templates is added using Clientlibs. Login to CRXDE Lite (http://localhost:4502/crx/de) and create folder /apps/touch-ui-page-filters

2) Create node /apps/touch-ui-page-filters/clientlib of type cq:ClientLibraryFolder and add a String property categories with value cq.authoring.editor.hook.assetfinder and String property dependencies with value cq.jquery.ui

3) Create file (nt:file) /apps/touch-ui-page-filters/clientlib/js.txt and add

                       page-filters.js

4) Create file (nt:file) /apps/touch-ui-page-filters/clientlib/page-filters.js and add the following code

(function (document, $, assetFinder) {
    var TEMPLATE_SELECT_ID = "experience-aem-filter-template";
    var c$templateSelect = null;

    //id assetfinder-filter and class .assetfilter.type are defined in
    ///libs/wcm/core/content/editor/jcr:content/sidepanels/edit/items/assetsTab/items/filterPanel/items/views/items/search/items/searchpanel
    var $assetFinderFilter = $('#assetfinder-filter');
    var $assetFinderType = $assetFinderFilter.find(".assetfilter.type");

    var addTemplateSelect = function () {
        var templateMarkup = '<span class="coral-Select" data-init="select" id="' + TEMPLATE_SELECT_ID + '">' +
            '<button type="button" class="coral-Select-button coral-MinimalButton">' +
            '<span class="coral-Select-button-text">Select</span>' +
            '</button>' +
            '<select class="coral-Select-select">' +
            '<option value="ALL">Of All Templates</option>' +
            '</select>' +
            '</span>';

        var $optionTemplate = $('<script type="text/x-jquery-tmpl">' +
                                    '<option value="${id}">${name}</option>' +
                                '</script>').appendTo($assetFinderType);

        var promise = $.ajax({
            type: 'GET',
            url: "/bin/experience-aem/touch-ui/page-filters/templates"
        });

        promise.done(function (data) {
            $("<div/>").appendTo($assetFinderType).append($(templateMarkup));

            $optionTemplate.tmpl(data).appendTo("#" + TEMPLATE_SELECT_ID + " .coral-Select-select");

            c$templateSelect = new CUI.Select({
                element: "#" + TEMPLATE_SELECT_ID,
                visible: true
            });

            c$templateSelect.hide();
        });

        promise.fail(function(){
            alert("error");
        });

        $assetFinderType.find("select").on('change', function (event) {
            var type = $(event.target).find("option:selected").val();

            if (type == "Pages") {
                c$templateSelect.show();
            }else{
                c$templateSelect.hide();
            }
        });
    };

    var pagesController = assetFinder.registry["Pages"];
    var loadAssets = pagesController.loadAssets;

    $.extend(pagesController, {
        loadAssets: function(query, lowerLimit, upperLimit){
            var template = c$templateSelect.getValue();

            if(template && ( template != "ALL")){
                query = '"jcr:content/sling:resourceType":"' + template + '" ' + query;
            }

            return loadAssets.call(this, query, lowerLimit, upperLimit);
        }
    });

    addTemplateSelect();
}(document, jQuery, Granite.author.ui.assetFinder));

5) In the above logic #32 we use JQuery templates to fill options in Select

$optionTemplate.tmpl(data).appendTo("#" + TEMPLATE_SELECT_ID + " .coral-Select-select");


6) The following logic #34 creates Touch UI Select Widget

c$templateSelect = new CUI.Select({
                element: "#" + TEMPLATE_SELECT_ID,
                visible: true
            });


1 comment:

  1. This comment has been removed by a blog administrator.

    ReplyDelete