Hi, I've a project requirement (AEM 6.2) where I need to restrict the specific component in parsys to a limited count? Let's say I've 3 component allowed for a particular section parsys. Let's call it {A, B, C}. The 'A' component can be dragged any number of time in parsys but if component 'B' is dragged on parsys then it shouldn't allow to drag component 'C' and vice-versa. Thanks, Vijay
Solved! Go to Solution.
Views
Replies
Total Likes
Here is the working example:- Experiencing Adobe Experience Manager - Day CQ: AEM 61 - Touch UI Limit the Number of Components Add...
But, Editable template has evolved big way now. I would recommend you to use Editable Template for this.
Views
Replies
Total Likes
Views
Replies
Total Likes
This is where when using a more recent version of AEM Editable Templates and policies are best practice. When setting policies in an editable template - you can control which components are allowed to be used.
Views
Replies
Total Likes
@smacdonald2008 can you help me how to do that?
This is where when using a more recent version of AEM Editable Templates and policies are best practice. When setting policies in an editable template - you can control which components are allowed to be used.
Views
Replies
Total Likes
Hi Rajashankar ,
Thanks for the reply . In the link you have provided , one with reply that is marked as correct seems like those urls are not valid any more.
thanks,
Vijay.
Views
Replies
Total Likes
Hi vijayk87714775,
You will have to write a custom JQuery listener to handle this on the drag and drop event.
Views
Replies
Total Likes
Here is the working example:- Experiencing Adobe Experience Manager - Day CQ: AEM 61 - Touch UI Limit the Number of Components Add...
But, Editable template has evolved big way now. I would recommend you to use Editable Template for this.
Views
Replies
Total Likes
I fix follow these steps:
1. Login crx/de and create a custom js folder touchui-limit-parsys
ui.apps/src/main/content/jcr_root/apps/myapp/clientlibs/touchui-limit-parsys
2. add the categories and dependencies for the clientlib folder
categories="[cq.authoring.dialog,cq.compat.authoring.widgets,myapp.components]"
dependencies="underscore"
3. create file ui.apps/src/main/content/jcr_root/apps/myapp/clientlibs/touchui-limit-parsys/js/touchui-limit-parsys.js
/* * #%L * ACS AEM Commons Package * %% * Copyright (C) 2013 Adobe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% * * Extends /libs/foundation/components/parsys to limit the components that be added * using drag/drop, copy/paste or insert actions * To enable limit feature set the property acsComponentsLimit with required limit on design node * eg. to limit the components to 4 on rightpar of /content/geometrixx/en.html * set acsComponentsLimit=4 on /etc/designs/geometrixx/jcr:content/homepage/rightpar */ (function ($, $document) { "use strict"; var ACS_COMPONENTS_LIMIT = "acsComponentsLimit"; /** AEM 6.2 does not have the function resolveProperty in util.js and thus * breaks authoring on a supported version. To deal with this we need to detect * if the function is available and fallback to 6.2 functions if it is not. */ function correctlyResolveProperty(design, path){ if ("resolveProperty" in Granite.author.util) { //function was found, use it. return Granite.author.util.resolveProperty(design, path); }else{ //didn't find the function in util.js, we'll use _discover instead. return Granite.author.components._discover(design, path); } } /** * mostly taken over from /libs/cq/gui/components/authoring/editors/clientlibs/core/js/storage/components.js _findAllowedComponentsFromPolicy */ function _findPropertyFromPolicy(editable, design, propertyName) { var cell = correctlyResolveProperty(design, editable.config.policyPath); if (!cell || !cell[propertyName]) { // Inherit property also from its parent (if not set in the local policy path) var parent = Granite.author.editables.getParent(editable); while (parent && !(cell && cell[propertyName])) { cell = correctlyResolveProperty(design, parent.config.policyPath); parent = Granite.author.editables.getParent(parent); } } if (cell && cell[propertyName]) { return cell[propertyName]; } return null; } /** * mostly taken over from /libs/cq/gui/components/authoring/editors/clientlibs/core/js/storage/components.js _findAllowedComponentsFromDesign * Returns the value of the given property name extracted from the given design configuration object (also supports content policies) */ function _findPropertyFromDesign(editable, design, propertyName) { if (editable && editable.config) { if (editable.config.policyPath) { return _findPropertyFromPolicy(editable, design, propertyName); } else { // All cell search paths var cellSearchPaths = editable.config.cellSearchPath; if (cellSearchPaths) { for (var i = 0; i < cellSearchPaths.length; i++) { var cell = correctlyResolveProperty(design, cellSearchPaths[i]); if (cell && cell[propertyName]) { return cell[propertyName]; } } } } } return null; } 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 getChildEditables(parsys){ var editables = Granite.author.edit.findEditables(), children = [], parent; _.each(editables, function(editable){ parent = editable.getParent(); if(parent && (parent.path === parsys.path)){ children.push(editable); } }); return children; } function isWithinLimit(parsysEditable, itemsToAdd){ var isWithin = true, currentLimit = ""; currentLimit = _findPropertyFromDesign(parsysEditable, Granite.author.pageDesign, ACS_COMPONENTS_LIMIT); if (currentLimit === null) { return true; } var limit = parseInt(currentLimit); var children = getChildEditables(parsysEditable); itemsToAdd = itemsToAdd ? itemsToAdd : 1; isWithin = children.length - 1 + itemsToAdd <= limit; if(!isWithin){ showErrorAlert("Limit of components within this component system exceeded, allowed only up to " + currentLimit + " components."); } return isWithin; } function extendComponentDrop(){ var dropController = Granite.author.ui.dropController, compDragDrop; if (dropController !== undefined) { compDragDrop = dropController.get(Granite.author.Component.prototype.getTypeName()); //handle drop action if (compDragDrop !== undefined) { //handle drop action compDragDrop.handleDrop = function(dropFn){ return function (event) { if(!isWithinLimit(event.currentDropTarget.targetEditable.getParent())){ return; } return dropFn.call(this, event); }; }(compDragDrop.handleDrop); } //handle paste action var pasteAction = Granite.author.edit.Toolbar.defaultActions.PASTE; // overwrite both execute and handler as both seem to be used pasteAction.execute = pasteAction.handler = function(pasteHandlerFn){ return function (editableBefore) { // only prevent copy but not move operations (if previous operation was cut) if(!Granite.author.clipboard.shouldCut()) { if(!isWithinLimit(editableBefore.getParent(), Granite.author.clipboard.length)){ return; } } return pasteHandlerFn.call(this, editableBefore); }; }(pasteAction.execute); // handle insert action var insertAction = Granite.author.edit.Toolbar.defaultActions.INSERT; // overwrite both execute and handler (for doubleclick and "+" icon click functionality) insertAction.execute = insertAction.handler = function(insertHandlerFn){ return function(editableBefore, param, target){ if(!isWithinLimit(editableBefore.getParent())){ return; } return insertHandlerFn.call(this, editableBefore, param, target); }; }(insertAction.execute); } } $(function() { if (Granite && Granite.author && Granite.author.edit && Granite.author.Component && Granite.author.ui && Granite.author.ui.dropController) { extendComponentDrop(); } }); }(jQuery, jQuery(document)));
4. create file ui.apps/src/main/content/jcr_root/apps/myapp/clientlibs/touchui-limit-parsys/js.txt
js/touchui-limit-parsys.js
5. set a limit on the policies
ui.content/src/main/content/jcr_root/conf/myapp/settings/wcm/policies/.content.xml
<testcomponent jcr:primaryType="nt:unstructured"> <testcomponent-style-system jcr:lastModified="{Date}2021-07-20T09:05:25.344+07:00" jcr:lastModifiedBy="admin" jcr:primaryType="nt:unstructured" jcr:title="Test Component Style System" sling:resourceType="wcm/core/components/policy/policy" acsComponentsLimit="2" autopauseDisabled="false" autoplay="false" components="[/apps/myapp/components/content/test1component]" delay="5000"> <jcr:content cq:lastReplicated="{Date}2021-03-08T06:29:29.280Z" cq:lastReplicatedBy="bmdesai" cq:lastReplicationAction="Activate" jcr:mixinTypes="[cq:ReplicationStatus]" jcr:primaryType="nt:unstructured"/> </contentsplit-style-system> </testcomponent>
Note: In the testcomponent we can add limit test1component by the config acsComponentsLimit="2"
Views
Likes
Replies