Search code examples
aemslingsightly

Idiomatic way to overcome difficulties with `@extension = 'html'` in AEM 6.3 Sightly/HTL?


AEM's HTL (f.k.a. Sightly) has a special idiom for reformatting URL properties, e.g.

<a href="${properties.path @ extension = 'html'}">

The purpose of this idiom is two-fold

  1. to append .html to internal links authored via a pathbrowser field
  2. to apply resource mappings which have been configured to strip /content/projectname

Unfortunately this well-intentioned feature has several problems:

  • It won't work with resource links, e.g. a PDF file in the DAM.
  • It won't work with external links that don't end in .html.
  • It escapes the "&" in URLs containing query string params, breaking the link.

My team is now tasked with fixing dozens of defects caused by over-use of this extension = 'html' trick, and we would like to fix them all consistently and quickly with a minimum risk of regressions.

Is there a quick fix, preferrably something that can be repeated via mindless search/replace of every occurrence of extension = 'html'?


Solution

  • I can suggest a combination of uri context and adding .html extension to resource URLs from server side.

    • It won't work with resource links, e.g. a PDF file in the DAM.

    Use @ context = 'uri', default context for href and src attributes and does not explicitly add .html extension.

    Input -

    <a href="${'/content/dam/repl/en.pdf'}">Resource Link</a> uses default uri context.

    Output -

    <a href="/content/dam/repl/en.pdf">Resource Link</a>

    On any other html attribute, use an attribute context - @ context='attribute'

    Input -

    <div data-link="${'/content/dam/repl/en.pdf' @ context='attribute'}"/>

    Output -

    <div data-link="/content/dam/repl/en.pdf"/>


    • It won't work with external links that don't end in .html.
    • It escapes the "&" in URLs containing query string params, breaking the link.

    Again use @ context = 'uri', does not escape & in URLs, works fine with selectors and # params as well. Added advantage of XSS protection.

    Input -

    <a href="${'http://www.reddit.com.selector1.selector2?a=1&b=2&c=3'}">URI context</a>

    Output -

    <a href="http://www.reddit.com.selector1.selector2?a=1&b=2&c=3">URI context</a>

    • To append .html to internal resource URLs

    You cannot use @ extension and @ context together in the same element. You could append .html like this <a href="${path}.html">Title</a> or better way would be to address this at the sling model level, a util method like this maybe.

    public static String getUrl(String link, String extension, ResourceResolver resourceResolver) {
            String updatedLink = "";
            if (link != null) {
                Resource pathResource = resourceResolver.getResource(link);
                // check if resource exists
                if (pathResource != null) {
                    // append .html
                    updatedLink = resourceResolver.map(link) + extension;
                }
            }
            return updatedLink;
        }
    

    Side note: Avoid @ context='unsafe' for obvious reasons - completely disables xss protection.

    Check this for the available context expression options.