Thursday, 11 August 2016

Sightly – Quick Reference

Sightly was introduced by AEM 6.0 to replace JSP by a new HTML Templating System. This post is a quick reference about Sightly. A list of best practices and things to know.
Java class or server side Javascript
With Sightly, you can create a component with two methods. By using Java Class or Javascript Server-Side File. Personnaly, I always use Java Class, but Javascript seems to be a really good deal if you want to develop your components with one language. But keep in mind that AEM Java API offer more functionnalities than Javascript API.
  • Sigthly component with Java
package apps.mycomponent;
  
import com.adobe.cq.sightly.WCMUse;
  
public class MyComponent extends WCMUse {
    private String title;
    private String description;
  
    @Override
    public void activate() throws Exception {
        title = getProperties().get("title", "");      
        description = getProperties().get("description", "");
    }
  
    // Must have to get back the value in html file
    // Explanation : 'get' + capitalize method name
    public String getTitle() {
        return title;
    }
    
    public String getDescription() {
        return description;
    }
}



  • Sigthly HTML code
<div id="my-component" data-sly-use.cpt="apps.mycomponent.MyComponent">
    <!-- /* Here you call the Java Method */ -->
    <!-- /* Explanation : Imported Class + '.' + Uncapitalized java method name withoud 'get' */ -->
    <h1>${cpt.title}</h1>
    <p>${cpt.description}</p>
</div>

  • Sightly Component with server side Javascript
use(function () {
     var title = currentPage.getTitle();
    var description = properties.get("jcr:description", "default desc");
  
    return {
        title: title,
        description: description
    };
});
You do have to know that you cannot pass argument to the method. But it is possible to pass argument at the activation of the Java/Javascript class. Example with Java Class :



package apps.mycomponent;


import com.adobe.cq.sightly.WCMUse;

public class MyComponent extends WCMUse {

    private String title;

    private String description;

    @Override

    public void activate() throws Exception {

        title = get("title", String.class); 

    }


    public String getTitle() {

        return title;

    }

}
Example HTML code



<div id="my-component" data-sly-use.cpt="apps.mycomponent.MyComponent @ title='my title'">


    <h1>${cpt.title}</h1>

    <p>${cpt.description}</p>

</div>


Context Objects
With Sightly you can directly use component/page properties in HTML file like JSP does. You can access to a wide range of Java Objects (currentPage, currentNode….) too :
Variable NameDescription
propertiesList of properties of the current Resource.
pagePropertiesList of page properties of the current Page.
inheritedPagePropertiesList of inherited page properties of the current Page.
Variable NameDescription
componentcom.day.cq.wcm.api.components.Component
componentContextcom.day.cq.wcm.api.components.ComponentContext
currentDesigncom.day.cq.wcm.api.designer.Design
currentNodejavax.jcr.Node
currentPagecom.day.cq.wcm.api.Page
currentSessionjavax.servlet.http.HttpSession
currentStylecom.day.cq.wcm.api.designer.Style
designercom.day.cq.wcm.api.designer.Designer
editContextcom.day.cq.wcm.api.components.EditContext
logorg.slf4j.Logger
outjava.io.PrintWriter
pageManagercom.day.cq.wcm.api.PageManager
readerjava.io.BufferedReader
requestorg.apache.sling.api.SlingHttpServletRequest
resourceorg.apache.sling.api.resource.Resource
resourceDesigncom.day.cq.wcm.api.designer.Design
resourcePagecom.day.cq.wcm.api.Page
responseorg.apache.sling.api.SlingHttpServletResponse
slingorg.apache.sling.api.scripting.SlingScriptHelper
slyWcmHelpercom.adobe.cq.sightly.WCMScriptHelper
wcmmodecom.day.cq.wcm.api.WCMMode (in Sightly, evaluates to a string, either“EDIT” or“DESIGN”)
xssAPIcom.adobe.granite.xss.impl.XSSAPImpl
All these objects are accessible using Sightly, server side Javascript and Java class.
Examples:



<!-- /* Access to simple component property defined in dialog.xml */ -->
${properties.my_property}

<!-- /* Access to JCR property */ -->
${properties.jcr:title}

<!-- /* Access to page property */ -->
${pageProperties.name}


<!-- /* Access to inherited page property */ -->
${inheritedPageProperties.inherited_property}

<!-- /* Visualize all accessible properties */ -->
${properties}



If you want to modify the value before accessing a property you can obviously use a Java Class/Server side Javascript as shown in the first part.
Conditional operators
With sightly you can use conditional operators :
${properties.jcr:title || properties.my_title}
${properties.my_title ? properties.my_title : properties.jcr:title}

You should mix conditional operators and data-sly-test block statement.



<!-- /* If/Else exemples */ -->
<p data-sly-test="${properties.my_property}">Ok</p>
<p data-sly-test="${!properties.my_property}">Ko</p>
<p data-sly-test="${properties.article_number < 5}">Number < 5</p>
<p data-sly-test="${properties.article_number == 5}">Number = 5</p>
<p data-sly-test="${properties.article_number > 5}">Number > 5</p>

String Formatting
<span>${'Hello {0} {1}' @ format=[properties.civility, properties.name]}</span>

I18n / Internationalization
<!-- /* Translates the 'Welcome' string to the language of the current page */ -->
<p>${'Welcome' @ i18n}</p>
<!-- /* Translates the 'Welcome' string to a specify language (french in our case) */ -->
<p>${'Welcome' @ i18n, locale='fr'}</p>
<!-- /* You can mix string formatting and internationalization */ -->
<p>${'Welcome {0} {1}' @ i18n, locale='fr', format=[civility, name]}</p>

Display Context
If you want to write a resource property as an HTML attribute or as an JS comment, the display context is different. That’s why sightly provides some context which will format/filter the property value.
HTML context:
Context NameWhen to useWhat it does
textDefault for content inside elementsEncodes all HTML special characters.
htmlTo safely output markupFilters HTML to meet the AntiSamy policy rules,
removing what doesn’t match the rules.
attributeDefault for attribute valuesEncodes all HTML special characters.
uriTo display links and paths
Default for href and src attribute values
Validates URI for writing as an href orsrc attribute value,
outputs nothing if validation fails.
numberTo display numbersValidates URI for containing an integer,
outputs zero if validation fails.
attributeNameDefault for data-sly-attribute when setting attribute namesValidates the attribute name,
outputs nothing if validation fails.
elementNameDefault for data-sly-elementValidates the element name,
outputs nothing if validation fails.
Javascript context:
ContextWhen to useWhat it does
scriptTokenFor JS identifiers, literal numbers, or literal stringsValidates the JavaScript token,
outputs nothing if validation fails.
scriptStringWithin JS stringsEncodes characters that would break out of the string.
scriptCommentWithin JS commentsValidates the JavaScript comment,
outputs nothing if validation fails.
CSS context:
ContextWhen to useWhat it does
styleTokenFor CSS identifiers, numbers, dimensions, strings, hex colours or functions.Validates the CSS token,
outputs nothing if validation fails.
styleStringWithin CSS stringsEncodes characters that would break out of the string.
styleCommentWithin CSS commentsValidates the CSS comment,
outputs nothing if validation fails.
Other context :
ContextWhen to useWhat it does
unsafeOnly if none of the above does the jobDisables escaping and XSS protection completely.
Display context can be used as below
<!-- /* write html text in a div */ -->
<div>${properties.wysiwygText @ context='html'}</div>
<!-- /* write style token */ -->
<span style="color: ${properties.color @ context='styleToken'};">Welcome</span>
<!-- /* possible but BAD IDEA (I think...) ! */ -->
<div>${script @ context='unsafe'}</div>

Block statement
data-sly-use : Initializes a helper object (defined in JavaScript or Java) and exposes it through a variable
<!-- /* java class */ -->
<div id="my-component" data-sly-use.cpt="apps.mycomponent.MyComponent">
    <h1>${cpt.title}</h1>
    <p>${cpt.description}</p>
</div>
<!-- /* js class */ -->
<div id="my-component" data-sly-use.cpt="cpt.js">
    <h1>${cpt.title}</h1>
    <p>${cpt.description}</p>
</div>
data-sly-unwrap : Removes the host HTML element.


<!-- /* This */ -->
<p data-sly-unwrap>Hello World</p>
<!-- /* Produces */ -->
Hello World
data-sly-attribute : Adds HTML attributes to the host element.


<!-- /* This */ -->
<div data-sly-attribute.class="${properties.myClass}"></div>
<!-- /* Produces */ -->
<div class="colorRed"></div>
With a map of attributes


attributes = {
    title: "beautiful title",
    class: "testClass",
}

<!-- /* This */ -->
<div data-sly-attribute="${attributes}"></div>
<!-- /* Produces */ -->
<div title="beautiful title" class="testClass"></div>
data-sly-test : Conditionally removes the HTML host element.


<p data-sly-test="${properties.my_property}">Ok</p>
<p data-sly-test="${!properties.my_property}">Ko</p>
data-sly-list : Repeats the content of the host element for each enumerable property in the provided object.


<ul data-sly-list="${properties}">
    <li>index: ${itemList.index}</li>
    <li>value: ${item}</li>
</ul>


ItemList is an object that is available in the data-sly-list statement and provide the following properties :
  • index : counter (0-n)
  • count : counter (1-n)
  • first if the current item is the first item
  • middle: if the current item is neither the first nor the last item
  • last: if the current item is the last item
  • odd: if index is odd
  • even: if index is even
data-sly-resource : Includes the indicated resource.
<!-- /* Include the component image */ !-->
<div data-sly-resource="${'image' @ resourceType='wcm/foundation/components/image'}"></div>
data-sly-template / data-sly-call : Defines a template and call it.


<!-- /* Define the template */ -->
<template data-sly-template.titleTemplate="${ @ title}">
<h1>${title}
</template>
<!-- /* Call the template */ -->
<div data-sly-call="${[email protected] title='title test'}" data-sly-unwrap></div>
You can define your template in a different file :

<!-- /* Define the template in template.html */ -->
<template data-sly-template.title="${ @ title}">
<h1>${title}
</template>
<!-- /* Call it in index.html /* -->
<div data-sly-use.template="template.html">
<div data-sly-call="${template.title @ title='testTitle'}"></div>
</div>

Clientlibs:

<!--/* Do not forget the data-sly-use ! */-->
<div data-sly-use.clientLib="${'/libs/granite/sightly/templates/clientlib.html'}">
<meta data-sly-call="${clientLib.css @ categories='myClientlib1'}" data-sly-unwrap/>></meta>
<meta data-sly-call="${clientLib.js @ categories='myClientlib2'}" data-sly-unwrap/>></meta>
<meta data-sly-call="${clientLib.all @ categories=['myClientlib1', 'myClientlib2']}" data-sly-unwrap/>></meta>
</div

No comments :

Post a comment