Every developer have experienced a situation where they are working with AEM multiple AEM components, where Touch UI dialogues consist of a common richtext Granite UI component configuration cq/gui/components/authoring/dialog/richtext. When I mention common richtext Granite UI component, I mean there are multiple AEM components that will have the richtext Granite UI component as one of it’s input fields, where only the “links*” and “format*” richtext features are enabled, as an example.
Enabling only the “links*” and “format*” richtext features, we catch ourselves repeating lines of code by copying and pasting the entire block of code for all of our Touch UI dialogues that require the richtext requirement. This works, but this is Write Everything Twice, “WET” code, and it’s not good implementation; this can be improved. What happens if there is a new requirement where the authors would like a new capability to the richtext field? Will we have to edit multiple dialogues? (like editing 20 component’s dialogues) The short answer is Yes. With this “WET” implementation, you must edit every single component’s dialogue configuration.
How can we do this better? How keep our code Don’t Repeat Yourself (DRY)?
Utilising the Granite UI component, granite/ui/components/coral/foundation/include, we are able to refer to common Granite UI component configurations in the JCR (that we are going to set up). Now changing the richtext configuration in one place will provide TouchUI dialogue changes to all 20+ components; see diagram below.
Advantages of using common richtext configurations
- Ease to read and maintain
- Reusability of the code
- Reduces uneseccary lines of code in the repo
- common Granite UI configs are easily accessible to manipulate
With the improvement, with the diagram above, you will notice multiple AEM components’ Touch UI dialogue utilises the common Granite UI component configuration in the JCR, for the richtext Granite UI component configurations.
The Implementation
In this section, code will be shared on how this configuration can be applied to your own AEM implementation. The example produced will be a summary of the diagram from above.
1. Register the common dialog namespace
We typically place the common Granite UI component configurations for “content TouchUI” in the JCR under a namespaced project, for example: /apps/sourcedcodeaem/components/dialogs/content/common.
You will notice that there are already 3 folders that I have created.
- fields – fields that are commonly used by Touch UI dialogue configs (for this article we will only be focusing on these configs)
- fieldsets – fieldsets that are commonly used by Touch UI dialogue configs; these consist of more than 1 Granite UI component which is wrapped around a granite/ui/components/foundation/container.
- tabs – tabs that are commonly used by Touch UI dialogue configs; these consist of more than 1 Granite UI component which is wrapped around a granite/ui/components/foundation/container.
2. Create and configure the common Granite UI component configurations, under the “fields” structure
/apps/sourcedcodeaem/components/dialogs/content/common/fields/_cq_dialog/.content.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <?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="Common Field Granite UI Config for Content Components" sling:resourceType="cq/gui/components/authoring/dialog"> <commonFields jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container"> <items jcr:primaryType="nt:unstructured"> <basicRTE jcr:primaryType="nt:unstructured" sling:resourceType="cq/gui/components/authoring/dialog/richtext"> <rtePlugins jcr:primaryType="nt:unstructured"> <format jcr:primaryType="nt:unstructured" features="*"/> <links jcr:primaryType="nt:unstructured" features="*"/> </rtePlugins> <uiSettings jcr:primaryType="nt:unstructured"> <cui jcr:primaryType="nt:unstructured"> <inline jcr:primaryType="nt:unstructured" toolbar="[links#modifylink,links#unlink,format#bold,format#italic]"/> <dialogFullScreen jcr:primaryType="nt:unstructured" toolbar="[links#modifylink,links#unlink,format#bold,format#italic]"/> </cui> </uiSettings> </basicRTE> </items> </commonFields> </jcr:root> |
3. From the targeted component, include the common Granite UI config
/apps/sourcedcodeaem/components/content/announcement
- line:32 – the standard, cq/gui/components/authoring/dialog/richtext, Granite UI component is being referred.
- line:38 – inclusion of the common richtext “rtePlugins” configuration, /apps/sourcedcodeaem/components/dialogs/content/common/fields/cq:dialog/commonFields/items/basicRTE/rtePlugins
- line:42 – inclusion of the common richtext “uiSettings” configuration, /apps/sourcedcodeaem/components/dialogs/content/common/fields/cq:dialog/commonFields/items/basicRTE/uiSettings
Together with line:32,38,42 the common richtext component will be setup and ready to be used.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | <?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="Announcement Component" 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/tabs" type="nav"/> <items jcr:primaryType="nt:unstructured"> <text jcr:primaryType="nt:unstructured" jcr:title="Hero Settings" sling:resourceType="granite/ui/components/foundation/section"> <layout jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns" margin="{Boolean}false"/> <items jcr:primaryType="nt:unstructured"> <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container"> <items jcr:primaryType="nt:unstructured"> <headerText jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/textfield" fieldLabel="Title Text" name="./headerText"/> <headingDescriptionText jcr:primaryType="nt:unstructured" sling:resourceType="cq/gui/components/authoring/dialog/richtext" name="./headingDescriptionText" required="true" useFixedInlineToolbar="{Boolean}true"> <rtePlugins jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/include" path="/apps/sourcedcodeaem/components/dialogs/content/common/fields/cq:dialog/commonFields/items/basicRTE/rtePlugins"/> <uiSettings jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/include" path="/apps/sourcedcodeaem/components/dialogs/content/common/fields/cq:dialog/commonFields/items/basicRTE/uiSettings"/> </headingDescriptionText> </items> </column> </items> </text> </items> </content> </jcr:root> |
4. Done
Now we have successfully referenced an AEM component to the common Touch UI dialogue field.