Select Audiofiles in the Assets Sidepanel

Luca Nerlich, aem

This post explains, how you can add a simple overlay to allow authors to filter and select audio files in the assets sidepanel.

Table of Contents


  1. Create audioController.js based on videoController.js
  2. Create ClientLibrary
  3. Deploy


By default, the AEM Assets Sidepanel does not allow to filter by audio files and therefore an author cannot drag and drop these onto pages and components. This is a great addition, if you want to build components which let the user list and download to audio files, such as podcasts, songs or shows.

The out of the box asset dropdown filters do not include a mime type for audio files. Therefore we need to add our own.



Fortunately, the solution is quite simple. Adobe provides a bunch of xyzController.js files which control the current behaviour and are responsible for the asset sidepanel dropdown filter. We can reuse one of them, adapt to our needs, sideload it enjoy the possibility to filter by audio (or any other mimetypes).

The controller provided by AEM can be found in this path /libs/cq/gui/components/authoring/editors/clientlibs/core/js/assetController. Almost all controller are very similar, their only real difference is the name, dropdown title/value and filtered mimetypes. Due to this, we can easily copy the /libs/cq/gui/components/authoring/editors/clientlibs/core/js/assetController/video/videoController.js for example and recreate it as an assetController.js.

There are now two ways to go about this, creating an overlay or adding it to a new ClientLibrary. The latter is a much cleaner solution, but I will quickly explain the overlay variant as well.

The mentioned audioController.js can be found added at the end of this post: audioController.js example.


AEM allows to quickly "edit" / overwrite files, using the Sling Resource Merger mechanism -> or "creating an overlay". This works via recreating a file with the same name under the exact same directory strucutre, just in /apps/ and not in /libs/.

Therefore on could create /apps/cq/gui/components/authoring/editors/clientlibs/core/js/assetController/audio/audioController.js and add that file to an overlay of its ClientLibraries /libs/cq/gui/components/authoring/editors/clientlibs/core/js.txt aggregation file, which would also need an overlay at /apps/cq/gui/components/authoring/editors/clientlibs/core/js.txt

# asset controllers
# Manuscripts are deprecated in AEM 6.2. Use content fragments instead of manuscripts.
# our new audioController

However, this solution is not encouraged. Overlays should be used sparesly and especially not for altering ClientLibraries. This can lead to major issues and unwanted sideeffects when upgrading AEM, since Adobe can not take your added overlay into account when updating "their own / libs" files.

Custom ClientLibrary

A better and cleaner solution is to add the audioController.js to a new ClientLibrary clientlib-sidepanel and load it when necessary. The category we need in this case is cq.authoring.dialog.all. By loading our ClientLibrary for pages specifying this category, we make sure, that our added audioController gets loaded whenever we need it -> an author edits pages.

The following files need to be created:

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq=""

After deployment, the assets sidepanel has a new audio filter dropdown entry and lists only files with audio mimetypes. Authors can now search and filter for songs etc.


Enable drag and drop

Assets from the sidepanel can also be drag and dropped, if your component as a configured cq:editConfig node. This is a quick example for ui.apps/src/main/content/jcr_root/apps/[myapp]/core/components/[mycomponent]/_cq_editConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="" xmlns:cq="" xmlns:jcr="" xmlns:nt=""
<cq:dropTargets jcr:primaryType="nt:unstructured">

This config defines the accepted mimetypes for drag and dropped assets and clarifies the property and resourceType of the targeted jcr node / property. In this case, the property ./link of the component [myapp]/core/components/[mycomponent] will be populated with the dropped files path.

audioController.js example

* Copyright 2013 Adobe Systems Incorporated
* All Rights Reserved.
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
(function ($, ns, channel, window, undefined) {
* Asset Controller for the video type
* @memberOf
* @inner
* @alias audioAssetController
* @ignore
* @type {}
var self = {},
name = 'Audio';
// make the loadAssets function more flexible
self.searchRoot = '/content/dam';
// open assets in the admin view (to edit properties)
self.viewInAdminRoot = '/assetdetails.html{+item}';
var searchPath = self.searchRoot,
imageServlet = '/bin/wcm/contentfinder/asset/view.html',
itemResourceType = 'cq/gui/components/authoring/assetfinder/asset';
Pre asset type switch hook
self.setUp = function () {};
Post asset type switch hook
self.tearDown = function () {};
* @param query {String} search query
* @param lowerLimit {Number} lower bound for paging
* @param upperLimit {Number} upper bound for paging
* @returns {jQuery.Promise}
self.loadAssets = function (query, lowerLimit, upperLimit) {
var param = {
'_dc': new Date().getTime(), // cache killer
'query': query.concat("order:\"-jcr:content/jcr:lastModified\" "), // sort by jcr:content/jcr:lastModified property
// we specify audio files only:
'mimeType': 'audio',
'itemResourceType': itemResourceType, // single item rendering (cards)
'limit': lowerLimit + ".." + upperLimit,
'_charset_': 'utf-8'
return $.ajax({
type: 'GET',
dataType: 'html',
url: Granite.HTTP.externalize(imageServlet) + searchPath,
data: param
* Set URL to image servlet
* @param {String} imgServlet - URL to image servlet
self.setServlet = function (imgServlet) {
imageServlet = imgServlet;
self.setSearchPath = function (spath) {
searchPath = spath;
self.setItemResourceType = function (rt) {
itemResourceType = rt;
self.resetSearchPath = function () {
searchPath = self.searchRoot;
// register as a asset tab
ns.ui.assetFinder.register(name, self);
}(jQuery,, jQuery(document), this));

Thanks for reading!


CC BY-NC 4.0  ©   Luca NerlichImprint + Privacy