AEM CQ 561 - Working with Scaffolding

Goal


Generate pages with similar structure and varying content quickly. Scaffolding provides form like interface with fields to generate pages, with content entered into the scaffold. Check demo

Creating a Scaffold Page


1) Let's work on creating pages with a par, some static content in header, footer with text and image components in middle section. So the steps involved are

              a) Create a page from siteadmin or copy existing page
              b) Drag and drop necessary components onto the page par ie. text and image components
              c) Enter content for text by opening component dialog; drag image from content finder

The resulting page is like one below



2) If too many pages in your site have similar structure but only the text and image change, its generally useful to create Scaffolding to generate such pages. With Scaffolding we get rid of two steps

               Create/Copy page by selecting templates from page dialog
               Drag and drop components from sidekick

    Depending on the number of components in page, page structure and number of look-alike pages to be generated scaffolding can save a lot of time

3) To create a scaffold, access Tools console http://localhost:4502/miscadmin and select Scaffolding in left tree; In the right pane select New, a dialog with single template Scaffolding Template appears. Enter title My Text Image. Click Create





4) Double click on My Text Image to open the scaffolding editor http://localhost:4502/cf#/etc/scaffolding/my-text-image.html. Click Sidekick -> Page tab -> Page properties and select the following

                       Target Template: The template used for page creation. In step 1 to create the page manually, we used a simple Basic Template.As we are generating pages of Basic Template select it
                       Target Path: The path where generated pages are stored




Here is the code for basic template page component jsp



5) After entering the details in page properties, a basic scaffold is created with Title to enter page title (stored as jcr:title) and Tags.




6) Every scaffolding has Dialog Editor to work on its form fields like Title above. Click on the Sidekick design mode (L shape at the bottom of sidekick) to access page having link for Dialog Editor. Click on the link to open Dialog Editor - http://localhost:4502/etc/scaffolding/my-text-image/_jcr_content/dialog.html



    Dialog in CRXDE Lite




7) Using the dialog editor we can add new properties for existing fields, but to add new fields a developer has to visit CRXDE; Access the created scaffold page in CRXDE http://localhost:4502/crx/de/index.jsp#/etc/scaffolding/my-text-image and add widget for Text field in the dialog - /etc/scaffolding/my-text-image/jcr:content/dialog/items/tab1/items/text ( you can copy an existing  richtext widget node available eg.  /etc/scaffolding/geometrixx/news/jcr:content/dialog/items/tab1/items/text)





The name of field is set to ./jcr:content/par/text/text. So any value entered for this field is stored in path /jcr:content/par/text/text relative to the newly created page

Similarly we need hidden fields for storing the value of sling:resourceType - foundation/components/text and textIsRich - true; so we create necessary hidden widgets




8) Similarly we need html5smartimage widget and hidden field for storing image specific values. As you can see the image specific values are stored under ./jcr:content/par/image relative to new page





The hidden field for storing Image Component resourceType




9) We have the scaffolding form now ready for creating pages http://localhost:4502/cf#/etc/scaffolding/my-text-image.html. Enter Title, Text, drag an Image from content finder, click Create and your page will be created (eg. http://localhost:4502/content/my-scaffolding-pages/ocean.html )





10) Here is the scaffolding page dialog xml - Package Install

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root 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:Dialog"
    xtype="tabpanel">
    <items jcr:primaryType="cq:WidgetCollection">
        <tab1
            jcr:primaryType="cq:Panel"
            title="Properties">
            <items jcr:primaryType="cq:WidgetCollection">
                <title
                    jcr:primaryType="cq:Widget"
                    fieldLabel="Title"
                    name="./jcr:content/jcr:title"/>
                <text
                    jcr:primaryType="cq:Widget"
                    fieldLabel="Text"
                    name="./jcr:content/par/text/text"
                    xtype="richtext">
                    <rtePlugins jcr:primaryType="nt:unstructured">
                        <table
                            jcr:primaryType="nt:unstructured"
                            features="*"/>
                        <format
                            jcr:primaryType="nt:unstructured"
                            features="*"/>
                        <lists
                            jcr:primaryType="nt:unstructured"
                            features="*"/>
                        <justify
                            jcr:primaryType="nt:unstructured"
                            features="*"/>
                        <edit
                            jcr:primaryType="nt:unstructured"
                            features="[paste-wordhtml]"/>
                        <findreplace
                            jcr:primaryType="nt:unstructured"
                            features="*"/>
                        <paraformat
                            jcr:primaryType="nt:unstructured"
                            features="*"/>
                        <subsuperscript
                            jcr:primaryType="nt:unstructured"
                            features="*"/>
                        <misctools
                            jcr:primaryType="nt:unstructured"
                            features="*"/>
                        <links
                            jcr:primaryType="nt:unstructured"
                            features="*"/>
                        <spellcheck
                            jcr:primaryType="nt:unstructured"
                            features="*"
                            invalidStyle="background-color: #ffdddd;"/>
                        <undo
                            jcr:primaryType="nt:unstructured"
                            features="*"/>
                        <image
                            jcr:primaryType="nt:unstructured"
                            features="*"/>
                    </rtePlugins>
                </text>
                <textResourceType
                    jcr:primaryType="cq:Widget"
                    ignoreData="{Boolean}true"
                    name="./jcr:content/par/text/sling:resourceType"
                    value="foundation/components/text"
                    xtype="hidden"/>
                <richFlag
                    jcr:primaryType="cq:Widget"
                    ignoreData="{Boolean}true"
                    name="./jcr:content/par/text/textIsRich"
                    value="true"
                    xtype="hidden"/>
                <image
                    jcr:primaryType="cq:Widget"
                    border="true"
                    cropParameter="./jcr:content/par/image/imageCrop"
                    ddGroups="[media]"
                    fieldLabel="Image"
                    fileNameParameter="./jcr:content/par/image/fileName"
                    fileReferenceParameter="./jcr:content/par/image/fileReference"
                    height="400"
                    hideLabel="false"
                    mapParameter="./jcr:content/par/image/imageMap"
                    name="./jcr:content/par/image/file"
                    requestSuffix="/jcr:content/par/image.img.png"
                    rotateParameter="./jcr:content/par/image/imageRotate"
                    sizeLimit="100"
                    xtype="html5smartimage"/>
                <imageResourceType
                    jcr:primaryType="cq:Widget"
                    ignoreData="{Boolean}true"
                    name="./jcr:content/par/image/sling:resourceType"
                    value="foundation/components/image"
                    xtype="hidden"/>
            </items>
        </tab1>
        <tab4
            jcr:primaryType="cq:Panel"
            title="Tags / Keywords">
            <items jcr:primaryType="cq:WidgetCollection">
                <tags
                    jcr:primaryType="cq:Widget"
                    name="./jcr:content/cq:tags"
                    xtype="tags"/>
            </items>
        </tab4>
    </items>
</jcr:root>

AEM CQ 561 - Working with Launches

Goal


Create a future release of page. Launches feature is useful when a business user likes to add or modify content released (promoted) to publish in a future date. Any content added in current source page is optionally, automatically synced, so that launch page always has latest content.

Creating a Launch


1) Access Geometrixx English page http://localhost:4502/cf#/content/geometrixx/en.html and make a copy of it ( Sidekick -> Page tab -> Copy Page). We'll work on the copy





2) Goto Websites console http://localhost:4502/siteadmin, select the page and click New Launch from grid toolbar






3) Enter name for launch ( visible in Sidekick for identifying this launch ). The Launch date entered below is for informational purpose and content is not automatically promoted when date is reached





4)  You can now access the created launch from control center http://localhost:4502/libs/launches/content/admin.html, but a better way is to reach from source page context; Access the page http://localhost:4502/cf#/content/geometrixx/en1.html -> Sidekick -> Versioning tab -> Launches -> (Select launch) Future English Page and click Switch to open launch page http://localhost:4502/cf#/content/launches/future_english_page/content/geometrixx/en1.html




5) Let try the auto content sync; Modify source page http://localhost:4502/cf#/content/geometrixx/en1.html and content updates automatically propagate to launch page. Click the Launches Switch in sidekick to see if launch page is modified





6) While you are on launch page http://localhost:4502/cf#/content/launches/future_english_page/content/geometrixx/en1.html modify the page (add new components)





7) As content is still not promoted, launch page content is different form source page http://localhost:4502/cf#/content/geometrixx/en1.html

8) Click on launch page http://localhost:4502/cf#/content/launches/future_english_page/content/geometrixx/en1.html -> Sidekick -> Page tab -> Promote Launch





9) Check source page http://localhost:4502/cf#/content/geometrixx/en1.html, and you can see the content promoted for activation





10) So launches are a convenient way to leisurely work on future versions of page without creating an entirely new page

AEM CQ 561 - Using Manuscripts

Goal


Add a Manuscript on Geometrixx page. Manuscripts are simple text files particularly useful for a business user who likes to create content pieces or articles in a simple text editor with no unsightly text-formatting controls like the ones you see in a WYSIWYG editor. Drag and drop features make it easy for presentation editors to add them across pages. A manuscripts Article Component example is also available on Geometrixx Media site /content/geometrixx-media/en/entertainment/summer-blockbuster-hits-and-misses.html. Check demo

Solution


1) Access manuscripts admin page http://localhost:4502/manuscriptsadmin

2) Select a folder and click New in right panel

3) Enter title Quick Brown Fox, click Create



4) Double click on the created manuscript to open copy editor /quick-brown-fox.copyeditor.html

6) Copy or enter content. Here a single # before Header text marks it as html H1. click Save on top right in editor to save content



7)  Open a page in design mode and add Article component of Geometrixx Media in allowed components of par



8) Drag and drop Article component onto the par from sidekick



9) Drag and drop the Quick Brown Fox manuscript from content finder onto the added Article component




10) The same manuscript can be reused on any number of pages and can be modified using the copy editor



AEM CQ 6 - Add new left rail nav item

Goal


Add a new left rail nav item in Touch UI console. To reach user admin an AEM user has to navigate through sub navs Tools -> Operations -> Security -> Users, here we provide a link on left rail main nav


Solution - 1


New in AEM(CQ) 6 is Sling Resource Merger. With resource merger you overlay the path in /apps and add only new nav items (in this case, Users)

1) Create the following folders in CRXDE Lite (http://localhost:4502/crx/de) or use the overlay creator servlet discussed here

            /apps/cq - nt:folder
            /apps/cq/core - nt:folder
            /apps/cq/core/content - sling:OrderedFolder
            /apps/cq/core/content/nav - nt:unstructured

    The structure above is an overlay of /libs/cq/core/content/nav

2) Create node /apps/cq/core/content/nav/users of type nt:unstructured with the following properties

             id - experience-aem-nav-users
             href - /libs/granite/security/content/useradmin.html
             jcr:description - Manage your users
             jcr:title - Users

     All properties are self-explanatory. Property id is to uniquely identify the nav item

     To position the newly created nav item, for example before Apps in the left rail, you can use property sling:orderBefore set to apps

Solution - 2


Taking a programmatic approach...

1) Login to CRXDE Lite (http://localhost:4502/crx/de) and create folder /apps/add-left-rail-item-users

2) Create node /apps/add-left-rail-item-users/clientlib of type cq:ClientLibraryFolder and add a String property categories with value granite.ui.foundation.admin

3) Create file (nt:file) /apps/add-left-rail-item-users/clientlib/js.txt and add

                       add-nav-item-user.js

4) Create file (nt:file) /apps/add-left-rail-item-users/clientlib/add-nav-item-user.js and add the following code

(function(document, Granite, $) {
    "use strict";

    $(document).on("ready", function() {
        //id of left rail nav is added by CQ here /libs/cq/core/content/nav
        var pRoot = $("nav[data-coral-columnview-id=root]");
        pRoot.first().append("<a class='coral-ColumnView-item' href='/libs/granite/security/content/useradmin.html'>Users</a>")
    });
})(document, Granite, Granite.$);

AEM CQ 56 - Add new Switcher (Top Menu) Item

Goal


Add a link in welcome screen (http://localhost:4502/libs/cq/core/content/welcome.html) and new switcher (top menu) item in Classic UI console (/siteadmin, /damadmin etc.)

In the following steps we are going to add a sample CRXDE switcher item for navigating to CRXDE (http://localhost:4502/crx/de/index.jsp)

Package Install


Welcome screen




Classic UI




Solution


1) To overlay, create folder /apps/wcm of type nt:folder and /apps/wcm/core of type nt:folder

2) Create folder /apps/wcm/core/content of type sling:Folder

3) Create node /apps/wcm/core/content/crxde of type cq:Widget and following properties (another way is to copy /libs/wcm/core/content/siteadmin to /apps/wcm/core/content, rename accordingly, use vlt to sync node to your IDE and update the xml with necessary properties )

<?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"
    jcr:mixinTypes="[cq:Console]"
    jcr:primaryType="cq:Widget"
    sling:redirect="{Boolean}false"
    sling:resourceType="/apps/switcher-item-crxde/sample-crxde"
    sling:vanityOrder="{Long}143"
    sling:vanityPath="/sample-crxde"
    consoleDescription="Show CRXDE"
    consoleTitle="CRXDE"
    iconClass="crxde"
    jsLibs="[cq.wcm.admin]"
    title="CRXDE"/>


4) The property sling:resourceType above is basically the action associated with that switcher item; so on click, user is taken to resource /apps/switcher-item-crxde/sample-crxde. Lets create the necessary resource component

5) Create folder /apps/switcher-item-crxde of type nt:folder 

6) For adding necessary icon css ( iconClass property in step 3 ) create clientlib /apps/switcher-item-crxde/clientlib of type cq:ClientLibraryFolder with categories of type String[] and values cq.shared cq.widgets




7) Create file (nt:file) /apps/switcher-item-crxde/clientlib/css.txt, add
               
                                               ui.css

8) Create file (nt:file) /apps/switcher-item-crxde/clientlib/ui.css, add

#cq-switcher .cq-switcher-crxde {
    background: url(/crx/de/icons/16x16/unstructured.png) no-repeat;
}

#cq-switcher .cq-switcher-crxde-inactive {
    background: url(/crx/de/icons/16x16/unstructured.png) no-repeat;
}

#apps .crxde {
    background: url(/crx/de/icons/16x16/unstructured.png) no-repeat scroll 15px 20px transparent;
}


9) Create node /apps/switcher-item-crxde/sample-crxde of type sling:Folder 

10) Create file (nt:file) /apps/switcher-item-crxde/sample-crxde/sample-crxde.jsp, add the following code for redirecting user to CRXDE

<script>
    window.location.href = "/crx/de";
</script>



AEM CQ 56 - Sort Tree Nodes of Browse Dialog in pathfield

Goal


Sort browse dialog tree nodes of pathfield (CQ.form.PathField) on dialog open.

Package install (contains a sample component using sortable pathfield)


Browse dialog of Product





Browse dialog tree nodes in descending order



Solution


1) Login to CRXDE Lite (http://localhost:4502/crx/de) and create folder /apps/sort-pathfield-tree

2) Create node /apps/sort-pathfield-tree/clientlib of type cq:ClientLibraryFolder and add a String property categories with value cq.widgets

3) Create file (nt:file) /apps/sort-pathfield-tree/clientlib/js.txt and add

                       sort-tree-nodes.js

4) Create file (nt:file) /apps/sort-pathfield-tree/clientlib/sort-tree-nodes.js and add the following code

CQ.Ext.ns("ExperienceAEM");

//asc=true for ascending order and asc=false for descending order
ExperienceAEM.sortTags =  function(pathfield, asc){
    pathfield.browseDialog.treePanel.on('load', function(node){
        node.childNodes.sort(function(a,b){
            a = a["text"].toLowerCase();
            b = b["text"].toLowerCase();
            return asc ? ( a > b ? 1 : (a < b ? -1 : 0) ) : ( a > b ? -1 : (a < b ? 1 : 0) ) ;
        });
    })
};

5) Here is a sample component dialog using sort on pathfield

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root 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:Dialog"
    helpPath="en/cq/current/wcm/default_components.html#Text"
    title="Text"
    xtype="tabpanel">
    <items jcr:primaryType="cq:WidgetCollection">
        <tab1
            jcr:primaryType="cq:Widget"
            anchor="100%"
            title="Text"
            xtype="panel">
            <items jcr:primaryType="cq:WidgetCollection">
                <path
                    jcr:primaryType="cq:Widget"
                    fieldLabel="Select path"
                    name="./path"
                    xtype="pathfield">
                    <listeners
                        jcr:primaryType="nt:unstructured"
                        dialogopen="function(){ExperienceAEM.sortTags(this, false);} "/>
                </path>
            </items>
        </tab1>
    </items>
</jcr:root>





AEM CQ 561 - Slide Show Component

Goal


Download package install for creating a simple slide show component. For Touch UI check this post

This component uses multi-image widget discussed here

The multi-image widget script was enhanced to support additional textfields, textareas etc. In the slide show created we add a textfield for title and textarea for description overlayed on image displayed

Add images using drag and drop from content finder, as the upload functionality in image widget has a bug yet to be fixed

Thank you David Gonzalez, Justin Edelson for ideas in developing this show...

Please leave a comment if you find bugs


Bug Fixes

Tested on AEM 6 SP2 Classic UI - Fix for Unable to drop images after removing existing multifield item (workaround was - after removing item, ok the dialog and reopen it to add new items)

Demo of Remove | Package Install

Tested with AEM 61 Classic UI - Add Item should appear at the end (after last multifield item) so that user doesn't need to scroll to the beginning of multifield for adding a new multifield item

Demo | Package Install


Single Image in Multifield item


Check Demo for single image in multifield item

Dialog

As xml

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="cq:Dialog"
    activeTab="{Long}0"
    title="Slideshow Images"
    xtype="tabpanel">
    <items jcr:primaryType="cq:WidgetCollection">
        <basic
            jcr:primaryType="cq:Widget"
            title="Images"
            xtype="panel">
            <items jcr:primaryType="cq:WidgetCollection">
                <images
                    jcr:primaryType="cq:Widget"
                    border="false"
                    name="./images"
                    xtype="imagemultifield">
                    <fieldConfig
                        jcr:primaryType="cq:Widget"
                        border="false"
                        layout="form"
                        xtype="imagemultifieldpanel">
                        <items jcr:primaryType="cq:WidgetCollection">
                            <title
                                jcr:primaryType="cq:Widget"
                                fieldLabel="Title Text"
                                name="./titleText"
                                width="250px"
                                xtype="textfield"/>
                            <description
                                jcr:primaryType="cq:Widget"
                                fieldLabel="Description Text"
                                name="./descText"
                                width="250px"
                                xtype="textarea"/>
                            <image
                                jcr:primaryType="cq:Widget"
                                cropParameter="./imageCrop"
                                ddGroups="[media]"
                                fieldLabel="Image"
                                fileNameParameter="./fileName"
                                fileReferenceParameter="./fileReference"
                                height="250"
                                imageSlingResourceType="foundation/components/parbase"
                                mapParameter="./imageMap"
                                name="./image"
                                rotateParameter="./imageRotate"
                                sizeLimit="100"
                                xtype="imagemultifieldsmartimage"/>
                        </items>
                    </fieldConfig>
                </images>
            </items>
        </basic>
    </items>
</jcr:root>


Dialog on Page




The Component instance in CRXDE



Slideshow




Multiple Images in Multifield item


Check Demo for multiple images in a single multifield item

Dialog

As xml

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="cq:Dialog"
    activeTab="{Long}0"
    title="Slideshow Images"
    xtype="tabpanel">
    <items jcr:primaryType="cq:WidgetCollection">
        <basic
            jcr:primaryType="cq:Widget"
            title="Images"
            xtype="panel">
            <items jcr:primaryType="cq:WidgetCollection">
                <images
                    jcr:primaryType="cq:Widget"
                    border="false"
                    name="./images"
                    xtype="imagemultifield">
                    <fieldConfig
                        jcr:primaryType="cq:Widget"
                        border="false"
                        layout="form"
                        xtype="imagemultifieldpanel">
                        <items jcr:primaryType="cq:WidgetCollection">
                            <title
                                jcr:primaryType="cq:Widget"
                                fieldLabel="Title Text"
                                name="./titleText"
                                width="250px"
                                xtype="textfield"/>
                            <description
                                jcr:primaryType="cq:Widget"
                                fieldLabel="Description Text"
                                name="./descText"
                                width="250px"
                                xtype="textarea"/>
                            <first
                                jcr:primaryType="cq:Widget"
                                cropParameter="./imageCrop"
                                ddGroups="[media]"
                                fieldLabel="First Image"
                                fileNameParameter="./fileName"
                                fileReferenceParameter="./fileReference"
                                height="250"
                                imageSlingResourceType="foundation/components/parbase"
                                mapParameter="./imageMap"
                                name="./first"
                                rotateParameter="./imageRotate"
                                sizeLimit="100"
                                xtype="imagemultifieldsmartimage"/>
                            <second
                                jcr:primaryType="cq:Widget"
                                cropParameter="./imageCrop"
                                ddGroups="[media]"
                                fieldLabel="Second Image"
                                fileNameParameter="./fileName"
                                fileReferenceParameter="./fileReference"
                                height="250"
                                imageSlingResourceType="foundation/components/parbase"
                                mapParameter="./imageMap"
                                name="./second"
                                rotateParameter="./imageRotate"
                                sizeLimit="100"
                                xtype="imagemultifieldsmartimage"/>
                        </items>
                    </fieldConfig>
                </images>
            </items>
        </basic>
    </items>
</jcr:root>


Dialog on page




Slideshow