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:- Jeff's Youtube series Programmer Vs World AEM Series
- HTL guide: https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/master/SPECIFICATION.md#225-test
- https://github.com/pankajchhatri/AEM
General Tips for Working with AEM
- Save often when creating objects - all the time. Create an object, then "Save All", or Ctl-S. All the time. Delete something? Save immediately.
- Remember to always to a hard reload of a browser after changing AEM content, Ctl-Shift-R.
- 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
Folder Structure
/apps: custom templates, components, /content: stores all content /etc: client library, design dialog info /libs: standard components - do not modify example: /libs/wcm/foundation/components/page/ /conf: All configuration /var: locks, /home: info about users and groups /oak:index: Jackrabbit Oak index definitions
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 e.g., http://localhost:4502/siteadmin
/system/console/bundles - shows versions and the console - e.g., 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> </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 you're running
http://localhost:4502/system/console/status-productinfo
To skip the AEM link check
add this class
<a x-cq-linkchecker="skip" href="..." />
Chrome screen creeping up?
In Chrome do you ever get CRX/DE screen creeping up the bottom left panel til it takes over the whole screen? The best solution I've found is to right-click and select "inspect" and make sure the Chrome browser is not in full screen mode.
How to get a list of tags and iterate over them
var categories = [];
var tags = resolver.getResource("/etc/tags/mysection").getChildren();
for (var i=1;i<tags.length;i++) {
categories.push(tags[i].name);//do something
}
What is a "Client Library"?
It organizes resources that we send to the browser (client side) - things like css and JavaScript.
How to include a resource in a page
<div data-sly-resource="${ 'myname' @ resourceType='wcm/foundation/components/parsys'}"></div>
To show a page title
${properties.jcr:title}
How to include other files
<sly data-sly-include="header.html"></sly>
How to iterate over properties
<ul data-sly-list.child="${currentPage.getProperties}">
<li>${child}</li>
</ul>
or
<ul data-sly-repeat.child="${currentPage.getParent.getProperties}">
<li>${child}</li>
</ul>
How to place a page property on the HTML page
Here's an example of reading a property from the page dialog in JavaScript and putting the value on the page.
<div data-sly-use.bannerTitle="getBannerTitle.js">
${bannerTitle}
</div>
getBannerTitle.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'}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
<x>Texas A & M University</x>
How to put in an AEM HTL comment
<!--/* This is an example comment that will not appear in the browser. */-->
How to use Sly Element so no "div" element is sent to the browser
Use the "sly" element when you don't want to have the extra "div" element
<div data-sly-include="head.html"></div> /* this produces: <div>myhead.html</div> */ use only the "sly" tag and the surrounding divs are not created. <sly data-sly-include="head.html"></sly> /* this produces: myhead.html */
How to replace content of HTML Element
<div data-sly-text="${currentPage.title}">This will not be seen</div>
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". ( I have since learned the right way to do this is with the "context='uri'"):
${'This is a test' @ context='uri'} //url:This%20is%20a%20test
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);
});
How to do a REST call to get json objects in server-side in JSP within a proxy
<%@include file="/libs/foundation/global.jsp"%>
<%@page import="org.apache.commons.httpclient.*,
org.apache.commons.httpclient.methods.*,
org.apache.commons.httpclient.params.HttpMethodParams,
org.apache.commons.httpclient.auth.*,
org.slf4j.Logger,
org.slf4j.LoggerFactory,
org.apache.sling.commons.json.*,
java.util.Date,
java.io.*"%>
<%
String proxyHost = "myproxy.mycompany.com";
int proxyPort = 80;
String username = "steven";
String password = "spielburg";
String url = "http://www.omdbapi.com/?t=alien&plot=full";
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
HttpStatus status = new HttpStatus();
HostConfiguration hostConfiguration = new HostConfiguration();
hostConfiguration.setProxy(proxyHost, proxyPort);
client.setHostConfiguration(hostConfiguration);
UsernamePasswordCredentials credentials = new org.apache.commons.httpclient.UsernamePasswordCredentials(username, password);
AuthScope authScope = new AuthScope(proxyHost, proxyPort);
client.getState().setProxyCredentials(authScope, credentials);
String jsonString = "[]";
try {
int statusCode = client.executeMethod(method);
application.log(" *** statusCode : " +statusCode);
if (statusCode != HttpStatus.SC_OK) {
application.log(" *** Method failed: " + method.getStatusLine());
throw new Exception(" *** client.executeMethod failed for url "+ url + " with http error code " + statusCode);
}
// Read the response body.
byte[] responseBody = method.getResponseBody();
jsonString = new String(responseBody);
} catch (HttpException e) {
application.log(" *** Fatal protocol violation: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
application.log(" *** Fatal transport error: " + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
application.log(" *** Fatal error: " + e.getMessage());
e.printStackTrace();
} finally {
method.releaseConnection();
}
JSONArray jsonArray = new JSONArray(jsonString);
String countofmoviesString = (String)properties.get("countofmovies");
int countofmovies = Integer.parseInt(countofmoviesString);
%>
<div class="movieTileContainer">
<ul class="movieTileList" >
<%
int maxMovies = jsonArray.length() > countofmovies ? countofmovies : jsonArray.length();
for(int i=0;i<maxMovies;i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String title = (String)jsonObject.get("title");
String jurl = (String)jsonObject.get("url");
JSONObject image = (JSONObject) jsonObject.get("movieEntryImage");
String thumbnailLocation = (String)image.get("thumbnailLocation");
JSONArray prices = (JSONArray) jsonObject.get("price");
String price = (String)prices.getJSONObject(0).get("price");
%>
<li class="movieTileListItem">
<div class="content">
<div class="movieTileBox">
<a class="movieTileLink" title="<%= title %> " href="https://www.MyMovieSite.com<%= jurl %>">
<p class="movieTileTitle"><%= title %> </p>
<img class="movieTileImage" width="185" height="101" src="https://www.MyMovieSite.com<%= thumbnailLocation %>"
alt="<%= title %>">
<p class="movieTilePrice" <%= price %>
</p>
</a>
</div>
</div>
</li>
<% } %>
</ul>
</div>
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 /libs/wcm/foundation/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:
Post a Comment