Quantcast
Channel: Adobe Experience Manager Podcast » Client Library

Why Client Libraries are Useful in CQ

$
0
0

The Web used to be a simple place. All you needed to know to build a site was a little HTML and you were good to go. It didn’t take long for browser makers to introduce styles and JavaScript to their products, and eventually developers realized that they could use CSS and JavaScript to make a page look beautiful and feel dynamic. Not long after, it became common for websites to have a tag filled with references to stylesheet files and JavaScript libraries.

Knowing how messy that can make source code look, not to mention the toll on site performance, the creators of Adobe Experience Manager (AEM formerly Adobe CQ) implemented what is called the Client Library. Without the proper experience, it is a system that can get you into a lot of trouble.

At its basic level, the Client Library allows a developer to keep all of his or her stylesheets and JavaScript libraries organized in project folders in the CRX repository. On the front end, all these files are compiled into a single location referenced on the page. The browser only makes a single request, which cuts down on a lot of HTTP chatter.

AEM-client-library

As you can see from the image above, AEM provides a straightforward method for developers to take advantage of this feature. Simply place your JS and CSS files in a cq:ClientLibraryFolder with the appropriate js.txt and css.txt files so the Client Library knows which files to include.

Here’s an example from the Geometrixx Outdoors sample site pulled from /etc/designs/geometrixx-outdoors/:

geometrix-outdoors-example-clientlibs

The Drawback
As long as you’re the only developer working on a site and you’ve kept your files well-organized and tested, the Client Library really simplifies things for you. However, if you are brought in to help on a large site that has had several iterations of developers working on it, the Client Library can be a large, intimidating labyrinth. Luckily, there are a couple of tools to help track down that JavaScript bug that’s been driving you crazy.

The first and most simple tool is to simply append “debugclientlibraries=true” to the query string of your page. This will divide the Client Library scripts and stylesheets into their individual parts, so you more easily utilize your browser’s debugging suite to track issues.

The second tool provided by AEM is the Library Dump Tool. It can be reached at http://localhost:4502/libs/granite/ui/content/dumplibs.html?debugclientlibraries=true (where you replace localhost and the port based on your AEM environment). This tool lists out all the files available to the Client Library as well as each file’s dependencies—giving you a powerful tool for stamping out defects in your site.


Debug Client Libs in Adobe Experience Manager (Formerly Adobe CQ)

$
0
0
Hello everyone, in this blog post, we will discuss managing Client Libraries in Adobe Experience Manager (formerly Adobe CQ). We are assuming that you know what ClientLibs are in AEM and how they work, and that you are aware of the dependency and the embed properties of ClientLibs. You should be familiar with how ClientLibs are combined into a single file. If you are not familiar with these terms, you can check out our “Why Client Libraries are Useful in CQ” post here.

One very difficult task that a AEM developer can face is debugging their Client Library folders. In AEM it is possible to have a ClientLib folder where all your JS and CSS can be compiled and returned to a Web page that uses the single ClientLib file; however, you can embed other ClientLib folders as well. As a result, one ClientLib folder could have multiple JS and CSS files strewn throughout the entire AEM repository inside multiple ClientLibs that you may not even know exist. How do you deal with an error in a ClientLib file that is included on your AEM template?

Useful Tools

Two helpful tools that you can use for debugging ClientLibs are as follows: 1. http://<AEM URL>:<AEM Port><Content URL>?debugClientLibs=true example: http://localhost:4502/content/geometrixx/en/community.html?debugClientLibs=true 2. http://<AEM URL>:<AEM Port>/libs/granite/ui/content/dumplibs.html example: http://localhost:4502/libs/granite/ui/content/dumplibs.html

Tool 1: ?debugClientLibs=true

The first utility is a query string parameter that you can pass into the Web page you are authoring. For example, take a look at the Geometrixx website. Lets focus our attention on the community website on Geometrixx (/content/geometrixx/en/community). We can see there is a comment element that has its style definition in ClientLib.css. Once we locate this file we can see that the ClientLib.css file is 2402 lines.

Sources ScreenShot |Debug Client Libs in Adobe Experience Manager (Formerly Adobe CQ) |AEMPodcast.com Lines ScreenShot |Debug Client Libs in Adobe Experience Manager (Formerly Adobe CQ) |AEMPodcast.com Where is the style found for this comment component? It is in the Geometrixx ClientLib, but where in the CRX tree structure is it located?

If you retype the URL with the following query parameter, ?debugClientLibs=true (http://localhost:4502/content/geometrixx/en/community.html?debugClientLibs=true), several actions will occur. You can see that the AEM instance will return all of the individual files that all ClientLibs include inside each file. In other words, the ClientLibs will be returned in pieces instead of one file. This may take a while depending on the size of the ClientLib and the dependencies.

You will discover that there is a file called ClientLib.css?debug=true in place of where the ClientLib file use to be. Inside this file, you will find a list of all of the CSS files that are included in this ClientLib. You will also have all of the paths that the CSS files are located in. The same can be found in the ClientLib.js?debug=true.

Debug True ScreenShot |Debug Client Libs in Adobe Experience Manager (Formerly Adobe CQ) |AEMPodcast.com This can be useful to find out which files are included in the ClientLib. The source tree returned from AEM will also be different. We can use this now in our example to learn that the CSS for this comment element is located in the qna.css file:

QNA ScreenShot |Debug Client Libs in Adobe Experience Manager (Formerly Adobe CQ) |AEMPodcast.com

We can also learn that the qna.css file is located in the CRX repository at: /libs/social/qna/components/qnaforum/clientlibs/qna.css. We learn this by looking at the source tree returned by the AEM instance. This may be a little confusing, so I prefer to refer to the ClientLib.css?debug=true file.

QNA File ScreenShot |Debug Client Libs in Adobe Experience Manager (Formerly Adobe CQ) |AEMPodcast.com Import URL ScreenShot |Debug Client Libs in Adobe Experience Manager (Formerly Adobe CQ) |AEMPodcast.com

Tool 2: http://<AEM URL>:<AEM Port>/libs/granite/ui/content/dumplibs.html

This utility that is built into AEM can also serve the same purpose as ?debugClientLibs=true as described above. It also gives you other advantages. You can see all the ClientLibs on the current AEM instance and what their dependencies and embeds are. This can be particularly useful if you are looking for the parent ClientLib of a particular ClientLib. The power of this overall view can also make refactoring ClientLibs useful as well. You can also see if a ClientLib contains JS, CSS or both.

Library Path  ScreenShot |Debug Client Libs in Adobe Experience Manager (Formerly Adobe CQ) |AEMPodcast.com One useful capability of this tool is that it also has a search feature for specific categories. Since it is possible in AEM to give multiple category names to multiple ClientLibs, searching for a specific ClientLib can become cumbersome. Using this search capability will enable you to see every ClientLib with the specified category. Note – If you are using a older version of AEM or CQ 5.6.1, the old url is: /cq/ui/content/dumplibs.html

Get Consistent and Organized ClientLibs

ClientLibs can be incredibly difficult to deal with in AEM because of the way that any ClientLib file can include another ClientLib in a completely different location. It may get even more frustrating when you are trying to maintain AEM JS and CSS that developers in the past have put in all sorts of locations. With the query parameter ?debugClientLibs=true and the /libs/granite/ui/content/dumplibs.html utility, you can manage and even organize your ClientLibs so they are consistent. It may be incredibly frustrating to know that two types of jQuery versions are being included but you can’t find out which ClientLib is the cause. With these tools, it makes hunting these issues down much easier.

Have you ever had to use these debugging tools to solve an interesting problem? Maybe you’ve used ClientLibs in an unusual way? The AEM Podcast would love to hear from you. Tweet us @Axis41 or email us at info@aempodcast.com. Don’t forget to follow our LinkedIn Adobe Experience Manager showcase page for the most up-to-date information and articles on AEM.

AEM’s CSSFileBuilder vs. Protocol-relative paths in ClientLibs

$
0
0

Protocol-relative paths

The first time I ever heard of protocol-relative URLs (properly called “network-path references”) was back in 2007 in an article by Ned Batchelder, who I know from Freenode’s #python channel. The most common use-case for these URLs are when you want your site to refer to some external resource, such as a stylesheet, web-font, image, etc. – but you cannot know at the time the site is coded whether the end-user will be using HTTPS or HTTP. (You should always be using HTTPS anyway, but we can’t always enforce that…)

However, if you use one of these protocol-relative paths in a CSS file that participates in a ClientLib, you’ll discover an un(der?)-documented behaviour. I think it would be easiest to just show you what’s going to happen if you try it, and then explain why, and what you can do about it.

Creating a ClientLib

In this example, I’m going to make a ClientLib that will contain a css.txt file, and a ‘css’ folder with one CSS file inside it. For purposes of this example, I’ll try to load a Google Webfont using a protocol relative URL – the font I selected is called “Gloria Hallelujah.”

I’m lazy, so I’m just going to drop all of this inside /apps/geometrixx. The following steps will basically echo those found in the Adobe Experience Manager documentation for creating a ClientLibrary – I’m just including them here so you don’t have to open a new tab. If you already know how to make a ClientLibrary, there’s nothing particular interesting going on here…

  1. Navigate to http://localhost:4502/crx/de/index.jsp#/apps/geometrixx and log in (if you’re not already).
  1. Right-click on ‘geometrixx’ and select ‘Create…’, then ‘Create Node…’apps-create-node
  1. Give the node a name you’ll be able to find later – I chose ‘clPathExample.’ The node type needs to be ‘cq:ClientLibraryFolder’. Click ‘Save All.’clientlib-dialog
  1. Select the new ‘clPathExample’ node. Go to the Properties pane and add a property called ‘categories’ of type String[]. Put a value in here that you’ll be able to remember – I went with ‘cl.loadfont’.
    clientlib-properties
  1. Right-click on ‘clPathExample’ and choose ‘Create …’, then ‘Create Folder.’ Name the folder ‘css’. Click ‘Save All.’css-folder-dialog
  1. Right-click on the new ‘css’ folder and chose ‘Create …’, then ‘Create File.’ Name the file ‘font.css’. Click ‘Save All.’
    font.css-file
  1. In the editor pane that opened for ‘font.css,’ enter the following text:font.css-content
    @import url(//fonts.googleapis.com/css?family=Gloria+Hallelujah);
    .example { font-family: 'Gloria Hallelujah', serif; }

This is the path to our Google Font, with a protocol-relative URL; we’re also setting up a CSS class we can use later to see it get applied. Click ‘Save All.’ Leave this editor tab open, as we’ll be using it again later.

  1. Right-click on ‘clPathExample’ and choose ‘Create …’, then ‘Create File.’ Name the file ‘css.txt’. Click ‘Save All.’css-txt-dialog
  1. In the editor pane that opens for ‘css.txt’, you have two options. You can either use the ‘#base’ method of setting the ‘relative root':css-text-content


#base=css
font.css

or, you can put the full relative path to the font.css file as a single line:

css/font.css

At Axis41, our habit is to use #base, so I’m going to go with that for now; however, neither option seems to have any effect on the behaviour we’re discussing today. Click ‘Save All.’ You can close the css.txt editor pane at this point.

For the next step, rather than go through the whole process of embedding this ClientLib in /etc/designs, then creating a page that uses <cq:includeClientLib /> to pull it into head.jsp, we’re just going to take a short-cut for purposes of demonstration, and make a static file under /content. If you really want to go the longer route, feel free to follow along with the Adobe Experience Manager example found here; or you can just take my word for it that the behaviour we’re demonstrating doesn’t change when used through an embed.

  1. Right-click on ‘/content’ and choose ‘Create…’, then ‘Create File.’ I’m going to name my file ‘example.html’. In the new editor pane that opens for ‘example.html’, put the following HTML code:


<html>
<head>
<link href="/apps/geometrixx/clPathExample.css" rel="stylesheet">
</head>
<body>
<div class="example">
This text should be using our Google Webfont.
</div>
</body>
</html>

Again, note that we’re not following the standard best practice of linking the ClientLibrary through /etc/designs; I would not recommend doing it this way in a production environment, but doing this here shaves several paragraphs off the example.

Click ‘Save All’ and load the example page in your browser (i.e., http://localhost:4502/content/example.html).

broken-page-only

What just happened there?!

Obviously, this is not loading our Google Font. If we look at ‘View Source’, everything looks OK on ‘example.html’, so what happened? Let’s take a look at our Developer tools to see what kind of hint that can give us.

broken-network-tab

Hmm – why does the Network tab show a 404 for the font request? Let’s see if the Console tab gives us any better information…

font-not-loaded

Wait – why is it trying to load the Google Font from localhost:4052? Let’s jump right to the CSS file itself:

css-code-broken

What happened?!

The problem lies in a little piece of code known as the CssFileBuilder, which runs as part of the “Day CQ HTML Library Manager” service (com.day.cq.widget.impl.HtmlLibraryManagerImpl). Adobe hints at this behaviour in their documentation, with the following aside:

When you embed CSS files, the generated CSS code uses paths to resources that are relative to the embedding library. For example, the publicly-accessible library /etc/client/libraries/myclientlibs/publicmain embeds the /apps/myapp/clientlib client library:

I mean, reading that sentence, you’d think, “Sure – makes sense, that seems like exactly the behaviour we want,” but the fact that the CssFileBuilder tried to turn a network-relative path into a series of parent-path components back to the site root certainly came as a surprise to me. So, what exactly can we do? Well, thankfully, there’s a feature inside of CssFileBuilder – which I can’t find any documentation for, unfortunately – that allows use to override this behaviour.

Make our URL absolute

Earlier, I told you we’d be re-visiting the font.css editor in CRX DELite. Let’s go there now and make a small change to the code:

@import url(absolute://fonts.googleapis.com/css?family=Gloria+Hallelujah);
.example { font-family: 'Gloria Hallelujah', serif; }

Now, let’s try re-loading the CSS file and see what happens:

css-code-working

Perfect – exactly what we were looking for! The addition of the pseudo-scheme ‘absolute:’ stopped the ClientLibrary code from breaking our URL. Now let’s make sure everything looks OK in our ‘example.html’ file:

all-is-well

Great! Looks exactly like we had hoped. The obvious drawback of this method is that we cannot now directly reference the CSS files used in a ClientLibrary – but, at least for Axis41, that had zero practical implications, as it wasn’t something we ever found ourselves doing, anyway.

Takeaway

So now you know – if you want to use protocol relative URLs (or “network-path references,” as we should probably all be calling them) in your CSS ClientLibrary files, you have to prefix them with the pseudo-scheme ‘absolute:’ to prevent CssFileBuilder from rewriting them as relative paths to the site root.

Featured picture by Tom Eversley

Using Client Libraries and Avoiding jQuery Headaches

$
0
0

05287_Using Client Libraries and Avoiding jQuery Headaches in AEM
AEM provides a feature called client libraries to allow for managing CSS and JavaScript in your site.

  • It allows you to bundle your files into one large file so you have fewer requests on your pages.
  • It allows you to minify them to make the download less expensive and faster.
  • It allows you to “categorize” them so you can define dependencies and control the order in which they are loaded (this is mainly important for JavaScript).
  • It allows you to store the JavaScript that is component specific in the repository location of the components (/apps/projectname/components/componentname/clientlibs). You can then load them by referring to their category from the “dependencies” or “embed” property of the clientlibs in your front-end design under /etc/designs/projectname/clientlibs.

App-specific client library folders
It is a best practice to keep all application-related files in their application folder below /apps. It is also a best practice to deny access for website visitors to the /apps folder. To satisfy both best practices, create a client library folder below the /etc folder that embeds the client library
that is below /apps.

However there is one snag you need to be very wary of…

The front-end designers tend to develop their code based on a recent version of jQuery and forget to mention this as a dependency (sometimes this jQuery library is not even provided together with the front-end design)! What this means is that all the custom JavaScript you received needs this version of jQuery to work properly.

Most of Adobe Experience Manager’s edit functionalities are JavaScript-based and it also uses jQuery! However, AEM 6.0 comes bundled with jQuery version 1.11.0, which is kind of prehistoric.

/etc/clientlibs/foundation/jquery: categories: cq.jquery, dependencies:
granite.jquery
/etc/clientlibs/granite/jquery/granite: categories: granite.jquery, dependencies:
jquery, granite.utils
/etc/clientlibs/granite/jquery: categories: jquery
/etc/clientlibs/granite/jquery/js.txt
#base=source
1.11.0/jquery-1.11.0.js
browser/browser.js

You are loading the jQuery library from AEM itself when you include the following line in a (custom) page component:

as this standard JSP contains the following code:

But even if you don’t load it explicitly this way, if you load other client libraries from Adobe Experience Manager, it is quite possible that some of them depend on “cq.jquery” so the standard jQuery will get loaded after all.

So the extra challenge is:

  1. Make sure the correct jQuery version required by the front-end design is added to the client libraries used by your AEM site (to avoid getting strange design issues that do not occur in the original front-end design)
  2. Make sure it is loaded before any custom code (component-specific JavaScript, front-end design JavaScript)
  3. Make sure it doesn’t conflict with the jQuery functionality of AEM itself

Load correct jQuery version into the client libraries used by the design of your site

  1. Put all CSS and JavaScript of the front-end design into a “clientlibs” folder under “/etc/designs/projectname” and categorize it as “sitename.frontend” (add a multivalue String property “categories”)
  2. Add the correct front-end jQuery library to the client libraries used by the design of your site to make sure it gets loaded, but…
  3. Due to the dependencies of other (standard) client libraries, the old Adobe Experience Manager jQuery library version will still be loaded and this can lead to nasty conflicts.
    1. Do not attempt to categorize your new jQuery client library as cq.jquery in the hopes of preventing the old one from loading. It will still do. The only way this might work is to use the identical folder structure and file names as the standard AEM jQuery library. But it wouldn’t make sense and be very confusing to rename a newer version to “1.11.0/jquery-1.11.0.js”. So just don’t.
    2. Also it may not be a good idea to try to overlay the AEM native jQuery library in the first place as it is part of the platform and we may break native functionality this way. Even if we succeeded to “upgrade” the native jQuery library, all sites running on the server would then be forced to use this version and each site design could depend on another jQuery version.
    3. Do not attempt to create a custom overlay of /libs/foundation/components/page/stats.jsp so it no longer includes cq.jquery, but apps.yourproject.jquery and provide a specific clientlibrary folder under /etc/designs/projectname/clientlibs. As other AEM native client libraries will still mention dependency “cq.jquery”, the AEM native jQuery will keep on getting loaded.
  4. Accept that loading the native AEM jQuery 1.11.0 version is unavoidable.

Load correct jQuery version before any custom JavaScript is loaded (component-specific or general front-end design stuff).

  1. Put the correct jQuery library inside its own “jquery” subfolder in your “clientlibs” folder and categorize it as “sitename.jquery” (add a multivalue String property “categories”).
    1. Put the correct jQuery library inside its own “jquery” subfolder in your “clientlibs” folder and categorize it as “sitename.jquery” (add a multivalue String property “categories”) and make it depend on the AEM native client library “jquery” (add a multivalue String property “dependencies=’[jquery]’”) to make sure this one is loaded before the your custom front-end jQuery library.
      jquery
  2. Categorize all “clientlibs” folders on your custom components as “projectname.components” (add a multivalue String property “categories”). (You can optionally categorize them as “projectname.components.componentname” as well, should you need to load only clientlibs for a specific component somewhere.)
  3. Now the magic words… To the “clientlibs” folder of your site under “/etc/designs/projectname”.
    1. Add a multivalue String property “dependencies=’[sitename.jquery]’” to make sure the jQuery library required by your front-end design is loaded before your own site design client libraries (and therefore before any custom JavaScript).
    2. Add a multivalue String property “embed=’[sitename.components,cq.foundation]’” to make sure the client libraries of your custom components are loaded after the jQuery library of your front-end design but can still be bundled together with your other site design client libraries into one big JavaScript file and minified.
      clientlibs
  4. This still leaves that fact that you are loading two different jQuery versions at the same time and both probably use $, which is a cause for conflicts.

– Replaced all $ with $j in components related .js file which didn’t refer to AEM, CQ, Granite specific .js libraries.

Load correct jQuery version into the client libraries used by the design of your site.

  1. Replace all $ in your custom JavaScript (component-specific clientlibs with JavaScript files, front-end design JavaScript files) with another reference like “$j” to avoid that your custom code uses the native AEM jQuery that is assigned to $ and $CQ.
    1. Also communicate this to your front-end designer so he never ever uses $ in their front-end design for your Adobe Experience Manager project again.
  2. Lift the conflict between your front-end jQuery library and the one native to AEM (https://api.jquery.com/jquery.noconflict/ -> If for some reason two versions of jQuery are loaded (which is not recommended), calling $.noConflict( true ) from the second version will return the globally scoped jQuery variables to those of the first version.)
    1. Add a new JavaScript file “jquery.noconflict.js” to the “source” folder inside the “jquery” clientlib folder (which you created in the first point of the previous topic) in your front-end design “clientlibs” Make sure it gets loaded by mentioning it in the accompanying “js.txt” file. Inside this new JavaScript you put the code.

var $j = jQuery.noConflict(true);

Add debug code to the body of your generic page component to be able to easily
check if the correct jQuery version is being used.  Add code that will:

  1. Print the version of the jQuery libraries assigned to references $ and $CQ (hopefully the native Adobe Experience Manager one)
  2. Then load the custom JavaScript from your front-end design client libraries, which
    1. First loads the native AEM jQuery if it wasn’t already loaded (your front-end design depends on your custom design jQuery, which depends on the native AEM jQuery)
    2. Then loads your custom design jQuery and at the end executes the noConflict code, which assigns it to reference $j
    3. Then adds the custom JavaScript from your custom components
    4. And finally loads all remaining custom JavaScript from your front-end design
  3. Then prints the version of the jQuery libraries assigned to references $, $CQ and $j. Here you should see that $ and $CQ are still assigned to the native AEM jQuery version and the $j to your custom design jQuery version.

Before $.noConflict(true)

--%> var $log = $( "#log" ); $log.append( "

After $.noConflict(true)

" ); $log.append( "jQuery version linked to ($): " + $.fn.jquery + "
" ); $log.append( "jQuery version linked to ($CQ): " + $CQ.fn.jquery + "
" ); $log.append( "jQuery version linked to ($j): " + $j.fn.jquery + "
" ); --%>

For further client libraries debugging tools, check out this other AEM Podcast article on this topic.

ivo_eersels2Author bio
Ivo Eersels is an industrial engineer and has been a software engineer on the Intershop Suite 6 E-commerce platform at Osudio, one of Europe’s largest e-business specialists, since 2007. He has been working with AEM since 2013. Ivo plays a large role in setting up projects, DTAP servers, deployment strategies, guidelines, and development.

Simple Touch UI Dialog Extensions for AEM

$
0
0

05287_Simple-Touch-UI-Dialog-Extensions-for-AEM
While there are a number of tools at a developer’s disposal to create clean, engaging dialogs within AEM, there are times when you may need to extend dialog functionalities in your Adobe Experience Manager implementation to suit your clients’ needs. Oftentimes, this can be achieved without too much effort.

As an exercise, we’ll use AEM 6.0 to create a Touch UI dialog. This dialog will contain a checkbox that toggles the visibility of a container that holds additional authorable fields.

Setting up the Dialog
There are two nodes that will be required to make our toggleable container in our Touch UI dialog: the toggle and the toggleable container itself. Each has its own important attributes. Let’s take a look at the cq:dialog.

We’ll start with the checkbox toggle:

There are a few key attributes that we want to look at here:

  • The “class” attribute will add that class to the checkbox when the dialog is rendered. This will allow us to target that checkbox later using JavaScript, allowing us to listen for any events on the checkbox. We’re using “showhide” as our class name.
  • The “value” attribute determines what the value of the checkbox will be when the checkbox is toggled.
  • The “showhide-target” will create a “data-showhide-target” attribute in our checkbox’s markup when the dialog is rendered. Our JavaScript will use this value to determine what it is we are trying to show or hide. We’ll target elements with the class name of “.showhide-target” for this example.

Let’s take a look at our toggleable container:


    
        
        
    

Above, we have a container with two textfields inside. We want to be able to show or hide this container dependent on whether or not our checkbox is checked. This container has two important attributes pertaining to our experiment:

  • The container’s “class” attribute will add the “showhide-target” class. Notice that this is the same class name that we are using in the “showhide-target” attribute of the checkbox. The toggle will target this container because of this class.
  • The “showhide-target-value” will create a “data-showhide-target” in our container’s markup when the dialog is rendered. This attribute will be set to the same value as the “value” attribute used in the checkbox. Our logic will check to see that our target container’s value of “true” matches that of the checkbox. If the checkbox is checked, they will match and we’ll show the container. If not, we’ll hide it.

Extending the Component with JavaScript
Our JavaScript will need to be added to a “cq:ClientLibraryFolder” that belongs to the “cq.authoring.dialog” category and depends on the “granite.jquery” client library. Let’s break down some of its functionality.

First, we’ll look at our event listeners.

$(document).on("foundation-contentloaded", function (e) {
  $(".showhide").each(function () {
    showHide($(this));
  });
});

$(document).on("change", ".showhide", function (e) {
  showHide($(this));
});

We’ve set up two listeners here. Our first will listen for the creation of our dialog (the “foundation-contentloaded” event). It will check for any toggle we may have set up and call the showHide function, passing the toggle object as a parameter. (Note: This allows us to see if a toggle is already checked when it is rendered. If it is, we’ll go ahead and show our toggleable container from the get-go.)

The second listener will look for any changes to the toggle. If a change event is triggered, we’ll again call the showHide function, passing the toggle object as a parameter.

Notice that we are looking for the “showhide” class in both listeners, which is the same class we gave to the checkbox toggle.

The showHide function is what is going to do the majority of the work:

function showHide(el) {
  var target = el.data("showhideTarget"),
    value = el.prop("checked") ? el.val() : "";

  // hide all targets by default
  $(target).not(".hide").addClass("hide");

  // show any targets with a matching target value
  $(target).filter("[data-showhide-target-value=\"" + value + "\"]").removeClass("hide");
}

This function will take the value of the checkbox (el) and compare it to the “data-showhide-target-value” of the toggleable container (target). If the values match, we’ll remove any “hide” class associated with the toggleable container. Otherwise, we’ll add that “hide” class to the container, which will hide it.

Here is a look at the JavaScript in its entirety:

(function (document, $) {
  "use strict";

  // listen for dialog injection
  $(document).on("foundation-contentloaded", function (e) {
    $(".showhide").each(function () {
      showHide($(this));
    });
  });

  // listen for toggle change
  $(document).on("change", ".showhide", function (e) {
    showHide($(this));
  });

  // show/hide our target depending on toggle state
  function showHide(el) {
    var target = el.data("showhideTarget"),
      value = el.prop("checked") ? el.val() : "";

    // hide all targets by default
    $(target).not(".hide").addClass("hide");

    // show any targets with a matching target value
    $(target).filter("[data-showhide-target-value=\"" + value + "\"]").removeClass("hide");
  }

})(document, Granite.$);

Through this simple exercise, you can see how easy it can be to build out more complex dialogs, allowing for a much improved authoring experience for your clients. We have talked about how we at Axis41 have extended some simple, out-of-the-box Adobe Experience Manager components in a prior blog post by Peter Nash. If you have other ideas about how to extend components or want to take a crack at sharing your method for extending more complex dialogs, then drop a line to info@aempodcast.com.

Versioning ClientLibs in AEM

$
0
0

05287_Versioning-ClientLibs-in-AEM
Recently in a project I was working on, we had the need to cache our clientlibs and have them reliably recache every time there was a change. I looked around and found that there is an ACS AEM Commons tool made for just this purpose. In this post I’ll demonstrate how we went about using this tool to version our clientlibs.

The Versioned ClientLibs ACS AEM Commons feature uses a Sling rewriter to add an MD5 hash to the paths of your clientlibs, forcing them to recache after every modification. Typically Adobe Experience Manager will use the lastModified property to determine when to recache, however versioned-clientlibs is a more reliable approach.

To implement the versioned-clientlibs feature, simply copy the node from /libs/cq/config/rewriter/default to some path inside your application. In this example, we’ll choose /apps/acslibs/config/rewriter. For the most part this path is arbitrary, however the config node must be inside a four-level-deep path that ends in config/rewriter to work.

Your config file should be named versioned-clientlibs.xml and should look something like this:


    

Along with your config for the versioned-clientlibs, you should also copy down the default config node and make sure versioned-clientlibs is added to the transformTypes. Here’s an example of the content.xml for the default config:


    
        
        
        
    

If you want to validate whether your configuration was successful, you can check the Sling Rewriter tab in the OSGI Web Console (/system/console/status-slingrewriter). Under “Active Configurations” you should see a configuration section for the versioned-clientlibs.

Versioned ClientLibs
defaultclientlibs

Default
versionedclientlibs

Along with the rewriter configuration, you’ll also need to configure Apache to send the right headers. Here’s an example of what the config should look like:

SetEnvIf Request_URI "(\.min)?\.[a-f0-9]+\.js" long_expires=true
    SetEnvIf Request_URI "(\.min)?\.[a-f0-9]+\.css" long_expires=true
    Header set Cache-Control max-age=2592000 env=long_expires

That’s it. Now your clientlibs should recompile every time there’s a change to them.

It should be noted that per the ACS Adobe Experience Manager Commons documentation there are exceptions to which files this rewriter will support. These are the files this rewriter will NOT support:

  • URIs embedded in CSS or JavaScript, including: background-images, web fonts, etc.
  • Relative URIs, e.g., etc/clientlibs/mysite/styles.css
  • URIs including a scheme or protocol-relative location, e.g., http://example.com/etc/clientlibs/mysite/styles.css and //example.com/etc/clientlibs/mysite/styles.css
  • URIs to non-AEM HtmlClientLibrary resources, e.g., /etc/designs/mysite.css
  • Tags contained in conditional comments
  • Clientlibs included by JavaScript (e.g., when leveraging the property channels)

So if you’re looking for a way to reliably update your ClientLibs every time there is a change, this is a pretty simple approach.





Latest Images