Monday, August 27, 2018

Adobe Experience Manager (AEM) Examples and Notes

Personal AEM Notes

I just recently started a project at work using Adobe Experience Manager (AEM). Here's my random, rambling collection of notes. If you know of a better way to do any of these examples please let me know by adding a comment.

Good resources:
  1. Jeff's Youtube series Programmer Vs World AEM Series
  2. HTL guide: https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/master/SPECIFICATION.md#225-test

General Tips for Working with AEM

  1. Save often when creating objects - all the time. Create an object, then "Save All", or Ctl-S. All the time. Delete something? Save immediately.
  2. Remember to always to a hard reload of a browser after changing AEM content, Ctl-Shift-R.
  3. Coming from Visual Studio, I found the IntelliJ "Live Edit" plugin and the Chrome plugin very useful.

Jeff's overview of AEM components:

Apache Felix - osgi framework - forces modular sw development - service orentation
Jackrabbit - JCR content repo, JSR-170,283, workspaces, nodes, properties
Sling - Restful Web Framework
Sencha EXT JS 4 - js application framework
Lucene - search engine
Quartz Scheduler - cron system programmatically accessable
CRX - Tar Journal, Package Manager, deploy and share, Servlet Engine CQSE
CRXDE Lite - ide
WCM (Web Content Manager) - this is what content writers use

Wierd Strings to Put in the URL

Strings to put after "http://localhost:4502" to do wonderful things:


/cf#/ - sets the old interface, e.g., http://localhost:4502/cf#/content/...
/editor.html/ - uses the new interface, e.g., http://localhost:4502/editor.html/content/...
/crx/de - goes straight to the CRXDE page e.g., http://localhost:4502/crx/de
/welcome - go to the Websites/DAM page e.g., http://localhost:4502/libs/cq/core/content/welcome.html
/siteadmin - go to the Websites http://localhost:4502/siteadmin
/system/console/bundles - shows versions and the console - http://localhost:4502/system/console/bundles

How to limit use of a template?

    allowed paths: /content(/.*)? /* anywhere under content */
    allowed paths: /content/sports/baseball  /* only under baseball */

How to get rid of <p>&nbsp;</p>?

Make sure the text you entered into the "text" element does not contain an extra carriage return.

How to only iterate a fixed number of times?

<ul data-sly-list="${thelist}">
    <li data-sly-test="${itemList.index < 4}">${itemList}</li>
</ul>

Set default values with the 'or' operator

  ${properties.pageTitle || properties.jcr:title || resource.name}

How to find what version of AEM I'm running

http://localhost:4502/system/console/status-productinfo

How to place a page property on the HTML page

Here's an example of reading a property from the page dialog and putting the value on the page.

<div data-sly-use.bannerTitle="request.js" class="bannerText">
    ${bannerTitle}
</div>
request.js
"use strict";
use(function () {
    return  resourcePage.getProperties().get("bannerTitle");
});

To See the Actual jcr Nodes

/content/....

To show an array as text with a seperator

${['apple', 'pear', 'papaya'] @ join=' - '}
generates
apple - pear - papaya

How to format strings

${'person {0} of {1}' @ format=[7,9]}

How to encode a string for a URL

This will replace non-URL friendly characters like ' ' with '%20'.

  ${properties.jcr:title @ context='uri'}
  or
  ${'This is a test' @ context='uri'} //url:This%20is%20a%20test

How to encode a string for simple html content

This will replace non-URL friendly characters like ' ' with '%20'.

${'Texas A & M University' @ context='text'}
generates
&lt;x&gt;Texas A &amp; M University&lt;/x&gt;  

How to put in an AEM comment

<!--/* This is an example comment that will not appear in the browser. */-->

Is a String contained in another String (case sensitive)

Simple Example of "use" to Call Server-side JavaScript and Pass Parameters

For example, suppose we need a social icon component, "sharethis", which will accept two variables, url encode them, and return an object with two url-encoded variables. The returned object is named "site".

In sharethis.html:

<div class="iconContainer" data-sly-use.site="${'sharethis.js' @ title=currentPage.title, url=request.requestURL.toString}">
    <p class="shareThisTitle">Share this:</p>
    <a href="https://www.facebook.com/sharer/sharer.php?href=${site.url}&title=${site.title}" alt="share on facebook" target="_blank" class="nodecoration">
        <img src="/content/dam/design/facebook.png" title="share on facebook" alt="share on facebook" />
    </a>
...
</div>

The variables passed in are accessed by prefacing them with "this.". In the file sharethis.js:

"use strict";
use(function () {
    return {
        title: encodeURIComponent(this.title),
        url: encodeURIComponent(this.url)
       }
});

To Have AEM Automatically Bundle Css And Javascript Files

clientlib
create node / cq:clientlibraryfolder

create clientlib named zurbfoundation
create property 'categories' string[], zurb.foundation
create property 'dependencies' "+" cq.jquery

js.txt
#base=style   //subdirectory name

css.txt
#base=source

<html data-sly-use.clientlib='/libs/granite/slightly/templates/clientlib.html'>

<sly data-sly-call="${clientlib.css @ categories='zurb.foundation'}" />
<sly data-sly-call="${clientlib.js @ categories='zurb.foundation'}" />
or to do both:
<sly data-sly-call="${clientlib.all @ categories='zurb.foundation'}" />

How to do a REST call to get json objects in server-side JavaScript within a proxy

"use strict";
function geturlcontents(url) {
    //put the following values in a config file 
    var proxyHost = "proxy.district13.gov",
    proxyPort = 80,
    username = "katniss",
    password = "ilovearchery";

    var method = new org.apache.commons.httpclient.methods.GetMethod(url),
    client = new org.apache.commons.httpclient.HttpClient(),
    status = new org.apache.commons.httpclient.HttpStatus(),
    inputStream;

    var hostConfiguration = new org.apache.commons.httpclient.HostConfiguration();
    hostConfiguration.setProxy(proxyHost,proxyPort);
    client.setHostConfiguration(hostConfiguration);

    var credentials = new org.apache.commons.httpclient.UsernamePasswordCredentials(username, password);
    var authScope =   new org.apache.commons.httpclient.auth.AuthScope(proxyHost, proxyPort);
    client.getState().setProxyCredentials(authScope, credentials);

 try {
  var statusCode = client.executeMethod(method);
  if (statusCode == status.SC_OK) {
   inputStream = method.getResponseBodyAsString();
  } else {
   console.log(':::Failed to execute http method. status code = '+statusCode + ' for url '+ url);
  }
 } catch (e) {
        console.log(":::exception: "+e);
 } finally {
        method.releaseConnection();
 }

 return inputStream;
};

use(function() {
  var inputStream = geturlcontents(this.api);
  return JSON.parse(inputStream).slice(0, this.maxitems);
});

Common Resource Types:

text field: granite/ui/components/coral/foundation/form/textfield

number: /libs/granite/ui/components/foundation/form/numberfield

DAM file: granite/ui/components/foundation/form/pathbrowser

How to lowercase a variable

More generally, how to invoke a JavaScript method on an htl variable. Call the method without parenthesis.

<a href="${myvariable.toLowerCase}/mypage.html">

Important AEM directories

/libs/granite/ui/components/foundation - new components

To Add An Editable Area

<div data-sly-resource="${ 'content' @ resourceType='wcm/foundation/components/parsys'}"></div>

To Show AEM Quickstart Frame

add this immediately after body tag and it will present the AEM quickstart frame

<div data-sly-call="/libs/wcm/core/components/init/init.jsp"></div>

How to Create an Editable Button

/components/materialize-button/dialog/items/items/tab1/items
fieldDescription / What do you want the button to say
fieldLabel / Button Text
jscr:primaryType cq:Widget
name / ./buttontext
xtype / textfield
<a>${properties.buttontext}</a>

Unorganized Snippets of Forgotten Thoughts

on components, "group" is category.
to add dialog: rt-click/create...dialog
on tab1, create a node with name of "items" and type of cq:WidgetCollection
  inside items create another node named "buttontext" of type cq:Widget
  in Properties add "xtype/String/textfield"
                add "fieldDescription/String/What do you want the button to say"
  add "fieldLabel/String/Button Text"
  add "name/String/./buttontext"  --name is where it puts the value

from component:
${properties.buttontext}
mainpage.tidy.4.json

(to get a list of entities, API Documentation/CQ/Ext/form)

No comments: