diff --git a/modules/apps/frontend-css/frontend-css-variables-api/.lfrbuild-portal b/modules/apps/frontend-css/frontend-css-variables-api/.lfrbuild-portal new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/modules/apps/frontend-css/frontend-css-variables-api/bnd.bnd b/modules/apps/frontend-css/frontend-css-variables-api/bnd.bnd new file mode 100644 index 00000000000000..731b8df78969b9 --- /dev/null +++ b/modules/apps/frontend-css/frontend-css-variables-api/bnd.bnd @@ -0,0 +1,4 @@ +Bundle-Name: Liferay Frontend CSS Variables API +Bundle-SymbolicName: com.liferay.frontend.css.variables.api +Bundle-Version: 1.0.0 +Export-Package: com.liferay.frontend.css.variables \ No newline at end of file diff --git a/modules/apps/frontend-css/frontend-css-variables-api/build.gradle b/modules/apps/frontend-css/frontend-css-variables-api/build.gradle new file mode 100644 index 00000000000000..276308a49d7a74 --- /dev/null +++ b/modules/apps/frontend-css/frontend-css-variables-api/build.gradle @@ -0,0 +1,8 @@ +dependencies { + compileOnly group: "com.liferay", name: "biz.aQute.bnd.annotation", version: "4.2.0.LIFERAY-PATCHED-1" + compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "default" + compileOnly group: "javax.portlet", name: "portlet-api", version: "3.0.1" + compileOnly group: "org.apache.felix", name: "org.apache.felix.http.servlet-api", version: "1.1.2" + compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations", version: "1.3.0" + compileOnly group: "org.osgi", name: "osgi.core", version: "6.0.0" +} \ No newline at end of file diff --git a/modules/apps/frontend-css/frontend-css-variables-api/src/main/java/com/liferay/frontend/css/variables/ScopedCSSVariables.java b/modules/apps/frontend-css/frontend-css-variables-api/src/main/java/com/liferay/frontend/css/variables/ScopedCSSVariables.java new file mode 100644 index 00000000000000..3ad689d2eadd15 --- /dev/null +++ b/modules/apps/frontend-css/frontend-css-variables-api/src/main/java/com/liferay/frontend/css/variables/ScopedCSSVariables.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2000-present Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + */ + +package com.liferay.frontend.css.variables; + +import java.util.Map; + +/** + * @author Iván Zaera Avellón + */ +public interface ScopedCSSVariables { + + public Map getCSSVariables(); + + public String getScope(); + +} \ No newline at end of file diff --git a/modules/apps/frontend-css/frontend-css-variables-api/src/main/java/com/liferay/frontend/css/variables/ScopedCSSVariablesProvider.java b/modules/apps/frontend-css/frontend-css-variables-api/src/main/java/com/liferay/frontend/css/variables/ScopedCSSVariablesProvider.java new file mode 100644 index 00000000000000..0ed600ac51cac2 --- /dev/null +++ b/modules/apps/frontend-css/frontend-css-variables-api/src/main/java/com/liferay/frontend/css/variables/ScopedCSSVariablesProvider.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2000-present Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + */ + +package com.liferay.frontend.css.variables; + +import java.util.Collection; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author Iván Zaera Avellón + */ +public interface ScopedCSSVariablesProvider { + + public Collection getScopedCSSVariablesCollection( + HttpServletRequest httpServletRequest); + +} \ No newline at end of file diff --git a/modules/apps/frontend-css/frontend-css-variables-api/src/main/resources/com/liferay/frontend/css/variables/packageinfo b/modules/apps/frontend-css/frontend-css-variables-api/src/main/resources/com/liferay/frontend/css/variables/packageinfo new file mode 100644 index 00000000000000..e2525561ab2e7b --- /dev/null +++ b/modules/apps/frontend-css/frontend-css-variables-api/src/main/resources/com/liferay/frontend/css/variables/packageinfo @@ -0,0 +1 @@ +version 1.0.0 \ No newline at end of file diff --git a/modules/apps/frontend-css/frontend-css-variables-web/.lfrbuild-portal b/modules/apps/frontend-css/frontend-css-variables-web/.lfrbuild-portal new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/modules/apps/frontend-css/frontend-css-variables-web/bnd.bnd b/modules/apps/frontend-css/frontend-css-variables-web/bnd.bnd new file mode 100644 index 00000000000000..18d4c052c986e8 --- /dev/null +++ b/modules/apps/frontend-css/frontend-css-variables-web/bnd.bnd @@ -0,0 +1,4 @@ +Bundle-Name: Liferay Frontend CSS Variables Web +Bundle-SymbolicName: com.liferay.frontend.css.variables.web +Bundle-Version: 1.0.0 +Web-ContextPath: /frontend-css-variables-web \ No newline at end of file diff --git a/modules/apps/frontend-css/frontend-css-variables-web/build.gradle b/modules/apps/frontend-css/frontend-css-variables-web/build.gradle new file mode 100644 index 00000000000000..83fd59c2f01ae7 --- /dev/null +++ b/modules/apps/frontend-css/frontend-css-variables-web/build.gradle @@ -0,0 +1,15 @@ +dependencies { + compileOnly group: "com.liferay", name: "biz.aQute.bnd.annotation", version: "4.2.0.LIFERAY-PATCHED-1" + compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "default" + compileOnly group: "javax.portlet", name: "portlet-api", version: "3.0.1" + compileOnly group: "org.apache.felix", name: "org.apache.felix.http.servlet-api", version: "1.1.2" + compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations", version: "1.3.0" + compileOnly group: "org.osgi", name: "osgi.core", version: "6.0.0" + compileOnly project(":apps:configuration-admin:configuration-admin-api") + compileOnly project(":apps:frontend-css:frontend-css-variables-api") + compileOnly project(":apps:static:portal-configuration:portal-configuration-metatype-api") + compileOnly project(":core:osgi-service-tracker-collections") + compileOnly project(":core:petra:petra-string") + + testCompile group: "junit", name: "junit", version: "4.12" +} \ No newline at end of file diff --git a/modules/apps/frontend-css/frontend-css-variables-web/src/main/java/com/liferay/frontend/css/variables/web/internal/servlet/taglib/ScopedCSSVariablesTopHeadDynamicInclude.java b/modules/apps/frontend-css/frontend-css-variables-web/src/main/java/com/liferay/frontend/css/variables/web/internal/servlet/taglib/ScopedCSSVariablesTopHeadDynamicInclude.java new file mode 100644 index 00000000000000..f7ab696590d837 --- /dev/null +++ b/modules/apps/frontend-css/frontend-css-variables-web/src/main/java/com/liferay/frontend/css/variables/web/internal/servlet/taglib/ScopedCSSVariablesTopHeadDynamicInclude.java @@ -0,0 +1,131 @@ +/** + * Copyright (c) 2000-present Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + */ + +package com.liferay.frontend.css.variables.web.internal.servlet.taglib; + +import com.liferay.frontend.css.variables.ScopedCSSVariables; +import com.liferay.frontend.css.variables.ScopedCSSVariablesProvider; +import com.liferay.osgi.service.tracker.collections.list.ServiceTrackerList; +import com.liferay.osgi.service.tracker.collections.list.ServiceTrackerListFactory; +import com.liferay.osgi.service.tracker.collections.map.PropertyServiceReferenceComparator; +import com.liferay.portal.kernel.servlet.taglib.BaseDynamicInclude; +import com.liferay.portal.kernel.servlet.taglib.DynamicInclude; + +import java.io.IOException; +import java.io.PrintWriter; + +import java.util.Collection; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.osgi.framework.BundleContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; + +/** + * @author Iván Zaera Avellón + */ +@Component(service = DynamicInclude.class) +public class ScopedCSSVariablesTopHeadDynamicInclude + extends BaseDynamicInclude { + + @Override + public void include( + HttpServletRequest httpServletRequest, + HttpServletResponse httpServletResponse, String dynamicIncludeKey) + throws IOException { + + PrintWriter printWriter = httpServletResponse.getWriter(); + + printWriter.print("\n"); + } + + @Override + public void register(DynamicIncludeRegistry dynamicIncludeRegistry) { + dynamicIncludeRegistry.register( + "/html/common/themes/top_head.jsp#post"); + } + + @Activate + protected void activate(BundleContext bundleContext) { + _scopedCssVariablesProviderServiceTrackerList = + ServiceTrackerListFactory.open( + bundleContext, ScopedCSSVariablesProvider.class, + new PropertyServiceReferenceComparator<>("service.ranking")); + + setScopedCSSVariablesProviders( + _scopedCssVariablesProviderServiceTrackerList); + } + + @Deactivate + protected void deactivate() { + setScopedCSSVariablesProviders(null); + + _scopedCssVariablesProviderServiceTrackerList.close(); + + _scopedCssVariablesProviderServiceTrackerList = null; + } + + protected void setScopedCSSVariablesProviders( + Iterable scopedCSSVariablesProviders) { + + _scopedCSSVariablesProviders = scopedCSSVariablesProviders; + } + + private void _writeCSSVariables( + PrintWriter printWriter, + Collection scopedCSSVariablesCollection) { + + for (ScopedCSSVariables scopedCSSVariables : + scopedCSSVariablesCollection) { + + printWriter.print(scopedCSSVariables.getScope()); + printWriter.print(" {\n"); + + Map cssVariables = + scopedCSSVariables.getCSSVariables(); + + for (Map.Entry entry : cssVariables.entrySet()) { + printWriter.print("--"); + printWriter.print(entry.getKey()); + printWriter.print(": "); + printWriter.print(entry.getValue()); + printWriter.print(";\n"); + } + + printWriter.print("}\n"); + } + } + + private Iterable _scopedCSSVariablesProviders; + private ServiceTrackerList + + _scopedCssVariablesProviderServiceTrackerList; + +} \ No newline at end of file diff --git a/modules/apps/frontend-css/frontend-css-variables-web/src/test/java/com/liferay/frontend/css/variables/web/internal/servlet/taglib/ScopedCSSVariablesTopHeadDynamicIncludeTest.java b/modules/apps/frontend-css/frontend-css-variables-web/src/test/java/com/liferay/frontend/css/variables/web/internal/servlet/taglib/ScopedCSSVariablesTopHeadDynamicIncludeTest.java new file mode 100644 index 00000000000000..a3221947327651 --- /dev/null +++ b/modules/apps/frontend-css/frontend-css-variables-web/src/test/java/com/liferay/frontend/css/variables/web/internal/servlet/taglib/ScopedCSSVariablesTopHeadDynamicIncludeTest.java @@ -0,0 +1,242 @@ +/** + * Copyright (c) 2000-present Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + */ + +package com.liferay.frontend.css.variables.web.internal.servlet.taglib; + +import com.liferay.frontend.css.variables.ScopedCSSVariables; +import com.liferay.frontend.css.variables.ScopedCSSVariablesProvider; +import com.liferay.petra.string.StringPool; +import com.liferay.portal.kernel.servlet.BufferCacheServletResponse; +import com.liferay.portal.kernel.servlet.taglib.DynamicInclude; +import com.liferay.portal.kernel.util.HashMapBuilder; +import com.liferay.portal.kernel.util.StreamUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.Assert; +import org.junit.Test; + +import org.mockito.Mockito; + +/** + * @author Iván Zaera Avellón + */ +public class ScopedCSSVariablesTopHeadDynamicIncludeTest { + + @Test + public void testInclude() throws IOException { + ScopedCSSVariablesTopHeadDynamicInclude + scopedCSSVariablesTopHeadDynamicInclude = + new ScopedCSSVariablesTopHeadDynamicInclude(); + + ScopedCSSVariablesProvider scopedCSSVariablesProvider = Mockito.mock( + ScopedCSSVariablesProvider.class); + + Collection scopedCSSVariables = Arrays.asList( + new ScopedCSSVariables() { + + @Override + public Map getCSSVariables() { + return Collections.singletonMap("color", "red"); + } + + @Override + public String getScope() { + return ":root"; + } + + }); + + Mockito.when( + scopedCSSVariablesProvider.getScopedCSSVariablesCollection( + Mockito.any(HttpServletRequest.class)) + ).thenReturn( + scopedCSSVariables + ); + + scopedCSSVariablesTopHeadDynamicInclude.setScopedCSSVariablesProviders( + Arrays.asList(scopedCSSVariablesProvider)); + + HttpServletRequest httpServletRequest = Mockito.mock( + HttpServletRequest.class); + + HttpServletResponse httpServletResponse = Mockito.mock( + HttpServletResponse.class); + + BufferCacheServletResponse bufferCacheServletResponse = + new BufferCacheServletResponse(httpServletResponse); + + scopedCSSVariablesTopHeadDynamicInclude.include( + httpServletRequest, bufferCacheServletResponse, + "/html/common/themes/top_head.jsp#post"); + + Assert.assertEquals( + _read("liferay_css_variables_1.html", true), + bufferCacheServletResponse.getString()); + } + + @Test + public void testIncludeWithMultipleProviders() throws IOException { + ScopedCSSVariablesTopHeadDynamicInclude + scopedCSSVariablesTopHeadDynamicInclude = + new ScopedCSSVariablesTopHeadDynamicInclude(); + + ScopedCSSVariablesProvider scopedCSSVariablesProvider1 = Mockito.mock( + ScopedCSSVariablesProvider.class); + + Collection scopedCSSVariables1 = Arrays.asList( + new ScopedCSSVariables() { + + @Override + public Map getCSSVariables() { + return HashMapBuilder.put( + "color", "red" + ).build(); + } + + @Override + public String getScope() { + return ":root"; + } + + }); + + Mockito.when( + scopedCSSVariablesProvider1.getScopedCSSVariablesCollection( + Mockito.any(HttpServletRequest.class)) + ).thenReturn( + scopedCSSVariables1 + ); + + ScopedCSSVariablesProvider scopedCSSVariablesProvider2 = Mockito.mock( + ScopedCSSVariablesProvider.class); + + Collection scopedCSSVariables2 = Arrays.asList( + new ScopedCSSVariables() { + + @Override + public Map getCSSVariables() { + return HashMapBuilder.put( + "color", "green" + ).put( + "font", "Comic Sans" + ).build(); + } + + @Override + public String getScope() { + return "body"; + } + + }, + new ScopedCSSVariables() { + + @Override + public Map getCSSVariables() { + return HashMapBuilder.put( + "color", "yellow" + ).put( + "font", "Arial" + ).build(); + } + + @Override + public String getScope() { + return ":root"; + } + + }); + + Mockito.when( + scopedCSSVariablesProvider2.getScopedCSSVariablesCollection( + Mockito.any(HttpServletRequest.class)) + ).thenReturn( + scopedCSSVariables2 + ); + + scopedCSSVariablesTopHeadDynamicInclude.setScopedCSSVariablesProviders( + Arrays.asList( + scopedCSSVariablesProvider1, scopedCSSVariablesProvider2)); + + HttpServletRequest httpServletRequest = Mockito.mock( + HttpServletRequest.class); + + HttpServletResponse httpServletResponse = Mockito.mock( + HttpServletResponse.class); + + BufferCacheServletResponse bufferCacheServletResponse = + new BufferCacheServletResponse(httpServletResponse); + + scopedCSSVariablesTopHeadDynamicInclude.include( + httpServletRequest, bufferCacheServletResponse, + "/html/common/themes/top_head.jsp#post"); + + Assert.assertEquals( + _read("liferay_css_variables_2.html", true), + bufferCacheServletResponse.getString()); + } + + @Test + public void testRegister() { + ScopedCSSVariablesTopHeadDynamicInclude + scopedCSSVariablesTopHeadDynamicInclude = + new ScopedCSSVariablesTopHeadDynamicInclude(); + + DynamicInclude.DynamicIncludeRegistry dynamicIncludeRegistry = + Mockito.mock(DynamicInclude.DynamicIncludeRegistry.class); + + scopedCSSVariablesTopHeadDynamicInclude.register( + dynamicIncludeRegistry); + + Mockito.verify( + dynamicIncludeRegistry + ).register( + "/html/common/themes/top_head.jsp#post" + ); + } + + private static final String _read(String fileName, boolean addNewLine) { + Class clazz = + ScopedCSSVariablesTopHeadDynamicIncludeTest.class; + + try (InputStream inputStream = clazz.getResourceAsStream(fileName)) { + ByteArrayOutputStream byteArrayOutputStream = + new ByteArrayOutputStream(); + + StreamUtil.transfer(inputStream, byteArrayOutputStream); + + String content = byteArrayOutputStream.toString("UTF-8"); + + if (addNewLine) { + content += StringPool.NEW_LINE; + } + + return content; + } + catch (IOException ioException) { + throw new RuntimeException(ioException); + } + } + +} \ No newline at end of file diff --git a/modules/apps/frontend-css/frontend-css-variables-web/src/test/resources/com/liferay/frontend/css/variables/web/internal/servlet/taglib/liferay_css_variables_1.html b/modules/apps/frontend-css/frontend-css-variables-web/src/test/resources/com/liferay/frontend/css/variables/web/internal/servlet/taglib/liferay_css_variables_1.html new file mode 100644 index 00000000000000..b9aded52377a7c --- /dev/null +++ b/modules/apps/frontend-css/frontend-css-variables-web/src/test/resources/com/liferay/frontend/css/variables/web/internal/servlet/taglib/liferay_css_variables_1.html @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/modules/apps/frontend-css/frontend-css-variables-web/src/test/resources/com/liferay/frontend/css/variables/web/internal/servlet/taglib/liferay_css_variables_2.html b/modules/apps/frontend-css/frontend-css-variables-web/src/test/resources/com/liferay/frontend/css/variables/web/internal/servlet/taglib/liferay_css_variables_2.html new file mode 100644 index 00000000000000..2109f3f3e0dded --- /dev/null +++ b/modules/apps/frontend-css/frontend-css-variables-web/src/test/resources/com/liferay/frontend/css/variables/web/internal/servlet/taglib/liferay_css_variables_2.html @@ -0,0 +1,13 @@ + \ No newline at end of file