AEM 62 - Sample 3 Step Wizard Selecting Assets in Column View

Goal


A sample 3 step wizard for selecting assets from different folders, provide additional information in steps and submit for project specific processing; useful for creating custom screens the AEM way

For selecting assets using list view check this post

Demo | Package Install | Git Hub


Wizardhttp://localhost:4502/apps/eaem-wizard-select-assets-column-view/eaem-3-step-wizard.html



Structure in CRX




Solution


1) Login to CRXDE Lite - http://localhost:4502/crx/de/index.jsp and create nt:folder /apps/eaem-wizard-select-assets-column-view

2) Create /apps/eaem-wizard-select-assets-column-view/eaem-3-step-wizard of type cq:Page with the following content

<?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="cq:Page">
    <jcr:content
        jcr:mixinTypes="[sling:VanityPath]"
        jcr:primaryType="nt:unstructured"
        jcr:title="EAEM 3 Step Wizard"
        sling:resourceType="/apps/eaem-wizard-select-assets-column-view/page">
        <head jcr:primaryType="nt:unstructured">
            <viewport
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/admin/page/viewport"/>
            <favicon
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/page/favicon"/>
            <clientlibs
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/includeclientlibs"
                categories="[coralui3,granite.ui.coral.foundation,eaem.wizard]"/>
        </head>
        <body
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/coral/foundation/page/body">
            <items jcr:primaryType="nt:unstructured">
                <form
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="granite/ui/components/coral/foundation/form"
                    action="/apps/eaem-wizard-select-assets-column-view/eaem-3-step-wizard/jcr:content"
                    foundationForm="{Boolean}true"
                    maximized="{Boolean}true"
                    method="post"
                    novalidate="{Boolean}true"
                    style="vertical">
                    <successresponse
                        jcr:primaryType="nt:unstructured"
                        jcr:title="Success"
                        sling:resourceType="granite/ui/components/coral/foundation/form/responses/openprompt"
                        open="/apps/eaem-wizard-select-assets-column-view/eaem-3-step-wizard.html"
                        redirect="/apps/eaem-wizard-select-assets-column-view/eaem-3-step-wizard.html"
                        text="Your data was submitted"/>
                    <items jcr:primaryType="nt:unstructured">
                        <charset
                            jcr:primaryType="nt:unstructured"
                            sling:resourceType="granite/ui/components/coral/foundation/form/hidden"
                            name="_charset_"
                            value="utf-8"/>
                        <wizard
                            jcr:primaryType="nt:unstructured"
                            jcr:title="Experience AEM 3 Step Wizard"
                            sling:resourceType="granite/ui/components/coral/foundation/wizard">
                            <items jcr:primaryType="nt:unstructured">
                                <step1
                                    jcr:primaryType="nt:unstructured"
                                    jcr:title="Select Folder"
                                    sling:resourceType="granite/ui/components/coral/foundation/container">
                                    <items jcr:primaryType="nt:unstructured">
                                        <title
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/foundation/section">
                                            <layout
                                                jcr:primaryType="nt:unstructured"
                                                sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"
                                                margin="{Boolean}false"/>
                                            <items jcr:primaryType="nt:unstructured">
                                                <column
                                                    jcr:primaryType="nt:unstructured"
                                                    sling:resourceType="granite/ui/components/foundation/container">
                                                    <items jcr:primaryType="nt:unstructured">
                                                        <assetsPath
                                                            jcr:primaryType="nt:unstructured"
                                                            sling:resourceType="granite/ui/components/foundation/form/pathbrowser"
                                                            fieldLabel="Assets Path"
                                                            name="eaemAssetsPath"
                                                            rootPath="/content/dam"/>
                                                    </items>
                                                </column>
                                            </items>
                                        </title>
                                    </items>
                                    <parentConfig jcr:primaryType="nt:unstructured">
                                        <next
                                            granite:class="foundation-wizard-control"
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/button"
                                            text="Next"
                                            variant="primary">
                                            <granite:data
                                                jcr:primaryType="nt:unstructured"
                                                foundation-wizard-control-action="next"/>
                                        </next>
                                    </parentConfig>
                                </step1>
                                <step2
                                    jcr:primaryType="nt:unstructured"
                                    jcr:title="Column View"
                                    sling:resourceType="granite/ui/components/coral/foundation/container">
                                    <items jcr:primaryType="nt:unstructured">
                                        <column
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/include"
                                            path="/libs/dam/gui/content/assets/jcr:content/views/column"/>
                                    </items>
                                    <parentConfig jcr:primaryType="nt:unstructured">
                                        <next
                                            granite:class="foundation-wizard-control"
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/button"
                                            text="Next"
                                            variant="primary">
                                            <granite:data
                                                jcr:primaryType="nt:unstructured"
                                                foundation-wizard-control-action="next"/>
                                        </next>
                                    </parentConfig>
                                </step2>
                                <step3
                                    jcr:primaryType="nt:unstructured"
                                    jcr:title="Additional Info"
                                    sling:resourceType="granite/ui/components/coral/foundation/container">
                                    <items jcr:primaryType="nt:unstructured">
                                        <footer
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/foundation/section">
                                            <layout
                                                jcr:primaryType="nt:unstructured"
                                                sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"
                                                margin="{Boolean}false"/>
                                            <items jcr:primaryType="nt:unstructured">
                                                <column
                                                    jcr:primaryType="nt:unstructured"
                                                    sling:resourceType="granite/ui/components/foundation/container">
                                                    <items jcr:primaryType="nt:unstructured">
                                                        <text
                                                            jcr:primaryType="nt:unstructured"
                                                            sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
                                                            fieldLabel="Text"
                                                            name="eaemText"/>
                                                    </items>
                                                </column>
                                            </items>
                                        </footer>
                                    </items>
                                    <parentConfig jcr:primaryType="nt:unstructured">
                                        <next
                                            granite:class="foundation-wizard-control"
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/button"
                                            text="GO"
                                            type="submit"
                                            variant="primary">
                                            <granite:data
                                                jcr:primaryType="nt:unstructured"
                                                foundation-wizard-control-action="next"/>
                                        </next>
                                    </parentConfig>
                                </step3>
                            </items>
                            <granite:data
                                jcr:primaryType="nt:unstructured"
                                suffix="${requestPathInfo.suffix}"/>
                        </wizard>
                    </items>
                </form>
            </items>
        </body>
    </jcr:content>
</jcr:root>

3) The extension clientlib #19, for page created above - eaem.wizard is added in next steps

4) #69, in step 1, select the folder path from where assets are to be picked by default



5) #98, in step 2, provide a column view of the assets in folder selected in step 1; column view here includes otb column view from Assets Console http://localhost:4502/assets.html/content/dam -  /libs/dam/gui/content/assets/jcr:content/views/column and extends it to provide the Selected Files section



6)  #133, in step 3, provide a text area widget for entering additional information



7) #28 has the wizard form action /apps/eaem-wizard-select-assets-column-view/eaem-3-step-wizard/jcr:content of sling:resourceType /apps/eaem-wizard-select-assets-column-view/page

8) Create /apps/eaem-wizard-select-assets-column-view/page with the following content

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="sling:Folder"
    sling:resourceSuperType="granite/ui/components/coral/foundation/page"/>

9) Create nt:file /apps/eaem-wizard-select-assets-column-view/page/POST.jsp with the necessary logic to process selected assets...

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

<%
    String eaemSelectedAssets = request.getParameter("eaemSelectedAssets");
    String eaemText = request.getParameter("eaemText");

    log.info("eaemText-------" + eaemText);
    log.info("eaemSelectedAssets-------" + eaemSelectedAssets);
%>

10) Create clientlib (type cq:ClientLibraryFolder) /apps/eaem-wizard-select-assets-column-view/clientlib with categories String[] eaem.wizard and dependencies String[] underscore to add some dynamic behavior to the wizard while navigating between the steps

11) Create nt:file /apps/eaem-wizard-select-assets-column-view/clientlib/js.txt and add the following content

               handle-wizard.js

12) Create nt:file /apps/eaem-wizard-select-assets-column-view/clientlib/handle-wizard.js, add the following logic

(function ($, $document) {
    var WIZARD_URL = "/apps/eaem-wizard-select-assets-column-view/eaem-3-step-wizard.html",
        COLUMN_VIEW = "coral-columnview",
        FOUNDATION_CONTENT_LOADED = "foundation-contentloaded",
        FOUNDATION_WIZARD_STEPCHANGE = "foundation-wizard-stepchange",
        FOUNDATION_WIZARD = "foundation-wizard",
        FOUNDATION_SELECTIONS_CHANGE = "foundation-selections-change",
        FOUNDATION_SELECTIONS_ITEM = "foundation-selections-item",
        FOUNDATION_COLLECTION = ".foundation-collection",
        FOUNDATION_COLLECTION_ITEM_ID = "foundation-collection-item-id",
        CORAL_COLUMN_VIEW_LOAD_ITEMS = 'coral-columnview:loaditems',
        CORAL_COLUMNVIEW_ITEM = "coral-columnview-item",
        SELECTION_MODE = "selectionmode",
        SUFFIX = "suffix",
        TABLES_DIV = "eaem-column-view-selections",
        TABLES_IN_ROW = 5,
        EAEM_ASSETS_PATH = "eaemAssetsPath",
        EAEM_SELECTED_ASSETS = "eaemSelectedAssets";

    var selectedAssets = {}, $sfContainer,
        tableWidth = (($(window).width() / TABLES_IN_ROW) - 5),
        itemTpl = Handlebars.compile(getItemTemplate()),
        sectionTpl = Handlebars.compile(getSectionTemplate());

    $document.on(FOUNDATION_CONTENT_LOADED, ifSuffixAvailableBuildUIMoveToStep2);

    $document.on(FOUNDATION_WIZARD_STEPCHANGE, handleSteps);

    function ifSuffixAvailableBuildUIMoveToStep2(){
        var $wizard = $("." + FOUNDATION_WIZARD);

        if(_.isEmpty($wizard)){
            return;
        }

        var suffix = $wizard.data(SUFFIX);

        if(_.isEmpty(suffix)){
            return;
        }

        var $columnView = $(COLUMN_VIEW);

        if(_.isEmpty($columnView)){
            return;
        }

        createSelectedAssetsUI($columnView);

        registerListeners($columnView);

        $wizard.adaptTo(FOUNDATION_WIZARD).next();
    }

    function handleSteps(event, nextStep, currentStep){
        if(_.isUndefined(currentStep)){
            return;
        }

        var $eaemAssetsPath = $("[name=" + EAEM_ASSETS_PATH + "]");

        if(isSecondStep() && !_.isEmpty($eaemAssetsPath.val())){
            $(nextStep).hide();
            redirectTo(WIZARD_URL + $eaemAssetsPath.val());
        }else if(isThirdStep()){
            addSelectedAssetsToForm();
        }
    }

    function registerListeners($columnView){
        $document.on(FOUNDATION_SELECTIONS_CHANGE, FOUNDATION_COLLECTION, collectAssets);

        $columnView.on(CORAL_COLUMN_VIEW_LOAD_ITEMS, listenerOnLoadedItems);
    }

    function addSelectedAssetsToForm(){
        if(_.isEmpty(selectedAssets)){
            return;
        }

        var $form = $("form"),
            $selectedAssets = $("[name=" + EAEM_SELECTED_ASSETS + "]");

        if(_.isEmpty($selectedAssets)){
            $selectedAssets = $('<input />').attr('type', 'hidden')
                .attr('name', EAEM_SELECTED_ASSETS)
                .appendTo($form);
        }

        var assetPaths = Object.keys(selectedAssets);

        $selectedAssets.val(assetPaths.join(","));

        if(_.isEmpty(assetPaths)){
            disableWizardNext();
        }else{
            enableWizardNext();
        }
    }

    function createSelectedAssetsUI($columnView){
        var height = $(window).height() - 350;

        $columnView.height(height).attr(SELECTION_MODE, Coral.ColumnView.selectionMode.SINGLE);

        $sfContainer = $("<div/>").appendTo($columnView.parent());

        addHeader($sfContainer);

        addNoSelFilesDiv($sfContainer);
    }

    function collectAssets(){
        var $asset, path;

        $("." + FOUNDATION_SELECTIONS_ITEM).each(function(index, asset){
            $asset = $(asset);

            path = $asset.data(FOUNDATION_COLLECTION_ITEM_ID);

            if(selectedAssets.hasOwnProperty(path)){
                return;
            }

            if(!isAsset($asset)){
                $asset.removeAttr("selected").removeClass(FOUNDATION_SELECTIONS_ITEM);
                return;
            }

            selectedAssets[path] = {
                path: path,
                thumbnail: $asset.find("coral-columnview-item-thumbnail > img").attr("src"),
                text: $asset.data("item-title")
            };
        });

        buildTable(selectedAssets, $sfContainer);
    }

    function buildTable(selectedAssets, $container) {
        if(_.isEmpty(selectedAssets)){
            addNoSelFilesDiv($sfContainer);
            return;
        }

        enableWizardNext();

        var itemHtml = "", index = 0,
            rowsInTable = getNoOfRowsInEachTable(selectedAssets),
            $tablesDiv = getTablesDiv();

        _.each(selectedAssets, function(itemData){
            itemHtml = itemHtml + itemTpl(itemData);

            if( (++index % rowsInTable) !== 0 ){
                return;
            }

            addToSection($tablesDiv, itemHtml);

            itemHtml = "";

            index = 0;
        });

        if(itemHtml){
            addToSection($tablesDiv, itemHtml);
        }

        $container.find("#" + TABLES_DIV).remove();

        $tablesDiv.appendTo($container);

        handleSelections($tablesDiv);
    }

    function handleSelections($tablesDiv){
        _.defer(function(){
            $tablesDiv.find("coral-checkbox").click().on('change', handleChecks);
        });

        function handleChecks(){
            var path = $(this).closest("tr").data("path");

            delete selectedAssets[path];

            buildTable(selectedAssets, $sfContainer);
        }
    }

    function addToSection($tablesDiv, itemHtml){
        var sectionHtml = sectionTpl({
            width: tableWidth + "px",
            itemHtml: itemHtml
        });

        $(sectionHtml).appendTo($tablesDiv);
    }

    function listenerOnLoadedItems(){
        $(CORAL_COLUMNVIEW_ITEM).click(ignoreFolderSelections);
    }

    function ignoreFolderSelections(){
        var $item = $(this);

        if(isAsset($item)){
            return;
        }

        _.defer(function(){
            $item.removeAttr("selected");
        });
    }

    function getNoOfRowsInEachTable(selectedAssets){
        return Math.ceil(Object.keys(selectedAssets).length / TABLES_IN_ROW);
    }

    function addHeader($container) {
        var html =  "<div style='text-align:center; padding: 5px; background-color: rgba(0,0,0,0.05)'>" +
                        "<h3>Selected Files</h3>" +
                    "</div>";

        return $(html).appendTo($container);
    }

    function addNoSelFilesDiv($container) {
        $container.find("#" + TABLES_DIV).remove();

        disableWizardNext();

        var html =  "<div style='text-align:center' id='" + TABLES_DIV + "'>" +
                        "<h4>No files have been added." +
                        "To add files, select the file by clicking on file thumnbnail</h4>" +
                    "</div>";

        return $(html).appendTo($container);
    }

    function getItemTemplate() {
        return '<tr is="coral-tr" data-path="{{path}}">' +
                    '<td is="coral-td" coral-tr-select></td>' +
                    '<td is="coral-td">' +
                        '<img src="{{thumbnail}}" class="image">' +
                    '</td>' +
                    '<td is="coral-td">{{text}}</td>' +
                '</tr>'
    }

    function getSectionTemplate(){
        return '<coral-table selectionmode="row" multiple style="display:inline-block" >' +
                    '<table is="coral-table-inner" style="width: {{width}}; overflow: hidden">' +
                        '<colgroup>' +
                            '<col is="coral-col" fixedwidth>' +
                            '<col is="coral-col" fixedwidth>' +
                            '<col is="coral-col" sortable alignment="left">' +
                        '</colgroup>' +
                        '<tbody is="coral-tbody">' +
                            '{{{itemHtml}}}' +
                        '</tbody>' +
                    '</table>' +
                '</coral-table>'
    }

    function isAsset($item){
        return ($item.data("item-type") === "asset");
    }

    function getTablesDiv(){
        return $("<div id='" + TABLES_DIV + "'></div>");
    }

    function disableWizardNext(){
        toggleWizard(false);
    }

    function enableWizardNext(){
        toggleWizard(true);
    }

    function toggleWizard(isEnable){
        var $wizard = $("." + FOUNDATION_WIZARD);

        if(_.isEmpty($wizard)){
            return;
        }

        var wizardApi = $wizard.adaptTo(FOUNDATION_WIZARD);
        wizardApi.toggleNext(isEnable);
    }

    function getStepNumber(){
        var $wizard = $("." + FOUNDATION_WIZARD),
            currentStep = $wizard.find(".foundation-wizard-step-active"),
            wizardApi = $wizard.adaptTo(FOUNDATION_WIZARD);

        return wizardApi.getPrevSteps(currentStep).length + 1;
    }

    function isSecondStep(){
        return (getStepNumber() === 2);
    }

    function isThirdStep(){
        return (getStepNumber() === 3);
    }

    function redirectTo(url){
        var ui = $(window).adaptTo("foundation-ui");

        ui.wait($("form"));

        window.location = url;
    }
}(jQuery, jQuery(document)));



No comments:

Post a Comment