From 462465b923eb024b34127d3e0bbe77e9d4b04b23 Mon Sep 17 00:00:00 2001 From: Stefan Seifert Date: Mon, 10 Jul 2023 15:05:24 +0200 Subject: [PATCH 1/7] support custom attributes for css and script includes --- .../ui/clientlibs/components/CSSInclude.java | 19 +++++-- .../ui/clientlibs/components/IncludeUtil.java | 50 +++++++++++++++++++ .../ui/clientlibs/components/JSInclude.java | 27 +++++----- 3 files changed, 80 insertions(+), 16 deletions(-) diff --git a/src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java b/src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java index 243a76d..180ad37 100644 --- a/src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java +++ b/src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java @@ -19,7 +19,9 @@ */ package io.wcm.wcm.ui.clientlibs.components; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import javax.annotation.PostConstruct; @@ -45,6 +47,8 @@ @ProviderType public class CSSInclude { + @SlingObject + private SlingHttpServletRequest request; @SlingObject private ResourceResolver resourceResolver; @OSGiService @@ -65,7 +69,8 @@ private void activate() { List libraryPaths = IncludeUtil.getLibraryUrls(htmlLibraryManager, resourceResolver, categoryArray, LibraryType.CSS); if (!libraryPaths.isEmpty()) { - this.include = buildIncludeString(libraryPaths); + Map customAttrs = IncludeUtil.getCustomAttributes(request); + this.include = buildIncludeString(libraryPaths, customAttrs); } } } @@ -73,12 +78,20 @@ private void activate() { /** * Build CSS link tags for all client libraries with the defined custom script tag attributes set. * @param libraryPaths Library paths + * @param customAttrs Custom HTML attributes for script tag * @return HTML markup with script tags */ - private @NotNull String buildIncludeString(@NotNull List libraryPaths) { + private @NotNull String buildIncludeString(@NotNull List libraryPaths, + @NotNull Map customAttrs) { StringBuilder markup = new StringBuilder(); for (String libraryPath : libraryPaths) { - markup.append("\n"); + Map combinedAttrs = new LinkedHashMap<>(); + combinedAttrs.put("rel", "stylesheet"); + combinedAttrs.put("href", libraryPath); + combinedAttrs.put("type", "text/css"); + combinedAttrs.putAll(customAttrs); + markup.append(IncludeUtil.buildHtmlElementOpenTag("link", combinedAttrs, xssApi)); + markup.append("\n"); } return markup.toString(); } diff --git a/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java b/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java index ff145a7..4dc8176 100644 --- a/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java +++ b/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java @@ -20,11 +20,17 @@ package io.wcm.wcm.ui.clientlibs.components; import java.lang.reflect.Array; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.TreeMap; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.xss.XSSAPI; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,6 +43,8 @@ */ final class IncludeUtil { + private static final String CUSTOM_ATTRIBUTE_PREFIX = "custom."; + private IncludeUtil() { // static methods only } @@ -100,4 +108,46 @@ else if (resourceResolver.getResource(library.getPath()) == null) { return path; } + /** + * Gets all request attributes that are prefixed with "custom.". + * @param request Request + * @return Map with custom attributes (keys without the "custom." prefix). + */ + public static @NotNull Map getCustomAttributes(@NotNull SlingHttpServletRequest request) { + Map result = new TreeMap<>(); + List customAttributeNames = Collections.list(request.getAttributeNames()).stream() + .filter(name -> StringUtils.startsWith(name, CUSTOM_ATTRIBUTE_PREFIX)) + .collect(Collectors.toList()); + customAttributeNames.forEach(customAttribute -> { + String name = StringUtils.substringAfter(customAttribute, CUSTOM_ATTRIBUTE_PREFIX); + Object value = request.getAttribute(customAttribute); + result.put(name, value != null ? value.toString() : null); + }); + return result; + } + + /** + * Builds opening HTML element with given name and attributes. + * @param elementName Element name + * @param attrs HTML attributes + * @param xssApi XSS API + * @return HTML element + */ + public static @NotNull String buildHtmlElementOpenTag(@NotNull String elementName, @NotNull Map attrs, + XSSAPI xssApi) { + StringBuilder markup = new StringBuilder(); + markup.append("<").append(elementName); + for (Map.Entry attr : attrs.entrySet()) { + markup.append(" "); + markup.append(attr.getKey()); + if (attr.getValue() != null) { + markup.append("=\""); + markup.append(xssApi.encodeForHTMLAttr(attr.getValue())); + markup.append("\""); + } + } + markup.append(">"); + return markup.toString(); + } + } diff --git a/src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java b/src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java index e57a9da..2e2ef70 100644 --- a/src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java +++ b/src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -59,6 +60,8 @@ public class JSInclude { private static final Set TYPE_ALLOWED_VALUES = new HashSet<>(Arrays.asList( "text/javascript", "module")); + @SlingObject + private SlingHttpServletRequest request; @SlingObject private ResourceResolver resourceResolver; @OSGiService @@ -96,7 +99,8 @@ private void activate() { categoryArray, LibraryType.JS); if (!libraryPaths.isEmpty()) { Map attrs = validateAndBuildAttributes(); - this.include = buildIncludeString(libraryPaths, attrs); + Map customAttrs = IncludeUtil.getCustomAttributes(request); + this.include = buildIncludeString(libraryPaths, attrs, customAttrs); } } } @@ -139,22 +143,19 @@ private void activate() { * Build script tags for all client libraries with the defined custom script tag attributes set. * @param libraryPaths Library paths * @param attrs HTML attributes for script tag + * @param customAttrs Custom HTML attributes for script tag * @return HTML markup with script tags */ - private @NotNull String buildIncludeString(@NotNull List libraryPaths, @NotNull Map attrs) { + private @NotNull String buildIncludeString(@NotNull List libraryPaths, @NotNull Map attrs, + @NotNull Map customAttrs) { StringBuilder markup = new StringBuilder(); for (String libraryPath : libraryPaths) { - markup.append("\n"); + Map combinedAttrs = new LinkedHashMap<>(); + combinedAttrs.put("src", libraryPath); + combinedAttrs.putAll(attrs); + combinedAttrs.putAll(customAttrs); + markup.append(IncludeUtil.buildHtmlElementOpenTag("script", combinedAttrs, xssApi)); + markup.append("\n"); } return markup.toString(); } From 6fe7adfdfdeb7a0848806377522cd30d7dc513fe Mon Sep 17 00:00:00 2001 From: Stefan Seifert Date: Mon, 10 Jul 2023 16:31:25 +0200 Subject: [PATCH 2/7] add unit tests --- changes.xml | 3 +++ .../wcm/wcm/ui/clientlibs/components/IncludeUtil.java | 2 +- .../wcm/ui/clientlibs/components/CSSIncludeTest.java | 11 +++++++---- .../wcm/ui/clientlibs/components/JSIncludeTest.java | 11 +++++++---- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/changes.xml b/changes.xml index 01d911a..81c0ec5 100644 --- a/changes.xml +++ b/changes.xml @@ -24,6 +24,9 @@ + + Support custom attributes for CSS and JS includes. + Switch to Java 11 as minimum version. diff --git a/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java b/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java index 4dc8176..1c51b85 100644 --- a/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java +++ b/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java @@ -43,7 +43,7 @@ */ final class IncludeUtil { - private static final String CUSTOM_ATTRIBUTE_PREFIX = "custom."; + private static final String CUSTOM_ATTRIBUTE_PREFIX = "custom-"; private IncludeUtil() { // static methods only diff --git a/src/test/java/io/wcm/wcm/ui/clientlibs/components/CSSIncludeTest.java b/src/test/java/io/wcm/wcm/ui/clientlibs/components/CSSIncludeTest.java index a3cb6cb..f9f9e3a 100644 --- a/src/test/java/io/wcm/wcm/ui/clientlibs/components/CSSIncludeTest.java +++ b/src/test/java/io/wcm/wcm/ui/clientlibs/components/CSSIncludeTest.java @@ -64,12 +64,15 @@ void testSingleProxy() { } @Test - void testMulti() { + void testMultiWithCustom() { context.request().setAttribute("categories", CATEGORIES_MULTIPLE); + context.request().setAttribute("custom-attr1", "value1"); + context.request().setAttribute("custom-attr-2", 5); + context.request().setAttribute("custom-attr3", null); CSSInclude underTest = AdaptTo.notNull(context.request(), CSSInclude.class); - assertEquals("\n" - + "\n" - + "\n", + assertEquals("\n" + + "\n" + + "\n", underTest.getInclude()); } diff --git a/src/test/java/io/wcm/wcm/ui/clientlibs/components/JSIncludeTest.java b/src/test/java/io/wcm/wcm/ui/clientlibs/components/JSIncludeTest.java index 0aa6caa..e40890d 100644 --- a/src/test/java/io/wcm/wcm/ui/clientlibs/components/JSIncludeTest.java +++ b/src/test/java/io/wcm/wcm/ui/clientlibs/components/JSIncludeTest.java @@ -126,18 +126,21 @@ void testSingleInvalidAttributes() { } @Test - void testMultiAttributes() { + void testMultiAttributesWithCustom() { context.request().setAttribute("categories", CATEGORIES_MULTIPLE); context.request().setAttribute("async", true); context.request().setAttribute("nomodule", true); context.request().setAttribute("type", "text/javascript"); + context.request().setAttribute("custom-attr1", "value1"); + context.request().setAttribute("custom-attr-2", 5); + context.request().setAttribute("custom-attr3", null); JSInclude underTest = AdaptTo.notNull(context.request(), JSInclude.class); assertEquals("\n" + + "async nomodule type=\"text/javascript\" attr-2=\"5\" attr1=\"value1\" attr3>\n" + "\n" + + "async nomodule type=\"text/javascript\" attr-2=\"5\" attr1=\"value1\" attr3>\n" + "\n", + + "async nomodule type=\"text/javascript\" attr-2=\"5\" attr1=\"value1\" attr3>\n", underTest.getInclude()); } From 0f6c818d089fa7d599e2ebc728a1317d27efe11f Mon Sep 17 00:00:00 2001 From: Stefan Seifert Date: Mon, 10 Jul 2023 16:50:56 +0200 Subject: [PATCH 3/7] switch to property for custom attributes --- .../ui/clientlibs/components/CSSInclude.java | 7 +-- .../ui/clientlibs/components/IncludeUtil.java | 44 +++++++++++-------- .../ui/clientlibs/components/JSInclude.java | 7 +-- .../clientlibs/components/CSSIncludeTest.java | 12 ++--- .../clientlibs/components/JSIncludeTest.java | 12 ++--- 5 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java b/src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java index 180ad37..6c49317 100644 --- a/src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java +++ b/src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java @@ -19,6 +19,7 @@ */ package io.wcm.wcm.ui.clientlibs.components; +import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -47,8 +48,6 @@ @ProviderType public class CSSInclude { - @SlingObject - private SlingHttpServletRequest request; @SlingObject private ResourceResolver resourceResolver; @OSGiService @@ -58,6 +57,8 @@ public class CSSInclude { @RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL) private Object categories; + @RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL) + private Collection customAttributes; private String include; @@ -69,7 +70,7 @@ private void activate() { List libraryPaths = IncludeUtil.getLibraryUrls(htmlLibraryManager, resourceResolver, categoryArray, LibraryType.CSS); if (!libraryPaths.isEmpty()) { - Map customAttrs = IncludeUtil.getCustomAttributes(request); + Map customAttrs = IncludeUtil.getCustomAttributes(customAttributes); this.include = buildIncludeString(libraryPaths, customAttrs); } } diff --git a/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java b/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java index 1c51b85..6f99fdc 100644 --- a/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java +++ b/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java @@ -20,15 +20,14 @@ package io.wcm.wcm.ui.clientlibs.components; import java.lang.reflect.Array; +import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.TreeMap; import java.util.stream.Collectors; -import org.apache.commons.lang3.StringUtils; -import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.xss.XSSAPI; import org.jetbrains.annotations.NotNull; @@ -43,8 +42,6 @@ */ final class IncludeUtil { - private static final String CUSTOM_ATTRIBUTE_PREFIX = "custom-"; - private IncludeUtil() { // static methods only } @@ -109,20 +106,31 @@ else if (resourceResolver.getResource(library.getPath()) == null) { } /** - * Gets all request attributes that are prefixed with "custom.". - * @param request Request - * @return Map with custom attributes (keys without the "custom." prefix). + * Transform list of custom attributes to a map. + * @param customAttributes List of custom attributes in syntax "attr=value" for each item. + * @return Map with custom attributes */ - public static @NotNull Map getCustomAttributes(@NotNull SlingHttpServletRequest request) { - Map result = new TreeMap<>(); - List customAttributeNames = Collections.list(request.getAttributeNames()).stream() - .filter(name -> StringUtils.startsWith(name, CUSTOM_ATTRIBUTE_PREFIX)) - .collect(Collectors.toList()); - customAttributeNames.forEach(customAttribute -> { - String name = StringUtils.substringAfter(customAttribute, CUSTOM_ATTRIBUTE_PREFIX); - Object value = request.getAttribute(customAttribute); - result.put(name, value != null ? value.toString() : null); - }); + public static @NotNull Map getCustomAttributes(@Nullable Collection customAttributes) { + if (customAttributes == null) { + return Collections.emptyMap(); + } + Map result = new LinkedHashMap<>(); + for (String item : customAttributes) { + if (item != null) { + int separator = item.indexOf('='); + String name; + String value; + if (separator > 0) { + name = item.substring(0, separator); + value = item.substring(separator + 1); + } + else { + name = item; + value = null; + } + result.put(name, value); + } + } return result; } diff --git a/src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java b/src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java index 2e2ef70..a92079e 100644 --- a/src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java +++ b/src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java @@ -20,6 +20,7 @@ package io.wcm.wcm.ui.clientlibs.components; import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -60,8 +61,6 @@ public class JSInclude { private static final Set TYPE_ALLOWED_VALUES = new HashSet<>(Arrays.asList( "text/javascript", "module")); - @SlingObject - private SlingHttpServletRequest request; @SlingObject private ResourceResolver resourceResolver; @OSGiService @@ -87,6 +86,8 @@ public class JSInclude { private String referrerpolicy; @RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL) private String type; + @RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL) + private Collection customAttributes; private String include; @@ -99,7 +100,7 @@ private void activate() { categoryArray, LibraryType.JS); if (!libraryPaths.isEmpty()) { Map attrs = validateAndBuildAttributes(); - Map customAttrs = IncludeUtil.getCustomAttributes(request); + Map customAttrs = IncludeUtil.getCustomAttributes(customAttributes); this.include = buildIncludeString(libraryPaths, attrs, customAttrs); } } diff --git a/src/test/java/io/wcm/wcm/ui/clientlibs/components/CSSIncludeTest.java b/src/test/java/io/wcm/wcm/ui/clientlibs/components/CSSIncludeTest.java index f9f9e3a..b9180fb 100644 --- a/src/test/java/io/wcm/wcm/ui/clientlibs/components/CSSIncludeTest.java +++ b/src/test/java/io/wcm/wcm/ui/clientlibs/components/CSSIncludeTest.java @@ -23,6 +23,8 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.when; +import java.util.List; + import org.apache.sling.api.resource.PersistenceException; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -66,13 +68,11 @@ void testSingleProxy() { @Test void testMultiWithCustom() { context.request().setAttribute("categories", CATEGORIES_MULTIPLE); - context.request().setAttribute("custom-attr1", "value1"); - context.request().setAttribute("custom-attr-2", 5); - context.request().setAttribute("custom-attr3", null); + context.request().setAttribute("customAttributes", List.of("attr1=value1", "data-attr2=5", "attr3")); CSSInclude underTest = AdaptTo.notNull(context.request(), CSSInclude.class); - assertEquals("\n" - + "\n" - + "\n", + assertEquals("\n" + + "\n" + + "\n", underTest.getInclude()); } diff --git a/src/test/java/io/wcm/wcm/ui/clientlibs/components/JSIncludeTest.java b/src/test/java/io/wcm/wcm/ui/clientlibs/components/JSIncludeTest.java index e40890d..a1cd232 100644 --- a/src/test/java/io/wcm/wcm/ui/clientlibs/components/JSIncludeTest.java +++ b/src/test/java/io/wcm/wcm/ui/clientlibs/components/JSIncludeTest.java @@ -23,6 +23,8 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.when; +import java.util.List; + import org.apache.sling.api.resource.PersistenceException; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -131,16 +133,14 @@ void testMultiAttributesWithCustom() { context.request().setAttribute("async", true); context.request().setAttribute("nomodule", true); context.request().setAttribute("type", "text/javascript"); - context.request().setAttribute("custom-attr1", "value1"); - context.request().setAttribute("custom-attr-2", 5); - context.request().setAttribute("custom-attr3", null); + context.request().setAttribute("customAttributes", List.of("attr1=value1", "data-attr2=5", "attr3")); JSInclude underTest = AdaptTo.notNull(context.request(), JSInclude.class); assertEquals("\n" + + "async nomodule type=\"text/javascript\" attr1=\"value1\" data-attr2=\"5\" attr3>\n" + "\n" + + "async nomodule type=\"text/javascript\" attr1=\"value1\" data-attr2=\"5\" attr3>\n" + "\n", + + "async nomodule type=\"text/javascript\" attr1=\"value1\" data-attr2=\"5\" attr3>\n", underTest.getInclude()); } From 7e0e1b05acc2176696765f9effbf0708367f2538 Mon Sep 17 00:00:00 2001 From: Stefan Seifert Date: Mon, 10 Jul 2023 17:09:24 +0200 Subject: [PATCH 4/7] finalize implementation --- .../ui/clientlibs/components/CSSInclude.java | 5 ++--- .../ui/clientlibs/components/IncludeUtil.java | 10 +++++----- .../wcm/ui/clientlibs/components/JSInclude.java | 5 ++--- .../app-root/sightly/templates/clientlib.html | 10 ++++++---- src/site/markdown/usage.md | 17 +++++++++++++++++ .../clientlibs/components/CSSIncludeTest.java | 4 +--- .../ui/clientlibs/components/JSIncludeTest.java | 4 +--- 7 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java b/src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java index 6c49317..be926c4 100644 --- a/src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java +++ b/src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java @@ -19,7 +19,6 @@ */ package io.wcm.wcm.ui.clientlibs.components; -import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -58,14 +57,14 @@ public class CSSInclude { @RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL) private Object categories; @RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL) - private Collection customAttributes; + private Object customAttributes; private String include; @PostConstruct private void activate() { // build include string - String[] categoryArray = IncludeUtil.toCategoryArray(categories); + String[] categoryArray = IncludeUtil.toArray(categories); if (categoryArray != null) { List libraryPaths = IncludeUtil.getLibraryUrls(htmlLibraryManager, resourceResolver, categoryArray, LibraryType.CSS); diff --git a/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java b/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java index 6f99fdc..0581798 100644 --- a/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java +++ b/src/main/java/io/wcm/wcm/ui/clientlibs/components/IncludeUtil.java @@ -20,7 +20,6 @@ package io.wcm.wcm.ui.clientlibs.components; import java.lang.reflect.Array; -import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -49,7 +48,7 @@ private IncludeUtil() { /** * @return Array of clientlib category names as specified in HTL script */ - public static @Nullable String[] toCategoryArray(Object categories) { + public static @Nullable String[] toArray(Object categories) { String[] categoryArray = null; if (categories instanceof String) { categoryArray = new String[] { (String)categories }; @@ -110,12 +109,13 @@ else if (resourceResolver.getResource(library.getPath()) == null) { * @param customAttributes List of custom attributes in syntax "attr=value" for each item. * @return Map with custom attributes */ - public static @NotNull Map getCustomAttributes(@Nullable Collection customAttributes) { - if (customAttributes == null) { + public static @NotNull Map getCustomAttributes(@Nullable Object customAttributes) { + String[] customAttributesArray = toArray(customAttributes); + if (customAttributesArray == null) { return Collections.emptyMap(); } Map result = new LinkedHashMap<>(); - for (String item : customAttributes) { + for (String item : customAttributesArray) { if (item != null) { int separator = item.indexOf('='); String name; diff --git a/src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java b/src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java index a92079e..a405193 100644 --- a/src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java +++ b/src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java @@ -20,7 +20,6 @@ package io.wcm.wcm.ui.clientlibs.components; import java.util.Arrays; -import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -87,14 +86,14 @@ public class JSInclude { @RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL) private String type; @RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL) - private Collection customAttributes; + private Object customAttributes; private String include; @PostConstruct private void activate() { // build include string - String[] categoryArray = IncludeUtil.toCategoryArray(categories); + String[] categoryArray = IncludeUtil.toArray(categories); if (categoryArray != null) { List libraryPaths = IncludeUtil.getLibraryUrls(htmlLibraryManager, resourceResolver, categoryArray, LibraryType.JS); diff --git a/src/main/webapp/app-root/sightly/templates/clientlib.html b/src/main/webapp/app-root/sightly/templates/clientlib.html index 5b5a0e1..c4be662 100644 --- a/src/main/webapp/app-root/sightly/templates/clientlib.html +++ b/src/main/webapp/app-root/sightly/templates/clientlib.html @@ -9,13 +9,14 @@ * @param nonce https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-nonce * @param referrerpolicy see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-referrerpolicy * @param type see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type + * @param customAttributes List of custom attributes, each list item in syntax 'attr=value' or just 'attr' */--> @@ -23,11 +24,12 @@ -