Thursday, November 1, 2012

The Fine Art of Minification in CQ5.5

The Problem:

Pages are taking too long to load in production, because the JavaScript pages contain comments, whitespaces and long variable names causing bloating in file size.

The Solution:

Minification! What is minification you ask?

The Theory:

In a nutshell, minification is a fancy term for getting rid of unnecessary characters in your JavaScript. It is a subset of obfuscation.

Minification in CQ5 does the following:
  1. Removes the following superfluous characters from the JavaScript code:
    1. White Space Characters
    2. New Line Characters
  2. Renames long variable and function names in the local namespace to something smaller
You need to be careful to note that if you have ridiculously long function names, you will still wind up with bloated JavaScript files, as the Minification engine in CQ5 does not yet 

The Implementation:

To activate minification, you will need to log in to your Felix console and enable the minify option.

  1. Go to {ServerURL}/system/console/configMgr
  2. Scroll down and click on "Day CQ HTML Library Manager"
  3. Click on the Minify checkbox
  4. (Optional) Enable Gzip

Where to Next?

If minification does not reduce your file size enough yet, you only have a few options. If you can think of more, please let me know so that we can collate them here.

1. Refactor your unnecessarily loquacious  names to more simple and understandable names. (Coming Soon: Link to post on how to get understandable names.)

2. Use an external JavaScript minifier such as
NOTE: If anyone out there thinks there is a better minifier, please comment below.

3. See if you can hang your code out to DRY

Customizing DAM image metadata

The Problem:

You have a CQ site that needs additional metadata globally attached to your images within the DAM.

The Solution:

The Theory:

Extend the DAM to capture the required information.

If you add a folder and image into the DAM, you are creating a JCR node with a binary blob attached, and whole slew of additional metadata.

As an exercise, go into the dam, create a new folder called /content/dam/TestPicture, and add any jpg image called TestJPG.jpg.

Go to your crx explorer by visiting localhost:4502/crx/explorer/browser/index.jsp, and navigate to content/dam/TestPicture

If you have added the image previously, you will find a dam:Asset node titled TestJPG.jpg.

If you expand this node, the jcr:content node and then click on metadata, you will see a list of the current metadata associated with the image.

Go back to the DAM, and double click on the TestJPG.jpg image, and you should see a properties popup, allowing you to enter a list of metadata to associate with the image.

Enter Test Title into the title field, and make the language English.

Go back to the crx explorer, click on jcr:content and back on metadata. This will refresh the list. You will see that dc:language is set to English, and dc:title is set to Test Title.

If you have done the Retrieve Data from JCR recipe (Coming Soon), you will see that you can retrieve this metadata freely from the JCR.

The implementation:

This is great if you only want to capture the information provided by default, but what if you want your application to have additional data, such as a clickable link for the picture, or phone and email details? 

What needs to happen, is you need to customise the DAM editor.

If you look into libs/dam/content/asseteditors/image/jpeg/formitems, you'll see that the list of nodes here is the list of items in the JPG image metadata properties page.

Now, you *could* just add new custom nodes here and end the tutorial, but this is definitely not a good thing to do, as you want to leave the libs folder alone.

Instead, you'll want to create a new folder structure down to /apps/dam/content/asseteditors/image, right click on the libs/dam/content/asseteditors/image/jpeg folder and click on copy, navigate to your newly created /apps/dam/content/asseteditors/image folder, and click on open.

Sling will render the apps/dam/...etc content before the libs/dam/...etc content if it exist, and you won't be messing around with the internals of CQ5.

OK, now let's say after the description, we want to add a new field called clickURL

Go to /apps/dam/content/asseteditors/image/jpeg/formitems in the crx/explorer, right click and select New Node. For the name, enter clickURL, and for the type, select cq:Widget from the dropdown. Left Click on the newly minted node, and double click on title. Enter Click URL.
Double click on xtype, and enter textfield.
for the name, enter ./dc:clickURL..

Go back to the TestJPG.jpg in the dam, double click on it, and you should see the new field.

Enter for the clickURL, Click on the save button down the bottom right.

If you now look at the metadata for the image in the crx/explorer, you'll see a dc:clickURL property, populated with

Note that if you don't fill in the information, the property is not created in the metadata.

Repeat the same process to create a new node for Person Name using personName as the name, and Location Address using locationAddress the name, both as text fields.

Go back to the dam, double click on the TestJPG.jpg again, and you will also see the new fields present.

Let's create two sub folders in TestPicture, content/dam/TestPicture/personnel and content/dam/TestPicture/locations.

Copy in a random JPG file called johnbrown.jpg and a random JPG called 123AnywhereSt.jpg.

Double click on johnbrown.jpg, and notice that you can now enter John Brown into the Person Name field.

Double click on 123AnywhereSt.jpg, and you can enter 123 Anywhere St into the Location Address field.

The problem here, is that you are now prompted anywhere in the DAM with the ability to label an image with Person Name and Location Address details. In this case, the Location Address should not show in the content/dam/TestPicture/personnel folder, and Person Name should not show in content/dam/TestPicture/locations.

Fear not, there is an answer. You can use a node listener to allow sling to determine whether the node should be shown or not, based upon the originating location of the folder.

You add a listener by navigating to the /apps/dam/content/asseteditors/image/jpeg/formitems/personName node in the crx/explorer, right clicking, and adding an nt:unstructured node called listeners. Right click on the listeners node, and select New Property, and call it beforeloadcontent. Leave it as a String property. Now for the magic.

Set the beforeloadcontent parameter to the following:
function(f, r, p) { if (p.indexOf("/content/dam/TestPicture/personnel") != 0) { f.hide(); } return true; }

Let's look at this in detail. First of all our function signature: function(f, r, p).

f stands for the field, r for the record, and p for the path.

The if statement ( if (p.indexOf("/content/dam/TestPicture/personnel") != 0) ) checks to see if the path of the folder we are working in matches with the listener. You can vary this logic however you may need to, but in our case, we want all of our images down from folders in personnel to show the personName field.

Click on save, go back to the DAM, and double click on the /content/dam/TestPicture/personnel/johnbrown.jpg file. You'll see that the Person Name field is still displayed.

Double click on content/dam/TestPicture/locations/123AnywhereSt.jpg file, and you'll see that PersonName is not there as a field.

Repeat the same process for the content/dam/TestPicture/locations path by repeating the above steps, but this time pasting the following line into the beforeloadcontent parameter:
function(f, r, p) { if (p.indexOf("/content/dam/TestPicture/locations") != 0) { f.hide(); } return true; }

You can repeat this process as needed.

Where to Next?

You can use a wide selection of widgets within the editors, such as date pickers, combo boxes, checkboxes. You can see a selection of components by visiting:

Navigate to CQ/Ext/form, and you'll see quite a few form field components. To use them, find the component you want, and declare it with the xtype variable instead of  using textfield. For example, if you wanted a checkbox, set the xtype variable to checkbox.

You can also Restrict Folders by User Using the ACL list (Coming Soon)