Article summary

Summary

Discusses how to create an Adobe Experience Manager multi-field component that supports a rich text editor and lets an AEM author drag images from the Content Finder and drop them into the component. This article covers the following points:

  • how to work with rich text plugins
  • how to develop and register a custom xtype
  • how to work with multifield component
  • how to control the behaviour of the component using a cq:EditConfig node
  • how to style the component (for example, add a strike through style)
  • how to use drag and drop functionality

A special thank you to Dheeraj Khanna, a CQ Solution Architect for helping with this development article.   

This article creates a custom xtype as part of creating a larger AEM component. Before reading this article, it is recommended that you are familiar with creating a custom xtype. For information, see Creating your first Adobe Experience Manager custom xtype.

Digital Marketing Solution(s) Adobe Experience Manager (Adobe CQ)
Audience
Developer (intermediate)
Required Skills
JavaScript, CSS, HTML
Tested On Adobe Experience Manager 5.5, 5.6

Note:

Download the multifield component from the following link. This article explains how to build the component and the application logic. To see the Hero component, install this package and then configure the sidekick to show the Nook category in Design mode. 

Once you install using package manager, you can access the page using this URL: http://localhost:4502/cf#/content/nook/en_US/homepage.html

Download

Introduction

You can create an Adobe Experience Manager (AEM) multi-field component that supports a rich text editor and lets an AEM author drag images from the AEM Content Finder and drop them into the component. In addition, when creating an AEM component, you can define a custom xtype and use it in the component. The custom xtype is rendered in the component’s dialog and an AEM author enters value into the custom xtype controls during design time.  

Note:

Developing a custom xtype is discussed within this development article.  

The AEM component developed in this development article is used by the CQ parsys system and is placed onto the AEM sidekick. An AEM author can drag the component from the CQ sidekick onto an AEM page during design time.  

HeroWebPage

 

The following illustration shows the component that is created by following this development article. 

Hero

 

In the previous illustration, notice that an image is dragged from the AEM Content Finder onto the component. Also notice this component supports multiple tabs, where each tab contains different fields. For example, when the user clicks the Title tab, a new panel is displayed with an Add Item control.  

Title

 

When the user clicks Add Item, a Rich Text Editor (RTE) appears that lets the user enter text, as shown in the following illustration.  

TitleText

 

The text entered into the RTE is displayed under the Title section of the AEM web page.  

TitleOutput

The following illustration shows the file structure of the AEM component that is developed in this article. 

FileStruc

The following table describes these AEM component files.  

Section Description
A The JS files that contain the JavaScript logic that defines a custom xtype. When defining a custom xtype, you use out-of-the-box xtype data types available with AEM (this is shown later in this development article).
B

The cq:dropTargets node defines the drop zone that lets AEM authors drag images from the Content Finder and drop them onto the component (see the illustration shown at the start of the development article).

The cq:inplaceEditing node (type cq:InplaceEditingConfig) defines an in place editing configuration for the component.

The cq:listeners (node type cq:EditListenersConfig) defines what happens before or after an action occurs on the component.
 

C

JCR nodes that belong to the component’s dialog. Notice that each node under the items node corresponds to a tab located in the component’s dialog. That is, there are seven tabs in the dialog:

  • Style and Hero image: corresponds to the style node
  • Title: corresponds to the title node
  • Sub title: corresponds to the subtitle node
  • Description: corresponds to the description node
  • Footnote: corresponds to the footnote node
  • Links: corresponds to the links node (this tab displays a control that is based on a custom xtype and defined in CustomWidget.js)
  • Images: corresponds to the otherimages node.  
D JCR nodes that are used as plug-ins for the Rich Text Editor.  

This development article steps you through how to build this AEM component using a custom xtype, JavaScript, JCR nodes, and CSS files. Once you read through this article, you will have a solid understanding of how to build an AEM custom component, including how to develop a custom xtype.

Create an Experience Manager application folder structure

Create an Experience Manager application folder structure that contains templates, components, and pages by using CRXDE Lite. 

CQAppSetup

The following describes each application folder:

  • application name: contains all of the resources that an application uses. The resources can be templates, pages, components, and so on.
  • components: contains components that your application uses.
  • page: contains page components. A page component is a script such as a JSP file.
  • global: contains global components that your application uses.
  • template: contains templates on which you base page components.
  • src: contains source code that comprises an OSGi component (this development article does not create an OSGi bundle using this folder).
  • install: contains a compiled OSGi bundles container.

To create an application folder structure:

  1. To view the CQ welcome page, enter the URL http://[host name]:[port] into a web browser. For example, http://localhost:4502.
  2. Select CRXDE Lite.
  3. Right-click the apps folder (or the parent folder), select Create, Create Folder.
  4. Enter the folder name into the Create Folder dialog box. Enter hook.
  5. Repeat steps 1-4 for each folder specified in the previous illustration.
  6. Click the Save All button.
     

Note:

You have to click the Save All button when working in CRXDE Lite for the changes to be made. 

Create a template  

You can create a template by using CRXDE Lite. A template enables you to define a consistent style for the pages in your application. A template comprises of nodes that specify the page structure. For more information about templates, see Templates.

To create a template, perform these tasks:

1. To view the welcome page, enter the URL http://[host name]:[port] into a web browser. For example, http://localhost:4502.

2. Select CRXDE Lite.

3. Right-click the template folder (within your application), select Create, Create Template.


4. Enter the following information into the Create Template dialog box:

  • Label: The name of the template to create. Enter templateHook.
  • Title: The title that is assigned to the template.
  • Description: The description that is assigned to the template.
  • Resource Type: The component's path that is assigned to the template and copied to implementing pages. Enter hook/components/page/templateHook.
  • Ranking: The order (ascending) in which this template will appear in relation to other templates. Setting this value to 1 ensures that the template appears first in the list.

5. Add a path to Allowed Paths. Click on the plus sign and enter the following value: /content(/.*)?.

6. Click Next for Allowed Parents.

7. Select OK on Allowed Children.
 

Create the page component based on the template 

Components are re-usable modules that implement specific application logic to render the content of your web site. You can think of a component as a collection of scripts (for example, JSPs, Java servlets, and so on) that completely realize a specific function. In order to realize this functionality, it is your responsibility as an Experience Manager developer to create scripts that perform specific functionality. For more information about components, see Components.

By default, a component has at least one default script, identical to the name of the component. To create a render component, perform these tasks:

1. To view the welcome page, enter the URL http://[host name]:[port] into a web browser. For example, http://localhost:4502.

2. Select CRXDE Lite.

3. Right-click /apps/hook/components/page, then select Create, Create Component.

4. Enter the following information into the Create Component dialog box:

  • Label: The name of the component to create. Enter templateHook.
  • Title: The title that is assigned to the component.
  • Description: The description that is assigned to the template.

5. Select Next for Advanced Component Settings and Allowed Parents.

6. Select OK on Allowed Children.

7. Open the templateHook.jsp located at: /apps/hook/components/page/templateHook/templateHook.jsp.

8. Enter the following HTML code.
 

<html>
<%@include file="/libs/foundation/global.jsp" %>
<cq:include script="/libs/wcm/core/components/init/init.jsp"/>
<body>
<h1>Here is where the component will go</h1>
<cq:include path="par" resourceType="foundation/components/parsys" />
</body>
</html>

Create the AEM multifield component that uses a custom xtype 

After you setup the AEM folder structure, create the multifield component that uses a custom xtype. Perform these tasks using CRXDE Lite:

1. Right click on /apps/hook/components and then select New, Component.
2. Enter the following information into the Create Component dialog box:

  • Label: The name of the component to create. Enter hero.
  • Title: The title that is assigned to the component. Enter AEM Hero component.
  • Description: The description that is assigned to the template. Enter AEM Hero component.
  • Super Resource Type: Enter foundation/components/parbase.
  • Group: The group in the side kick where the component appears. Enter Hook
  • Allowed parents: Enter */*parsys.

3. Click Ok.
 

Note:

The remaining part of this article talks about how to create the hero component that uses a custom xtype and allows an author to drag images from the AEM Content Finder. The hero.jsp file located at /apps/hook/components/hero/hero.jsp is populated with JavaScript logic later in this development article.  

Add a dialog to the multifield component 

A dialog lets an author click on the component during design time and enter values that are used by the component. The component created in this development article lets a user drag an image from the AEM Content Finder onto the component (see the illustration shown at the start of this development article). Once set in the AEM component, the image then appears in the AEM web page.

To add a dialog to the hero component, perform these tasks:

1. Select /apps/hook/components/hero, right click and select Create, Create Dialog.
2. In the Title field, enter Hero Component.
3. Click Ok.
4. Delete the tab1 node under /apps/hook/components/hero/dialog/items/items.
 

Creating the Style and Hero Image tab 

Create the first tab in the dialog titled Style and Hero. The following illustration shows this tab in the CQ dialog.  

StyleTab

 

You build the controls on this tab by setting JCR nodes and properties. Once done, your dialog nodes for this tab resembles the following illustration. 

Style

 

The options node corresponds to the Display Type drop-down control. Under the options node, there are children nodes named o1, o2, o3, and o4. These children nodes define the text values that are displayed in the Display Type drop down control.

To create the Style and Hero Image tab, perform these tasks:

1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: style
  • Type: cq:Panel

3. Select the /apps/hook/components/hero/dialog/items/items/style node.
4. Add the following property to the style node.

Name Type   Value Description
title String Style and Hero Image Specifies the title displayed on the dialog tab.

5. Select the /apps/hook/components/hero/dialog/items/items/style node.

6. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: cq:WidgetCollection

7. Select the /apps/hook/components/hero/dialog/items/items/style/items node.

8. Right click and select Create, Create Node. Enter the following values:

  • Name: type
  • Type: cq:Widget

9. Add the following properties to the type node.

Name Type Value Description
anchor String 60% An anchor that belongs to the component.
fieldLabel String Display Type Specifies the field label that is displayed.  
name String ./displayType Specifies the name of the control. You can reference this value in component’s JavaScript file (hero.js) to get the value of this field.&nbsp; For example:

<%String displayType = properties.get("displayType", String.class);%>
type String select Specifies the type of control.
xtype String selection Specifies the data type of the control. The value selection corresponds to the CQ.form.Selection xtype. For information, see Class CQ.form.Selection.

10. Select /apps/hook/components/content/hero/dialog/items/items/style/items/type.
11. Right click and select Create, Create Node. Enter the following values:

  • Name: options
  • Type: cq:WidgetCollection

Note:

This node is responsible for defining the values that appear in the displayType selection field. 

12. Select /apps/hook/components/hero/dialog/items/items/style/items/type/options.
13. Right click and select Create, Create Node. Enter the following values:

  • Name: o1
  • Type: nt:unstructured

14. Select the /apps/hook/components/hero/dialog/items/items/style/items/type/options/o1 node.
15. Add the following properties to the o1 node.

Name Type Value Description
text String Image on Left of Content Specifies the text that is displayed.
value String imageLeft Specifies the corresponding value.

16. Select /apps/hook/components/hero/dialog/items/items/style/items/type/options.
17. Right click and select Create, Create Node. Enter the following values:

  • Name: o2
  • Type: nt:unstructured

18. Select the /apps/hook/components/hero/dialog/items/items/style/items/type/options/o2 node.
19. Add the following properties to the o2 node.

Name Type Value Description
text String Image on Right of Content
Specifies the text that is displayed.
value String imageRight
Specifies the corresponding value.

20. Select /apps/hook/components/hero/dialog/items/items/style/items/type/options.
21. Right click and select Create, Create Node. Enter the following values:

  • Name: o3
  • Type: nt:unstructured

22. Select the /apps/hook/components/hero/dialog/items/items/style/items/type/options/o3 node.
23. Add the following properties to the o3 node.

Name Type Value Description
text String Image on Top of Content
Specifies the text that is displayed.
value String imageTop
Specifies the corresponding value.

24. Select /apps/hook/components/hero/dialog/items/items/style/items/type/options.
25. Right click and select Create, Create Node. Enter the following values:

  • Name: o4
  • Type: nt:unstructured

26. Select the /apps/hook/components/hero/dialog/items/items/style/items/type/options/o4 node.
27. Add the following properties to the o4 node.

Name Type Value Description
text String Image on Bottom of Content
Specifies the text that is displayed.
value String imageBottom
Specifies the corresponding value.

28. Select the /apps/hook/components/hero/dialog/items/items/style/items node.
29. Right click and select Create, Create Node. Enter the following values:

  • Name: imageurl
  • Type: cq:Widget

30. Add the following properties to the imageurl node.

Name Type Value Description
anchor String 60% An anchor that belongs to the component.
fieldLabel String Image Action Link Specifies the corresponding value.
name String ./imageurl Specifies the name of the control.  
xtype String textfield Specifies the data type of the control. This value corresponds to CQ.Ext.form.TextField. For information, see CQ.Ext.form.TextField.

31. Select the /apps/hook/components/hero/dialog/items/items/style/items node.
32. Right click and select Create, Create Node. Enter the following values:

  • Name: imagealttext
  • Type: cq:Widget

33. Add the following properties to the imagealttext node.

Name Type Value Description
anchor String 60% An anchor that belongs to the component.
fieldLabel String Image Alt Text Specifies the field label.  
name String ./imagealttext Specifies the name of the control.  
xtype String textfield Specifies the data type of the control. This value corresponds to CQ.Ext.form.TextField. For information, see CQ.Ext.form.TextField.

34. Select the /apps/hook/components/hero/dialog/items/items/style/items node.
35. Right click and select Create, Create Node. Enter the following values:

  • Name: image
  • Type: cq:Widget

36. Add the following properties to the image node.

Name Type Value Description
cropParameter String ./imageCrop Name of the form field used for posting the cropping rect.
ddGroups String[] media Groups involved in drag & drop (no default specified).
fileNameParameter String ./fileName Name of the form field used for posting the file name.  
fileReferenceParameter String ./fileReference Name of the form field used for posting the file reference.
height Long 300 Height of the SmartImage component.
mapParameter String ./imageMap Name of the form field used for posting the image map data.
name String ./file The field's HTML name attribute.
requestSuffix String .img.png This suffix is used to get the processed version of an image. It is simply appended to the data path.
rotateParameter String ./imageRotate Name of the form field used for posting the rotation angle.
title String Image The title text to be used as innerHTML (html tags are accepted) to display in the panel header.
xtype String html5smartimage Specifies the data type of the control. The value selection corresponds to CQ.form.SmartImage. For information, see Class CQ.form.SmartImage

Creating the Title tab 

Create the second tab in the dialog named Title. The following illustration shows this tab in the CQ dialog.  

Title

You build the controls on this tab by setting nodes and properties. Once done, your dialog resembles the following illustration. 

titleDialog

To create the title tab, perform these tasks:

1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: title
  • Type: cq:Panel

3. Select the /apps/hook/components/hero/dialog/items/items/title node.
4. Add the following property to the title node.

Name Type Value Description
title String Title Specifies the title displayed on the dialog tab.

5. Select the /apps/hook/components/hero/dialog/items/items/title node.
6. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: cq:WidgetCollection

7. Select the /apps/hook/components/hero/dialog/items/items/title/items node.
8. Right click and select Create, Create Node. Enter the following values:

  • Name: title
  • Type: cq:Widget

9. Add the following properties to the title node.

Name Type Value Description
externalStyleSheets String /apps/hook/components/hero/clientlib/css/static.css Specifies the CSS file to use. (This style sheet is created in a later step.)
fieldLabel String Title Specifies the field label that is displayed.  
name String ./title Specifies the name of the control. You can reference this value in component’s JavaScript file (hero.js) to get the value of this field.
xtype String multifield Specifies the data type of the control. The value selection corresponds to CQ.form.MultiField. For information, see CQ.form.MultiField.

10. Select the /apps/hook/components/hero/dialog/items/items/title/items/title node.
11. Right click and select Create, Create Node. Enter the following values:

  • Name: fieldConfig
  • Type: nt:unstructured

12. Select the /apps/hook/components/hero/dialog/items/items/title/items/title/fieldConfig node.
13. Add the following properties to the fieldConfig node.

Name Type Value Description
externalStyleSheets String[] /apps/hook/components/hero/clientlib/css/static.css Specifies the CSS file to use. (This style sheet is created in a later step.) 
removeSingle
ParagraphContainer
 
Boolean true True if the paragraph element of texts that consist only of a single paragraph.  
xtype String richtext  Specifies the data type of the control. The value selection corresponds to CQ.form.RichText. For information, see CQ.form.RichText

14. Select the /apps/hook/components/hero/dialog/items/items/title/items/title/fieldConfig node.
15. Right click and select Create, Create Node. Enter the following values:

  • Name: rtePlugins
  • Type: cq:Widget

16. Select the /apps/hook/components/hero/dialog/items/items/title/items/title/fieldConfig/rtePlugins node.
17. Add the following properties to the rtePlugins node.

Name Type Value Description
path String /apps/hook/components/rteconfig/rtePlugins.infinity.json The path to the rich text editor plugins. (These files are are developed later in this development article.)  
xtype String cqinclude Pseudo xtype that includes widget definitions from a different path in the AEM JCR repository.

Creating the Subtitle tab 

Create the third tab in the dialog named Subtitle. The following illustration shows this tab in the CQ dialog.  

subtitletab

You build the controls on this tab by setting nodes and properties. Once done, you dialog resembles the following illustration. 

subtitle

To create the subtitle tab, perform these tasks:

1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: subtitle
  • Type: cq:Panel

3. Select the /apps/hook/components/hero/dialog/items/items/subtitle node.
4. Add the following property to the subtitle node.

Name Type Value Description
title String Sub Title Specifies the title displayed on the dialog tab.

5. Select the /apps/hook/components/hero/dialog/items/items/subtitle node.
6. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: cq:WidgetCollection

7. Select the /apps/hook/components/hero/dialog/items/items/subtitle/items node.

8. Right click and select Create, Create Node. Enter the following values:

  • Name: subtitle
  • Type: cq:Widget

9. Add the following properties to the subtitle node.

Name Type Value Description
fieldLabel String Sub-Title Specifies the field label that is displayed.  
name String ./subtitle Specifies the name of the control. You can reference this value in component’s JavaScript file (hero.js) to get the value of this field.&nbsp;  
xtype String multifield Specifies the data type of the control. The value selection corresponds to CQ.form.MultiField. For information, see CQ.form.MultiField.

10. Select the /apps/hook/components/hero/dialog/items/items/subtitle/items/subtitle node.
11. Right click and select Create, Create Node. Enter the following values:

  • Name: fieldConfig
  • Type: nt:unstructured

12. Select the /apps/hook/components/hero/dialog/items/items/subtitle/items/subtitle/fieldConfig node.
13. Add the following properties to the fieldConfig node.

Name Type Value Description
externalStyleSheets String[] /apps/hook/components/hero/clientlib/css/static.css Specifies the CSS file to use. (This style sheet is created in a later step.)
removeSingle
ParagraphContainer
Boolean true True if the paragraph element of texts that consist only of a single paragraph.  
xtype String richtext Specifies the data type of the control. The value selection corresponds to CQ.form.RichText. For information, see CQ.form.RichText.

14. Select the /apps/hook/components/hero/dialog/items/items/subtitle/items/subtitle/fieldConfig node.
15. Right click and select Create, Create Node. Enter the following values:

  • Name: rtePlugins
  • Type: cq:Widget

16. Select the /apps/hook/components/hero/dialog/items/items/subtitle/items/subtitle/fieldConfig/rtePlugins node.
17. Add the following properties to the rtePlugins node.

Name Type Value Description
path String /apps/hook/components/rteconfig/rtePlugins.infinity.json The path to the rich text editor plugins. (These files are are developed later in this development article.)  
xtype String cqinclude Pseudo xtype that includes widget definitions from a different path in the AEM JCR repository.

Creating the Description tab 

Create the fourth tab in the dialog named Description. The following illustration shows this tab in the CQ dialog.  

DescTab

You build the controls on this tab by setting nodes and properties. Once done, you dialog resembles the following illustration. 

descriptiontab

To create the description tab, perform these tasks:
1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: description
  • Type: cq:Panel

3. Select the /apps/hook/components/hero/dialog/items/items/description node.
4. Add the following property to the description node.

Name Type Value Description
title  String  Description  Specifies the title displayed on the dialog tab. 

5. Select the /apps/hook/components/hero/dialog/items/items/description node.
6. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: cq:WidgetCollection

7. Select the /apps/hook/components/hero/dialog/items/items/description/items node.
8. Right click and select Create, Create Node. Enter the following values:

  • Name: description
  • Type: cq:Widget

9. Add the following properties to the description node.

Name Type Value Description
fieldLabel String Description Specifies the field label that is displayed.  
name String ./description Specifies the name of the control. You can reference this value in component’s JavaScript file (hero.js) to get the value of this field.
xtype String multifield Specifies the data type of the control. The value selection corresponds to CQ.form.MultiField. For information, see CQ.form.MultiField.

10. Select the /apps/hook/components/hero/dialog/items/items/description/items/description node.
11. Right click and select Create, Create Node. Enter the following values:

  • Name: fieldConfig
  • Type: nt:unstructured

12. Select the /apps/hook/components/hero/dialog/items/items/description/items/description/fieldConfig node.
13. Add the following properties to the fieldConfig node.

Name Type Value Description
externalStyleSheets String[] /apps/hook/components/hero/clientlib/css/static.css Specifies the CSS file to use. (This style sheet is created in a later step.)
removeSingle
ParagraphContainer
Boolean true True if the paragraph element of texts that consist only of a single paragraph.  
xtype String richtext Specifies the data type of the control. The value selection corresponds to CQ.form.RichText. For information, see CQ.form.RichText.

14. Select the /apps/hook/components/hero/dialog/items/items/description/items/description/fieldConfig node.
15. Right click and select Create, Create Node. Enter the following values:

  • Name: rtePlugins
  • Type: cq:Widget

16. Select the /apps/hook/components/hero/dialog/items/items/description/items/description/fieldConfig/rtePlugins node.
17. Add the following properties to the rtePlugins node.

Name Type Value Description
Path
String /apps/hook/components/rteconfig/rtePlugins.infinity.json The path to the rich text editor plugins. (These files are are developed later in this development article.)  
xtype String cqinclude Pseudo xtype that includes widget definitions from a different path in the AEM JCR repository.

Creating the Footnote tab

Create the fifth tab in the dialog named Footnote. The following illustration shows this tab in the CQ dialog.

 

footnoteDialog

You build the controls on this tab by setting nodes and properties. Once done, you dialog resembles the following illustration. 

footnote

To create the footnote tab, perform these tasks:
1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: footnote
  • Type: cq:Panel

3. Select the /apps/hook/components/hero/dialog/items/items/footnote node.
4. Add the following property to the footnote node.

Name Type Value Description
title String Footnote Specifies the title displayed on the dialog tab.

5. Select the /apps/hook/components/hero/dialog/items/items/footnote node.
6. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: cq:WidgetCollection

7. Select the /apps/hook/components/hero/dialog/items/items/footnote/items node.
8. Right click and select Create, Create Node. Enter the following values:

  • Name: footnote
  • Type: cq:Widget

9. Add the following properties to the footnote node.

Name Type Value Description
fieldLabel String Footnote Specifies the field label that is displayed.  
name String ./footnote Specifies the name of the control. You can reference this value in component’s JavaScript file (hero.js) to get the value of this field.&nbsp;  
xtype String  multifield
Specifies the data type of the control. The value selection corresponds to CQ.form.MultiField. For information, see CQ.form.MultiField.

10. Select the /apps/hook/components/hero/dialog/items/items/footnote/items/footnote node.
11. Right click and select Create, Create Node. Enter the following values:

  • Name: fieldConfig
  • Type: nt:unstructured

12. Select the /apps/hook/components/hero/dialog/items/items/footnote/items/footnote/fieldConfig node.
13. Add the following properties to the fieldConfig node.

Name Type Value Description
externalStyleSheets String[] /apps/hook/components/hero/clientlib/css/static.css Specifies the CSS file to use. (This style sheet is created in a later step.)
removeSingle
ParagraphContainer
Boolean true True if the paragraph element of texts that consist only of a single paragraph.  
xtype String richtext Specifies the data type of the control. The value selection corresponds to CQ.form.RichText. For information, see CQ.form.RichText.

14. Select the /apps/hook/components/hero/dialog/items/items/footnote/items/footnote/fieldConfig node.
15. Right click and select Create, Create Node. Enter the following values:

  • Name: rtePlugins
  • Type: cq:Widget

16. Select the /apps/hook/components/hero/dialog/items/items/footnote/items/footnote/fieldConfig/rtePlugins node.
17. Add the following properties to the rtePlugins node.
 

Name Type Value Description
Path String /apps/hook/components/rteconfig/rtePlugins.infinity.json The path to the rich text editor plugins. (These files are are developed later in this development article.)  
xtype String cqinclude Pseudo xtype that includes widget definitions from a different path in the AEM JCR repository.

Creating the links tab 

Create the sixth tab in the dialog named Links. The following illustration shows this tab in the CQ dialog.  

linkTab

The links tab is based on a custom xtype that is created in this development article. That is, all three controls shown in the previous illustration are defined by a custom xtype.

The following illustration shows the dialog of the links tab.
 

Links

Note:

The name of the custom xtype is ejstcustom.

1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: links
  • Type: cq:Panel

3. Select the /apps/hook/components/hero/dialog/items/items/links node.
4. Add the following property to the links node.

Name Type Value Description
title String Links Specifies the title displayed on the dialog tab.

5. Select the /apps/hook/components/hero/dialog/items/items/links node.
6. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: cq:WidgetCollection

7. Select the /apps/hook/components/hero/dialog/items/items/links/items node.
8. Right click and select Create, Create Node. Enter the following values:

  • Name: links
  • Type: cq:Widget

9. Add the following properties to the links node.

Name Type Value Description
fieldLabel String Links Specifies the field label that is displayed.  
name String ./links Specifies the name of the control. You can reference this value in component’s JavaScript file (hero.js) to get the value of this field.   
xtype String multifield Specifies the data type of the control. The value selection corresponds to CQ.form.MultiField. For information, see CQ.form.MultiField.

10. Select the /apps/hook/components/hero/dialog/items/items/links/items/links node.
11. Right click and select Create, Create Node. Enter the following values:

  • Name: fieldConfig
  • Type: nt:unstructured

12. Select the /apps/hook/components/hero/dialog/items/items/links/items/links/fieldConfig node.
13. Add the following properties to the fieldConfig node.

Name Type Value Description
optionsProvider String Ejst.x3.provideOptions Specifies the custom xtype for this field.  
xtype String ejstcustom Specifies the name of the custom xtype. A custom xtype is defined by using JavaScript. Before this is successful, you have to register the custom xtype. (This is shown later in this development article.)

Creating the Images tab 

Create the final tab in the dialog named Images. The following illustration shows this tab in the CQ dialog.  

otherlinks

You build the controls on this tab by setting nodes and properties. Once done, your dialog resembles the following illustration. 

otherimagesdialog

To create the Images tab, perform these tasks:

1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: otherimages
  • Type: cq:Panel

3. Select the /apps/hook/components/hero/dialog/items/items/otherimages node.
4. Add the following property to the otherimages node.

Name Type Value Description
title String Images Specifies the title displayed on the dialog tab.

5. Select the /apps/hook/components/hero/dialog/items/items/otherimages node.
6. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: cq:WidgetCollection

7. Select the /apps/hook/components/hero/dialog/items/items/otherimages/items node.
8. Right click and select Create, Create Node. Enter the following values:

  • Name: image1
  • Type: cq:Widget

9. Add the following properties to the image1 node.

Name Type Value Description
ddGroups String[] media Groups involved in drag & drop (no default specified).
fieldLabel String Image1 Specifies the label of the control.  
fileNameParameter String ./image1/fileName Name of the form field used for posting the file name.  
fileReferenceParameter String ./image1/fileReference Name of the form field used for posting the file reference.
height Long 100 Height of the SmartImage component.
name String ./image1/image1file The field's HTML names attribute.
sling:resourceType String foundation/components/image
The Sling resource type.
title String Image1 The title text to be used as innerHTML (html tags are accepted) to display in the panel header.
width Long 200 Width of the SmartImage component.
xtype String html5smartimage Specifies the data type of the control. The value selection corresponds to CQ.form.SmartImage. For information, see Class CQ.form.SmartImage.

10. Select the /apps/hook/components/hero/dialog/items/items/otherimages/items node.
11. Right click and select Create, Create Node. Enter the following values:

  • Name: image2
  • Type: cq:Widget

12. Add the following properties to the image2 node.

Name Type Value Description
ddGroups String[] media Groups involved in drag & drop (no default specified).
fieldLabel String Image2 Specifies the label of the control.  
fileNameParameter String ./image2/fileName Name of the form field used for posting the file name.  
fileReferenceParameter String ./image2/fileReference Name of the form field used for posting the file reference.
height Long 100 Height of the SmartImage component.
name String ./image2/image1file The field's HTML names attribute.
sling:resourceType String foundation/components/image
The Sling resource type.
title String Image2 The title text to be used as innerHTML (html tags are accepted) to display in the panel header.
width Long 200 Width of the SmartImage component.
xtype String html5smartimage Specifies the data type of the control. The value selection corresponds to CQ.form.SmartImage. For information, see Class CQ.form.SmartImage.

13. Select the /apps/hook/components/hero/dialog/items/items/otherimages/items node.
14. Right click and select Create, Create Node. Enter the following values:

  • Name: image3
  • Type: cq:Widget

15. Add the following properties to the image3 node.

Name Type Value Description
ddGroups String[] media Groups involved in drag & drop (no default specified).
fieldLabel String Image3 Specifies the label of the control.  
fileNameParameter String ./image3/fileName Name of the form field used for posting the file name.  
fileReferenceParameter String ./image3/fileReference Name of the form field used for posting the file reference.
height Long 100 Height of the SmartImage component.
name String ./image3/image1file The field's HTML names attribute.
sling:resourceType String foundation/components/image
The Sling resource type.
title String Image3 The title text to be used as innerHTML (html tags are accepted) to display in the panel header.
width Long 200 Width of the SmartImage component.
xtype String html5smartimage Specifies the data type of the control. The value selection corresponds to CQ.form.SmartImage. For information, see Class CQ.form.SmartImage.

Add JavaScript files to a CQ:ClientLibraryFolder node 

Add the following JavaScript files to an AEM CQ:ClientLibraryFolder node:

  • CustomWidget.js: defines the custom xtype that is used in the Links tab. The name of the custom xtype is ejstcustom.
  • RichText.js: defines the rich text editor that is used in in the AEM component.
  • Component.js: defines helper methods used by the component.

To add these JS and CSS files to your component, add a cq:ClientLibraryFolder node. After you create the node, set properties that allow the component script to find the CSS files and the JS files. 

Name Type Value
dependencies String[] cq.widgets
categories String[] hook.components

Create JS files 

Create the required JS files to create the component. Place the JS files in a folder named js as shown in this illustration. 

JSFOlder

CustomWidget.js 

To develop a custom xtype, you can use a CQ.form.CompositeField instance, which is the base class for panels. A panel can include one or more form fields. For information, see class CQ.form.CompositeField

In this example, the CustomWidget.js file contains application logic that is responsible for defining and registering a custom xtype.

// register xtype
CQ.Ext.reg("ejstcustom", Ejst.CustomWidget);

The component’s dialog references the custom xtype. The following file represents the CustomWidget.js file.
 

Ejst.CustomWidget = CQ.Ext.extend(CQ.form.CompositeField, {

    /**
     * @private
     * @type CQ.Ext.form.TextField
     */
    hiddenField: null,

   /**
    * @private
    * @type CQ.Ext.form.TextField
    */
    linkText: null,

    /**
    * @private
    * @type CQ.Ext.form.TextField
    */
    linkHref: null,


    /**
     * @private
     * @type CQ.Ext.form.ComboBox
     */
    linkType: null,

    /**
     * @private
     * @type CQ.Ext.form.TextField
     */

    formPanel: null,
    
    constructor: function(config) {
        config = config || { };
        var defaults = {
            "border": true,
            "layout": "table",
            "columns":4
        };
        config = CQ.Util.applyDefaults(config, defaults);
        Ejst.CustomWidget.superclass.constructor.call(this, config);
    },

    // overriding CQ.Ext.Component#initComponent
    initComponent: function() {
        Ejst.CustomWidget.superclass.initComponent.call(this);
        //Hidden Field
        this.hiddenField = new CQ.Ext.form.Hidden({
            name: this.name
        });

        this.add(this.hiddenField);

		//DROP DOWN

        this.linkType = new CQ.form.Selection({
            type:"select",
            cls:"customwidget-1",
            listeners: {
                selectionchanged: {
                    scope:this,
                    fn: this.updateHidden
                }
            },
            optionsProvider: this.optionsProvider
        });
        this.add(new CQ.Ext.form.Label({
            cls:"customwidget-label",
            text: "Type"}));
        this.add(this.linkType);

        //Link Text

        this.linkText = new CQ.Ext.form.TextField({
            cls:"customwidget-2",
            listeners: {
                change: {
                    scope:this,
                    fn:this.updateHidden
                }
            }
        });
        this.add(new CQ.Ext.form.Label({
            cls:"customwidget-label",
            text: "Text"}));
        this.add(this.linkText);

        //Link HREF Starts

        this.linkHref = new CQ.Ext.form.TextField({
            cls:"customwidget-3",
            listeners: {
                change: {
                    scope:this,
                    fn:this.updateHidden
                }
            }
        });
        this.add(new CQ.Ext.form.Label({
            cls:"customwidget-label",
            text: "URL"}));
        this.add(this.linkHref);

        //Link HREF ends

    },

    // overriding CQ.form.CompositeField#processPath
    processPath: function(path) {
        console.log("CustomWidget#processPath", path);
		this.linkType.processPath(path);
        this.linkType.processPath(path);
    },

    // overriding CQ.form.CompositeField#processRecord
    processRecord: function(record, path) {
        console.log("CustomWidget#processRecord", path, record);
        this.linkType.processRecord(record, path);
        this.linkType.processRecord(record, path);
    },

    // overriding CQ.form.CompositeField#setValue
    setValue: function(value) {
        var parts = value.split("\\");
        //this.linkType.setValue(parts[0]);
        this.linkType.setValue(parts[0]);
        this.linkText.setValue(parts[1]);
        this.linkHref.setValue(parts[2]);
        this.hiddenField.setValue(value);
    },

    // overriding CQ.form.CompositeField#getValue
    getValue: function() {
        this.getRawValue();
        return this.getRawValue();
    },

    // overriding CQ.form.CompositeField#getRawValue
    getRawValue: function() {
	   return this.linkType.getValue() + "\\" +
               this.linkText.getValue() + "\\" +
               this.linkHref.getValue();
    },

    // private
    updateHidden: function() {
        //alert('customwidget updatehidden');
        this.hiddenField.setValue(this.getValue());
    }

});

// register xtype
CQ.Ext.reg("ejstcustom", Ejst.CustomWidget);

//------------------------------------------------------------------------------

Ejst.x3 = {};

Ejst.x3.provideOptions = function(path, record) {
    // do something with the path or record
    return [{
        text:"Button",
        value:"button"
    },{
        text:"Link",
        value:"link"
    }];
};


RichText.js file 

The RichText.js file contains application logic that defines the RichText editor. You can copy the RichText.js file from the following AEM JCR location:

/libs/cq/ui/widgets/source/widgets/form/RichText.js

Note:

You have to modify a line of code in the RichText.js file. For details, see http://aemfaq.blogspot.ca/2013/04/richtext-in-multifield-widget.html.

components.js 

The components.js file contains helper methods that are used by the component. The following file represents the components.js file.  

/*
 * Copyright 1997-2009 Day Management AG
 * Barfuesserplatz 6, 4001 Basel, Switzerland
 * All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * Day Management AG, ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Day.
 */

var Ejst = {};

Ejst.toggleProperties = function(id, expand) {
    var box = CQ.Ext.get(id);
    var arrow = CQ.Ext.get(id + '-arrow');
    if (expand || !box.hasClass('open')) {
        box.addClass('open');
        arrow.update('&laquo;');
    } else {
        box.removeClass('open');
        arrow.update('&raquo;');
    }
};

Ejst.expandProperties = function(comp) {
    comp.refresh();
    var id = comp.path.substring(comp.path.lastIndexOf('/')+1); 
    Ejst.toggleProperties(id, true);
};

Create CSS files 

Create the required CSS files to create the component. Place the CSS files in a folder named CSS as shown in this illustration. 

CSSFolder

component.css file 

The following CSS file represents the component.css file. 

/*#CQ .x-form-text.x-form-field.x-trigger-noedit {
    width:40px;
}*

/* widgets */
#CQ .customwidget-label {
    width:70px;
    margin-top:10px;
    margin-right:5px;
    margin-left:20px;
font:normal 12px tahoma, arial, helvetica, sans-serif;

}
#CQ .customwidget-label-2 {
    width:70px;
    margin-top:10px;
    margin-right:5px;
    margin-left:20px;


}

#CQ .customwidget-1 {
    width:100px !important;
    margin-top:4px;
    margin-right:10px;

}

#CQ .customwidget-2 {
    width:190px;
    margin-top:4px;
    margin-right:10px;
    margin-left:5px;
}

#CQ .customwidget-3 {
    width:190px;
    margin-top:4px;
    margin-right:10px;
    margin-left:5px;
}

static.css file 

The following CSS file represents the static.css file. 

/* parsys component */
div.par {
    clear: both;
}
div.parsys_column {
    height: 100%;
    width: 100%;
    float: left;
    border: 0;
    vertical-align:top;
    padding: 0;
    margin: 0;
}

div.section {
    /* Property added to avoid IE hasLayout issue on paragraphs
       see #20817 - IE6: div around Drag Components image not big enough
    */
    zoom: 1;
}

div.parsys_column .section {
    overflow:hidden;
    width: 100%;
}

/* column control layouts */
div.cq-colctrl-cols {width: 100%; float: left; }

div.cq-colctrl-default { width: 100%;}

/* layout 0 : 50% 50% ( grid6 + grid6 ) */
div.cq-colctrl-lt0 { }
div.cq-colctrl-lt0-c0 { width: 48%; margin-right:10px}
div.cq-colctrl-lt0-c1 { width: 48%; margin-left: 10px}

/* layout 1 : 33% 33% 33%( grid4 + grid4 + grid4 ) */
div.cq-colctrl-lt1 { }
div.cq-colctrl-lt1-c0 { width: 32%; margin-right: 10px;}
div.cq-colctrl-lt1-c1 { width: 32%; margin-left: 10px; margin-right: 10px;}
div.cq-colctrl-lt1-c2 { width: 32%; margin-left: 10px; }

/* layout 2: 16% 16% 16% 33% ( grid2.6 + grid2.6 + grid2.6 + grid4 ) */
div.cq-colctrl-lt2 { }
div.cq-colctrl-lt2-c0 { width: 24%; margin-right: 10px;}
div.cq-colctrl-lt2-c1 { width: 24%; margin-left: 10px; margin-right: 10px}
div.cq-colctrl-lt2-c2 { width: 24%; margin-left: 10px; margin-right: 10px}
div.cq-colctrl-lt2-c3 { width: 23%; margin-left: 10px }


span.strikethrough {
    text-decoration:line-through;
}
#CQrte span.strikethrough {
    text-decoration:line-through;
}

Text files 

You have to add two text files to the clientlibs folder. These text files map to the JS file and the CSS file. The names of the text files are: css.txt and js.txt. The following shows the contents of the js.txt file.

#base=js
RichText.js
components.js
CustomWidget.js

The following shows the content of the css.txt file.

#base=css
components.css
static.css

 

Add the files to the ClientLibs folder 

  1. Right-click /apps/hook/components/hero then select New, Node.
  2. Make sure that the node type is cq:ClientLibraryFolder and name the node clientlibs.
  3. Right click on clientlibs and select Properties. Add the two properties specified in the previous table to the node.
  4. Right click on clientlibs and select Create, Create Folder. Name the folder js.
  5. Right click on the js folder and select Create, Create File. Create the three files: RichText.js, components.js, and CustomWidget.js. Add the code specified in this article to each file.
  6. Right click on clientlibs and select Create, Create Folder. Name the folder css.
  7. Right click on the css folder and select Create, Create File. Create the two CSS files: components.css and static.css. Add the code specified in this article to each file.
  8. Add a TXT file to the clientlibs folder named js.txt. Add the content specified in this section.
  9. Add a TXT file to the clientlibs node named css.txt. Add the content specified in this section.
     

Configuring the Edit Behavior 

You can configure the component’s edit behavior by adding a node of type cq:EditConfig below the hero component. You determine the component’s behavior by setting child nodes and properties. For more information, see Configuring the Edit Behaviour of a Component.  

The component specifies the drop target for dragging an image from the AEM content finder to the image. To define a drop target, you use a node of type cq:DropTargetConfig. The following illustration shows the cq:EditConfig node that belongs to the hero component.  

editNodes

To add a cq:EditConfig node to the component, perform these tasks:

1. Select /apps/hook/components/hero, right click and select Create, Create Node.
2. Enter the following values:

  • Name: cq:EditConfig
  • Type: cq:EditConfig

3. Click Ok.
 

Creating cq:dropTargets nodes 

Define the cq:dropTargets node. This node defines a list of drop targets that accept a drop from an asset of the content finder. To define the cq:dropTargets node, perform these tasks:

1. Click on the following node: /apps/hook/components/hero/cq:editConfig.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: cq:dropTargets
  • Type: nt:unstructured

3. Select the /apps/hook/components/hero/cq:editConfig/cq:dropTargets node.
4. Right click and select Create, Create Node. Enter the following values:

  • Name: image
  • Type: cq:DropTargetConfig

5. Add the following properties to the image node.

Name Type Value Description
accept String[] image/.* List of mime types accepted by this drop target; e.g. ["image/*"]
groups String[] media List of drag and drop groups that accept a source.
propertyName String ./image/fileReference Name of the property used to store the reference.

6. Select the /apps/hook/components/hero/cq:editConfig/cq:dropTargets/image node.
7. Right click and select Create, Create Node. Enter the following values:

  • Name: parameters
  • Type: nt:unstructured

8. Add the following property to the parameters node.

Name Type Value Description
sling:resourceType String foundation/components/textimage Specifies the sling resource type.

9. Select the /apps/hook/components/hero/cq:editConfig/cq:dropTargets/image/parameters node.
10. Right click and select Create, Create Node. Enter the following values:

  • Name: image
  • Type: nt:unstructured

11. Add the following property to the image node.
 

Name Type Value Description
sling:resourceType String foundation/components/image Specifies the sling resource type.

12. Select the /apps/hook/components/hero/cq:editConfig/cq:dropTargets node.
13. Right click and select Create, Create Node. Enter the following values:

  • Name: image1
  • Type: cq:DropTargetConfig

14. Add the following properties to the image1 node.

Name Type Value Description
accept String[] image/.* List of mime types accepted by this drop target; e.g. ["image/*"]
groups String[] media List of drag and drop groups that accept a source.
propertyName String ./image1/fileReference Name of the property used to store the reference.

15. Select the /apps/hook/components/hero/cq:editConfig/cq:dropTargets/image1 node.
16. Right click and select Create, Create Node. Enter the following values:

  • Name: parameters
  • Type: nt:unstructured

17. Add the following property to the parameters node.

Name Type Value Description
sling:resourceType String foundation/components/textimage Specifies the sling resource type.

18. Select the /apps/hook/components/hero/cq:editConfig/cq:dropTargets/image1/parameters node.
19. Right click and select Create, Create Node. Enter the following values:

  • Name: image1
  • Type: nt:unstructured

20. Add the following property to the image1 node.

Name Type Value Description
sling:resourceType String foundation/components/image
Specifies the sling resource type.

Creating the cq:InplaceEditing node 

The cq:inplaceEditing node (node type cq:InplaceEditingConfig) defines an inplace editing configuration for the component. To define the cq:InplaceEditingConfig node, perform these tasks:

1. Click on the following node: /apps/hook/components/hero/cq:editConfig.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: cq:inplaceEditing
  • Type: cq:InplaceEditingConfig

3. Add the following property to the cq:inplaceEditing node.

Name Type Value Description
sling:resourceType String foundation/components/image Specifies the sling resource type.

Creating the cq:listeners node

The cq:listeners node (node type cq:EditListenersConfig) defines what happens before or after an action on the component. To define the cq:EditListenersConfig node, perform these tasks:

1. Click on the following node: /apps/hook/components/hero/cq:editConfig.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: cq:listeners
  • Type: cq:EditListenersConfig

3. Add the following property to the cq:listeners node.
 

Name Type Value Description
afteredit
String REFRESH_PAGE
The handler is triggered after the component is edited.

Configuring the Rich Text Editor 

This AEM component contains a Rich Text Editor. When the user clicks on a tab and then clicks the Add Item control, a Rich Text Editor is displayed as shown in this illustration.  

RTE

The Rich Text Editor provides authors with a wide range of functionality for editing their textual content; providing them with icons, selection boxes and menus for a WYSIWYG experience. For more information, see Configuring the Rich Text Editor.

To configure the AEM RTE, you build JCR nodes and properties, similar to building a component dialog (that you performed earlier in this development article). The following illustration shows the JCR nodes that controls the behaviour of the AEM RTE.
 

RTENodes

To configure the AEM RTE, perform these tasks:

1. Select /apps/hook/components, right click and and then select New, Component.
2. Enter the following information into the Create Component dialog box:

  • Label: The name of the component to create. Enter rteconfig.
  • Title: The title that is assigned to the component. Enter rteconfig.
  • Description: The description that is assigned to the template. Enter rteconfig.

3. Click OK.
4. Select /apps/hook/components/rteconfig.
5. Right click and select Create, Create Node. Enter the following values:

  • Name: rtePlugins
  • Type: nt:unstructured

6. Add the following properties to the rtePlugins node.

Name Type Value Description
removeSingleParagraphContainer Boolean true You can keep the RTE from surrounding your text with tags by setting the removeSingleParagraphContainer property to true as long as you only create one paragraph. This property excludes the default <p> tag in the RTE.
singleParagraphContainerReplacement String "" RTE uses as a container for complete html that you enter by default until you use removeSingleParagraphContainer or singleParagraphContainerReplacement.  

Creating misctools

Miscellaneous tools allow you to enter special characters or edit the HTML source. Special characters can be made available to your rich text editor; these might vary according to your installation. For example, consider the following illustration.  

SpecialChars

 

Create the misctools nodes by performing these tasks:

1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: misctools
  • Type: nt:unstructured

3. Add the following property to the misctools node.

Name Type Value Description
features String * Defines which features of the plugin are activated. You may provide a String value of "*" to enable all features.

4. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools.
5. Right click and select Create, Create Node. Enter the following values:

  • Name: specialCharsConfig
  • Type: nt:unstructured

6. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig.
7. Right click and select Create, Create Node. Enter the following values:

  • Name: chars
  • Type: nt:unstructured

8. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig/chars.
9. Right click and select Create, Create Node. Enter the following values:

  • Name: pound
  • Type: nt:unstructured

10. Add the following property to the pound node.

Name Type Value Description
entity
String &#163;
Specifies the HTML representation of the required character.

11. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig/chars.
12. Right click and select Create, Create Node. Enter the following values:

  • Name: nbsp
  • Type: nt:unstructured

13. Add the following property to the nbsp node.

Name Type Value Description
features String &#160;
Specifies the HTML representation of the required character.

14. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig/chars.
15. Right click and select Create, Create Node. Enter the following values:

  • Name: registered
  • Type: nt:unstructured

16. Add the following property to the registered node.

Name Type Value Description
features String &#174; Specifies the HTML representation of the required character.

17. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig/chars.
18. Right click and select Create, Create Node. Enter the following values:

  • Name: copyright
  • Type: nt:unstructured

19. Add the following property to the copyright node.

Name Type Value Description
features String &#169;
Specifies the HTML representation of the required character.

20. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig/chars.
21. Right click and select Create, Create Node. Enter the following values:

  • Name: trademark
  • Type: nt:unstructured

22. Add the following property to the trademark node.

Name Type Value Description
features String &#8482;
Specifies the HTML representation of the required character.

23. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig/chars.
24. Right click and select Create, Create Node. Enter the following values:

  • Name: emDash
  • Type: nt:unstructured

25. Add the following property to the emDash node.

Name Type Value Description
features String &#8212;
Specifies the HTML representation of the required character.

Edit functionality 

You can create basic editing functions (cut, copy, paste) as a plugin. Create the edit node by performing these tasks:

1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: edit
  • Type: nt:unstructured

3. Add the following properties to the edit node.

Name Type Value Description
defaultPasteMode String plaintext Default mode when pasting is executed using the Ctrl + V key or the main paste button (defaults to "wordhtml").
stripHtmlTags Boolean true True if HTML tags should be stripped off before inserting it on paste.

Justify functionality 

You can create simple character formatting (bold, italic, underlined) as a plugin. Create the justify node by performing these tasks:

1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: justify
  • Type: nt:unstructured

3. Add the following properties to the justify node.

Name Type Value Description
features String *
Defines which features of the plugin are activated. You may provide a String value of "*" to enable all features.

Findreplace functionality 

You can create find and replace functionality as a plugin. Create the findreplace node by performing these tasks:
1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: findreplace
  • Type: nt:unstructured

3. Add the following property to the findreplace node.
 

Name Type Value Description
features String *
Defines which features of the plugin are activated. You may provide a String value of "*" to enable all features.

Spellcheck functionality 

You can create spellcheck functionality as a plugin. Create the spellcheck node by performing these tasks:

1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: spellcheck
  • Type: nt:unstructured

3. Add the following property to the spellcheck node.

Name Type Value Description
features String *
Defines which features of the plugin are activated. You may provide a String value of "*" to enable all features.

Subsuperscript functionality 

You can create sub and superscript functionality as a plugin. Create the subsuperscript node by performing these tasks:

1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: subsuperscript
  • Type: nt:unstructured

3. Add the following property to the subsuperscript node.
 

Name Type Value Description
features String *
Defines which features of the plugin are activated. You may provide a String value of "*" to enable all features.

Styles functionality

You can create styling text fragments with a CSS class (using "span" tags) functionality as a plugin. In this example, a Strike Through style is specified. This results in the Strike Through being an available option in the RTE Style dropdown as shown in the following illustration.  

StrikeThrough

Create the styles node by performing these tasks:

1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:

  • Name: styles
  • Type: nt:unstructured

3. Add the following properties to the styles node.

Name Type Value Description
features String *
Defines which features of the plugin are activated. You may provide a String value of "*" to enable all features.

4. Select the following node: /apps/hook/components/rteconfig/rtePlugins/styles.
5. Right click and select Create, Create Node. Enter the following values:

  • Name: styles
  • Type: cq:WidgetCollection

6. Select the following node: /apps/hook/components/rteconfig/rtePlugins/styles/styles.
7. Right click and select Create, Create Node. Enter the following values:

  • Name: strikethrough
  • Type: nt:unstructured

8. Add the following properties to the strikethrough node.

Name Type Value Description
cssName String strikethrough Specifies CSS name.
Text String Strike Through The text that is displayed in the Style dropdown.  

Modify the hero JSP file 

Modify the hero JPS file to include JavaScript logic. The Java script contains application logic to display values entered into the components dialog. Included in the JavaScript is application logic to display the image that is dragged from the AEM Content Finder to the image dialog. The following code fragment shows the JavaScript logic that renders the image that is dragged from the AEM content finder.

<b>&nbsp;Hero Image:</b>
<br>
<%
Image img = new Image(resource);
img.setSelector(".img");
img.setDoctype(Doctype.fromRequest(request));
img.setAlt("image alt text");
img.draw(out);
%>
<br><br>

Add the following JavaScript to the hero.jsp file located at the following location: /apps/hook/components/hero/hero.jsp.
 

<%@include file="/libs/foundation/global.jsp"%>
<cq:includeClientLib categories="hook.components" />

<%@ page import="com.day.cq.commons.Doctype,
                    com.day.cq.wcm.foundation.Image,
                    com.day.cq.wcm.api.components.DropTarget,
                    com.day.cq.wcm.api.components.EditConfig,
                    com.day.cq.wcm.commons.WCMUtils,
					org.apache.jackrabbit.commons.JcrUtils"
                        %>
<br>
----------------------------------
<br>
<b>&nbsp;HERO HOOK COMPONENT:&nbsp;&nbsp;</b>
<br>
----------------------------------
<br>
<br>
<%String displayType = properties.get("displayType", String.class);%>
<b>&nbsp;Display Type:&nbsp;&nbsp;</b><cq:text property="jcr:text" value="<%= displayType %>" />
<br>
<%String imageurl = properties.get("imageurl", String.class);%>
<b>&nbsp;URL:&nbsp;&nbsp;</b><cq:text property="jcr:text" value="<%= imageurl %>" />
<br>
<%String imagealttext = properties.get("imagealttext", String.class);%>
<b>&nbsp;Alt Text:&nbsp;&nbsp;</b><cq:text property="jcr:text" value="<%= imagealttext %>" />

<br>
<br>
<b>&nbsp;Hero Image:</b>
<br>  
<%
        Image img = new Image(resource);
        img.setSelector(".img");
        img.setDoctype(Doctype.fromRequest(request));
        img.setAlt("image alt text");
        img.draw(out); 
%>
<br><br>
-------------------------------
<br>
<b>TITLE:</b>
<br>
<c:forEach var="title" items="${properties.title}">
${title} <br>
</c:forEach>
<br><br>
-------------------------------
<br>
<b>SUB TITLE:</b>
<br>
<c:forEach var="subtitle" items="${properties.subtitle}">
${subtitle} <br>
</c:forEach>
<br><br>
-------------------------------
<br>
<b>DESCRIPTION:</b>
<br>
<c:forEach var="description" items="${properties.description}">
${description} <br>
</c:forEach>
<br><br>
-------------------------------
<br>
<b>FOOT NOTE:</b>
<br>
<c:forEach var="footnote" items="${properties.footnote}">
${footnote} <br>
</c:forEach>
<br><br>

-------------------------------
<br>
<b>&nbsp;LINKS TAB:</b>
<br><br>
<% Node node = null;
    if(resource.adaptTo(Node.class)!=null)
    {

    node=resource.adaptTo(Node.class);

    PropertyIterator props=null;
    if (node.getProperties()!=null)
        props = node.getProperties();

		while (props.hasNext()) {
            Property prop = props.nextProperty();
            String name = prop.getName();
            //System.out.println("property -- "+name);
            String value=null;
            String[] linkFields =null;

                if (prop.getDefinition().isMultiple() && (name.equalsIgnoreCase("links"))) {
                    StringBuffer buf = new StringBuffer();
                    //buf.append("Link Type : ");
                    Value[] values = prop.getValues();
                    for (int i = 0; i < values.length; i++) {
                        buf.append(i > 0 ? "," : "");
                        buf.append(values[i].getString());
                    }

                    value = buf.toString();
                    String[] tokens = value.split(",");

                    for (int i=0;i<tokens.length;i++) 
                        {
                            //System.out.println(" tokens "+tokens[i]);
                            linkFields = tokens[i].split("\\\\");
                            for (int k=0; k<linkFields.length; k++)
                                {
                                //System.out.println(" value of k "+ k + "    linkfield"  + linkFields[k] );
                                if (k==0){
                                    %> <b>Link Type:</b> <%= linkFields[k] %>,<% continue;}
                                if (k==1){
                                    %> <b> Link Text: </b><%= linkFields[k] %>,<%continue;}
                                if (k==2){
                                    %> <b>Link URL: </b><%= linkFields[k] %><br /><%continue;}
                                }
                        }
    
                }
                else {
                    if (name.equalsIgnoreCase("links")){
                value = prop.getString();
                    linkFields = value.split("\\\\");
                            for (int k=0; k<linkFields.length; k++)
                                {
                                //System.out.println(" value of k "+ k + "    linkfield"  + linkFields[k] );
                                if (k==0){
                                    %> <b>Link Type:</b> <%= linkFields[k] %>,<% continue;}
                                if (k==1){
                                    %> <b> Link Text: </b><%= linkFields[k] %>,<%continue;}
                                if (k==2){
                                    %> <b>Link URL: </b><%= linkFields[k] %><br /><%continue;}
                                }

                	}
                }
        }
        %>
<br>
-------------------------------
<br><br>

<b>OTHER IMAGES:</b>
<br>
<% 
       for (Node n1 : JcrUtils.getChildNodes(node)){
    		String imagePath = n1.getPath().toString();
    		Resource imageResource = resourceResolver.getResource(imagePath);
    		Node imageNode = imageResource.adaptTo(Node.class);
    		ValueMap imageNodeProps = imageResource.adaptTo(ValueMap.class);
    		String imageName = null;
            imageName= imageNodeProps.get("fileReference", "None");


%>
<br>
<b>Image Path :</b> <%= imageName %>
<br>
<%

       }
    }

%><br><br>
-------------------------------<br>
<b>**HERO ENDS**</b><br>
-------------------------------
<br>

Create an AEM site that contains a page that displays the Hero component 

The final task is to create an AEM site that lets an author drag the hero component onto a page during design time, as shown in the following illustration. 

HeroWebPage

Create a CQ web page that lets you test the Hero component:

  1. Go to the CQ welcome page at http://[host name]:[port]; for example, http://localhost:4502.
  2. Select Websites. (If you are using AEM 5.6, click Tools from the menu on the left.)
  3. From the left hand pane, select Websites.
  4. Select New Page.
  5. Specify the title of the page in the Title field.
  6. Specify the name of the page in the Name field.
  7. Select templateHook from the template list that appears. This value represents the template that is created in this development article. If you do not see it, then repeat the steps in this development article. For example, if you made a typing mistake when entering in path information, the template will not show up in the New Page dialog box.
  8. Open the new page that you created by double-clicking it in the right pane. The new page opens in a web browser.

You will see the CQ sidekick and the Hero component under the Hook category. You can drag and drop the Hero component onto the CQ page.
If the CQ sidekick is empty, you can populate it by clicking the Design button located at the bottom of the sidekick. Next click the Edit button that appears and select Hook from the list of categories that appear as shown here.
 

HookCat

To view the sidekick with the Hook category, click the down arrow icon that appears on the sidekick.
Drag the Hero component on the AEM web page. Double click on the component and you see the dialog that you created in this development article. You can drag images from the AEM content finder to the component. Click Ok and you will see the values in the AEM web page.
 

See also

Congratulations, you have just created an advanced AEM component that uses many features such as drag and drop, a rich text editor, and a custom xtype. Please refer to the AEM community page for other articles that discuss how to build AEM component, services, and applications.

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License  Twitter™ and Facebook posts are not covered under the terms of Creative Commons.

Legal Notices   |   Online Privacy Policy