Author Archive

August 27, 2012

How to prevent users from entering duplicate vanity URL’s

This is something which should come very handy at every CQ implementation. The requirement for vanity URLs is that you cant have two pages in CQ with the same vanity URL. In this blog I will try to go over an implementation which will prevent your content authors from entering duplicate vanity URL in the first place.

1. First thing you will need to do is override the OOTB page component dialog and the tab_basic node. To do this, please copy the following nodes

    • /libs/foundation/components/page/dialog
    • /libs/foundation/components/page/tab_basic

2. Paste these nodes as the child of your projects page component whose “sling:resourceSuperType” is “foundation/components/page”


3. For the dialog node, change the path to the basic tab to match the path of the “tab_basic” you pasted in your projects page component.
4. For the “tab_basic” node update the “tab_basic/items/vanity/items/vanityPath/fieldConfig” node to add the following two properties
  • vtype
  • vtypeText
5. Override  the following in your apps folder
  • /libs/cq/ui/widgets/js.txt
  • /libs/cq/ui/widgets/source/widgets
6. To your overridden widgets directory at “/apps/cq/ui/widgets/source/widgets”, add a file called duplicateVanityCheck.js
CQ.Ext.apply(CQ.Ext.form.VTypes, {
duplicateVanityCheck: function(v, f) {var dialog = f.findParentByType("dialog");
var dialogPath = dialog.path;
var cqresponse = CQ.HTTP.get("/apps/duplicateVanityCheck?vanityPath="+v+"&pagePath="+dialogPath);
var json = eval(cqresponse);
var vanitypathsjson = json.responseText;
var JSONObj = JSON.parse(vanitypathsjson);
var jsonVanityPath = JSONObj.vanitypaths;
if (jsonVanityPath.length == 0) {
return true;
} else {
// check whether the path of the page where the vanity path is defined matches the dialog's path
// which means that the vanity path is legal
return false;
//alert( "Checking Duplicate" );


7. In your overridden js.txt file, add this line

  • widgets/duplicateVanityCheck.js


8. You also need to make sure that your foundation client lib has a dependency on “cq.widgets”.

9. Now, we have to create an OSGi bundle that will query the JCR for an entered vanity and return the JSON that will be used by duplicateVanityCheck.js. The code for this class will look something like below

 * @scr.component immediate="true" metatype="false"
 * @scr.service interface="javax.servlet.Servlet"
 * name="sling.servlet.methods" values.0="GET"
 * name="sling.servlet.paths" values.1="/apps/duplicateVanityCheck"
public class VanityDuplicateCheck extends SlingAllMethodsServlet{
    private static final Logger logger = LoggerFactory.getLogger(VanityDuplicateCheck.class);
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
            Session session = request.getResourceResolver().adaptTo(Session.class);
            final String vanityPath = request.getParameter("vanityPath");
            final String pagePath = request.getParameter("pagePath");
  "vanity path parameter passed is {}", vanityPath);
  "page path parameter passed is {}", pagePath);
            try {
                QueryManager qm = session.getWorkspace().getQueryManager();
                String xpath = "//element(*)[sling:vanityPath='"+ vanityPath + "']";
      "xpath is {}", xpath);
                Query query = qm.createQuery(xpath, Query.XPATH);
      "Xpath Query Statement is {}", query.getStatement());
                QueryResult result = query.execute();
                NodeIterator nodes = result.getNodes();
      "result is ", result.getNodes().toString());
                TidyJSONWriter tidyJSONWriter = new TidyJSONWriter(response.getWriter());
                while (nodes.hasNext()) {
                    Node node = nodes.nextNode();
          "Node path is {}", node.getPath());
          "Page path is {}", pagePath);
                    if(node != null && node.getPath().contains("/content"))
                        // check whether the path of the page where the vanity path is defined matches the dialog's path
                        // which means that the vanity path is legal.
                            //do not add that to the list
                  "Node path is {}", node.getPath());
                  "Page path is {}", pagePath);
                        } else {
            catch(RepositoryException re){
                logger.error( "Error in doGet", re );
        } catch (JSONException e) {
            logger.error( "Error in doGet", e );

8. At this point you should have everything you need to prevent content authors from entering duplicate vanity URL’s. If they do enter a URL that is already in use, it will fail the validation and they will see an error message similar to what you entered in the vtypeText property.


Enjoy..and as always, please leave comments/questions and I will try to answer them as soon as possible.

5:49 PM Permalink
June 6, 2012

How to fix CRXDE performance issues

Is CRXDE too slow or is not loading at all? Try these steps below to possibly fix the issue.

Make sure the crxde:paths property doesn’t include anything that you dont want to load in CRXDE.

  • Open the Content Explorer and browse to /etc/crxde/profiles/default, on the right hand panel there will be the crxde:paths property, this defines what nodes CRXDE will try to load. Having nodes like /content will make it slow/unresponsive.

Locate and open the CRXDE.ini file and assign more memory to CRXDE.

  • On OSX right click on and select Show Package Contents.
  • Browse to Contents/MacOS
  • Open the CRXDE.ini file and change the values for Xms, Xmx and the MaxPermSize to suit your needs and what your system will support.

Delete the .crxde folder

  • CRXDE created a hidden .crxde folder under the users home directory.
  • Delete that folder

Start CRXDE from command line.

  • Open -a CRXDE –args -clean (This is for OSX only)

Hope this helps. Please leave a comment/question and I will try to answer them as soon as I can.

11:26 AM Permalink
February 10, 2012

How to add align options to the textimage component

If you have ever looked at the textimage component on the geometrixx site and seen that it has a align option for the image.

But, dont see that option when you added  the textimage component on your site.

To add align options for the text and image component for your site, just like the geometrixx site, follow these steps.

1. Locate the paragraph system where you will be adding the text and image component on your site, inside your site’s design folder.

2. Inside the par node, create a node “textimage” of type “nt:unstructured”

3. Inside the textimage node, create a node “cq:styles” of type “nt:unstructured”.

4. Inside the cq:styles node, create a node “imagealign” of type “nt:unstructured”.

5. Inside the imagealign node, you can create as many alignment nodes as you wish.

  • Create a node “image_left” of type “nt:unstructured” and create a property “text” of type String, with the value “Left”
  • Create a node “image_right” of type “nt:unstructured” and create a property “text” of type String, with the value “Right”

6. You will have to handle the actual alignment of the images in your CSS file for divs “image_right” and “image_left” or whatever other values you add to the imagealign node.


1:07 PM Permalink

How to save nodes to a dynamic path when using scaffolding

The out of the box scaffolding lets you choose a target path which where all the pages you create using the scaffolding will be stored.

I recently ran into a use case where the client wanted to save the pages to a dynamic path based on the date on which the page was created. One can achieve the fore mentioned use case by doing something similar to what I will lay out in this blog post.

1. Override the out of the box wcm/scaffolding path by creating the same path structure in the apps folder. The new structure should look like below.

You can copy the contents of the folder in the apps directory from the libs directory.

2. We will have to update the wcm/scaffolding/components/scaffolding/body.jsp file to add our custom code to change the save location.

  • Make sure the following classes are imported.
  • The code to get the current date

  • In the myForm.addButton method, update the out of the box code to change the formUrl to your dynamic value. Code below.


That should be it! You are now saving pages created using a scaffolding in dynamic locations

12:42 PM Permalink
November 17, 2011

How to make the component dialog floating and set a default size

I recently ran into a situation where I wrote a custom widget for a client which had a list of 25 items to be displayed. The default dialog size of CQ wasn’t big enough for that and the users would have had to scroll up, down, right and left to cover the whole list. I figured out a way to make the dialog floating (which would give the users the ability to resize it by dragging) and to set a default size that can be as big or small than the default CQ dialog box. Here’s how to do it.


1. Create a node in your component of type cq:EditConfig and name cq:editConfig, this should be a sibling of the dialog node.

2. To the cq:editConfig node add a property with name “cq:dialogMode”, type “String” and value “floating”

3. To your dialog node add two properties of type Long, name height and width and value to what the you want the size of the dialog to be.

4. That should be it. This should open the dialog with the size that you mention in the height and width properties you created in the earlier step and give the users the ability to resize the window by dragging.


3:46 PM Permalink
  • Authors

  • Archives

  • Developer Resources