Goal
Touch UI pathbrowser widget of AEM - /libs/granite/ui/components/foundation/form/pathbrowser is based on paths, showing the results of path selector - .pages.json; this post is on extending ootb pathbrowser and creating a new search based pathbrowser
For demo purposes, the linkURL property - /libs/foundation/components/image/cq:dialog/content/items/column/items/linkURL, of foundation image component dialog was modified to use search based pathbrowser
Demo | Package Install
Widget and Query Parameters
sling:resourceType - String - /apps/eaem-touchui-search-pathbrowser/search-pathbrowser
queryParameters - String[] - jcr:content/cq:template=/apps/geometrixx/templates/contentpage
jcr:content/cq:lastModifiedBy=admin
Inline Dialog
Full Screen Dialog
Solution
1) Login to CRXDE Lite and create folder /apps/eaem-touchui-search-pathbrowser
2) Create sling:Folder /apps/eaem-touchui-search-pathbrowser/search-pathbrowser for adding the widger renderer jsp
3) Add the widget renderer jsp /apps/eaem-touchui-search-pathbrowser/search-pathbrowser/search-pathbrowser.jsp with the following code extending /libs/granite/ui/components/foundation/form/pathbrowser
<%@ page import="com.adobe.granite.ui.components.Config" %> <%@include file="/libs/granite/ui/global.jsp" %> <% Config mCfg = cmp.getConfig(); String SEARCH_PATHBROWSER_WRAPPER_ID = "eaem-search-pathbrowser-wrapper-" + mCfg.get("name", String.class).substring(2); String EAEM_PREFIX = "eaem.granite.ui.search.pathBrowser"; %> <div id="<%=SEARCH_PATHBROWSER_WRAPPER_ID%>"> <%--include ootb pathbrowser--%> <sling:include resourceType="/libs/granite/ui/components/foundation/form/pathbrowser"/> </div> <script> (function($){ var wrapper = $("#<%=SEARCH_PATHBROWSER_WRAPPER_ID%>"), pathBrowser = wrapper.find("[data-init='pathbrowser']"); if(_.isEmpty(pathBrowser)){ console.log("EAEM - search path browser wrapper not found"); return; } //set the search based pathbrowser loaders and renderers defined in search-based-pathbrowser.js pathBrowser.attr("data-autocomplete-callback", "<%=EAEM_PREFIX%>" + ".autocompletecallback"); pathBrowser.attr("data-option-loader", "<%=EAEM_PREFIX%>" + ".optionLoader"); pathBrowser.attr("data-option-renderer", "<%=EAEM_PREFIX%>" + ".optionRenderer"); }(jQuery)); </script>
4) Create a clientlib /apps/eaem-touchui-search-pathbrowser/clientlib with categories cq.authoring.dialog and dependencies underscore
5) Add file /apps/eaem-touchui-search-pathbrowser/clientlib/js.txt with the following content
search-based-pathbrowser.js
6) Add file /apps/eaem-touchui-search-pathbrowser/clientlib/search-based-pathbrowser.js for adding the necessary autocomplete callback, option loader and option renderer used by the widget, with following code
(function(){ var EAEM_PREFIX = "eaem.granite.ui.search.pathBrowser", ROOT_PATH = "rootPath", QUERY_PARAMS = "queryparameters", // somehow queryParameters is read as queryparameters QUERY = "/bin/querybuilder.json?"; //executed when user initiates search in pathbrowser by typing in a keyword function searchBasedAutocompleteCallback(){ return{ name: EAEM_PREFIX + '.autocompletecallback', handler: autoCompleteHandler }; function autoCompleteHandler(searchTerm){ var self = this, deferred = $.Deferred(); if(_.isEmpty(searchTerm)){ return; } var searchParams = getSearchParameters(self, searchTerm); self.optionLoader(searchParams, callback); function callback(results){ if(_.isEmpty(results)){ deferred.resolve([]); return; } self.options.options = results; deferred.resolve(_.range(results.length)); } return deferred.promise(); } function getSearchParameters(widget,searchTerm){ var searchParams = { fulltext: searchTerm }; var path = widget.$element.data(ROOT_PATH), tokens, queryParams = widget.$element.data(QUERY_PARAMS); if(!_.isEmpty(path)){ searchParams.path = path; } if(!_.isEmpty(queryParams)){ queryParams = queryParams.split(" "); _.each(queryParams, function(param, index){ tokens = param.split("="); searchParams[ (index + 1) + "_property" ] = tokens[0]; searchParams[ (index + 1) + "_property.value" ] = tokens[1]; }) } return searchParams; } } CUI.PathBrowser.register('autocompleteCallback', searchBasedAutocompleteCallback()); //the option loader for requesting query results function searchBasedOptionLoader() { return { name: EAEM_PREFIX + ".optionLoader", handler: optionLoaderHandler }; function optionLoaderHandler(searchParams, callback) { var query = QUERY; _.each(searchParams, function(value, key){ query = query + key + "=" + value + "&"; }); query = query.substring(0, query.length - 1); console.log("EAEM - Search query - " + query); $.get(query).done(handler); function handler(data){ var results = []; if(!_.isEmpty(data.hits)){ results = _.pluck(data.hits, "path"); } if (callback){ callback(results); } } return false; } } CUI.PathBrowser.register('optionLoader', searchBasedOptionLoader()); //option renderer for creating the option html function searchBasedOptionRenderer() { return { name: EAEM_PREFIX + ".optionRenderer", handler: optionRendererHandler }; function optionRendererHandler(iterator, index) { var value = this.options.options[index]; return $('<li class="coral-SelectList-item coral-SelectList-item--option" data-value="' + value + '">' + value + '</li>'); } } CUI.PathBrowser.register('optionRenderer', searchBasedOptionRenderer()); }());
Hi Sreekanth,
ReplyDeleteI have seen many of your articles and its very good that mainly on customization in AEM. But I am not understanding the exact code logic how it written.
May I know, if any document or anything else, that I can learn.
Thanks,
Ratna.
I tried to use but it was only finding if full word....I built in *searchterm* so it will find contains. Makes it work better.
ReplyDelete