Results tagged “CQ5”

File Titles, Size and Thumbnail MetaData in CQ5

Recently, I noticed a quirk in obtaining the file title in CQ5. To be clear, I am only obtaining file metadata here if the file type (dc:format property is a PDF, or 'application/pdf'). The file title (dc:title property in the jcr:content node), is stored as a String. However, when actual metadata is stored with the actual document, it is stored as a String array (String[]). 

Basically, what I have done is to obtain the dc:title metadata property, but if this is empty, then I simply display the file name in place of the title on the front end. What was happening is that, even though a file title was transfered from the document when it was uploaded to the DAM, it could not obtain the dc:title property so it simply displayed my fallback, which is the name of the file. 

The fix is to simply obtain the Asset and determine if it is an Object[] instead of a simple String, and if it is an instance of an Object array, simply get the first item in the array and store that as the title. An example of how you may do this is below:

First, get the Resource from the path, and adapt this to an Asset.

Resource resource = resourceResolver.getResource("/a/path/to/a/file/in/the/dam");
Asset asset = resource.adaptTo(Asset.class);

Next, get the metadata property that contains the title.

String fileName = asset.getMetadataValue("dc:title");

Finally, assess that the fileName is empty or null. (You can use the StringUtils class in the package org.apache.commons.lang3 or your own method.) If it is empty or null, determine if it is an instance of an Object array, and if it is, get the first item in the array as below.

if (fileName instanceof Object[]) {
  Object[] titleArray = (Object[]) asset.getMetadata("dc:title");
  fileName = (titleArray.length > 0) ? titleArray[0].toString() : "";
} else {
  fileName = asset.getName();
}

File size and thumbnails can also be obtained. To get the size of a file, simply adapt it to a Property. The path to the jcr:data node will need to be obtained, similar to the below. Note that one can use the JcrConstants class from the package com.day.cq.commons.jcr in order to get various property names in the Java content repository. The dam creates the following structure to store the uploaded PDF: PDF>jcr:content>renditions>original>jcr:data

Property property = asset.adaptTo(Node.class).getNode(JcrConstants.JCR_CONTENT + "/renditions/original/" + JcrConstants.JCR_CONTENT).getProperty(JcrConstants.JCR_DATA);

To get the size of the file from the property, simply:

fileSize = property.getBinary().getSize();

This file size can then be adapted to display user-friendly units and text, such as "100 MB". 

Thumbnails can be obtained in a similar way, except we do not need to adapt these to Property objects; the path is what we need in order to display the image. Different renditions of the PDF thumbnail are created from the first page in the document when it has been uploaded, and a thumbnail can also be uploaded and overwrite the renditions created at upload time. Decide which rendition will work for you, and simply obtain the path. The dam creates the following structure to store the uploaded PDF's thumbnails: PDF>jcr:content>renditions>.

String thumbnailPath = asset.adaptTo(Node.class).getNode(JcrConstants.JCR_CONTENT + "/renditions/" + "you/rendition/to/use").getPath();

Dynamic Dialog Data with JSON in CQ5

A little over a year ago, I posted about creating dynamic dialogs in CQ5 (Using JSON to Populate CQ5 CMS Dialogs); this was a method I used in CQ5 4.0. In CQ5 5.0, it is much easier to do this. Here's an up-to-date tutorial that makes adding dynamic dialogs in CQ5 with JSON much easier. In this tutorial, I will explain how to make a dyamic selection (drop-down menu) and a dynamic checkbox group. 
cq5states.jpg
 

Creating the Component and its Dialog

The first step is to create the component with the dialog.xml file for the component. Create the component in the 'apps/' directory in the usual way, and create the dialog.xml file. In this file, make sure that you specify a 'selection' xtype. You will also need to include the following:
  • options: This should point to the output of the JSON file. (In this tutorial, we will be creating our JSON using Java Server Pages, but you could simply create a static JSON file instead.
  • optionsRoot: This defines the JSON data root.
  • optionsTextField: This defines the text label for an option in the select box.
  • optionsValueField: This defines the value for a selected option in the drop-down.
I've included an example of this selection xtype below. This drop-down will display a list of US States.
<items jcr:primaryType="cq:WidgetCollection">
                <states
                        jcr:primaryType="cq:Widget"
                        fieldLabel="Select US State:"
                        name="./state"
                        type="select"
                        options="$PATH.states.json"
                        optionsRoot = 'states'
                        optionsTextField = 'label'
                        optionsValueField = 'id'
                        xtype="selection"/>
</items>
In the example above, we point our 'options' variable at the current path to the node in the JCR. The variable $PATH will give us this value dynamically. The JSON node should be accessible via the following:
http://localhost:4502/cf#/content/PATH-TO-PAGE/NAME-OF-COMPONENT.states.json
You can get the above path from looking at CRXDE; simply click onto the component in the 'apps' directory and view the path to the file.
We then create our dynamic file (which will output the JSON) in the same directory. (This file is referenced in the dialog above, and it will dynamically add the results of the JSON.) Our file structure will look like the following:
- states
  - .content.xml
  - dialog.xml
  - states.json.jsp
  - states.jsp
 

Creating the dynamic JSON

The dynamic JSON file should be saved as states.json.jsp as it uss Java Server Pages to render. At the top of the page, be sure to add the contentType 'application/json' so that it knows to render the output as JSON. Then, include your link to the Java tag. Print out the items by looping through using the JSTL core library, as demonstrated below:
<%@ page contentType="application/json" %>
<%@ page import="java.util.*" %>
<%@ include file="/libs/foundation/global.jsp" %>
<%@ taglib prefix="mylocation" uri="http://myapp.mysite.com/locations" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<mylocation:states currentPage="${currentPage}" />
{"states":[
<c:forEach var="item" items="${states}" varStatus="loop">
  { "id": "${item.name}", "label": "${item.name}"} ${not loop.last ? ',' : ''}
</c:forEach>
]}
 

Add your Java Tag Descriptor

In the above example for the JSON file, we referenced our own tag library, known as "mylocation". This will need to be added to the tag library descriptor (TLD) file. Simply locate this in your Java package and add the descriptor. In the above example, we are passing the current page (currentPage). Remember that the prefix described in the JSON file needs to be the same as the 'name' in the TLD file.
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0">

<tag>
<name>myloction</name>
<tag-class>com.path.to.file.LOCATIONS</tag-class>
<body-content>empty</body-content>
<attribute>
<name>currentPage</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>com.day.cq.wcm.api.Page</type>
</attribute>
</tag>

</taglib>

 

Add your Java Tag

After the tag descriptor has been created, add the Java file in the same location as defined in the tag descriptor. You will add your logic to this class, and you will pass back (to the JSP page) the value to render the states. It is likely that you will need to also create a Java model to describe this data (for states). For example, you should probably create a model for the states and use getters and setters to set up your data for each state. (You possibly want to associate the state name, abbreviation, and other data about a state for this.)
In the tag, you should add your getters and setters for the data passed into the tag. As we are passing in the currentPage, we need to add a getter and setter for this. To do this, we want to add the following to our Java Tag file:
At the top of the file, we will add the variable: 
private Page currentPage;

In the Java Tag file, we simply add our getter and setter methods, as below:

public Page getCurrentPage() {

return currentPage;
}

public void setCurrentPage(Page currentPage) {
this.currentPage = currentPage;
}

When we have completed the logic to retrieve our data, we need to pass the data back to the JSP page. In the following method, we use pageContext to pass the name of the variable (which we use to get the object in the JSP), and the name of the object. For example, the states object is the second parameter, and it would be a type StateModel, as discussed.

pageContext.setAttribute("states", states);

Completed

 

Once you have followed the steps above, your dialog should print out dynamic data. You may need to debug this by viewing the JSON output as provided by accessing the JSON link detailed above. And, you should use JSONLint to ensure that your JSON is valid JSON mark-up.

Dynamic Checboxes and Radio Buttons

Once you have completed the above, making a dynamic radio button or checkbox button group is a piece of cake. You can use the same code as above, but there is only one change that needs to be made here. This change needs to be made in the dialog.xml file. In the 'type' field, add 'checkbox' (instead of 'select'). You're all set to go!

cq5states-check.jpg

Problems and Issues

This method was slightly different to my older implementation, but this is much easier. I spent over a day trying to locate an issue, however, as I could not get my JSON to load. I assumed that it was not being rendered correctly, and I was not expecting the results. It turned out that it seemed to be cacheing the JSON. I know that JSON can cache, and Google Chrome is notorious for cache issues, even when you have cleared the cache and forced refresh.

Another problem was environment-related. For some reason, two instances of CQ5 were running, and the environment (localhost) was confused! The old JSON was being rendered, despite making obvious changes, and it wasn't clear why CQ5 was hanging on to the old file. I spent ages going over (and then back over) my JSON and the method I was using only to discover that it was an environment issue with two CQ5 instances running in the background.
Of course, check the obvious issues first. Make sure that your paths are correct. And, perhaps start with dummy JSON data just to ensure that the JSON is being dynamically loaded into your dialog. That way, you can isolate any issues that may be related to Java errors. Also, don't forget to use JSONLint to validate your JSON mark-up.

Enjoy!

I had fun making this, despite annoyances with the environment. I hope you do too! 

Editing Column Widths in CQ5

Hopefully, you would have read the entry "Creating Web Templates in CQ5" before reading this article. In that article, I mentioned the importance of getting the site structure and visual designs correct beforehand, otherwise extensive rework may be needed.

  • This article explains how to set and edit column widths in Adobe CQ5 CMS for your websites. This article assumes that you can edit the CSS and decide which grid or column framework to use for your website, dependent on the designs.


Set up the CSS for the columns

Once the templates have been identified, the developer can identify column widths and set up a grid framework for the column widths, keeping in mind if the website will be a fluid one or a fixed-width one. The developer will need to identify the acceptable widths available for each template and create the CSS classes for the columns. The CSS will be included in the file, and I suggest splitting the CSS into multiple manageable files as this is good practice. For example, layout-specific CSS should be put in a layout.css. The CSS files will be concatenated and minified in the build process.


Set up columns for the templates

The page information and column information for a page can be found in the file:
[PATH]/etc/designs/[PROJECT-NAME]/content.xml

This file's contents are split by the template, and below is an excerpt of this file showing one template. In the example below, the name of the template is "level1". This file is updated when the columns are edited in the CMS.

Notes: 
  • The columns for this website (Mysite) are put into a group named Mysite.
  • Each section in the template is separated in this file. The following different sections, marking the parsys in the template, are described below:
    • main
    • secondary
  • For each parsys section, the "colctrl" is the column control area, and it defines the available layouts and the CSS style. For example, 3 Columns (25%, 25%, 50%)&#xa;3;grid-363 is the name of the column layout and the CSS class. (The column class is "grid-363", and the rest of the string above is the text that the content editor will see when they use the CMS to select a column.) The content editor will see the description for each column option to understand what column type to use in the parsys. 

<level1 jcr:primaryType="nt:unstructured">

            <main

                jcr:lastModified="{Date}2013-01-06T10:45:25.586Z"

                jcr:lastModifiedBy="admin"

                jcr:primaryType="nt:unstructured"

                sling:resourceType="foundation/components/parsys"

                components="[group:Columns,group:Mysite]">

                <section jcr:primaryType="nt:unstructured"/>

                <colctrl

                    jcr:lastModified="{Date}2013-01-06T10:39:03.337Z"

                    jcr:lastModifiedBy="admin"

                    jcr:primaryType="nt:unstructured"

                    sling:resourceType="foundation/components/parsys/colctrl"

                    layouts="3;grid-333&#x9;3 Columns&#xa;4;grid-44&#x9;2 Columns&#xa;4;grid-2222&#x9;4 Columns"/>

                <col_end13242935548710

                    jcr:primaryType="nt:unstructured"

                    sling:resourceType="foundation/components/parsys/colctrl"

                    controlType="end"/>

            </main>

            <secondary

                jcr:lastModified="{Date}2013-01-06T10:46:16.990Z"

                jcr:lastModifiedBy="admin"

                jcr:primaryType="nt:unstructured"

                sling:resourceType="foundation/components/parsys"

                components="[/libs/foundation/components/flash,group:Columns,group:Mysite]">

                <section jcr:primaryType="nt:unstructured"/>

                <colctrl

                    jcr:lastModified="{Date}2013-01-06T10:38:52.144Z"

                    jcr:lastModifiedBy="admin"

                    jcr:primaryType="nt:unstructured"

                     sling:resourceType="foundation/components/parsys/colctrl"

                    layouts="2;grid-66&#x9;2 Columns (50%,50%)&#xa;2;grid-93&#x9;2 Columns (75%, 15%)&#xa;2;grid-39&#x9;2 Columns (15%, 75%)&#xa;2;grid-48&#x9;2 Columns (40%, 60%)&#xa;2;grid-84&#x9;2 Columns (60%, 40%)&#xa;3;grid-633&#x9;3 Columns (50%, 25%, 25%)&#xa;3;grid-336&#x9;3 Columns (25%, 25%, 50%)&#xa;3;grid-363&#x9;3 Columns (25%, 50%, 25%)&#xa;3;grid-444&#x9;3 Columns (33%, 33%, 33%)&#xa;4;grid-3333&#x9;4 Columns (25%, 25%, 25%, 25%)"/>

                <col_end13243732957980

                    jcr:primaryType="nt:unstructured"

                     sling:resourceType="foundation/components/parsys/colctrl"

                    controlType="end"/>

            </secondary>

        </level1>



Have fun

Make sure that the file above is saved each time so that the content editor can select the column that they wish to use for the area. Enjoy!

Creating Web Templates in CQ5

In the Adobe CQ5 CMS projects that I worked on, the front-end developers worked closely with the user experience (UX) and visual design (UI) resources. Establishing the site structure and the available templates is extremely important for CQ5 projects. Changes to the site structure can lead to extensive re-work, particularly in cases where specific breadcrumbs are implemented or areas where the developer needs to extract information about parent or child pages to display on the current page. Moving pages around is not easy. Also, there is no way to change a page's template once the page has been set up. (I can understand why they do this as otherwise, things can get very messy in the JCR.) 

For the reasons mentioned above, details of templates and site structure is necessary at an early stage. For the purpose of this discussion, let's assume that we are building a website (unimaginatively dubbed MySite) with a home page, a page that lists data organised by category, and the lowest-level page, which would display content about the list item (an article). we will have the following three types of template used throughout the website:

  • Home Page
  • List Page
  • Article Page

Now that we know that we have the templates to build, we need to complete the following tasks:

  • create the main JSP page for the project, which will inherit the accompanying Java classes to use in our later templates.
  • create a base template that extends the foundation page and separates the HTML into multiple files and that will be extended by other templates
  • create additional templates that extend the base template and create JSP files to overwrite any of the base template files.

Creating the Main Page JSP, Extending global.jsp

Since we will need to develop our own Java methods to complete specific actions used on the pages, we should extend the /libs/foundation/global.jsp file and include specific Java pageHelper classes that we have created. 

If we have multiple websites managed through our CQ5 installation, it is important to break the various Java files down into a core file to be used by all websites and then site-specific Java files. This path to the project.jsp file is: [PATH]/apps/[PROJECT-NAME]/project.jsp

Each project will have its own project.jsp file, and this file's imports will reflect the project. The project.jsp file will contain the below mark-up to import the particular files, a core PageHelper and a MysitePageHelper. We will also be including the global.jsp file so we can use the other elements specified in the foundation global.jsp.

The Java classes (PageHelper) listed below would be placed in the directory: [JAVA-PATH]/src/main/java/com/[COMPANY-NAME]/

project.jsp

<%@page session="false" import="
        static com.mycompany.cq.core.util.PageHelper.*,
        static com.mycompany.mysite.util.MysitePageHelper.*
        "%><%
%><%
%><%@page session="false"%><%@include file="/libs/foundation/global.jsp"%>

Now that we've set up this project.jsp file, we can move on to the next step, which is creating our base page template. 


Creating the Base Page Template

Now, the page templates need to be set up. The path to the templates is located at: [PATH]/apps/[PROJECT-NAME]/templates

To create a new template, we simply create a new directory under the 'templates' directory mentioned above. The name of the directory will coincide with the name of the template, without spaces and illegal characters. Inside this directory we will place the file .content.xml. This file stores information about the template. We should also include a screenshot of the template, saved as thumbnail.png, so that the content editor can easily see the template that they wish to use when they create a new page.

The first template that we will create is a "base template". This template will allow us to set up the base structure, which will be inherited by other templates. I've named the directory "base-page". The .content.xml file contents is shown below:

<?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:primaryType="cq:Template"

    jcr:title="MySite Base Page"

    allowedPaths="/content(/.*)?">

    <jcr:content

        cq:designPath="/etc/designs/mysite"

        jcr:primaryType="cq:PageContent"

        sling:resourceType="mysite/components/template-components/base-page"/>

</jcr:root>


Note that the jcr:resourceType in the file above points to the location where the JSP file is stored. The template files are displayed in the path: [PROJECT-NAME]/components/template-components.

Underneath this path, create a directory for each template to match  the template name in the templates directory, as detailed above. This directory will also include the .content.xml and the relevant JSP files. The details of the .content.xml are below.

<?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:description="Mysite Base Page Component"

    jcr:primaryType="cq:Component"

    jcr:title="Mysite base page component"

    sling:resourceSuperType="foundation/components/page"

    componentGroup=".hidden"/>


Note that the sling:resourceSuperType in the base template should point to the foundation's component 'page'.

After creating the directories with the relevant details, we now create the JSP pages, which need to be placed in the directory mentioned above:  [PROJECT-NAME]/components/template-components/base-page

Separating the different parts of the HTML page is recommended here, and I recommend using the HTML5 Boilerplate as an example of your HTML file and break the HTML page down. You should break your main HTML template down into smaller files, such as header.jsp, headlibs.jsp (contains scripts loaded in the header), footer.jsp, body-tag.jsp, seo-footer.jsp (contains SEO-specific scripts), libs.jsp, and so on. I've created an example of what one file (footer.jsp) could look like below:

footer.jsp (example)

<%@include file="/apps/mysite/project.jsp"%><%
%><div id="footer">
     <cq:include script="seo-footer.jsp" />
     <p>Put static content here.</p>
     <cq:include path="copyright" resourceType="foundation/components/parsys"/>
</div>

In addition to your specific JSP files, you will also need to include a file called init.jsp which is copied from one of the core files for CQ5, /lib/wcm/core/init/init.jsp. However, the only difference here is setting previewReload = true so that the page refreshes when the user switches from 'edit' mode to 'preview' mode. Naming this file the same as the original file overwrites it, so our file below will be used instead.

init.jsp

<%@include file="/libs/foundation/global.jsp" %><%
%><%@page import="com.day.cq.wcm.api.WCMMode" %><%
if (WCMMode.fromRequest(request) != WCMMode.DISABLED) {
    String dlgPath = null;
    if (editContext != null && editContext.getComponent() != null) {
        dlgPath = editContext.getComponent().getDialogPath();
    }
    %><cq:includeClientLib categories="cq.wcm.edit" />
    <script type="text/javascript">
        CQ.WCM.launchSidekick("<%= currentPage.getPath() %>", {
            propsDialog: "<%= dlgPath == null ? "" : dlgPath %>",
            locked: <%= currentPage.isLocked() %>,
            previewReload: "true"
        });
    </script>
<% } %>

The following file is the content.jsp file, which will be overwritten for each template. The template imports various CQ5 classes and sets the "cq" taglib variable to be used to access other elements, such as the components.

content.jsp

<%@include file="/apps/mysite/project.jsp"%>
<%@page import="com.day.cq.wcm.api.WCMMode, com.day.cq.wcm.foundation.ELEvaluator, com.day.cq.commons.Doctype"%>
<%@page session="false"%>
<%@taglib prefix="cq" uri="http://www.day.com/taglibs/cq/1.0" %>
<div id="content">
    <cq:include path="main" resourceType="foundation/components/parsys"/>
</div>

Now that we have set up our base template, we need to set up our individual templates, all of which will extend this base template.


Set up the Home Page Template

Now that we've created the "base template", we will create the other templates in the same format. We will use the 'Home' template as an example. 

 .content.xml in [PATH]/apps/[PROJECT-NAME]/templates/home

<?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:primaryType="cq:Template"

    jcr:title="MySite Homepage"

    allowedPaths="[/content/mysite(/.*)?]">

    <jcr:content

        cq:designPath="/etc/designs/mysite"

        jcr:primaryType="cq:PageContent"

        sling:resourceType="mysite/components/template-components/home"/>

</jcr:root>


Notes: Note that we set the allowedPath to this project (mysite) only if we are inheriting from a core project and have multiple projects set up under the environment. If you have multiple projects, you would set this to the site that you want to access this template. 

.content.xml in [PROJECT-NAME]/components/template-components/home

<?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:description="Mysite Homepage Component"

    jcr:primaryType="cq:Component"

    jcr:title="Mysite homepage component"

    sling:resourceSuperType="mysite/components/template-components/base-page"

    componentGroup=".hidden"/>


Notes: Note that we set the sling:resourceSuperType to the base-page that we created. All sub-templates should inherit the base template.

In the above folder (under template-components/home), we have two JSP files. You can have as many as you like, and if you wish to overwrite one of the JSP files from the base template, you can do so by creating a file with the same name in the directory. I have overwritten the body-tag.jsp for the home page. The reason that I have done this is because I want to add a different class on the 'body' tag for the home page so that we display some elements slightly differently on this page.

The contents of body-tag.jsp

<%@page session="false"%><%
%><%@include file="/apps/mysite/project.jsp"%><%
%><!--[if IE 7]>    <body class="no-js ie7 home"> <![endif]-->
<!--[if IE 8]>    <body class="no-js ie8 home"> <![endif]-->
<!--[if IE 9]>    <body class="no-js ie9 home"> <![endif]-->
<!--[if gt IE 9]><!--> <body class="no-js gtie9 home"> <!--<![endif]-->

<script type="text/javascript">
//remove the no-js class from the body tag
var bodyTag = document.getElementsByTagName('body')[0];
bodyTag.className = bodyTag.className.replace('no-js ','');
</script>

Notes: The standard browser checks are in place and set against the body tags here. We use Javascript to remove the 'no-js' class if Javascript is enabled. The only difference with this template is that we append the extra class dubbed 'home' to pages that use this template so that we can style the home page template slightly differently. You may not need this for your site, but it's good practice to see this in action and to see how you can change your pages for slight design differences. For more information about detecting browsers, you may wish to have a look at HTML5 Boilerplate. You can adapt this to fit your own needs.

The contents of content.jsp

<%@include file="/apps/mysite/project.jsp"%><%
%>
<div id="content">
    <cq:include path="main" resourceType="foundation/components/parsys"/>
    <cq:include path="secondary" resourceType="foundation/components/parsys"/>
</div>

Notes: We set up two parsys components here for content editors to drag and drop their components into.


Set up the Additional Templates

Now that we have the Home template example, we can continue to set up our other templates using this as an example. The main difference is that we will probably not need to replace the body-tag.jsp. Instead, we will replace the content.jsp file with the basic page elements and components that we will place on the page automatically and other areas (parsys) where the content editor will insert custom components.

The contents of content.jsp

<%@include file="/apps/mysite/project.jsp"%><%
%>
<div class="left-col" id="content">
<cq:include path="header" resourceType="mysite/components/header"/>
<cq:include path="main" resourceType="foundation/components/parsys"/>
<div class="secondary">
           <cq:include path="left-nav" resourceType="mysite/components/component1"/>
    </div>
</div>


Have Fun

That's all you need to know in order to get started creating your CQ5 templates. The above framework should allow you to create extensive components for multiple projects from a core framework. Have fun creating these and let me know if you have any observations.

Recent Project: IG INSIGHT

Last summer and early autumn, I worked on a project that displays news and shares knowledge. The website can only be launched as a part of the dealing platform, so only customers who are able to log in will be able to see this website, which is known as INSIGHT. The project was developed in Adobe CQ5 CMS.

The knowledge section of the website is colour-coded depending on the category, and articles are displayed so that the user can learn the different terms. The 'news' section is the area that I developed on my own using Java, JSP, CSS, HTML, and Javascript in the Adobe CQ5 CMS platform. Simply, content editors can add news stories written by one of the analysts, and these articles are displayed and sorted. There's also a Twitter feed from the analysts and links to related areas in the 'knowledge' section. Most of the section for 'news' is automated, so this required a lot of coding to automate this and to display it as intended. The news stories are also organised by category, and there are areas that can be filtered, such as obtaining a list of all stories by author. There's also much more to it than the screenshots that I have posted.

This is one of the most exciting projects that I have worked on in a while, and I really enjoyed the mix of development in Java and translating the designs to HTML and CSS and Javascript. During my time at the company, this was the work I did for the "news and analysis" section was the most enjoyable.

The following image shows a news article. The image and first part of the text is obtained and displayed in the preview on the home page and category pages - as well as the author and the date.

ixi2.jpg

The following screenshot is a section under one of the categories, and I built the navigation section under the heading, which are anchors in the current page and sibling pages and the grey box, as well as contributed to the CSS. This is a large area of the website.

ixi1.jpg

Latest Project: NADEX Website

I have been a very busy girl over the past three months. I have been the technical lead for the re-development of a website, including incorporating the new design into a new Content Management System (Adobe CQ5 CMS), which I have been developing in for nearly a year. In fact, another website that I spent the majority of the past year developing using the same CMS went live in January, so a lot has been happening this year.

This project certainly had some challenges, all of which were not surprising considering that the project was the first public-facing website (consisting of many additional dependencies) to use the new CMS, and the deadline was tight and had to be met in time. I have noted the following list of challenges:
  • The redevelopment of this website had to be achieved by 1 February. This meant that we only had approximately two months to spend for development tasks.
  • To meet the tight mid-week deadline, we had to break from some internal processes. Typically, releases are completed at weekends, and code was being redeveloped until two weeks before the go-live date, and bugs were being fixed up until the go-live date.
  • Many environment and infrastructure issues needed to be addressed, and new environments needed to be built. This was the first time that the new CMS was used for a public-facing website.
  • Other web-based applications use files that exist under the domain, and it was not always clear where the files were being used. These files, HTML pages, and links needed to be migrated and approprite RewriteRules needed to be written so that the changes would not affect these other web-based systems.
  • A new brand and designs for the website were being created at the same time, and the branding was received half-way through the design process. (Due to the tight deadline, designs had to be started before a new brand was created.) Additionally, the development process started at the same time as the designs were being created during the first two sprints. This, of course, meant that we needed to constantly make small changes to the CSS and HTML for design changes.
  • The development for the project was achieved in approximately two months, including bug-fixing during the final two weeks, and some earlier development work needed to be tweaked as unfinished designs were evolved. (We certainly did work Agile.)

nadex_home.jpg

Despite the mentioned challenges, everyone did a fantastic effort, and I largely enjoyed it. Many disciplines (such as development, design, QA, content writers, system developers, etc) worked well together to ensure the success of the project. 

With such a project, the low points were working long hours over the Christmas and New Year weeks while colleagues and most of the company were on holiday, working through most of my lunches throughout the past three months, and ensuring that the dependent systems were seemingly unaffected by the changes. The highs were speaking to the clients and being involved at a high level, developing new components in the CMS using Java, and working together toward a common goal to launch a complete website. Now that this project is finished, I think some sort of recovery is in order.

Using JSON to Populate CQ5 CMS Dialogs

Although Adobe's CQ5 CMS has many quirks, it can be a powerful tool once you discover the how to achieve certain tasks. For example, one of my tasks recently was to obtain a list of users in a particular group in CQ5 and to display all users in a drop-down menu in a dialog. The Content Editor could then select a user, and the user's name and other details about the user would be displayed on the web page. (This was built to associate a particular user, that may or may not be the Content Editor, with specific content.) The component created would display automatically within the page template, and the Content Editor would simply be able to edit the component directly.

This article explains how the task can be achieved. This article also assumes that you have created a group and added users to the group.


Create the Component and Include it in the Template

1. Create a folder (type cq:Component) for the component, and name it mygroup-users.

2. In your template, include the new component directly, as below:
<cq:include path="users" resourceType="[my project]/components/mygroup-users"/>


Create the Dialog

3. In the mygroup-users component folder, add a new dialog (cq:Dialog) named 'dialog'. (Add a 'title' property for the dialog and an xtype of 'panel'.)

4. Underneath your dialog, add a new node - cq:WidgetCollection. Name it "items".

5. Underneath the 'items' node, add a cq:Widget, and name it 'users'. Add new properties, described in the list below:

  • fieldLabel = Select User: (String)
  • name = ./users (String)
  • xtype = selection (String)
  • type = select (String)
6. Add one last new property to the 'users' node. This will allow the dialog to look up the script that processes the data. The property is known as optionsProvider (String). The path is to the JSON code, which will be created in the next step, with a cachebreaker.
function(path, record){
return CQ.Util.formatData(
CQ.HTTP.eval(CQ.HTTP.noCaching(
 '/apps/[path to component]/users.list.json?' 
+ (new Date().getTime()))));
}

Create your JSON, JSP and a Reference

7. Now, you will create a JSP file (nt:file) to include the Java code that you will write to obtain the data. The file will be placed in the root of your mygroups-users component. (It should be named mygroup-users.jsp.) Here, you will write the code to output the data onto the web page. (I'll let you sort this yourseldf, but I used the UserManager class.)

8. Now, you will create the JSON code. This file (nt:file) should be named list.json.jsp, and it will be placed in the root of the component (mygroup-users). The naming is important to specify the component's default in CQ5; we're extending this list component. The code simply is a loop to list all users to print them out.

  • Initialise the content type: response.setContentType("application/json");
  • resolve the UserManager: final UserManager um = resourceResolver.adaptTo(UserManager.class);
  • Get the Groups: Iterator<Group> groups = um.getGroups();
  • You'll need a framework, as below:
%>[<%
String delim = "";
while (groups.hasNext()) {
   // get the name of the group, and extract all the members from that group.
  // the member is an Authorizable class.
%><%= delim %><%
%>{<%
%>"value":"<%=  member.getProfile().getAuthorizable().getID() %>",<%
%>"text":"<%= member.getProfile().getName() %>",<%
%>"qtip":""<%
%>}<%
if ("".equals(delim)) {
}
    delim = ",";
        }
    }
}
%>]

9. Now, you'll need a reference (sling:Folder) to your users. Underneath the mygroups-users component, create a new sling:Folder, and give it the name 'users'. Add a new property called sling:resourceType, and it should be the path to your component: [myproject]/components/mygroups-user


Test

10. Test your changes.

The JSON should be output to http://localhost:4502/apps/[path to component]/users.list.json.

The JSON will be returned in the browser, if working correctly. It will look like below:

[

  • -
    {
    • value: "john_doe"
    • text: "John Doe"
    • qtip: ""
    }
  • -
    {
    • value: "joebloggs"
    • text: "Joe Bloggs"
    • qtip: ""
    }
]


I hope that you have fun building your own custom components based on the JCR.

The Adobe CQ5 Content Management System

Over the past four months, I have been involved in a project using Day's (now owned by Adobe) Comminique 5 (CQ5) Content Management System. In the past, I've used several off-the-shelf and custom Content Management System. CQ5 is most comparable to Magnolia, a product that I used last year. CQ5 uses the Java Content Repository and Apache Sling to create a powerful tool. This Content Management System is being used by General Motors, McDonalds, Volkswagen, and Audi (1).

When installed, the application comes with a default project to base ideas on. CQ5 also allows marketing campaigns and the ability to serve up content across multiple channels, such as mobile. It also comes with social networking aspects, including blogs and forums and the ability to set up custom workflows for publishing and approval of various aspects (2).


Here are a few of my thoughts about CQ5 over the past three months:

1) I think the tool could be a powerful one, but there is a steep learning curve involved, and I've had to pick this up myself, without any training or guidance. (The same happened last year when I learned Magnolia.) Unfortunately, there's little of documentation available and a lack of a support group; there is a Google forum and an API.

2) Lack of consistency with the code.

3) Stability issues with the environment.

4) Lack of up-to-date and correct documentation available. On the Day website, there are tutorials to help you get started, but these tutorials were out-dated and simply did not work when followed. This was not due to user error as it was also reported by all of my colleagues. (At least there is an API to help guide you, but a lot of the comments are out-of-date or non-descriptive.)

5) The development environment that you need to use to develop is CRXDE, which is based on Eclipse, but it is buggy and adding a file manager (Vault) to the process causes even more complications. I was also getting many crashes using this, and a lot of Java "Out of Memory" errors. (This mainly seems to have been solved with a new machine, however.)

6) Ability to make content editing easier. Despite the product's downfalls, I think that the finished product can be customised enough to give more freedom to the content editors. They will still need training, but the ability to drag and drop components around a page and copy and paste them to a new area is more flexible and quicker. However, there are areas where it can be just as slow; for example, I am not quite happy with table management aspect. It does not give the content editor enough freedom to copy and paste multiple rows/columns and apply styles across multiple rows/columns.

7) Extending components is fiddly.

8) Incomplete and incorrect code. For example, I wanted to create an Accordion-style layout by using a Multifield component that takes a CompositeField, consisting of a 'richtext' component and a 'text' component. Although this is meant to work, it didn't. A quick look into Day's code showed that this feature had areas commented out with "//TODO" comments to get the multifield working with other combinations. (I decided to find another way to accomplish the task, and I must have tried three other ways before brainstorming with a colleague to come up with a completely different solution that wasn't as user-friendly for the content editor, but it worked.)

9) A lot of patience is needed as well as a lot of fiddling around and trial and error.

10) There's generally been a lack of support from Adobe or a lack of training/consultants available from Adobe to get started or fix issues initially.


Here are a few thoughts from other developers.

Guseva, Irina. Day's Software CQ5 WMS. http://irinaguseva.wordpress.com/review-day-softwares-cq5-wcm/ [2009].


(1) Websmart. What is Adobe CQ5? http://websmart.tv/learn/what-is-adobe-cq5/ [2011].

(2) Taft, Darryl K. 10 Ways Adobe is Transforming Enterprise Digital Experiences. http://www.eweek.com/c/a/Messaging-and-Collaboration/10-Ways-Adobe-Is-Transforming-Enterprise-Digital-Experiences-591898 [February 28, 2011].

1

Tags

Archives

Recent Comments

  • jenn: Thank you. read more
  • Murge: Amazing post. read more
  • Herbert: good post. site read more
  • Frank Quake: Hey, This is great when you said that I had read more
  • Chappy: You mention peptides here? I have had first hand experience read more
  • jenn: Thanks! I love the work. I have got more recent read more
  • Fanakapan: Thanks for the write up. This was some of my read more
  • jenn: Yes.... but that's only for the islands. Mostar and Montenegro read more
  • jenn: Hello, the code is not mine to hand out. I'll read more
  • pantich: More info about the best day trips from Dubrovnik can read more
OpenID accepted here Learn more about OpenID