Created
June 1, 2016 04:08
-
-
Save nateyolles/8299b134c2b56faec93326212e293972 to your computer and use it in GitHub Desktop.
Custom ClientLibUseObject Java-Use POJO to create custom HTML markup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package apps.clientlib_async.sightly.templates; | |
import java.io.IOException; | |
import java.io.PrintWriter; | |
import java.io.StringWriter; | |
import java.util.Collection; | |
import java.util.List; | |
import java.util.ArrayList; | |
import javax.script.Bindings; | |
import org.apache.commons.lang3.StringUtils; | |
import org.apache.sling.api.SlingHttpServletRequest; | |
import org.apache.sling.api.scripting.SlingBindings; | |
import org.apache.sling.api.scripting.SlingScriptHelper; | |
import org.apache.sling.api.resource.Resource; | |
import com.day.cq.widget.ClientLibrary; | |
import com.day.cq.widget.HtmlLibraryManager; | |
import com.day.cq.widget.LibraryType; | |
import com.adobe.granite.xss.XSSAPI; | |
import org.slf4j.Logger; | |
import io.sightly.java.api.Use; | |
/** | |
* Sightly Clientlibs that can accept expression options for 'defer', 'async' | |
* 'onload' and 'crossorigin'. | |
* | |
* See: https://github.com/nateyolles/aem-clientlib-async | |
* | |
* This class is mostly code from /libs/granite/sightly/templates/ClientLibUseObjec.java, | |
* found in your local AEM instance. The differences are that this class gets | |
* the 'loading' and 'onload' attributes, gets the categories retrieved from | |
* {@link com.day.cq.widget.HtmlLibraryManager#getLibraries(String[], LibraryType, boolean, boolean)} | |
* and writes it's own HTML script elements rather than have the HtmlLibrary | |
* manger do it for us using {@link com.day.cq.widget.HtmlLibraryManager#writeIncludes(SlingHttpServletRequest, Writer, String...)}. | |
* | |
* @author Nate Yolles <[email protected]> | |
* @version 2.0.0 | |
* @since 2015-03-19 | |
* @see libs.granite.sightly.templates.ClientLibUseObject | |
* @see com.day.cq.widget.HtmlLibraryManager | |
*/ | |
public class ClientLibUseObject implements Use { | |
private static final String BINDINGS_CATEGORIES = "categories"; | |
private static final String BINDINGS_MODE = "mode"; | |
/** | |
* Sightly parameter that becomes the script element void attribute such as | |
* 'defer' and 'async'. Valid values are listed in {@link #VALID_JS_ATTRIBUTES}. | |
*/ | |
private static final String BINDINGS_LOADING = "loading"; | |
/** | |
* Sightly parameter that becomes the javascript function value in the | |
* script element's 'onload' attribute. | |
*/ | |
private static final String BINDINGS_ONLOAD = "onload"; | |
/** | |
* Sightly parameter that becomes the value in the script and link elements' | |
* 'crossorigin' attribute. | |
*/ | |
private static final String BINDINGS_CROSS_ORIGIN = "crossorigin"; | |
/** | |
* HTML markup for javascript. Add 'type="text/javascript"' if you are not | |
* using HTML 5. | |
*/ | |
private static final String TAG_JAVASCRIPT = "<script src=\"%s\"%s></script>"; | |
/** | |
* HTML markup for stylesheets. | |
*/ | |
private static final String TAG_STYLESHEET = "<link rel=\"stylesheet\" href=\"%s\"%s>"; | |
/** | |
* HTML markup for onload attribute of script element. | |
*/ | |
private static final String ONLOAD_ATTRIBUTE = " onload=\"%s\""; | |
/** | |
* HTML markup for crossorigin attribute of script and link elements. | |
*/ | |
private static final String CROSS_ORIGIN_ATTRIBUTE = " crossorigin=\"%s\""; | |
/** | |
* Valid void attributes for HTML markup of script element. | |
*/ | |
private static final List<String> VALID_JS_ATTRIBUTES = new ArrayList<String>(){{ | |
add("async"); | |
add("defer"); | |
}}; | |
/** | |
* Valid values for crossorigin attribute for HTML markup of script and link | |
* elements. | |
*/ | |
private static final List<String> VALID_CROSS_ORIGIN_VALUES = new ArrayList<String>(){{ | |
add("anonymous"); | |
add("use-credentials"); | |
}}; | |
private HtmlLibraryManager htmlLibraryManager = null; | |
private String[] categories; | |
private String mode; | |
private String loadingAttribute; | |
private String onloadAttribute; | |
private String crossoriginAttribute; | |
private SlingHttpServletRequest request; | |
private PrintWriter out; | |
private Logger log; | |
private Resource resource; | |
private XSSAPI xssAPI; | |
/** | |
* Same as AEM provided method with the addition of getting the XSSAPI | |
* service and the two additional bindings for loading and onload. | |
* | |
* @see libs.granite.sightly.templates.ClientLibUseObject#init(Bindings) | |
*/ | |
public void init(Bindings bindings) { | |
loadingAttribute = (String) bindings.get(BINDINGS_LOADING); | |
onloadAttribute = (String) bindings.get(BINDINGS_ONLOAD); | |
crossoriginAttribute = (String) bindings.get(BINDINGS_CROSS_ORIGIN); | |
resource = (Resource) bindings.get("resource"); | |
Object categoriesObject = bindings.get(BINDINGS_CATEGORIES); | |
if (categoriesObject != null) { | |
if (categoriesObject instanceof Object[]) { | |
Object[] categoriesArray = (Object[]) categoriesObject; | |
categories = new String[categoriesArray.length]; | |
int i = 0; | |
for (Object o : categoriesArray) { | |
if (o instanceof String) { | |
categories[i++] = ((String) o).trim(); | |
} | |
} | |
} else if (categoriesObject instanceof String) { | |
categories = ((String) categoriesObject).split(","); | |
int i = 0; | |
for (String c : categories) { | |
categories[i++] = c.trim(); | |
} | |
} | |
if (categories != null && categories.length > 0) { | |
mode = (String) bindings.get(BINDINGS_MODE); | |
request = (SlingHttpServletRequest) bindings.get(SlingBindings.REQUEST); | |
log = (Logger) bindings.get(SlingBindings.LOG); | |
SlingScriptHelper sling = (SlingScriptHelper) bindings.get(SlingBindings.SLING); | |
htmlLibraryManager = sling.getService(HtmlLibraryManager.class); | |
xssAPI = sling.getService(XSSAPI.class); | |
} | |
} | |
} | |
/** | |
* Essentially the same as the AEM provided method with the exception that | |
* the HtmlLibraryManger's writeIncludes methods have been replaced with | |
* calls to #includeLibraries. | |
* | |
* @see libs.granite.sightly.templates.ClientLibUseObject#include() | |
*/ | |
public String include() { | |
StringWriter sw = new StringWriter(); | |
if (categories == null || categories.length == 0) { | |
log.error("'categories' option might be missing from the invocation of the /apps/beagle/sightly/templates/clientlib.html" + | |
"client libraries template library. Please provide a CSV list or an array of categories to include."); | |
} else { | |
PrintWriter out = new PrintWriter(sw); | |
if ("js".equalsIgnoreCase(mode)) { | |
includeLibraries(out, LibraryType.JS); | |
} else if ("css".equalsIgnoreCase(mode)) { | |
includeLibraries(out, LibraryType.CSS); | |
} else { | |
includeLibraries(out, LibraryType.CSS); | |
includeLibraries(out, LibraryType.JS); | |
} | |
} | |
return sw.toString(); | |
} | |
/** | |
* Construct the HTML markup for the script and link elements. | |
* | |
* @param out The PrintWriter object responsible for writing the HTML. | |
* @param LibraryType The library type either CSS or JS. | |
*/ | |
private void includeLibraries(PrintWriter out, LibraryType libraryType) { | |
if (htmlLibraryManager != null && libraryType != null && xssAPI != null) { | |
Collection<ClientLibrary> libs = htmlLibraryManager.getLibraries(categories, libraryType, false, false); | |
String attribute = StringUtils.EMPTY; | |
if (libraryType.equals(LibraryType.JS)) { | |
if (StringUtils.isNotBlank(loadingAttribute) && VALID_JS_ATTRIBUTES.contains(loadingAttribute.toLowerCase())) { | |
attribute = " ".concat(loadingAttribute.toLowerCase()); | |
} | |
if (StringUtils.isNotBlank(onloadAttribute)) { | |
String safeOnload = xssAPI.encodeForHTMLAttr(onloadAttribute); | |
if (StringUtils.isNotBlank(safeOnload)) { | |
attribute = attribute.concat(String.format(ONLOAD_ATTRIBUTE, safeOnload)); | |
} | |
} | |
} | |
if (StringUtils.isNotBlank(crossoriginAttribute) && VALID_CROSS_ORIGIN_VALUES.contains(crossoriginAttribute.toLowerCase())) { | |
attribute = attribute.concat(String.format(CROSS_ORIGIN_ATTRIBUTE, crossoriginAttribute.toLowerCase())); | |
} | |
for (ClientLibrary lib : libs) { | |
out.write(String.format(libraryType.equals(LibraryType.JS) ? TAG_JAVASCRIPT : TAG_STYLESHEET, lib.getIncludePath(libraryType, htmlLibraryManager.isMinifyEnabled()), attribute)); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment