AEM 61 - Touch UI Limit the Number of Components Added in Parsys

Goal


Limit the number of Components added in a Parsys of Touch UI

For Classic UI check this post

Demo | Package Install


Bug Fixes

Applying limit to copy / paste of components - Demo | Package Install


Set the Limit - Design Mode



Stored in CRX



Limit Exceeded Error on Component Drop or Insert - Edit Mode



Solution


1) Login to CRXDE Lite, create folder (nt:folder) /apps/touchui-limit-parsys

2) Create clientlib (type cq:ClientLibraryFolder/apps/touchui-limit-parsys/clientlib and set property categories of String[] type to cq.authoring.dialog, cq.compat.authoring.widgets and dependencies to underscore

3) Create file ( type nt:file ) /apps/touchui-limit-parsys/clientlib/js.txt, add the following

                         limit-parsys.js

4) Create file ( type nt:file ) /apps/touchui-limit-parsys/clientlib/limit-parsys.js, add the following code

// for touchui design mode
(function(){
    var pathName = window.location.pathname,
        EAEM_COMPONENT_LIMIT = "eaemComponentLimit";

    if( !pathName.endsWith("dialogwrapper.html") ){
        return;
    }

    CQ.Ext.onReady(function () {
        findDesignDialogWindow();
    });

    function findDesignDialogWindow(){
        var wMgr = CQ.Ext.WindowMgr, winId;

        var W_INTERVAL = setInterval(function () {
            wMgr.each(function (win) {
                if(!win || !win.id){
                    return;
                }

                clearInterval(W_INTERVAL);

                addLimitTextField(win);
            });
        }, 250);
    }

    function addLimitTextField(win){
        var compSelector = win.findByType("componentselector");

        if(compSelector.length == 0){
            return;
        }

        compSelector = compSelector[0];

        var dialog = compSelector.findParentByType("dialog");

        $.ajax( dialog.path + ".2.json" ).done(handler);

        function handler(data){
            var limitField = new CQ.Ext.form.TextField({
                value: data[EAEM_COMPONENT_LIMIT] || "",
                fieldLabel: "Limit Components to ",
                name: "./" + EAEM_COMPONENT_LIMIT,
                style: {
                    marginBottom: '10px'
                }
            });

            compSelector.ownerCt.insert(2, limitField);

            compSelector.ownerCt.doLayout();
        }
    }
}());

// for touchui edit mode
(function ($document, gAuthor) {
    var pathName = window.location.pathname;

    if( pathName.endsWith("dialogwrapper.html") ){
        return;
    }

    var EAEM_COMPONENT_LIMIT = "eaemComponentLimit";

    $(extendComponentDrop);

    function getDesignPath(editable){
        var parsys = editable.getParent(),
            designSrc = parsys.config.designDialogSrc,
            result = {}, param;

        designSrc = designSrc.substring(designSrc.indexOf("?") + 1);

        designSrc.split(/&/).forEach( function(it) {
            if (_.isEmpty(it)) {
                return;
            }
            param = it.split("=");
            result[param[0]] = param[1];
        });

        return decodeURIComponent(result["content"]);
    }

    function extendComponentDrop(){
        var dropController = gAuthor.ui.dropController,
            compDragDrop = dropController.get(gAuthor.Component.prototype.getTypeName());

        //handle drop action
        compDragDrop.handleDrop = function(dropFn){
            return function (event) {
                if(showError(event.currentDropTarget.targetEditable)){
                    return;
                }

                return dropFn.call(this, event);
            };
        }(compDragDrop.handleDrop);

        //handle insert action
        gAuthor.edit.actions.openInsertDialog = function(openDlgFn){
            return function (editable) {
                if(showError(editable)){
                    return;
                }

                return openDlgFn.call(this, editable);
            }
        }(gAuthor.edit.actions.openInsertDialog);

        //handle paste action
        var insertAction = gAuthor.edit.Toolbar.defaultActions["INSERT"];

        insertAction.handler = function(insertHandlerFn){
            return function(editableBefore, param, target){
                if(showError(editableBefore)){
                    return;
                }

                return insertHandlerFn.call(this, editableBefore, param, target)
            }
        }(insertAction.handler);

        function showError(editable){
            var limit = isWithinLimit(editable);

            if(!limit.isWithin){
                showErrorAlert("Limit exceeded, allowed - " + limit.currentLimit);
                return true;
            }

            return false;
        }
    }

    function getChildEditables(parsys){
        var editables = gAuthor.edit.findEditables(),
            children = [], parent;

        _.each(editables, function(editable){
            parent = editable.getParent();

            if(parent && (parent.path === parsys.path)){
                children.push(editable);
            }
        });

        return children;
    }

    function showErrorAlert(message, title){
        var fui = $(window).adaptTo("foundation-ui"),
            options = [{
                text: "OK",
                warning: true
            }];

        message = message || "Unknown Error";
        title = title || "Error";

        fui.prompt(title, message, "error", options);
    }

    function isWithinLimit(editable){
        var path = getDesignPath(editable),
            children = getChildEditables(editable.getParent()),
            isWithin = true, currentLimit = "";

        $.ajax( { url: path + ".2.json", async: false } ).done(function(data){
            if(_.isEmpty(data) || !data[EAEM_COMPONENT_LIMIT]){
                return;
            }

            currentLimit = data[EAEM_COMPONENT_LIMIT];

            var limit = parseInt(data[EAEM_COMPONENT_LIMIT]);

            isWithin = children.length <= limit;
        });

        return {
            isWithin: isWithin,
            currentLimit: currentLimit
        };
    }
})($(document), Granite.author);


No comments:

Post a Comment