Showing posts with label Editable Templates. Show all posts
Showing posts with label Editable Templates. Show all posts

January 4, 2021
Estimated Post Reading Time ~

Content Fragment with Component

Browse and use Content fragment inside the custom component
AEM introduced Content Fragment with 6.2 and now almost everyone knows about Content Fragments and How to create and use them.

But we are restricted to use Content Fragments inside page only via Content Fragment components (WCM core content fragment and foundation Content Fragment components)

What if we need to use Content Fragments like other assets e.g. images using PathField or PathBrowser in the component.

There is a possibility to achieve this and Content Fragment can be browsed and used from any component. Content Fragments variations can also be added from the component.

Content Fragment(without variation)
  • In the component, dialog creates a PathField to browse Content Fragment.
  • In HTL, use JAVA API to read HTML content from content fragments master variation node's jcr:data property.


Example :
Component Dailog:

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/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="nt:unstructured"
jcr:title="CF Test Dialog"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<heading
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/textfield"
fieldLabel="Heading"
name="./heading"
required="{Boolean}true"/>
<cf-field
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
fieldDescription="Browse CF"
fieldLabel="Browse CF"
name="./cfdata"
rootPath="/content/dam"/>
</items>
</column>
</items>
</content>
</jcr:root>


HTL:
<h2>Content Fragment Test Component</h2>
<h3>${properties.heading}</h3>
<div data-sly-use.cf="${'com.aem.community.core.components.ContentFragmentContent' @ cfInput=properties.cfdata}">
${cf.content @ context='html'}
</div>


JAVA:
Above com.aem.community.core.components.ContentFragmentContent java code is available at GitHub
ContentFragmentContent.java

Content Fragment(with variation)

  • In the component, dialog creates a PathField to browse Content Fragment.
  • Create dropdown with options to populate content fragment variation
  • Create a hidden field item to store content fragment variation value on dialog submit. this value will be used to set the preselected variation option in the dropdown when the dialog will be loaded again.
  • In HTL, use JAVA API to read HTML content from content fragments master or selected variation node's jcr:data property.
  • Create clientlibs with category 'cq.authoring.dialog', add Javascript to populate dropdown option for component variations, variations can be retrieved by making an ajax call to browsed Content Fragment with cfm.info selectors and with JSON extension e.g. http://localhost:4502/content/dam/we-retail/en/experiences/arctic-surfing-in-lofoten/arctic-surfing-in-lofoten.cfm.info.json?ck=0.8366689055424192&_=1535814701363 . Below is the response to the above request, variations can be read and dialog variations dropdown options can be created.
{"name":"arctic-surfing-in-lofoten","title":"Arctic Surfing in Lofoten","description":"Surfing in Northern Norway","path":"/content/dam/we-retail/en/experiences/arctic-surfing-in-lofoten/arctic-surfing-in-lofoten","elements":[{"name":"main","title":"Main","contentType":"text/html"}],"variations":[{"name":"master","title":"Master","description":"Represents the original content fragment"},{"name":"teaser","title":"Teaser","description":""}]}

sample javascript created for demo at cf-variation-handler.js

Example :
Component Dailog:

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/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="nt:unstructured"
jcr:title="CF Test Dialog"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<heading
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/textfield"
fieldLabel="Heading"
name="./heading"
required="{Boolean}true"/>
<cf-field
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
fieldDescription="Browse CF"
fieldLabel="Browse CF"
name="./cfdata"
rootPath="/content/dam"/>
<variation
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/select"
emptyText="Select"
fieldLabel="Variation"
name="./variation"/>
<varhidden
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/hidden"
name="./selectVariation"/>
</items>
</column>
</items>
</content>
</jcr:root>


HTL:
<h2>Content Fragment Test Component</h2>
<h3>${properties.heading}</h3>
<div data-sly-use.cf="${'com.aem.community.core.components.ContentFragmentContent' @ cfInput=properties.cfdata, variation=properties.variation}">
${cf.content @ context='html'}
</div>


JAVA:
Same java code is compatible with both ContentFragmentContent.java




By aem4beginner

January 3, 2021
Estimated Post Reading Time ~

Restrict Allowed Component Group in Template Policy

In Dynamic/Editable Template, The Component level policy allows configuring various properties. One of the properties for responsivegrid or container or any other container component is to allow child components inside parsys/responsivegrid, which template author can define.

To Allow Components, the Template author has to create a policy and select components from the Allowed Components list.

But Template Author can see all the components group to select and sometimes you just want to enable few components to be allowed, for example, a card container can only have card components. But you cannot restrict the template Author to choose from.

How to Restrict Groups in the Allowed Components list

Unfortunately, there is no OOTB configuration/solution to achieve this. If you want to restrict allowed components then you have to write a custom solution. I am going to explain one of the custom solutions here. 

The Allowed Component list is generated from /libs/cq/gui/components/authoring/allowedcomponents , so I will create custom allowedcomponents (/apps/commons/components/authoring/allowedcomponents) based on /libs/cq/gui/components/authoring/allowedcomponents

I am going to create a custom allowed component which will be used wherever I have to restrict allowedcomponents.

Steps :

1. Copy allowedcomponent node with all the subnode from /libs/cq/gui/components/authoring/allowedcomponents to apps folder e.g. /apps/commons/components/authoring/allowedcomponents


2. Modify /apps/commons/components/authoring/allowedcomponents/allowedcomponents.html to update JAVA reference, the package name should be the same as the location of allowedcomponents folder which was copied in Step 1 i.e. apps.commons.components.authoring.allowedcomponents.AllowedComponents

3. Modify /apps/commons/components/authoring/allowedcomponents/AllowedComponents.java to add logic to filter group list. 
I am using logic to read allowed groups from the node property where this custom component is used via resourceType. e.g.

JAVA Logic - AllowedComponents.java
3.1 update package 
package apps.commons.components.authoring.allowedcomponents;

3.2 Read allowedGroups property inside the activate method
    @Override
    public void activate() throws Exception {
        // get all available components
        Map<String, Component> components = getAllComponents();
        // get selected groups and components from properties
        Set<String> selected = getSelectedComponents();
        // keeps track of encountered resources types
        Set<String> resourceTypes = new HashSet<String>();
        // stores groups indexed by their name
        Map<String, GroupInfo> groupsMap = new HashMap<String, GroupInfo>();

        // Get Allowed Groups
        ValueMap vmAG = getResource().getValueMap();
        String resGroup[] = vmAG.get("allowedGroups", new String[] {});

        // iterate over all components and build component and group info
        for (Component component : components.values()) {

3.3 Update condition to skip groups similar to groups start with.
// filter components that are part of a hidden group and non allowed group
            if (group.startsWith(".") || (resGroup.length > 0 && notAllowedGroup(resGroup, group))) {
                continue;
            }

3.4 Create notAllowedGroup method at the bottom(you can create anywhere I just created at the bottom of the file)

     /**
     * Returns true if component groups is not allowed
     */

    public boolean notAllowedGroup(String[] resGroup, String group) {
        for (int i = 0; i < resGroup.length; i++) {
if (group.matches(resGroup[i])) {
return false;
}
}
return true;
    }

4. Refresh the Template. And we are done.


By aem4beginner