AEM 6550 - Extend AEM Asset Picker Card View to select Image Smart Crops and Video Dynamic Renditions


AEM Asset Picker (http://localhost:4502/aem/assetpicker) out of the box does not show Dynamic Renditions for selecting them in third party applications (using iframe). This post is on extending the Asset Picker card view to show (and select) Video Renditions (encodes) and Image Smart Crops...

For showing dynamic renditions in column view check this post


Demo | Package Install | Github


Configure Image Profiles



Dynamic Renditions in Assets Details View



Extension - Dynamic Renditions in Asset Picker Browse



Extension - Dynamic Renditions in Asset Picker Search



Extension - JSON to Parent Window on Select



Solution

1) Login to CRXDE Lite (http://localhost:4502/crx/de), create folder /apps/eaem-asset-selector-card-show-dyn-renditions

2) Create the following nt:file /apps/eaem-asset-selector-card-show-dyn-renditions/smart-crop-renditions/smart-crop-renditions.jsp to return the smart crop renditions of an image as JSON

<%@include file="/libs/granite/ui/global.jsp"%>

<%@page session="false"
        import="java.util.Iterator,
                  org.apache.sling.commons.json.JSONObject,
                  com.adobe.granite.ui.components.Config,
                  com.adobe.granite.ui.components.Tag"%>
<%@ page import="com.adobe.granite.ui.components.ds.ValueMapResource" %>

<%
    Config cfg = cmp.getConfig();
    ValueMap dynVM = null;

    JSONObject dynRenditions = new JSONObject();
    Resource dynResource = null;

    response.setContentType("application/json");

    for (Iterator<Resource> items = cmp.getItemDataSource().iterator(); items.hasNext();) {
        JSONObject dynRendition = new JSONObject();

        dynResource = items.next();

        dynVM = dynResource.getValueMap();

        String name = String.valueOf(dynVM.get("breakpoint-name"));

        dynRendition.put("type", "IMAGE");
        dynRendition.put("name", name);
        dynRendition.put("image", dynVM.get("copyurl"));
        dynRendition.put("url", dynVM.get("copyurl"));

        dynRenditions.put(name, dynRendition);
    }

    dynRenditions.write(response.getWriter());
%>


3) Set the datasource for Image Smart Crops /apps/eaem-asset-selector-card-show-dyn-renditions/smart-crop-renditions/renditions/datasource@sling:resourceType = dam/gui/components/s7dam/smartcrop/datasource


4) Create the following nt:file /apps/eaem-asset-selector-card-show-dyn-renditions/video-dyn-renditions/video-dyn-renditions.jsp to return the encodes of a video as JSON

<%@include file="/libs/granite/ui/global.jsp"%>

<%@page session="false"
        import="java.util.Iterator,
                org.apache.sling.commons.json.JSONObject,
                com.adobe.granite.ui.components.Config,
                com.adobe.granite.ui.components.Tag"%>
<%@ page import="com.adobe.granite.ui.components.ds.ValueMapResource" %>
<%@ page import="org.apache.sling.api.SlingHttpServletRequest" %>
<%@ page import="com.day.cq.dam.api.Asset" %>
<%@ page import="com.day.cq.dam.api.renditions.DynamicMediaRenditionProvider" %>
<%@ page import="com.day.cq.dam.api.Rendition" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.List" %>
<%@ page import="org.apache.commons.lang3.StringUtils" %>

<%
    response.setContentType("application/json");

    SlingHttpServletRequest eaemSlingRequest = slingRequest;
    String contentPath = eaemSlingRequest.getRequestPathInfo().getSuffix();

    Resource currentResource = eaemSlingRequest.getResourceResolver().getResource(contentPath);
    Asset asset = (currentResource != null ? currentResource.adaptTo(Asset.class) : null);

    JSONObject dynRenditions = new JSONObject();

    if( (asset == null) || !(asset.getMimeType().startsWith("video/")) || (asset.getMetadata("dam:scene7ID") == null)) {
        dynRenditions.write(response.getWriter());
        return;
    }

    DynamicMediaRenditionProvider dmRendProvider = sling.getService(DynamicMediaRenditionProvider.class);
    String s7Domain = String.valueOf(asset.getMetadata("dam:scene7Domain"));
    String scene7FileAvs = String.valueOf(asset.getMetadata("dam:scene7FileAvs"));

    HashMap<String, Object> rules = new HashMap<>();
    rules.put("remote", true);
    rules.put("video", true);

    List<Rendition> dmRenditions = dmRendProvider.getRenditions(asset, rules);
    JSONObject dynRendition = new JSONObject();
    String image = null, avsName = scene7FileAvs.substring(scene7FileAvs.lastIndexOf("/") + 1);

    dynRendition.put("type", "VIDEO");
    dynRendition.put("url", getScene7Url(s7Domain, scene7FileAvs));
    dynRendition.put("image", getRendThumbnail(s7Domain, scene7FileAvs));
    dynRendition.put("name", avsName);

    dynRenditions.put(avsName, dynRendition);

    String previewUrl = null;

    for (Rendition dmRendition : dmRenditions) {
        dynRendition = new JSONObject();

        image = dmRendition.getPath();

        if(image.endsWith(".mp4")){
            image = image.substring(0, image.lastIndexOf(".mp4"));

            if(StringUtils.isEmpty(previewUrl)){
                previewUrl = getPreviewUrl(s7Domain, dmRendition.getPath());
                previewUrl = previewUrl.substring(0, previewUrl.lastIndexOf(".mp4"));
            }
        }

        dynRendition.put("type", "VIDEO");
        dynRendition.put("name", dmRendition.getName());
        dynRendition.put("image", getRendThumbnail(s7Domain, image));
        dynRendition.put("url", getScene7Url(s7Domain, dmRendition.getPath()));
        dynRendition.put("preview", previewUrl);

        dynRenditions.put(dmRendition.getName(), dynRendition);
    }

    ((JSONObject)dynRenditions.get(avsName)).put("preview", previewUrl);

    dynRenditions.write(response.getWriter());
%>

<%!
    private static String getScene7Url(String s7Domain, String rendPath){
        return s7Domain + "/s7viewers/html5/VideoViewer.html?asset=" + rendPath;
    }

    private static String getPreviewUrl(String s7Domain, String rendPath){
        return s7Domain + "/is/content/" + rendPath;
    }

    private static String getRendThumbnail(String s7Domain, String rendPath){
        return s7Domain + "/is/image/" + rendPath + "?fit=constrain,1&wid=200&hei=200";
    }
%>


5) Create node /apps/eaem-asset-selector-card-show-dyn-renditions/clientlib of type cq:ClientLibraryFolder, add String[] property categories with value [cq.gui.damadmin.assetselector], String[] property dependencies with value lodash.


6) Create file (nt:file) /apps/eaem-asset-selector-card-show-dyn-renditions/clientlib/js.txt, add

                        

                                            card-view-show-dyn-renditions.js


7) Create file (nt:file) /apps/eaem-asset-selector-card-show-dyn-renditions/clientlib/card-view-show-dyn-renditions.js, add the following code

(function($, $document){
    var CORAL_COLUMNVIEW_PREVIEW = "coral-columnview-preview",
        THUMB_PATH = "/_jcr_content/renditions/cq5dam.thumbnail.48.48.png",
        EAEM_DATA_ASSET_PATH = "data-eaem-asset-path",
        EAEM_RENDITION_DATA = "data-eaem-rendition",
        EAEM_RENDITION_FIELD = "eaem-rendition-name",
        EAEM_CARD_DYN_RENDS_BLOCK = ".eaem-card-dyn-rends-block",
        EAEM_CARD_ASSETS_BLOCK = ".eaem-card-assets-block",
        SEARCH_RESULTS_CONTAINER = "#granite-pickerdialog-search-result-content",
        EAEM_DONE_ACTION = "EAEM_DONE",
        FUI = $(window).adaptTo("foundation-ui"),
        BROWSE_CARDS_CONTAINER = ".foundation-layout-panel-content",
        GET_SMART_CROPS_URL = "/apps/eaem-asset-selector-card-show-dyn-renditions/smart-crop-renditions/renditions.html",
        GET_VIDEO_RENDS_URL = "/apps/eaem-asset-selector-card-show-dyn-renditions/video-dyn-renditions/renditions.html";

    $document.on("foundation-contentloaded", registerSelectListener);

    $document.on("foundation-selections-change", function(){
        if(!(isBrowseCardsView() || isSearchCardsView())){
            return;
        }

        FUI.wait();

        _.defer(handleCardViewSelections);
    });

    function registerSelectListener(){
        $document.off('click', '.asset-picker-done');

        $(document).on("click", ".asset-picker-done", function(e) {
            e.stopImmediatePropagation();
            exportAssetInfo(e);
        });
    }

    function exportAssetInfo(e){
        var message = {
            config: {
                action: EAEM_DONE_ACTION
            },
            data: []
        };

        var $selItem, selected;

        if(isSearchCardsView() || isBrowseCardsView()){
            $selItem = $(".eaem-card-dyn-rends-block coral-masonry-item.is-selected");

            if(_.isEmpty($selItem)){
                $selItem = $(".eaem-card-assets-block coral-masonry-item.is-selected");
            }
        }else{
            $selItem = $("coral-columnview-item.is-selected");
        }

        var renditionData = $selItem.attr(EAEM_RENDITION_DATA);

        if(!renditionData){
            let path = $selItem.attr("data-foundation-collection-item-id"),
                name = path.substring(path.lastIndexOf("/") + 1),
                type = $selItem.find("coral-card-context").html();

            selected = {
                type: type ? type.trim() : "",
                image: path,
                name: name,
                aemPath: path,
                url : ""
            }
        }else{
            selected = JSON.parse(renditionData);
            selected["aemPath"] = $selItem.data("eaemAssetPath");
        }

        message.data.push(selected);

        console.log(message);

        getParent().postMessage(JSON.stringify(message), $(".assetselector-content-container").data("targetorigin"));

        if(isBrowseCardsView()){
            $("coral-masonry-item.is-selected").removeClass("is-selected");
        }
    }

    function handleCardViewSelections(){
        var $selItem = $("coral-masonry-item.is-selected");

        if(_.isEmpty($selItem)){
            hideDynRenditionsContainer();
            return;
        }

        $(".asset-picker-done")[0].disabled = false;

        var $dynRendsContainer;

        if(isSearchCardsView()){
            $dynRendsContainer = $(SEARCH_RESULTS_CONTAINER).find(EAEM_CARD_DYN_RENDS_BLOCK);
        }else if(isBrowseCardsView()){
            $dynRendsContainer = $(BROWSE_CARDS_CONTAINER).find(EAEM_CARD_DYN_RENDS_BLOCK);
        }

        if(_.isEmpty($dynRendsContainer)){
            $dynRendsContainer = createCardRenditionsContainer();
        }else{
            if(isBrowseCardsView()){
                showDynRenditionsContainer();
            }
        }

        var assetType = $selItem.find("coral-card-context").html(),
            rendsUrl = isImage(assetType) ? GET_SMART_CROPS_URL : GET_VIDEO_RENDS_URL,
            assetPath = $selItem.attr("data-granite-collection-item-id");

        if(!assetPath){
            FUI.clearWait();
            hideDynRenditionsContainer();
            return;
        }

        rendsUrl = rendsUrl + assetPath;

        $.ajax( { url: rendsUrl, async: false } ).done(function(data){
            var html = '<coral-masonry>';

            _.each(data, function(dynRendition, dynName){
                html = html + getCardDynamicRenditionHtml(dynRendition, assetPath);
            });

            html = html + '</coral-masonry>';

            $dynRendsContainer.html(html);

            _.defer(handCardDynRendSelection);

            FUI.clearWait();
        });
    }

    function getCardDynamicRenditionHtml(dynRendition, assetPath) {
        return  '<coral-masonry-item data-foundation-collection-item-id="' + dynRendition.image + '" ' + EAEM_DATA_ASSET_PATH + '="' + assetPath
                        + '" ' + EAEM_RENDITION_DATA + '="' + JSON.stringify(dynRendition).replace(/\"/g, """) + '">' +
                    '<coral-card>' +
                        '<coral-card-asset>' +
                            '<img src="' + dynRendition.image + '">' +
                        '</coral-card-asset>' +
                        '<coral-card-content>' +
                            '<coral-card-context>Dynamic Rendition</coral-card-context>' +
                            '<coral-card-title>' + dynRendition.name + '</coral-card-title>' +
                        '</coral-card-content>' +
                    '</coral-card>' +
                '</coral-masonry-item>' ;
    }

    function showDynRenditionsContainer(){
        $(EAEM_CARD_DYN_RENDS_BLOCK).show();

        $(EAEM_CARD_ASSETS_BLOCK).css("width", "85%");
    }

    function hideDynRenditionsContainer(){
        FUI.clearWait();

        $(EAEM_CARD_DYN_RENDS_BLOCK).hide();

        $(EAEM_CARD_ASSETS_BLOCK).css("width", "100%");
    }

    function handCardDynRendSelection(){
        var $dynRends = $(".eaem-card-dyn-rends-block").find("coral-masonry-item");

        $dynRends.click(function(){
            var $dynRend = $(this);

            $dynRends.removeClass("is-selected");

            $dynRend.addClass("is-selected");
        })
    }

    function createCardRenditionsContainer(){
        var $container = isSearchCardsView() ? $(SEARCH_RESULTS_CONTAINER) : $(BROWSE_CARDS_CONTAINER);

        $container.wrapInner("<div style='display:block'><div class='eaem-card-assets-block'></div></div>");

        return $("<div class='eaem-card-dyn-rends-block'></div>").appendTo($container.children("div"));
    }

    function isBrowseCardsView(){
        return ( ($(".foundation-layout-panel-content coral-masonry").length > 0)
        && !($(".foundation-layout-panel-content")[0].hasAttribute("hidden")));
    }

    function isSearchCardsView() {
        return ($(SEARCH_RESULTS_CONTAINER).length > 0);
    }

    function isImage(typeValue){
        if(!typeValue){
            return false;
        }

        return (typeValue.trim() == "IMAGE");
    }

    function isVideo(typeValue){
        if(!typeValue){
            return false;
        }
        return (typeValue.trim() == "MULTIMEDIA");
    }

    function getParent() {
        if (window.opener) {
            return window.opener;
        }
        return parent;
    }
}(jQuery, jQuery(document)));

No comments:

Post a Comment