Skip to content

Commit

Permalink
add allowMultipleIncludes - by default, multiple includes of the sa…
Browse files Browse the repository at this point in the history
…me script in a single request are eliminated. If setting this property to `true`, they are included multiple times if requested
  • Loading branch information
stefanseifert committed Sep 10, 2024
1 parent 79e3e8c commit 9f27943
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 22 deletions.
17 changes: 10 additions & 7 deletions src/main/java/io/wcm/wcm/ui/clientlibs/components/CSSInclude.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public class CSSInclude {
@RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL)
private String rel;
@RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL)
private String allowMultipleIncludes;
@RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL)
private Object customAttributes;

private String include;
Expand Down Expand Up @@ -111,13 +113,14 @@ private void activate() {
*/
private @NotNull String buildIncludeString(@NotNull List<String> libraryPaths, @NotNull Map<String, String> attrs,
@NotNull Map<String, String> customAttrs) {
return new RequestIncludedLibraries(request).buildMarkupIgnoringDuplicateLibraries(libraryPaths, libraryPath -> {
HtmlTagBuilder builder = new HtmlTagBuilder("link", false, xssApi);
builder.setAttrs(attrs);
builder.setAttrs(customAttrs);
builder.setAttr("href", request.getContextPath() + libraryPath);
return builder;
});
return new RequestIncludedLibraries(request, allowMultipleIncludes)
.buildMarkupIgnoringDuplicateLibraries(libraryPaths, libraryPath -> {
HtmlTagBuilder builder = new HtmlTagBuilder("link", false, xssApi);
builder.setAttrs(attrs);
builder.setAttrs(customAttrs);
builder.setAttr("href", request.getContextPath() + libraryPath);
return builder;
});
}

/**
Expand Down
17 changes: 10 additions & 7 deletions src/main/java/io/wcm/wcm/ui/clientlibs/components/JSInclude.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ public class JSInclude {
@RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL)
private String type;
@RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL)
private String allowMultipleIncludes;
@RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL)
private Object customAttributes;

private String include;
Expand Down Expand Up @@ -147,13 +149,14 @@ private void activate() {
*/
private @NotNull String buildIncludeString(@NotNull List<String> libraryPaths, @NotNull Map<String, String> attrs,
@NotNull Map<String, String> customAttrs) {
return new RequestIncludedLibraries(request).buildMarkupIgnoringDuplicateLibraries(libraryPaths, libraryPath -> {
HtmlTagBuilder builder = new HtmlTagBuilder("script", true, xssApi);
builder.setAttrs(attrs);
builder.setAttrs(customAttrs);
builder.setAttr("src", request.getContextPath() + libraryPath);
return builder;
});
return new RequestIncludedLibraries(request, allowMultipleIncludes)
.buildMarkupIgnoringDuplicateLibraries(libraryPaths, libraryPath -> {
HtmlTagBuilder builder = new HtmlTagBuilder("script", true, xssApi);
builder.setAttrs(attrs);
builder.setAttrs(customAttrs);
builder.setAttr("src", request.getContextPath() + libraryPath);
return builder;
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
import java.util.Set;
import java.util.function.Function;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.jetbrains.annotations.Nullable;

import com.adobe.granite.ui.clientlibs.HtmlLibraryManager;
import com.drew.lang.annotations.NotNull;
Expand All @@ -38,9 +40,12 @@ class RequestIncludedLibraries {
private static final String RA_INCLUDED_LIBRARY_PATHS = HtmlLibraryManager.class.getName() + ".included";

private final SlingHttpServletRequest request;
private final boolean allowMultipleIncludes;

RequestIncludedLibraries(SlingHttpServletRequest request) {
RequestIncludedLibraries(@NotNull SlingHttpServletRequest request,
@Nullable String allowMultipleIncludes) {
this.request = request;
this.allowMultipleIncludes = BooleanUtils.toBoolean(allowMultipleIncludes);
}

/**
Expand Down Expand Up @@ -81,17 +86,16 @@ void storeIncluded(@NotNull String libraryPath) {
*/
String buildMarkupIgnoringDuplicateLibraries(@NotNull List<String> libraryPaths,
@NotNull Function<String, HtmlTagBuilder> htmlTagBuilderFactory) {
RequestIncludedLibraries includedLibraries = new RequestIncludedLibraries(request);
StringBuilder markup = new StringBuilder();
for (String libraryPath : libraryPaths) {
// ignore libraries that are already included
if (includedLibraries.isInlucded(libraryPath)) {
if (!allowMultipleIncludes && isInlucded(libraryPath)) {
continue;
}
// build markup for library
markup.append(htmlTagBuilderFactory.apply(libraryPath).build());
// mark library as included
includedLibraries.storeIncluded(libraryPath);
storeIncluded(libraryPath);
}
return markup.toString();
}
Expand Down
12 changes: 8 additions & 4 deletions src/main/webapp/app-root/sightly/templates/clientlib.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@
* @param nonce see 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 allowMultipleIncludes If set to true, duplicate inclusions of this client library in a single request are not eliminated.
* @param customAttributes List of custom attributes, each list item in syntax 'attr=value' or just 'attr'
*/-->
<template data-sly-template.js="${@ categories, async, crossorigin, defer, integrity,
nomodule, nonce, referrerpolicy, type, customAttributes}">
nomodule, nonce, referrerpolicy, type, allowMultipleIncludes, customAttributes}">
<sly data-sly-test="${request.getResourceResolver}"
data-sly-use.clientlib="${'io.wcm.wcm.ui.clientlibs.components.JSInclude' @
categories=categories, async=async, crossorigin=crossorigin, defer=defer, integrity=integrity,
nomodule=nomodule, nonce=nonce, referrerpolicy=referrerpolicy, type=type, customAttributes=customAttributes}">
nomodule=nomodule, nonce=nonce, referrerpolicy=referrerpolicy, type=type,
allowMultipleIncludes=allowMultipleIncludes, customAttributes=customAttributes}">
${clientlib.include @ context='unsafe'}
</sly>
</template>
Expand All @@ -25,12 +27,14 @@
* Template used for including CSS client libraries.
* @param categories Client Library categories
* @param rel prefetch|preload see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel
* @param allowMultipleIncludes If set to true, duplicate inclusions of this client library in a single request are not eliminated.
* @param customAttributes List of custom attributes, each list item in syntax 'attr=value' or just 'attr'
*/-->
<template data-sly-template.css="${@ categories, customAttributes}">
<template data-sly-template.css="${@ categories, allowMultipleIncludes, customAttributes}">
<sly data-sly-test="${request.getResourceResolver}"
data-sly-use.clientlib="${'io.wcm.wcm.ui.clientlibs.components.CSSInclude' @
categories=categories, rel=rel, customAttributes=customAttributes}">
categories=categories, rel=rel,
allowMultipleIncludes=allowMultipleIncludes, customAttributes=customAttributes}">
${clientlib.include @ context='unsafe'}
</sly>
</template>
Expand Down
2 changes: 2 additions & 0 deletions src/site/markdown/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ The following advanced script tag attributes are supported:
* `nonce` = {string}
* `referrerpolicy` = no-referrer | no-referrer-when-downgrade | origin | origin-when-cross-origin | same-origin | strict-origin | strict-origin-when-cross-origin | unsafe-url
* `type` = module | text/javascript
* `allowMultipleIncludes` - by default, multiple includes of the same script in a single request are eliminated. If setting this property to `true`, they are included multiple times if requested.
* `customAttributes` - set arbitrary HTML attributes, e.g. `customAttributes=['attr1=value 1','data-attr2=5','attr3']`

See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#Attributes for a full documentation of this attributes.
Expand All @@ -44,4 +45,5 @@ Include CSS without special attributes:
The following advanced link tag attributes are supported:

* `rel` = prefetch | preload (if not given, `rel="stylesheet" type="text/css"` is set)
* `allowMultipleIncludes` - by default, multiple includes of the same script in a single request are eliminated. If setting this property to `true`, they are included multiple times if requested.
* `customAttributes` - set arbitrary HTML attributes, e.g. `customAttributes=['attr1=value 1','data-attr2=5','attr3']`
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,23 @@ void testMultiIgnoreDuplicates() {
underTest.getInclude());
}

@Test
void testMultiAllowDuplicates() {
final String expectedInclude = "<link href=\"/etc/clientlibs/app1/clientlib3.min.css\" rel=\"stylesheet\" type=\"text/css\">\n"
+ "<link href=\"/etc.clientlibs/app1/clientlibs/clientlib4_proxy.min.css\" rel=\"stylesheet\" type=\"text/css\">\n"
+ "<link href=\"/etc.clientlibs/app1/clientlibs/clientlib5_proxy.min.css\" rel=\"stylesheet\" type=\"text/css\">\n";

context.request().setAttribute("categories", CATEGORIES_MULTIPLE);
context.request().setAttribute("allowMultipleIncludes", "true");
CSSInclude underTest = AdaptTo.notNull(context.request(), CSSInclude.class);
assertEquals(expectedInclude,
underTest.getInclude());

// include again - should be included again (no duplicates removed)
context.request().setAttribute("categories", CATEGORIES_MULTIPLE);
context.request().setAttribute("allowMultipleIncludes", "true");
underTest = AdaptTo.notNull(context.request(), CSSInclude.class);
assertEquals(expectedInclude, underTest.getInclude());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,22 @@ void testMultiIgnoreDuplicates() {
underTest.getInclude());
}

@Test
void testMultiAllowDuplicates() {
final String expectedInclude = "<script src=\"/etc/clientlibs/app1/clientlib3.min.js\"></script>\n"
+ "<script src=\"/etc.clientlibs/app1/clientlibs/clientlib4_proxy.min.js\"></script>\n"
+ "<script src=\"/etc.clientlibs/app1/clientlibs/clientlib5_proxy.min.js\"></script>\n";

context.request().setAttribute("categories", CATEGORIES_MULTIPLE);
context.request().setAttribute("allowMultipleIncludes", "true");
JSInclude underTest = AdaptTo.notNull(context.request(), JSInclude.class);
assertEquals(expectedInclude, underTest.getInclude());

// include again - should be included again (no duplicates removed)
context.request().setAttribute("categories", CATEGORIES_MULTIPLE);
context.request().setAttribute("allowMultipleIncludes", "true");
underTest = AdaptTo.notNull(context.request(), JSInclude.class);
assertEquals(expectedInclude, underTest.getInclude());
}

}

0 comments on commit 9f27943

Please sign in to comment.