AEM 61 - Classic UI Configure Parsys Components Limit in Design Dialog

Goal


Limit number of components added in a parsys, where the limit is configurable in design dialog

For a different implementation (configure component limit in each page) - check this post

For TouchUI check this post

Demo | Package Install


Parsys Limit - Design Mode (added by Extension)



Stored in CRX



Limit Exceeded - Drag and Drop



Limit Exceeded - New menu item disabled



Solution


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

2) Create clientlib (type cq:ClientLibraryFolder/apps/classicui-design-configurable-limit-parsys/clientlib and set property categories of String type to cq.widgets and dependencies to underscore

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

                         limit-parsys.js

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

(function(){
    var PARSYS_DESIGN_DIALOG = "/libs/foundation/components/parsys/design_dialog",
        PARSYS_LIMIT = "eaemComponentLimit";

    CQ.Ext.onReady(function () {
        if(CQ.WCM.isEditMode()){
            handleEditMode();
        }

        if(CQ.WCM.isDesignMode()){
            handleDesignMode();
        }
    });

    function handleDesignMode(){
        extendShowDialog();
    }

    function handleEditMode(){
        CQ.WCM.on("editablesready", applyLimitAndExtendDrop, this);
    }

    function getSiblings(editable){
        var parent, siblings = [];

        _.each(CQ.WCM.getEditables(), function(e){
            parent = e.getParent();

            if(!parent || (parent.path !== editable.getParent().path)){
                return;
            }

            siblings.push(e);
        });

        return siblings;
    }

    function isWithinLimit(editComponent){
        var pageInfo = CQ.utils.WCM.getPageInfo(editComponent.path),
            isWithin = true, currentLimit = "",
            cellSearchPath, parentPath, parName;

        if(!pageInfo || !pageInfo.designObject){
            return;
        }

        try{
            cellSearchPath = editComponent.cellSearchPath;
            parentPath = editComponent.getParent().path;

            cellSearchPath = cellSearchPath.substring(0, cellSearchPath.indexOf("|"));
            parName = parentPath.substring(parentPath.lastIndexOf("/") + 1);
            currentLimit = pageInfo.designObject.content[cellSearchPath][parName][PARSYS_LIMIT];

            if(currentLimit){
                isWithin = getSiblings(editComponent).length <= parseInt(currentLimit);
            }
        }catch(err){
            console.log("Experience AEM - Error getting the component limit", err);
        }

        return {
            isWithin: isWithin,
            currentLimit: currentLimit
        };
    }

    function extendDrop(dropFn){
        return function(dragSource, e, data){
            var limit = isWithinLimit(this.editComponent);

            if(!limit.isWithin){
                this.editComponent.hideTarget();
                CQ.Ext.Msg.alert('Error', "Limit exceeded, allowed - " + limit.currentLimit);
                return false;
            }

            return dropFn.call(this, dragSource, e, data);
        };
    }

    function disableNewMenuItem(){
        var component = this.element.linkedEditComponent;

        if (!component || !component.menuComponent) {
            return;
        }

        var menu = component.menuComponent;

        if (menu.eaemLimitSet) {
            return;
        }

        menu.eaemLimitSet = true;

        var limit = isWithinLimit(this);

        var newItem = menu.findBy(function(comp){
            return comp.text === "New...";
        })[0];

        if(!limit.isWithin){
            newItem.setDisabled(true);
        }
    }

    function isParsysNew(editable){
        return _.isObject(editable.params)
            && (editable.params["./sling:resourceType"] == CQ.wcm.EditBase.PARSYS_NEW);
    }

    function applyLimitAndExtendDrop() {
        var editables = CQ.utils.WCM.getEditables();

        _.each(editables, function (editable) {
            if (isParsysNew(editable)) {
                editable.emptyComponent.el.on("contextmenu", disableNewMenuItem, editable);
            }

            var dropTargets = editable.getDropTargets();

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

            dropTargets[0].notifyDrop = extendDrop(dropTargets[0].notifyDrop);
        });
    }

    function extendShowDialog(){
        CQ.wcm.EditBase.showDialog = (function(showDialogFn) {
            return function(editComponent, type, ignoreIsContainer){
                if(editComponent.dialog !== PARSYS_DESIGN_DIALOG){
                    return;
                }

                var isFirstRun = !editComponent.dialogs[CQ.wcm.EditBase.EDIT];

                showDialogFn.call(this, editComponent, type, ignoreIsContainer);

                if(isFirstRun){
                    editComponent.getEditDialog().on("loadcontent", extendParsysDialog);
                }
            }
        }(CQ.wcm.EditBase.showDialog));
    }

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

        function handler(data){
            dialog.un("loadcontent", extendParsysDialog);

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

            var compSelector = dialog.findByType("componentselector")[0],
                ownerCt = compSelector.ownerCt;

            ownerCt.insert(2, limitField);

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


2 comments:

  1. Hi,
    I have come across a requirement like component need to be locked if anyone is working on that component. i.e it should get locked if any one working on it so that nobody wil work on the component simultaneously . Is this possible to achieve?
    Regards,

    ReplyDelete
  2. I have installed the package but it is not saving the value of the field "eaemComponentLimit" in my case.

    "Error: Experience AEM - Error getting the component limit TypeError: Cannot read property 'eaemComponentLimit' of undefined(…)"

    ReplyDelete