Technical Conventions

3 minute read

These sections that follow are samples that should be built upon to adopt to your situation. Please refer to (Conventions)[/manual/conventions/] and (Image Conventions)[/manual/image-conventions/] for more detailed descriptions of conventions that need to be considered when developing AEM components.

Reference Material

Architecture Overview 5.6.1

AEM Links

Sample JS Project Namespace

location: /etc/designs/`/js/namespace-aem-design.js

//namespace-aemdesign.js
window.AEMDESIGN = window.AEMDESIGN || {};
window.AEMDESIGN.jQuery = window.jQuery || {};
window.AEMDESIGN.$ = window.jQuery || $;

;(function ($, ns, window, undefined) { //add additional dependencies

    "use strict";
    var _version = "0.1";

    ns.version = function () {
        return _version;
    };

    var http = AEMDESIGN.HTTP;

    $.ajaxSetup({ // necessary global modifications for ajax calls
        statusCode: {
            403: function(jqXHR) {
                if (jqXHR.getResponseHeader("X-Reason") === "Authentication Failed") {
                    // login session expired: redirect to login page
                    http.handleLoginRedirect();
                }
            }
        }
    });

    $.ajaxSettings.traditional = true;


})(AEMDESIGN.jQuery, AEMDESIGN, this); //pass in additional dependencies

Sample JS Console Log Utility Class

location: /etc/designs/aem-design/js/aem-design.log.js

//aem-design.log.js
window.AEMDESIGN = window.AEMDESIGN || {};
window.AEMDESIGN.log = window.AEMDESIGN.log || {};

(function ($, ns, window, undefined) { //add additional dependencies

    //"use strict";
    var _version = "0.1";
    var settings = {
        enableLog: false
    }

    ns.version = function () {
        return _version;
    };

    ns.enableLog = function() {
        settings.enableLog = true;
    }

    ns.disableLog = function() {
        settings.enableLog = false;
    }


    ns.log = function (data) {

        if (window.console && window.console.log) {
            var url = $(location).attr('href');

            var traceStack;
            if (typeof printStackTrace == "function") {
                traceStack = printStackTrace();
            }
            var debug = {
                "caller": arguments.caller,
                "traceStack": traceStack
            };

            if (settings.enableLog) {
                console.log([url,data,debug]);
            }
        }

    };

})(AEMDESIGN.jQuery, AEMDESIGN.log, this); //pass in additional dependencies

Sample JS Component Namespace

location: /apps/aemdesign/componentX/clientslibs/js.txt

#base=js

functions.js
behaviour.js

location: /apps/aemdesign/componentX/clientslibs/js/behaviour.js

//componentX - behaviour

window.AEMDESIGN = window.AEMDESIGN || {};
window.AEMDESIGN.components = AEMDESIGN.components || {};
window.AEMDESIGN.components.componentX = AEMDESIGN.components.componentX || {};

;(function($, _, ko, componentXNs, window, undefined) { //add additional dependencies

    function onDocumentReady() {

        console.group("loading componentX");

        //init component on all found instances
        var elements = document.querySelectorAll(ns.selector);
        for (var i = 0; i < elements.length; i++) {
            componentXNs.init($(elements[i]));
        }

        //init component on all future instances when they are added to the DOM
        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
        var body = document.querySelector("body");
        var observer = new MutationObserver(function(mutations) {
            mutations.forEach(function(mutation) {
                // needed for IE
                var nodesArray = [].slice.call(mutation.addedNodes);
                if (nodesArray.length > 0) {
                    nodesArray.forEach(function(addedNode) {
                        if (addedNode.querySelectorAll) {
                            var elementsArray = [].slice.call(addedNode.querySelectorAll(ns.selector));
                            elementsArray.forEach(function(element) {
                                componentXNs.init($(element));
                            });
                        }
                    });
                }
            });
        });

        observer.observe(body, {
            subtree: true,
            childList: true,
            characterData: true
        });

        console.groupEnd();
    }

    if (document.readyState !== "loading") {
        onDocumentReady();
    } else {
        document.addEventListener("DOMContentLoaded", onDocumentReady);
    }

})(AEMDESIGN.jQuery, _, ko,  AEMDESIGN.components.componentX, this); //pass in additional dependencies

location: /apps/aemdesign/componentX/clientslibs/js/functions.js

//componentX - functions

window.AEMDESIGN = window.AEMDESIGN || {};
window.AEMDESIGN.components = AEMDESIGN.components || {};
window.AEMDESIGN.components.componentX = AEMDESIGN.components.componentX || {};

;(function ($, _, ko, ns, window, undefined) { //add additional dependencies

    "use strict";
    var _version = "0.1";

    ns.selector = "[data-modules='componentX']";

    ns.version = function () {
        return _version;
    };

    ns.init = function($el) {

        return $el; //chaining
    };

})(AEMDESIGN.jQuery,_,ko, AEMDESIGN.components.componentX, this); //pass in additional dependencies

Sample Health Check

package com.aem-design.health;

import java.io.IOException;
import javax.servlet.ServletException;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.felix.scr.annotations.Property;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;

@SlingServlet(paths = "/bin/aem-design/health", methods = "GET", metatype = true)
@Property(name = "sling.auth.requirements", value = "-/bin/aem-design/health", propertyPrivate = true)
public class HealthServlet extends SlingAllMethodsServlet {
    private static final long serialVersionUID = 636174686179L;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        response.getWriter().write("AEM-OK");
    }
}

Sample Adaptive Image

location: /apps/aemdesign/content/image/variant.responsive.jsp

<a href="/content/geometrixx-media/en/events/andrew-novokov.html">
    <div data-picture data-alt='Interview with Russian author Andrew Novokov'>
        <div data-src='/content/geometrixx-media/en/events/andrew-novokov.image.370.150.medium.jpg' data-media="(min-width: 1px)"></div>
        <div data-src='/content/geometrixx-media/en/events/andrew-novokov.image.480.190.medium.jpg' data-media="(min-width: 480px)"></div>
        <div data-src='/content/geometrixx-media/en/events/andrew-novokov.image.770.300.medium.jpg' data-media="(min-width: 768px)"></div>
        <div data-src='/content/geometrixx-media/en/events/andrew-novokov.image.940.340.high.jpg'   data-media="(min-width: 980px)"></div>
        <div data-src='/content/geometrixx-media/en/events/andrew-novokov.image.1170.400.high.jpg'  data-media="(min-width: 1199px)"></div>
        <noscript>
            <img src='/content/geometrixx-media/en/events/andrew-novokov.image.370.150.low.jpg' alt='Interview with Russian author Andrew Novokov'>
        </noscript>
    </div>
</a>

location: /apps/aemdesign/content/image/clientslibs/js/functions.js

$("div[data-picture]", context).each(function () {
    var currentPicture = this;
    var matches = [];
    $("div[data-media]", currentPicture).each(function () {
        var media = $(this).attr("data-media");
        if (!media || ( w.matchMedia && w.matchMedia(media).matches )) {
            matches.push(this);
        }
    });

    var $picImg = $("img", currentPicture).first();

    if (matches.length) {
        if ($picImg.size() === 0) {
            var $currentPicture = $(currentPicture);
            $picImg = $("<img />").attr("alt", $currentPicture.attr("data-alt")).appendTo($currentPicture);
        }
        $picImg.attr("src", matches.pop().getAttribute("data-src"));
    } else {
        $picImg.remove();
    }
});

Sample Sling Content Manipulation

Sling allows ability to automate content creation, deletion and updates.

Sling API Manipulation Manual : https://sling.apache.org/documentation/bundles/manipulating-content-the-slingpostservlet-servlets-post.html

Import UTF Characters using Sling

curl -X POST -u "admin:admin" -F"_charset_=utf-8" --form-string "text-ja=あなたが喜んで学ぶならば、誰かが喜んで教えるでしょう!。" http://localhost:4502/content/testpage/jcr:content/par/label

Updated:

Leave a Comment