Showing posts with label Clientlibs. Show all posts
Showing posts with label Clientlibs. Show all posts

Saturday, 12 January 2019

Cannot read property 'extend' of undefined': ContextHub

While adding ContextHub to AEM site could see below errors

Change ContextHub entry in head section from 
<sly data-sly-resource="${'contexthub' @ resourceType='granite/contexthub/components/contexthub'}"/>


!--/* Include Context Hub */-->
<sly data-sly-call="${clientlib.js @ categories='granite.utils'}"/>
<sly data-sly-resource="${'contexthub' @ resourceType='granite/contexthub/components/contexthub'}"/>

Click here to check how to setup ContextHub in AEM.

Using script reference in AEM ContextHub

While creating audience in AEM contextHub, we see a component called Script Reference. When we drag-n-drop the component, we don't see any scripts by default in the drop down.

Saturday, 9 June 2018

Access ClientLibs under apps folder through ClientLibraryProxyServlet

AEM provides ClientLibs feature to organize JS and CSS. Clientlibs can be created as 

  1. Approach 1: Place all files under /etc/designs/{project}/clientlibs path.
  2. Approach 2: Creating clientlibs under each component. Disadvantage with this approach is it increases number of calls to load clientlibs throuhout the page. This doesn't follow best practices as CSS will not be loaded in head section.
  3. Approach 3: Place clientlibs under /apps/project/. 
/apps folder is restricted to access by dispatcher. So we need to enable ClientLibraryProxyServlet  to access the clientlibs from apps folder.  Below are the steps to enable clientLibrary Proxy.

  • Create a new client library under /apps/... with new category. Let's say myapp.all
  • Add a embed property and  include all modular component library. (firstcomp,secondcomp)
  • Add boolean allowProxy = 'true'
  • On the headlibs.jsp include the above 
  • Then the clientlib will then be proxied via  there by passing access control set on the clientlib.

    • Configure dispatcher.any to allow for /etc.clientlibs/

Saturday, 23 April 2016

Versioning ClientLibs in AEM

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.Read More

Monday, 18 April 2016

Enable JS and CSS minification in AEM

The CQ "CQ Html Library Manager" component control the handling of client libraries (JavaScript, CSS) minification to remove CRLF and whitespace characters in order to reduce the size of the file. In Earlier version of CQ with minification enabled OR disabled, both the minified OR unminified library version has the same URL.  

This blog post will take you through the steps on how to enable minification.
You need to go to http://localhost:4502/system/console/configMgr. This is a configuration page listing all the services that has configurations. Just look for ‘HTML Library Manager’ and click it. You will see the configurations like following:

Friday, 13 November 2015

Customization of parsys to restrict number of compnents in CQ 5.6.1

  1. Copy the parsys component from(/libs/foundation/components/parsys) to your poroject(/apps/<project nmae>/components/).
     2.  In the design dialog add number filed configuration to enter the number of components.

           Crate node noofcomp of type cq:widget under /apps/<project nmae>/components/parsys
           Add the following properties

           xtype : numberfield
           name : noOfComp
           maxValue : 20
           fieldLabel : No of components

     3.   Create ajax.jsp and write the below logic.
           <%@page import=""%>
           <%@include file="/libs/foundation/global.jsp"%>
                 ParagraphSystem parSys = ParagraphSystem.create(resource, slingRequest);
                 int totalComponents=parSys.paragraphs().size();
                 int restrictCompoNo=Integer.parseInt(currentStyle.get("noOfComp","20"));

                if(totalComponents >= restrictCompoNo){

    4.  You need to overlay the EditBase.js and Sidekick.js

          Create the following structure   /apps/cq/ui/widgets/source/widgets/wcm

         then copy the EditBase.js and Sidekick.js form libs . Place under /wcm /
         In Sidekic.js at line 4098 in set timeout method add this snippet.

            var parentPath=editComponent.path;
            var ajaxUrl=parentPath.substr(0,parentPath.lastIndexOf("/"))+".ajax";
            var notAllowToCreate = CQ.HTTP.eval(ajaxUrl);

                                   msg: 'You reached  the maximun limit. You can set the limit in disign mode.',
                                   buttons: CQ.Ext.Msg.OK,
                                   icon: CQ.Ext.MessageBox.WARNING


         In EditBase.js at line 1181  in set timeout method add this snippet.
           var parentPath=e.path;
            var ajaxUrl=parentPath.substr(0,parentPath.lastIndexOf("/"))+".ajax";
            var notAllowToCreate = CQ.HTTP.eval(ajaxUrl);    

                    msg: 'You reached  the maximun limit. You can set the limit in disign mode.',
                    buttons: CQ.Ext.Msg.OK,
                    icon: CQ.Ext.MessageBox.WARNING

Colorpicker RTE plugin for Richtext

1.  Create a clientlibs node (nodeTypecq:ClientLibraryFolder) under the root node of the project.
e.g. /apps/training
Assign the following properties to the newly created clientlibs node 
the property that identifies the category these custom Widgets will be referenced by

Name  = categories
Type  String []
Value  colorpicker.widgets
the property that defines JS library dependencies

Name  dependencies
Type  String[]
Value  cq.jquery#cq.foundaion-main

2.  Create a css folder under the newly created clientlibs node.
3.  Create a js folder under the newly created clientlibs node.
4.  Create a css.txt file under the newly created clientlibs node.
5.  Create a js.txt file under the newly created clientlibs node.
6.  Create colorpickerplugin.Js and colorpickerdialog.js in js folder under  clientlibs


 * @class CQ.form.rte.plugins.HtmlColorPickerPlugin
 * @extends CQ.form.rte.plugins.Plugin
 * <p>This class builds a Colorpicker pop up as a plugin.</p>
 * <p>The plugin ID is "<b>Colorpicker</b>".</p>
 * <p><b>Features</b></p>
 * <ul>
 *   <li><b>colorpicker</b> - pops up Colorpicker dialog</li>
 * </ul>
CQ.form.rte.plugins.HtmlColorPickerPlugin = CQ.Ext.extend(CQ.form.rte.plugins.Plugin, {

 * @private
htmlColorPickerDialog: null,
 * @private
colorPickerText: null,
 * @private

constructor: function(editorKernel) {,
callDialog: function(context) {

if (CQ.Ext.isIE) {
this.savedRange = context.doc.selection.createRange();
var editorKernel = this.editorKernel;

var configdialog = {
"editContext": context,
"title": CQ.I18n.getMessage("Color Picker"),
"colorPickerText": this.colorPickerText,
"insertContentIntoRTE": this.insertContentIntoRTE.createDelegate(this),
"cancelFn": this.execCancel.createDelegate(this),
"listeners": {
"show": function() {
"hide": function() {
this.htmlColorPickerDialog =
                                        new CQ.form.rte.plugins.HtmlColorPickerDialog(configdialog);
window.setTimeout(function() {
}.createDelegate(this), 10);

getYourData: function(){

 // You might want to do something here and populate a value that needs to go inside your dialog.
this.colorPickerText = "Color Picker RTE Plugin";

// This gets called when you click OK button from your dialog
insertContentIntoRTE: function(context, options, dialog) {
 var selectionDef = this.editorKernel.analyzeSelection();
 var nodelist = selectionDef["nodeList"];
 var node = nodelist["nodes"][0];
 var nodeDom = node["dom"];
 var nodeText = nodeDom["nodeValue"];
 var selectedText=nodeText.substring(node["startPos"], node["startPos"] +
 var color;
 for(var opt in options){
if(opt!=undefined && opt!="" && opt!='remove' && opt!='indexOf'){
                                              //for IE alone indexOf comes as a function
color = options[opt].value;
var style="style=color:#"+color;
var htmlCode = '<span '+style+'>' + selectedText + '</span>';

this.editorKernel.execCmd("inserthtml", htmlCode);

// This gets called when you click Cancel button from your dialog
execCancel: function() {


getFeatures: function() {
return [ "colorpicker" ];

initializeUI: function(tbGenerator) {
var plg = CQ.form.rte.plugins;
var ui = CQ.form.rte.ui;
if (this.isFeatureEnabled("colorpicker")) {
this.checkTextUI = new ui.TbElement("colorpicker", this,
tbGenerator.addElement("htmlColorPicker", plg.Plugin.SORT_LISTS,


notifyPluginConfig: function(pluginConfig) {
pluginConfig = pluginConfig || { };
CQ.Util.applyDefaults(pluginConfig, {
"tooltips": {
"colorpicker": {
"title": CQ.I18n.getMessage("Color Picker"),
"text":  CQ.I18n.getMessage("Color Picker pop-up")
this.config = pluginConfig;

execute: function(id, value, env) {
switch (id) {
case "colorpicker":
this.envEditContext = env.editContext;


updateState: function(selDef) {

// todo implement


// register plugin



 * @class CQ.form.rte.plugins.HtmlColorPickerDialog
 * @extends CQ.Ext.Window
 * @private
 * This class implements the Hello World dialog.
CQ.form.rte.plugins.HtmlColorPickerDialog = CQ.Ext.extend(CQ.Ext.Window, {
editContext: null,
insertContentIntoRTE: null,
constructor: function(config) {
var dialogRef = this;
var dialogItems = [ ];
var buttonItems = [ ];
var defaults = {
"title": "Html Color Picker"
CQ.Util.applyDefaults(config, defaults);
CQ.Ext.apply(this, config);
"itemId": "colorPickerField",
"name": "colorPickerField",
"xtype": "colorfield",           
"fieldLabel": "colorPickerField",
"colors":['000000', '993300', '333300', '003300', '003366', '000080', '333399',
                                                    '333333','800000', 'FF6600', '808000', '008000', '008080', '0000FF',
                                                   '666699', '808080','FF0000', 'FF9900', '99CC00', '339966', '33CCCC',
                                                   '3366FF', '800080', '969696','FF00FF', 'FFCC00', 'FFFF00', '00FF00',
                                                   '00FFFF', '00CCFF', '993366', 'C0C0C0','FF99CC', 'FFCC99',
                                                    'FFFF99', 'CCFFCC', 'CCFFFF', '99CCFF', 'CC99FF', 'FFFFFF' ]
// Buttons
"itemId": "ok",
"name": "ok",
"text": "OK",
"handler": function() {
this.applyDialog(this.insertContentIntoRTE, null);
"scope": this
"text": "Cancel",
"handler": function() {
if (this.cancelFn) {
"scope": this
});, {
"renderTo": CQ.Util.ROOT_ID,
"title": this.title,
"stateful": false,
"minWidth": 400,
"minHeight": 170,
"width": 400,
"height": 310,
"plain": true,
"layout": "fit",
"items": [ {
"xtype": "panel",
"layout": "fit",
"stateful": false,
"items": [ {
"border": false,
"xtype": "form",
"itemId": "ColorPickerForm",
"name": "ColorPickerForm",
"stateful": false,
"autoHeight": true,
"items": dialogItems,
"bodyStyle": "overflow: auto;",
"afterRender": function() {;
dialogRef.findItems = this.items;
"buttons": buttonItems,
"modal": true
applyDialog: function(fn, options) {
options = options || [];
if (fn) {
var colorPickerTextValue = this.findItems.get("colorPickerField").getValue();
options.push({value: colorPickerTextValue, name: 'colorPickerTextValue'});
fn(this.editContext, options, this);
cancelFn: function(){

//Implement here

7.  List colorpickerplugin.js and  colorpickerdialog.js in js.txt file.
8.  Create cloorpicker.css in css folder under  clientlibs.


#CQ .x-html-editor-tb .x-edit-colorpicker{
  background: url(/libs/cq/ui/widgets/themes/default/icons/16x16/colorpicker.jpg)
                           center no-repeat;

9.  List cloorpicker.css in css.txt file underclientlibs.

10. Create a htmlColorPicker node (nodeType nt:unstructured) under the Training Complex Component's Dialog tab 1 widget collection.

 Assign the following properties to the newly created htmlColorPicker node:

 the property that will define where the content is stored

Name  features
Type  String
Value  *