├── .gitignore ├── README.md ├── core ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── surajkamdi │ └── core │ ├── models │ ├── CustomHeadingModel.java │ ├── HierarchyPage.java │ └── impl │ │ ├── BaseComponentExporter.java │ │ ├── HierarchyComponentContextWrapper.java │ │ └── HierarchyPageImpl.java │ └── package-info.java ├── my-aem-react-app ├── .gitignore ├── README.md ├── clientlib.config.js ├── package-lock.json ├── package.json ├── pom.xml ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── .env.development │ ├── App.js │ ├── App.test.js │ ├── components │ │ ├── CustomHeading │ │ │ ├── CustomHeading.js │ │ │ └── CustomHeading.scss │ │ ├── MappedComponents.js │ │ └── page │ │ │ ├── Page.js │ │ │ └── Page.scss │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── serviceWorker.js │ └── utils │ │ └── RouteHelper.js ├── styleguide.config.js └── yarn.lock ├── pom.xml ├── ui.apps ├── .gitignore ├── pom.xml └── src │ └── main │ └── content │ ├── META-INF │ └── vault │ │ └── filter.xml │ └── jcr_root │ └── apps │ ├── .content.xml │ ├── my-aem-project │ ├── clientlibs │ │ ├── clientlib-base │ │ │ ├── .content.xml │ │ │ ├── css.txt │ │ │ └── js.txt │ │ ├── clientlib-site │ │ │ ├── .content.xml │ │ │ ├── css.txt │ │ │ └── less │ │ │ │ └── grid.less │ │ └── react-app │ │ │ ├── .content.xml │ │ │ ├── css.txt │ │ │ ├── css │ │ │ └── main.963feb16.chunk.css │ │ │ ├── js.txt │ │ │ └── js │ │ │ ├── 2.6550cedb.chunk.js │ │ │ ├── main.36b4d8cb.chunk.js │ │ │ └── runtime~main.2a9f8c0c.js │ ├── components │ │ ├── content │ │ │ └── custom-heading │ │ │ │ ├── .content.xml │ │ │ │ └── _cq_dialog │ │ │ │ └── .content.xml │ │ └── structure │ │ │ └── page │ │ │ ├── .content.xml │ │ │ ├── body.html │ │ │ ├── customfooterlibs.html │ │ │ └── customheaderlibs.html │ ├── config.author │ │ └── com.day.cq.wcm.mobile.core.impl.MobileEmulatorProvider-my-aem-project.xml │ ├── config │ │ └── org.apache.sling.commons.log.LogManager.factory.config-my-aem-project.xml │ ├── i18n │ │ ├── .content.xml │ │ └── fr.xml │ └── templates │ │ ├── page-content │ │ └── .content.xml │ │ └── page-home │ │ └── .content.xml │ └── sling │ └── servlet │ └── errorhandler │ ├── 404.html │ └── ResponseStatus.java └── ui.content ├── pom.xml └── src └── main └── content ├── META-INF └── vault │ └── filter.xml └── jcr_root ├── .content.xml ├── conf ├── .content.xml └── my-aem-project │ ├── .content.xml │ └── settings │ ├── .content.xml │ └── wcm │ ├── .content.xml │ ├── policies │ ├── .content.xml │ └── _rep_policy.xml │ ├── template-types │ ├── .content.xml │ ├── _rep_policy.xml │ └── empty-page │ │ ├── .content.xml │ │ ├── initial │ │ └── .content.xml │ │ ├── policies │ │ └── .content.xml │ │ ├── structure │ │ └── .content.xml │ │ ├── thumbnail.png │ │ └── thumbnail.png.dir │ │ ├── .content.xml │ │ └── _jcr_content │ │ └── _dam_thumbnails │ │ ├── _dam_thumbnail_300.png │ │ └── _dam_thumbnail_48.png │ └── templates │ ├── .content.xml │ ├── _rep_policy.xml │ └── content-page │ ├── .content.xml │ ├── initial │ └── .content.xml │ ├── policies │ └── .content.xml │ ├── structure │ └── .content.xml │ ├── thumbnail.png │ └── thumbnail.png.dir │ ├── .content.xml │ └── _jcr_content │ └── _dam_thumbnails │ ├── _dam_thumbnail_300.png │ └── _dam_thumbnail_48.png └── content ├── .content.xml └── my-aem-project ├── .content.xml └── blog-page └── .content.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/eclipse,java,maven 2 | 3 | ### Eclipse ### 4 | *.pydevproject 5 | .metadata 6 | .gradle 7 | bin/ 8 | tmp/ 9 | *.tmp 10 | *.bak 11 | *.swp 12 | *~.nib 13 | local.properties 14 | .settings/ 15 | .loadpath 16 | 17 | # Eclipse Core 18 | .project 19 | 20 | # External tool builders 21 | .externalToolBuilders/ 22 | 23 | # Locally stored "Eclipse launch configurations" 24 | *.launch 25 | 26 | # CDT-specific 27 | .cproject 28 | 29 | # JDT-specific (Eclipse Java Development Tools) 30 | .classpath 31 | 32 | # Java annotation processor (APT) 33 | .factorypath 34 | 35 | # PDT-specific 36 | .buildpath 37 | 38 | # sbteclipse plugin 39 | .target 40 | 41 | # TeXlipse plugin 42 | .texlipse 43 | 44 | # Visual Studio Code 45 | .vscode 46 | 47 | ### Java ### 48 | *.class 49 | 50 | # Mobile Tools for Java (J2ME) 51 | .mtj.tmp/ 52 | 53 | # Package Files # 54 | *.jar 55 | *.war 56 | *.ear 57 | 58 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 59 | hs_err_pid* 60 | 61 | 62 | ### Maven ### 63 | target/ 64 | pom.xml.tag 65 | pom.xml.releaseBackup 66 | pom.xml.versionsBackup 67 | pom.xml.next 68 | release.properties 69 | dependency-reduced-pom.xml 70 | buildNumber.properties 71 | .mvn/timing.properties 72 | 73 | ### Vault ### 74 | .vlt 75 | 76 | ### IntelliJ ### 77 | .idea/ 78 | *.iml 79 | 80 | ### MacOS ### 81 | .DS_Store 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Creating Your First Custom AEM Component Using React 2 | 3 | Visit My Profile: https://blogs.perficientdigital.com/author/skamdi/ 4 | 5 | Blog link: https://blogs.perficientdigital.com/2019/09/17/creating-your-first-custom-aem-component-using-react-part-1/ 6 | 7 | ### Example: 8 | ![Custom React Component in AEM by Suraj Kamdi](https://drive.google.com/uc?export=view&id=1Kd_UGKEbEBzHDyJkJj1TqRVM6-Tt_Hs6) 9 | 10 | ### AEM + project template 11 | 12 | This is a project template for AEM-based applications. 13 | 14 | ### Modules 15 | 16 | The main parts of the template are: 17 | 18 | * core: Java bundle containing all core functionality like OSGi services, listeners or schedulers, as well as component-related Java code such as servlets or request filters. 19 | * ui.apps: contains the /apps (and /etc) parts of the project, ie JS&CSS clientlibs, components, templates, runmode specific configs as well as Hobbes-tests 20 | * ui.content: contains sample content using the components from the ui.apps 21 | * my-aem-react-app: Contains sample react app 22 | 23 | ### How to build 24 | 25 | To build all the modules run in the project root directory the following command with Maven 3: 26 | 27 | `mvn clean install` 28 | 29 | If you have a running AEM instance you can build and package the whole project and deploy into AEM with 30 | 31 | `mvn clean install -PautoInstallPackage -Padobe-public` 32 | 33 | Or to deploy only the bundle to the author, run 34 | 35 | `mvn clean install -PautoInstallBundle -Padobe-public` 36 | 37 | To build react modules, then use 38 | 39 | `npm run build` 40 | 41 | ### Maven settings 42 | 43 | The project comes with the auto-public repository configured. To setup the repository in your Maven settings, refer to: 44 | 45 | http://helpx.adobe.com/experience-manager/kb/SetUpTheAdobeMavenRepository.html 46 | -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 4.0.0 20 | 21 | com.surajkamdi-aem-project 22 | my-aem-project 23 | 1.0-SNAPSHOT 24 | ../pom.xml 25 | 26 | my-aem-project.core 27 | bundle 28 | my-aem-project - Core 29 | Core bundle for my-aem-project 30 | 31 | 32 | 33 | org.apache.sling 34 | maven-sling-plugin 35 | 36 | 37 | org.apache.felix 38 | maven-bundle-plugin 39 | true 40 | 41 | 42 | generate-osgi-metadata-for-unittests 43 | 44 | manifest 45 | 46 | process-classes 47 | 48 | 49 | scr-metadata 50 | 51 | manifest 52 | 53 | 54 | true 55 | 56 | 57 | 58 | 59 | true 60 | 61 | 62 | 63 | javax.inject;version=0.0.0, 64 | javax.annotation;version=0.0.0, 65 | * 66 | 67 | 68 | com.surajkamdi.core 69 | 70 | <_dsannotations>* 71 | <_metatypeannotations>* 72 | <_plugin> 73 | 74 | org.apache.sling.bnd.models.ModelsScannerPlugin, 75 | 76 | org.apache.felix.scrplugin.bnd.SCRDescriptorBndPlugin;destdir=${project.build.outputDirectory} 77 | 78 | 79 | 80 | 81 | 82 | org.apache.felix 83 | org.apache.felix.scr.bnd 84 | 1.9.0 85 | 86 | 87 | org.apache.sling 88 | org.apache.sling.bnd.models 89 | 1.0.0 90 | 91 | 92 | 93 | 94 | org.apache.maven.plugins 95 | maven-surefire-plugin 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | org.osgi 104 | osgi.core 105 | 106 | 107 | org.osgi 108 | osgi.cmpn 109 | 110 | 111 | org.osgi 112 | osgi.annotation 113 | 114 | 115 | javax.inject 116 | javax.inject 117 | 118 | 119 | javax.annotation 120 | javax.annotation-api 121 | 122 | 123 | 124 | org.slf4j 125 | slf4j-api 126 | 127 | 128 | javax.jcr 129 | jcr 130 | 131 | 132 | javax.servlet 133 | javax.servlet-api 134 | 135 | 136 | com.adobe.aem 137 | uber-jar 138 | apis 139 | 140 | 141 | org.apache.sling 142 | org.apache.sling.models.api 143 | 144 | 145 | org.junit.jupiter 146 | junit-jupiter 147 | test 148 | 149 | 150 | org.mockito 151 | mockito-core 152 | test 153 | 154 | 155 | org.mockito 156 | mockito-junit-jupiter 157 | test 158 | 159 | 160 | junit-addons 161 | junit-addons 162 | 163 | 164 | io.wcm 165 | io.wcm.testing.aem-mock.junit5 166 | 167 | 168 | uk.org.lidalia 169 | slf4j-test 170 | 171 | 172 | com.google.code.findbugs 173 | jsr305 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /core/src/main/java/com/surajkamdi/core/models/CustomHeadingModel.java: -------------------------------------------------------------------------------- 1 | package com.surajkamdi.core.models; 2 | 3 | import com.adobe.cq.export.json.ComponentExporter; 4 | import com.adobe.cq.export.json.ExporterConstants; 5 | import javax.annotation.Nonnull; 6 | import org.apache.sling.api.SlingHttpServletRequest; 7 | import org.apache.sling.models.annotations.DefaultInjectionStrategy; 8 | import org.apache.sling.models.annotations.Exporter; 9 | import org.apache.sling.models.annotations.Model; 10 | import org.apache.sling.models.annotations.injectorspecific.ValueMapValue; 11 | 12 | @Model(adaptables = SlingHttpServletRequest.class, 13 | resourceType = CustomHeadingModel.RESOURCE_TYPE, 14 | adapters = {CustomHeadingModel.class, ComponentExporter.class}, 15 | defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) 16 | @Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION) 17 | public class CustomHeadingModel implements ComponentExporter { 18 | 19 | protected static final String RESOURCE_TYPE = "my-aem-project/components/content/custom-heading"; 20 | 21 | @ValueMapValue(name = "heading") 22 | private String heading; 23 | 24 | @ValueMapValue(name = "headingType") 25 | private String headingType; 26 | 27 | @ValueMapValue(name = "headingColor") 28 | private String headingColor; 29 | 30 | public String getHeading() { 31 | return heading; 32 | } 33 | 34 | public String getHeadingType() { 35 | return headingType; 36 | } 37 | 38 | public String getHeadingColor() { 39 | return headingColor; 40 | } 41 | 42 | @Nonnull 43 | @Override 44 | public String getExportedType() { 45 | return RESOURCE_TYPE; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/java/com/surajkamdi/core/models/HierarchyPage.java: -------------------------------------------------------------------------------- 1 | package com.surajkamdi.core.models; 2 | 3 | import com.adobe.cq.export.json.ContainerExporter; 4 | import com.adobe.cq.export.json.hierarchy.HierarchyNodeExporter; 5 | import com.fasterxml.jackson.annotation.JsonIgnore; 6 | import com.fasterxml.jackson.annotation.JsonProperty; 7 | 8 | public interface HierarchyPage extends HierarchyNodeExporter, ContainerExporter { 9 | 10 | /** 11 | * Title of the page. 12 | * 13 | * @return 14 | */ 15 | @JsonProperty("title") 16 | public String getTitle(); 17 | 18 | /** 19 | * URL to the root model of the App 20 | * 21 | * @return 22 | */ 23 | @JsonIgnore 24 | public String getRootUrl(); 25 | 26 | @JsonIgnore 27 | public HierarchyPage getRootModel(); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/com/surajkamdi/core/models/impl/BaseComponentExporter.java: -------------------------------------------------------------------------------- 1 | package com.surajkamdi.core.models.impl; 2 | 3 | import com.adobe.cq.export.json.ComponentExporter; 4 | import com.adobe.cq.export.json.ExporterConstants; 5 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 6 | import javax.annotation.Nonnull; 7 | import org.apache.sling.api.SlingHttpServletRequest; 8 | import org.apache.sling.api.resource.Resource; 9 | import org.apache.sling.api.resource.ResourceResolver; 10 | import org.apache.sling.models.annotations.*; 11 | import org.apache.sling.models.annotations.injectorspecific.Self; 12 | import org.apache.sling.models.annotations.injectorspecific.SlingObject; 13 | /** 14 | * This file focuses on making a Sling Model compatible with AEM Content Services (and thus SPA Editor), as this requires: 15 | * a) Implementing the ComponentExporter interface. 16 | * 17 | * Note that these is a sibling interface to ComponentExporter, com.adobe.cq.export.json.ContainerExporter, that is used for components that included other components (like the Layout Container). 18 | * 19 | * For more detailed examples of Sling Models and Sling Model Exporters, see this file's sibling sample files (SampleSlingModel.class and SampleSlingModelExporter.class). 20 | */ 21 | @Model( 22 | // This must adapt from a SlingHttpServletRequest, since this is invoked directly via a request, and not via a resource. 23 | // If can specify Resource.class as a second adaptable as needed 24 | adaptables = { SlingHttpServletRequest.class }, 25 | 26 | // This Model should have the specific Model class (SampleComponentExporter.class) 27 | // AS WELL AS the ComponentExporter.class. Its required that ComponentExporter.class to be set at an adapter 28 | // since this how the AEM Content Services JSON Exporter figures out which resources to serialize. 29 | adapters = { BaseComponentExporter.class, ComponentExporter.class }, 30 | 31 | // The resourceType is required if you want Sling to "naturally" expose this model as the exporter for a Resource. 32 | resourceType = BaseComponentExporter.RESOURCE_TYPE, 33 | 34 | defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL 35 | ) 36 | // name = the registered name of the exporter ( ExporterConstants.SLING_MODEL_EXPORTER_NAME => jackson ) 37 | // extensions = the extensions this exporter is registered to (ExporterConstants.SLING_MODEL_EXTENSION => json) 38 | // selector = defaults to "model", can override as needed; This is helpful if a single resource needs 2 different JSON renditions. 39 | // (ExporterConstants.SLING_MODEL_SELECTOR => model) 40 | @Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, 41 | selector = ExporterConstants.SLING_MODEL_SELECTOR, // The default is 'model', this is just reiterating this. 42 | extensions = ExporterConstants.SLING_MODEL_EXTENSION, 43 | options = { // options are optional... this just shows that it is possible... 44 | /** 45 | * Jackson options: 46 | * - Mapper Features: http://static.javadoc.io/com.fasterxml.jackson.core/jackson-databind/2.8.5/com/fasterxml/jackson/databind/MapperFeature.html 47 | * - Serialization Features: http://static.javadoc.io/com.fasterxml.jackson.core/jackson-databind/2.8.5/com/fasterxml/jackson/databind/SerializationFeature.html 48 | */ 49 | @ExporterOption(name = "MapperFeature.SORT_PROPERTIES_ALPHABETICALLY", value = "true"), 50 | @ExporterOption(name = "SerializationFeature.WRITE_DATES_AS_TIMESTAMPS", value="false") 51 | } 52 | ) 53 | 54 | 55 | // Mark as JSON Serializable as the Model's class (SampleComponentExporter.class) or interface if those are used. 56 | @JsonSerialize(as = BaseComponentExporter.class) 57 | 58 | // Make sure the Model implementation implements (or the Model interface extends) com.adobe.cq.export.json.ComponentExporter. 59 | public class BaseComponentExporter implements ComponentExporter { 60 | static final String RESOURCE_TYPE = "wknd-events/base/component-exporter"; 61 | 62 | @Self 63 | private SlingHttpServletRequest request; 64 | 65 | @Self 66 | private Resource resource; 67 | 68 | // Injection will occur over all Injectors based on Ranking; 69 | // Force an Injector using @Source(..) 70 | // If an Injector is not working; ensure you are using the latest version of Sling Models 71 | @SlingObject 72 | @Required 73 | private ResourceResolver resourceResolver; 74 | 75 | @Nonnull 76 | @Override 77 | public String getExportedType() { 78 | // This method is required by ComponentExporter and its value populates the `:type` key in the JSON object. 79 | // The resource value is ~always the ResourceType for this model (See @Model(..) above). 80 | return request.getResource().getResourceType(); 81 | } 82 | 83 | /** 84 | * Jackson Annotations on the method level are supported; ie. @JsonIgnore, @JsonProperty(..), etc. 85 | * 86 | * For Jackson Annotations: https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations 87 | */ 88 | public String getMessage() { 89 | return String.format("Hi! from %s! I don't have my own exporter class and am inheriting the default behavior from BaseComponentExporter.java", request.getResource().getResourceType()); 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /core/src/main/java/com/surajkamdi/core/models/impl/HierarchyComponentContextWrapper.java: -------------------------------------------------------------------------------- 1 | package com.surajkamdi.core.models.impl; 2 | 3 | import java.util.Set; 4 | 5 | import org.apache.sling.api.resource.Resource; 6 | 7 | import com.day.cq.wcm.api.Page; 8 | import com.day.cq.wcm.api.components.AnalyzeContext; 9 | import com.day.cq.wcm.api.components.Component; 10 | import com.day.cq.wcm.api.components.ComponentContext; 11 | import com.day.cq.wcm.api.components.EditContext; 12 | import com.day.cq.wcm.api.designer.Cell; 13 | 14 | public class HierarchyComponentContextWrapper implements ComponentContext { 15 | 16 | private ComponentContext wrappedComponentContext; 17 | private Page hierarchyPage; 18 | 19 | HierarchyComponentContextWrapper(ComponentContext wrappedComponentContext, Page hierarchyPage) { 20 | this.wrappedComponentContext = wrappedComponentContext; 21 | this.hierarchyPage = hierarchyPage; 22 | } 23 | 24 | @Override 25 | public ComponentContext getParent() { 26 | return this.wrappedComponentContext.getParent(); 27 | } 28 | 29 | @Override 30 | public ComponentContext getRoot() { 31 | return this.wrappedComponentContext.getRoot(); 32 | } 33 | 34 | @Override 35 | public boolean isRoot() { 36 | return this.wrappedComponentContext.isRoot(); 37 | } 38 | 39 | @Override 40 | public Resource getResource() { 41 | return this.wrappedComponentContext.getResource(); 42 | } 43 | 44 | @Override 45 | public Cell getCell() { 46 | return this.wrappedComponentContext.getCell(); 47 | } 48 | 49 | @Override 50 | public EditContext getEditContext() { 51 | return this.wrappedComponentContext.getEditContext(); 52 | } 53 | 54 | @Override 55 | public AnalyzeContext getAnalyzeContext() { 56 | return this.wrappedComponentContext.getAnalyzeContext(); 57 | } 58 | 59 | @Override 60 | public Component getComponent() { 61 | return this.wrappedComponentContext.getComponent(); 62 | } 63 | 64 | @Override 65 | public Page getPage() { 66 | return hierarchyPage; 67 | } 68 | 69 | @Override 70 | public Object getAttribute(String s) { 71 | return this.wrappedComponentContext.getAttribute(s); 72 | } 73 | 74 | @Override 75 | public Object setAttribute(String s, Object o) { 76 | return this.wrappedComponentContext.setAttribute(s, o); 77 | } 78 | 79 | @Override 80 | public Set getCssClassNames() { 81 | return this.wrappedComponentContext.getCssClassNames(); 82 | } 83 | 84 | @Override 85 | public boolean hasDecoration() { 86 | return this.wrappedComponentContext.hasDecoration(); 87 | } 88 | 89 | @Override 90 | public void setDecorate(boolean b) { 91 | this.wrappedComponentContext.setDecorate(b); 92 | } 93 | 94 | @Override 95 | public String getDecorationTagName() { 96 | return this.wrappedComponentContext.getDecorationTagName(); 97 | } 98 | 99 | @Override 100 | public void setDecorationTagName(String s) { 101 | this.wrappedComponentContext.setDecorationTagName(s); 102 | } 103 | 104 | @Override 105 | public String getDefaultDecorationTagName() { 106 | return this.wrappedComponentContext.getDefaultDecorationTagName(); 107 | } 108 | 109 | @Override 110 | public void setDefaultDecorationTagName(String s) { 111 | this.wrappedComponentContext.setDecorationTagName(s); 112 | } 113 | } -------------------------------------------------------------------------------- /core/src/main/java/com/surajkamdi/core/models/impl/HierarchyPageImpl.java: -------------------------------------------------------------------------------- 1 | package com.surajkamdi.core.models.impl; 2 | 3 | import javax.annotation.Nonnull; 4 | import javax.annotation.Nullable; 5 | import com.surajkamdi.core.models.HierarchyPage; 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import java.util.Iterator; 9 | import java.util.LinkedHashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.regex.Pattern; 13 | import javax.inject.Inject; 14 | import org.apache.commons.lang3.ArrayUtils; 15 | import org.apache.commons.lang3.StringUtils; 16 | import org.apache.sling.api.SlingHttpServletRequest; 17 | import org.apache.sling.api.request.RequestParameter; 18 | import org.apache.sling.api.resource.Resource; 19 | import org.apache.sling.api.resource.ResourceResolver; 20 | import org.apache.sling.api.resource.ValueMap; 21 | import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper; 22 | import org.apache.sling.models.annotations.Exporter; 23 | import org.apache.sling.models.annotations.Model; 24 | import org.apache.sling.models.annotations.injectorspecific.ScriptVariable; 25 | import org.apache.sling.models.annotations.injectorspecific.Self; 26 | import org.apache.sling.models.factory.ModelFactory; 27 | import com.adobe.cq.export.json.ComponentExporter; 28 | import com.adobe.cq.export.json.ContainerExporter; 29 | import com.adobe.cq.export.json.ExporterConstants; 30 | import com.adobe.cq.export.json.SlingModelFilter; 31 | import com.adobe.cq.export.json.hierarchy.type.HierarchyTypes; 32 | import com.day.cq.wcm.api.Page; 33 | import com.day.cq.wcm.api.PageManager; 34 | import com.day.cq.wcm.api.Template; 35 | import com.day.cq.wcm.api.TemplatedResource; 36 | import com.day.cq.wcm.api.components.ComponentContext; 37 | import com.day.cq.wcm.api.designer.Style; 38 | import com.day.cq.wcm.api.policies.ContentPolicy; 39 | import com.day.cq.wcm.api.policies.ContentPolicyManager; 40 | import com.fasterxml.jackson.annotation.JsonIgnore; 41 | 42 | @Model(adaptables = SlingHttpServletRequest.class, adapters = {HierarchyPage.class, ContainerExporter.class}, resourceType = HierarchyPageImpl.RESOURCE_TYPE) 43 | @Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION) 44 | public class HierarchyPageImpl implements HierarchyPage { 45 | 46 | /** 47 | * Resource type of associated with the current implementation 48 | */ 49 | protected static final String RESOURCE_TYPE = "my-aem-project/components/structure/page"; 50 | 51 | /** 52 | * Request attribute key of the component context 53 | */ 54 | private static final String COMPONENT_CONTEXT_ATTR = "com.day.cq.wcm.componentcontext"; 55 | 56 | /** 57 | * Request attribute key of the current page 58 | */ 59 | private static final String CURRENT_PAGE_ATTR = "currentPage"; 60 | 61 | /** 62 | * Request attribute key of the request page entry point 63 | */ 64 | private static final String HIERARCHY_ENTRY_POINT_PAGE_ATTR = "com.surajkamdi.core.models.impl.entryPointPage"; 65 | 66 | /** 67 | * Flags the child pages. Optionally available as a request attribute 68 | */ 69 | private static final String IS_CHILD_PAGE_ATTR = "com.surajkamdi.core.models.impl.isChildPage"; 70 | 71 | /** 72 | * Is the current model to be considered as a model root 73 | */ 74 | private static final String PR_IS_ROOT = "isRoot"; 75 | 76 | /** 77 | * Depth of the tree of pages 78 | */ 79 | private static final String STRUCTURE_DEPTH_PN = "structureDepth"; 80 | 81 | /** 82 | * List of Regexp patterns to filter the exported tree of pages 83 | */ 84 | private static final String STRUCTURE_PATTERNS_PN = "structurePatterns"; 85 | 86 | /** 87 | * URL extension specific to the Sling Model exporter 88 | */ 89 | private static final String URL_MODEL_EXTENSION = ".model.json"; 90 | 91 | @Self 92 | private SlingHttpServletRequest request; 93 | 94 | @Inject 95 | private ModelFactory modelFactory; 96 | 97 | @Inject 98 | private PageManager pageManager; 99 | 100 | @ScriptVariable 101 | @JsonIgnore 102 | private Resource resource; 103 | 104 | @Inject 105 | private SlingModelFilter slingModelFilter; 106 | 107 | private Map childPages = null; 108 | 109 | private Map childModels = null; 110 | 111 | @ScriptVariable 112 | @JsonIgnore 113 | protected ResourceResolver resolver; 114 | 115 | @ScriptVariable 116 | protected com.day.cq.wcm.api.Page currentPage; 117 | 118 | @ScriptVariable 119 | protected Style currentStyle; 120 | 121 | @Nullable 122 | @Override 123 | public String getExportedHierarchyType() { 124 | return HierarchyTypes.PAGE; 125 | } 126 | 127 | @Nonnull 128 | @Override 129 | public Map getExportedChildren() { 130 | if (childPages == null) { 131 | childPages = getChildPageModels(request, HierarchyPage.class); 132 | } 133 | 134 | return childPages; 135 | } 136 | 137 | @Nonnull 138 | @Override 139 | public Map getExportedItems() { 140 | if (childModels == null) { 141 | childModels = getItemModels(request, ComponentExporter.class); 142 | } 143 | 144 | return childModels; 145 | } 146 | 147 | @Nonnull 148 | @Override 149 | public String[] getExportedItemsOrder() { 150 | Map models = getExportedItems(); 151 | 152 | if (models.isEmpty()) { 153 | return ArrayUtils.EMPTY_STRING_ARRAY; 154 | } 155 | 156 | return models.keySet().toArray(ArrayUtils.EMPTY_STRING_ARRAY); 157 | } 158 | 159 | @Nonnull 160 | @Override 161 | public String getExportedType() throws IllegalStateException { 162 | Resource contentResource = currentPage.getContentResource(); 163 | 164 | if (contentResource == null) { 165 | throw new IllegalStateException("No page content found: " + currentPage.getPath()); 166 | } 167 | 168 | return contentResource.getResourceType(); 169 | } 170 | 171 | @Nonnull 172 | private SlingHttpServletRequest getHierarchyServletRequest(@Nonnull SlingHttpServletRequest request, @Nonnull Page hierarchyPage) { 173 | SlingHttpServletRequest wrapper = new SlingHttpServletRequestWrapper(request); 174 | 175 | ComponentContext componentContext = (ComponentContext) request.getAttribute(COMPONENT_CONTEXT_ATTR); 176 | 177 | // When traversing child pages the currentPage must be updated 178 | wrapper.setAttribute(COMPONENT_CONTEXT_ATTR, new HierarchyComponentContextWrapper(componentContext, hierarchyPage)); 179 | wrapper.setAttribute(CURRENT_PAGE_ATTR, hierarchyPage); 180 | 181 | return wrapper; 182 | } 183 | 184 | /** 185 | * Returns a map (resource name => Sling Model class) of the given resource children's Sling Models that can be adapted to {@link T}. 186 | * 187 | * @param slingRequest The current request. 188 | * @param modelClass The Sling Model class to be adapted to. 189 | * @return Returns a map (resource name => Sling Model class) of the given resource children's Sling Models that can be adapted to {@link T}. 190 | */ 191 | @Nonnull 192 | private Map getItemModels(@Nonnull SlingHttpServletRequest slingRequest, 193 | @Nonnull Class modelClass) { 194 | Map itemWrappers = new LinkedHashMap<>(); 195 | 196 | Iterable iterable = slingModelFilter.filterChildResources(request.getResource().getChildren()); 197 | 198 | if (iterable == null) { 199 | return itemWrappers; 200 | } 201 | 202 | for (final Resource child : iterable) { 203 | itemWrappers.put(child.getName(), modelFactory.getModelFromWrappedRequest(slingRequest, child, modelClass)); 204 | } 205 | 206 | return itemWrappers; 207 | } 208 | 209 | /** 210 | * Returns a flat list of all the child pages of a given page 211 | * 212 | * @param page - Page from which to extract child pages 213 | * @param slingRequest - Request 214 | * @param structurePatterns - Patterns to filter child pages 215 | * @param depth - Depth of the traversal 216 | * @return 217 | */ 218 | @Nonnull 219 | private List getChildPageRecursive(Page page, SlingHttpServletRequest slingRequest, List structurePatterns, int depth) { 220 | // By default the value is 0 meaning we do not expose child pages 221 | // If the value is set as a positive number it is going to be exposed until the counter is brought down to 0 222 | // If the value is set to a negative value all the child pages will be exposed (full traversal tree - aka infinity) 223 | // Child pages do not expose their respective child pages 224 | if (page == null || depth == 0 || Boolean.TRUE.equals(slingRequest.getAttribute(IS_CHILD_PAGE_ATTR))) { 225 | return Collections.emptyList(); 226 | } 227 | 228 | List pages = new ArrayList<>(); 229 | Iterator childPagesIterator = page.listChildren(); 230 | 231 | if (childPagesIterator == null || !childPagesIterator.hasNext()) { 232 | return Collections.emptyList(); 233 | } 234 | 235 | // we are about to explore one lower level down the tree 236 | depth--; 237 | 238 | boolean noPageFilters = structurePatterns.isEmpty(); 239 | 240 | while (childPagesIterator.hasNext()) { 241 | Page childPage = childPagesIterator.next(); 242 | boolean found = noPageFilters; 243 | 244 | for (Pattern pageFilterPattern : structurePatterns) { 245 | if (pageFilterPattern.matcher(childPage.getPath()).find()) { 246 | found = true; 247 | break; 248 | } 249 | } 250 | 251 | if (!found) { 252 | continue; 253 | } 254 | 255 | pages.add(childPage); 256 | 257 | pages.addAll(getChildPageRecursive(childPage, slingRequest, structurePatterns, depth)); 258 | } 259 | 260 | return pages; 261 | } 262 | 263 | /** 264 | * Optionally add a child page that is the entry point of a site model request when this child is not added by the root structure configuration 265 | * 266 | * @param slingRequest The current servlet request 267 | * @param childPages List of child pages 268 | */ 269 | private void addAsynchronousChildPage(@Nonnull SlingHttpServletRequest slingRequest, @Nonnull List childPages) { 270 | // Child pages are only added to the root page 271 | if (Boolean.TRUE.equals(slingRequest.getAttribute(IS_CHILD_PAGE_ATTR))) { 272 | return; 273 | } 274 | 275 | // Eventually add a child page that is not part page root children of the but is the entry point of the request 276 | Page entryPointPage = (Page) slingRequest.getAttribute(HIERARCHY_ENTRY_POINT_PAGE_ATTR); 277 | 278 | if (entryPointPage == null) { 279 | return; 280 | } 281 | 282 | // Filter the root page 283 | if (entryPointPage.getPath().equals(currentPage.getPath())) { 284 | return; 285 | } 286 | 287 | // Filter duplicates 288 | if (childPages.contains(entryPointPage)) { 289 | return; 290 | } 291 | 292 | childPages.add(entryPointPage); 293 | } 294 | 295 | @Nonnull 296 | private Map getChildPageModels(@Nonnull SlingHttpServletRequest slingRequest, 297 | @Nonnull Class modelClass) { 298 | 299 | int pageTreeTraversalDepth = getPageTreeTraversalDepth(); 300 | 301 | List pageFilterPatterns = getStructurePatterns(slingRequest); 302 | 303 | // Setting the child page to true to prevent child pages to expose their own child pages 304 | SlingHttpServletRequest slingRequestWrapper = new SlingHttpServletRequestWrapper(slingRequest); 305 | 306 | Map itemWrappers = new LinkedHashMap<>(); 307 | 308 | List childPages = getChildPageRecursive(currentPage, slingRequestWrapper, pageFilterPatterns, pageTreeTraversalDepth); 309 | 310 | addAsynchronousChildPage(slingRequest, childPages); 311 | 312 | // Add a flag to inform the model of the child pages that they are not the root of the tree 313 | slingRequestWrapper.setAttribute(IS_CHILD_PAGE_ATTR, true); 314 | 315 | for (Page childPage: childPages) { 316 | Resource childPageContentResource = childPage.getContentResource(); 317 | 318 | if (childPageContentResource == null) { 319 | continue; 320 | } 321 | 322 | // Try to pass the templated content resource 323 | TemplatedResource templatedResource = childPageContentResource.adaptTo(TemplatedResource.class); 324 | 325 | if (templatedResource != null) { 326 | childPageContentResource = templatedResource; 327 | } 328 | 329 | // TODO: CQ-4245895 - [Content Service][Editable SPA] routing and export based on page URL - use URL instead of path 330 | itemWrappers.put(childPage.getPath(), modelFactory.getModelFromWrappedRequest(getHierarchyServletRequest(slingRequestWrapper, childPage), childPageContentResource, modelClass)); 331 | } 332 | 333 | return itemWrappers; 334 | } 335 | 336 | /** 337 | * Returns the page structure patterns to filter the child pages to be exported. 338 | * The patterns can either be stored on the template policy of the page or provided as a request parameter 339 | * 340 | * @param slingRequest - Request 341 | * @return 342 | */ 343 | @Nonnull 344 | private List getStructurePatterns(@Nonnull SlingHttpServletRequest slingRequest) { 345 | RequestParameter pageFilterParameter = slingRequest.getRequestParameter(STRUCTURE_PATTERNS_PN.toLowerCase()); 346 | 347 | String rawPageFilters = null; 348 | 349 | if (pageFilterParameter != null) { 350 | rawPageFilters = pageFilterParameter.getString(); 351 | } 352 | 353 | if (currentStyle != null && StringUtils.isBlank(rawPageFilters)) { 354 | rawPageFilters = currentStyle.get(STRUCTURE_PATTERNS_PN, String.class); 355 | } 356 | 357 | if (StringUtils.isBlank(rawPageFilters)) { 358 | return Collections.emptyList(); 359 | } 360 | 361 | String[] pageFilters = rawPageFilters.split(","); 362 | 363 | List pageFilterPatterns = new ArrayList<>(); 364 | for (String pageFilter : pageFilters) { 365 | pageFilterPatterns.add(Pattern.compile(pageFilter)); 366 | } 367 | 368 | return pageFilterPatterns; 369 | } 370 | 371 | /** 372 | * Returns the first numeric selector. The default value is 0 373 | * 374 | * @return 375 | */ 376 | private int getPageTreeTraversalDepth() { 377 | Integer pageTreeTraversalDepth = null; 378 | 379 | if (currentStyle != null) { 380 | pageTreeTraversalDepth = currentStyle.get(STRUCTURE_DEPTH_PN, Integer.class); 381 | } 382 | 383 | if (pageTreeTraversalDepth == null) { 384 | return 0; 385 | } 386 | 387 | return pageTreeTraversalDepth; 388 | } 389 | 390 | @Nonnull 391 | @Override 392 | public String getExportedPath() { 393 | return currentPage.getPath(); 394 | } 395 | 396 | /** 397 | * TODO Replace with the core component Utils.getURL function 398 | * 399 | * https://git.corp.adobe.com/CQ/aem-core-wcm-components/blob/development/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/Utils.java#L60 400 | * 401 | * @param request 402 | * @param page 403 | * @return 404 | */ 405 | private String getURL(@Nonnull SlingHttpServletRequest request, @Nonnull Page page) { 406 | String vanityURL = page.getVanityUrl(); 407 | return StringUtils.isEmpty(vanityURL) ? request.getContextPath() + page.getPath() + ".html" : request.getContextPath() + vanityURL; 408 | } 409 | 410 | /** 411 | * Returns a model URL for the given page 412 | * 413 | * @param request 414 | * @param page 415 | * @return 416 | */ 417 | private String getModelUrl(@Nonnull SlingHttpServletRequest request, @Nonnull Page page) { 418 | String url = getURL(request, page); 419 | 420 | if (StringUtils.isBlank(url)) { 421 | return null; 422 | } 423 | 424 | int dotIndex = url.indexOf("."); 425 | 426 | if (dotIndex < 0) { 427 | dotIndex = url.length(); 428 | } 429 | 430 | return url.substring(0, dotIndex) + URL_MODEL_EXTENSION; 431 | } 432 | 433 | /** 434 | * @return Returns the root model of the given page 435 | */ 436 | public HierarchyPage getRootModel() { 437 | if (currentStyle != null && currentStyle.containsKey(PR_IS_ROOT)) { 438 | return this; 439 | } 440 | 441 | Page rootPage = getRootPage(); 442 | 443 | if (rootPage == null) { 444 | return null; 445 | } 446 | 447 | request.setAttribute(HIERARCHY_ENTRY_POINT_PAGE_ATTR, currentPage); 448 | 449 | return modelFactory.getModelFromWrappedRequest(getHierarchyServletRequest(request, rootPage), rootPage.getContentResource(), this.getClass()); 450 | } 451 | 452 | /** 453 | * @return Returns the root (app) page the current page is part of 454 | */ 455 | private Page getRootPage() { 456 | Page page = currentPage; 457 | boolean isRootModel = false; 458 | 459 | ContentPolicyManager contentPolicyManager = resource.getResourceResolver().adaptTo(ContentPolicyManager.class); 460 | 461 | do { 462 | page = page.getParent(); 463 | 464 | if (page == null) { 465 | continue; 466 | } 467 | 468 | Template template = page.getTemplate(); 469 | 470 | if (template == null || !template.hasStructureSupport()) { 471 | continue; 472 | } 473 | 474 | Resource pageContentResource = page.getContentResource(); 475 | 476 | if (pageContentResource == null) { 477 | continue; 478 | } 479 | 480 | ContentPolicy pageContentPolicy = contentPolicyManager.getPolicy(pageContentResource); 481 | 482 | if (pageContentPolicy == null) { 483 | continue; 484 | } 485 | 486 | ValueMap properties = pageContentPolicy.getProperties(); 487 | 488 | if (properties == null) { 489 | continue; 490 | } 491 | 492 | isRootModel = properties.containsKey(PR_IS_ROOT); 493 | 494 | } while(page != null && !isRootModel); 495 | 496 | return page; 497 | } 498 | 499 | @Nullable 500 | @Override 501 | public String getRootUrl() { 502 | if (currentStyle != null && currentStyle.containsKey(PR_IS_ROOT)) { 503 | return getModelUrl(request, currentPage); 504 | } 505 | 506 | Page page = getRootPage(); 507 | 508 | if (page != null) { 509 | return getModelUrl(request, page); 510 | } 511 | 512 | return null; 513 | } 514 | 515 | @Nullable 516 | @Override 517 | public String getTitle() { 518 | if (!StringUtils.isBlank(currentPage.getNavigationTitle())) { 519 | return currentPage.getNavigationTitle(); 520 | } 521 | 522 | if (!StringUtils.isBlank(currentPage.getTitle())) { 523 | return currentPage.getTitle(); 524 | } 525 | 526 | return currentPage.getPageTitle(); 527 | } 528 | 529 | } 530 | -------------------------------------------------------------------------------- /core/src/main/java/com/surajkamdi/core/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Adobe Systems Incorporated 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | @Version("1.0") 17 | package com.surajkamdi.core; 18 | 19 | import org.osgi.annotation.versioning.Version; -------------------------------------------------------------------------------- /my-aem-react-app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /node 6 | 7 | # testing 8 | /coverage 9 | 10 | # production 11 | /build 12 | 13 | # misc 14 | .DS_Store 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | -------------------------------------------------------------------------------- /my-aem-react-app/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /my-aem-react-app/clientlib.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // default working directory 3 | context: __dirname, 4 | 5 | // path to the clientlib root folder 6 | clientLibRoot: "./../ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs", 7 | 8 | libs: { 9 | name: "react-app", 10 | allowProxy: true, 11 | categories: ["com.surajkamdi-aem-project.react"], 12 | serializationFormat: "xml", 13 | jsProcessor: ["min:gcc"], 14 | dependencies:["my-aem-project.grid"], 15 | assets: { 16 | js: [ 17 | "build/static/**/*.js" 18 | ], 19 | css: [ 20 | "build/static/**/*.css" 21 | ] 22 | } 23 | } 24 | }; -------------------------------------------------------------------------------- /my-aem-react-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-aem-react-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.9.0", 7 | "react-dom": "^16.9.0", 8 | "react-scripts": "3.1.1", 9 | "@adobe/cq-react-editable-components": "^1.1.0", 10 | "@adobe/cq-spa-component-mapping": "^1.0.3", 11 | "@adobe/cq-spa-page-model-manager": "^1.0.7", 12 | "@fortawesome/fontawesome-svg-core": "^1.2.17", 13 | "@fortawesome/free-solid-svg-icons": "^5.8.1", 14 | "@fortawesome/react-fontawesome": "^0.1.4", 15 | "i": "^0.3.6", 16 | "node-sass": "^4.11.0", 17 | "npm": "^6.14.6", 18 | "react-fast-compare": "^2.0.4", 19 | "react-live-clock": "^3.1.0", 20 | "react-router": "^5.0.0", 21 | "react-router-dom": "^5.0.0", 22 | "react-styleguidist": "^9.0.6" 23 | }, 24 | "scripts": { 25 | "start": "react-scripts start", 26 | "build": "react-scripts build && clientlib --verbose", 27 | "test": "react-scripts test", 28 | "eject": "react-scripts eject", 29 | "styleguide": "styleguidist server", 30 | "styleguide:build": "styleguidist build" 31 | }, 32 | "eslintConfig": { 33 | "extends": "react-app" 34 | }, 35 | "proxy": "http://localhost:4502", 36 | "browserslist": { 37 | "production": [ 38 | ">0.2%", 39 | "not dead", 40 | "not op_mini all" 41 | ], 42 | "development": [ 43 | "last 1 chrome version", 44 | "last 1 firefox version", 45 | "last 1 safari version" 46 | ] 47 | }, 48 | "devDependencies": { 49 | "aem-clientlib-generator": "^1.4.4", 50 | "ajv": "^6.10.0", 51 | "clone": "^2.1.2", 52 | "typescript": "^3.4.2" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /my-aem-react-app/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | 7 | 8 | 9 | com.surajkamdi-aem-project 10 | my-aem-project 11 | 1.0-SNAPSHOT 12 | ../pom.xml 13 | 14 | 15 | 16 | 17 | 18 | my-aem-project.react 19 | pom 20 | my-aem-project - React App 21 | UI React application code for my-aem-project (React App) 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | com.github.eirslett 31 | frontend-maven-plugin 32 | ${frontend-maven-plugin.version} 33 | 34 | 35 | 36 | 37 | install node and npm 38 | 39 | install-node-and-npm 40 | 41 | 42 | ${node.version} 43 | ${npm.version} 44 | 45 | 46 | 47 | 48 | npm install 49 | 50 | npm 51 | 52 | 53 | 54 | install 55 | 56 | 57 | 58 | 59 | npm run build 60 | 61 | npm 62 | 63 | 64 | run build 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /my-aem-react-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerficientDigital/my-aem-project/ab12ce3576ec3eac4206fefd35fb794fbde96b3f/my-aem-react-app/public/favicon.ico -------------------------------------------------------------------------------- /my-aem-react-app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /my-aem-react-app/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerficientDigital/my-aem-project/ab12ce3576ec3eac4206fefd35fb794fbde96b3f/my-aem-react-app/public/logo192.png -------------------------------------------------------------------------------- /my-aem-react-app/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerficientDigital/my-aem-project/ab12ce3576ec3eac4206fefd35fb794fbde96b3f/my-aem-react-app/public/logo512.png -------------------------------------------------------------------------------- /my-aem-react-app/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /my-aem-react-app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /my-aem-react-app/src/.env.development: -------------------------------------------------------------------------------- 1 | #Request the JSON from AEM at http://localhost:4502 2 | REACT_APP_PAGE_MODEL_PATH=/content/my-aem-project/blog-page.model.json 3 | -------------------------------------------------------------------------------- /my-aem-react-app/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Page, withModel, EditorContext, Utils } from '@adobe/cq-react-editable-components' 3 | 4 | class App extends Page { 5 | 6 | render() { 7 | return ( 8 |
9 | { this.childComponents } 10 | { this.childPages } 11 |
12 | ); 13 | } 14 | } 15 | 16 | export default withModel(App); -------------------------------------------------------------------------------- /my-aem-react-app/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /my-aem-react-app/src/components/CustomHeading/CustomHeading.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {MapTo} from '@adobe/cq-react-editable-components'; 3 | require('./CustomHeading.scss'); 4 | 5 | const CustomHeadingEditConfig = { 6 | emptyLabel: 'Custom Heading', 7 | isEmpty: function(props) { 8 | return !props.heading || props.heading.trim().length < 1; 9 | } 10 | }; 11 | 12 | export default class CustomHeading extends Component { 13 | render() { 14 | let headingElement = this.props.headingType ? React.createElement(this.props.headingType, {className: this.props.headingColor},this.props.heading) : ''; 15 | return (
{headingElement}
); 16 | } 17 | } 18 | MapTo('my-aem-project/components/content/custom-heading')(CustomHeading, CustomHeadingEditConfig); -------------------------------------------------------------------------------- /my-aem-react-app/src/components/CustomHeading/CustomHeading.scss: -------------------------------------------------------------------------------- 1 | .heading{ 2 | .red-color{ 3 | color: #fc0b03; 4 | } 5 | .green-color{ 6 | color : #39fc03; 7 | } 8 | .blue-color{ 9 | color : #2403fc; 10 | } 11 | } -------------------------------------------------------------------------------- /my-aem-react-app/src/components/MappedComponents.js: -------------------------------------------------------------------------------- 1 | /* 2 | Dedicated file to include all React components that map to an AEM component 3 | */ 4 | 5 | require('./page/Page'); 6 | require('./CustomHeading/CustomHeading'); -------------------------------------------------------------------------------- /my-aem-react-app/src/components/page/Page.js: -------------------------------------------------------------------------------- 1 | import {Page, MapTo, withComponentMappingContext } from "@adobe/cq-react-editable-components"; 2 | import {withRoute} from '../../utils/RouteHelper'; 3 | require('./Page.scss'); 4 | class AemPage extends Page { 5 | 6 | get containerProps() { 7 | let attrs = super.containerProps; 8 | attrs.className = (attrs.className || '') + ' react-aem-page ' + (this.props.cssClassNames || ''); 9 | return attrs 10 | } 11 | } 12 | 13 | MapTo('my-aem-project/components/structure/page')(withComponentMappingContext(withRoute(AemPage))); 14 | -------------------------------------------------------------------------------- /my-aem-react-app/src/components/page/Page.scss: -------------------------------------------------------------------------------- 1 | .react-aem-page { 2 | margin: 0 auto; 3 | padding: 0; 4 | } 5 | -------------------------------------------------------------------------------- /my-aem-react-app/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /my-aem-react-app/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { ModelManager, Constants } from '@adobe/cq-spa-page-model-manager'; 4 | import App from './App'; 5 | import "./components/MappedComponents"; 6 | import './index.css'; 7 | 8 | function render(model) { 9 | ReactDOM.render(( 10 | ), document.getElementById('root')); 12 | } 13 | 14 | ModelManager.initialize({ path: process.env.AEM_REACT_APP_PAGE_MODEL_PATH }).then(render); -------------------------------------------------------------------------------- /my-aem-react-app/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /my-aem-react-app/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /my-aem-react-app/src/utils/RouteHelper.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {Route} from 'react-router-dom'; 3 | import { withRouter } from 'react-router'; 4 | 5 | /** 6 | * Helper that facilitate the use of the {@link Route} component 7 | */ 8 | 9 | /** 10 | * Returns a composite component where a {@link Route} component wraps the provided component 11 | * 12 | * @param {React.Component} WrappedComponent - React component to be wrapped 13 | * @param {string} [extension=html] - extension used to identify a route amongst the tree of resource URLs 14 | * @returns {CompositeRoute} 15 | */ 16 | export const withRoute = (WrappedComponent, extension) => { 17 | return class CompositeRoute extends Component { 18 | render() { 19 | let routePath = this.props.cqPath; 20 | if (!routePath) { 21 | return ; 22 | } 23 | 24 | extension = extension || 'html'; 25 | 26 | // Context path + route path + extension 27 | return { 28 | return ; 29 | } } /> 30 | } 31 | } 32 | }; 33 | 34 | /** 35 | * ScrollToTop component will scroll the window on every navigation. 36 | * wrapped in in `withRouter` to have access to router's props. 37 | */ 38 | class ScrollToTop extends Component { 39 | componentDidUpdate(prevProps) { 40 | if (this.props.location !== prevProps.location) { 41 | window.scrollTo(0, 0) 42 | } 43 | } 44 | render() { 45 | return this.props.children 46 | } 47 | } 48 | export default withRouter(ScrollToTop); -------------------------------------------------------------------------------- /my-aem-react-app/styleguide.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | module.exports = { 3 | components: 'src/components/**/[A-Z]*.js', 4 | assetsDir: 'public/images', 5 | require: [ 6 | path.join(__dirname, 'src/index.scss') 7 | ], 8 | ignore: ['src/components/**/Page.js','src/components/**/MappedComponents.js','**/__tests__/**', '**/*.test.{js,jsx,ts,tsx}', '**/*.spec.{js,jsx,ts,tsx}', '**/*.d.ts'] 9 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 4.0.0 21 | com.surajkamdi-aem-project 22 | my-aem-project 23 | pom 24 | 1.0-SNAPSHOT 25 | my-aem-project 26 | 27 | 28 | core 29 | ui.apps 30 | ui.content 31 | my-aem-react-app 32 | 33 | 34 | 35 | localhost 36 | 4502 37 | localhost 38 | 4503 39 | admin 40 | admin 41 | admin 42 | admin 43 | 2.4.0 44 | 45 | 46 | 1.6 47 | v10.16.0 48 | 6.11.3 49 | 50 | UTF-8 51 | UTF-8 52 | 53 | 54 | 55 | 56 | 57 | 58 | org.apache.maven.plugins 59 | maven-release-plugin 60 | 2.5.3 61 | 62 | [maven-scm] : 63 | clean install 64 | install 65 | release 66 | 67 | 68 | 69 | 70 | org.apache.maven.plugins 71 | maven-source-plugin 72 | 3.0.1 73 | true 74 | 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-jar-plugin 79 | 3.0.2 80 | 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-enforcer-plugin 85 | 86 | 87 | enforce-maven 88 | 89 | enforce 90 | 91 | 92 | 93 | 94 | [3.3.9,) 95 | 96 | 97 | Project must be compiled 98 | with Java 8 or higher 99 | 1.8.0 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | org.apache.maven.plugins 109 | maven-compiler-plugin 110 | 111 | 1.8 112 | 1.8 113 | 114 | 115 | 116 | 117 | org.apache.maven.plugins 118 | maven-idea-plugin 119 | 2.2.1 120 | 121 | 1.8 122 | true 123 | true 124 | 125 | 126 | 127 | 128 | org.apache.maven.plugins 129 | maven-eclipse-plugin 130 | 2.10 131 | 132 | true 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | org.apache.maven.plugins 141 | maven-clean-plugin 142 | 3.0.0 143 | 144 | 145 | 146 | org.apache.maven.plugins 147 | maven-resources-plugin 148 | 3.0.2 149 | 150 | 151 | 152 | org.apache.maven.plugins 153 | maven-compiler-plugin 154 | 3.6.1 155 | 156 | 157 | 158 | org.apache.maven.plugins 159 | maven-install-plugin 160 | 2.5.2 161 | 162 | 163 | 164 | org.apache.maven.plugins 165 | maven-surefire-plugin 166 | 2.22.1 167 | 168 | false 169 | 170 | 171 | 172 | 173 | org.apache.maven.plugins 174 | maven-failsafe-plugin 175 | 2.22.1 176 | 177 | 178 | 179 | org.apache.maven.plugins 180 | maven-deploy-plugin 181 | 2.8.2 182 | 183 | 184 | 185 | org.apache.sling 186 | maven-sling-plugin 187 | 2.2.0 188 | 189 | http://${aem.host}:${aem.port}/system/console 190 | WebConsole 191 | 192 | 193 | 194 | 195 | org.apache.sling 196 | htl-maven-plugin 197 | 1.0.6 198 | 199 | true 200 | 201 | 202 | 203 | 204 | validate 205 | 206 | 207 | 208 | 209 | 210 | 211 | org.apache.jackrabbit 212 | filevault-package-maven-plugin 213 | 1.0.3 214 | 215 | src/main/content/META-INF/vault/filter.xml 216 | 217 | 218 | 219 | 220 | com.day.jcr.vault 221 | content-package-maven-plugin 222 | 1.0.2 223 | 224 | http://${aem.host}:${aem.port}/crx/packmgr/service.jsp 225 | true 226 | ${vault.user} 227 | ${vault.password} 228 | 229 | 230 | 231 | 232 | org.apache.felix 233 | maven-bundle-plugin 234 | 4.1.0 235 | true 236 | 237 | 238 | 239 | org.apache.maven.plugins 240 | maven-enforcer-plugin 241 | 1.4.1 242 | 243 | 244 | 245 | org.apache.maven.plugins 246 | maven-dependency-plugin 247 | 3.0.0 248 | 249 | 250 | 251 | org.codehaus.mojo 252 | build-helper-maven-plugin 253 | 3.0.0 254 | 255 | 257 | 258 | org.eclipse.m2e 259 | lifecycle-mapping 260 | 1.0.0 261 | 262 | 263 | 264 | 265 | 266 | org.apache.maven.plugins 267 | maven-enforcer-plugin 268 | [1.0.0,) 269 | 270 | enforce 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | org.apache.maven.plugins 281 | 282 | 283 | maven-dependency-plugin 284 | 285 | 286 | [2.2,) 287 | 288 | 289 | copy-dependencies 290 | unpack 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | org.codehaus.mojo 301 | 302 | 303 | build-helper-maven-plugin 304 | 305 | 306 | [1.5,) 307 | 308 | 309 | 310 | reserve-network-port 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | adobe-public 332 | 333 | 334 | true 335 | 336 | 337 | 338 | adobe-public-releases 339 | Adobe Public Releases 340 | https://repo.adobe.com/nexus/content/groups/public 341 | 342 | 343 | 344 | 345 | adobe-public-releases 346 | Adobe Public Repository 347 | https://repo.adobe.com/nexus/content/groups/public 348 | 349 | true 350 | never 351 | 352 | 353 | false 354 | 355 | 356 | 357 | 358 | 359 | 360 | adobe-public-releases 361 | Adobe Public Repository 362 | https://repo.adobe.com/nexus/content/groups/public 363 | 364 | true 365 | never 366 | 367 | 368 | false 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | autoInstallBundle 377 | 386 | 387 | false 388 | 389 | 390 | 391 | 392 | 393 | org.apache.sling 394 | maven-sling-plugin 395 | 396 | 397 | install-bundle 398 | 399 | install 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | autoInstallPackage 411 | 412 | false 413 | 414 | 415 | 416 | 417 | 418 | org.apache.jackrabbit 419 | filevault-package-maven-plugin 420 | 421 | 422 | create-package 423 | 424 | package 425 | 426 | 427 | 428 | 429 | 430 | com.day.jcr.vault 431 | content-package-maven-plugin 432 | 433 | 434 | install-package 435 | 436 | install 437 | 438 | 439 | http://${aem.host}:${aem.port}/crx/packmgr/service.jsp 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | autoInstallPackagePublish 451 | 452 | false 453 | 454 | 455 | 456 | 457 | 458 | org.apache.jackrabbit 459 | filevault-package-maven-plugin 460 | 461 | 462 | create-package 463 | 464 | package 465 | 466 | 467 | 468 | 469 | 470 | com.day.jcr.vault 471 | content-package-maven-plugin 472 | 473 | 474 | install-package-publish 475 | 476 | install 477 | 478 | 479 | http://${aem.publish.host}:${aem.publish.port}/crx/packmgr/service.jsp 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | org.osgi 500 | osgi.core 501 | 6.0.0 502 | provided 503 | 504 | 505 | org.osgi 506 | osgi.cmpn 507 | 6.0.0 508 | provided 509 | 510 | 511 | org.osgi 512 | osgi.annotation 513 | 6.0.1 514 | provided 515 | 516 | 517 | javax.inject 518 | javax.inject 519 | 1 520 | 521 | 522 | javax.annotation 523 | javax.annotation-api 524 | 1.3.2 525 | provided 526 | 527 | 528 | 529 | org.slf4j 530 | slf4j-api 531 | 1.7.21 532 | provided 533 | 534 | 535 | 536 | com.adobe.aem 537 | uber-jar 538 | 6.5.0 539 | apis 540 | provided 541 | 542 | 543 | com.adobe.cq 544 | core.wcm.components.all 545 | zip 546 | ${core.wcm.components.version} 547 | 548 | 549 | com.adobe.cq 550 | core.wcm.components.examples 551 | zip 552 | ${core.wcm.components.version} 553 | 554 | 555 | 556 | org.apache.sling 557 | org.apache.sling.models.api 558 | 1.3.6 559 | provided 560 | 561 | 562 | 563 | javax.servlet 564 | javax.servlet-api 565 | 3.1.0 566 | provided 567 | 568 | 569 | javax.servlet.jsp 570 | jsp-api 571 | 2.1 572 | provided 573 | 574 | 575 | 576 | javax.jcr 577 | jcr 578 | 2.0 579 | provided 580 | 581 | 582 | 583 | com.day.cq.wcm 584 | cq-wcm-taglib 585 | 5.7.4 586 | provided 587 | 588 | 589 | 590 | 591 | org.junit 592 | junit-bom 593 | 5.4.1 594 | pom 595 | import 596 | 597 | 598 | org.slf4j 599 | slf4j-simple 600 | 1.7.25 601 | test 602 | 603 | 604 | org.mockito 605 | mockito-core 606 | 2.25.1 607 | test 608 | 609 | 610 | org.mockito 611 | mockito-junit-jupiter 612 | 2.25.1 613 | test 614 | 615 | 616 | junit-addons 617 | junit-addons 618 | 1.4 619 | test 620 | 621 | 622 | io.wcm 623 | io.wcm.testing.aem-mock.junit5 624 | 2.4.4 625 | test 626 | 627 | 628 | uk.org.lidalia 629 | slf4j-test 630 | 1.0.1 631 | test 632 | 633 | 634 | com.google.code.findbugs 635 | jsr305 636 | 3.0.0 637 | 638 | 639 | 640 | 641 | 642 | -------------------------------------------------------------------------------- /ui.apps/.gitignore: -------------------------------------------------------------------------------- 1 | # ui.apps/.gitignore 2 | # Ignore React generated client libraries from source control 3 | my-aem-react-app -------------------------------------------------------------------------------- /ui.apps/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | 21 | 22 | 23 | 24 | com.surajkamdi-aem-project 25 | my-aem-project 26 | 1.0-SNAPSHOT 27 | ../pom.xml 28 | 29 | 30 | 31 | 32 | 33 | my-aem-project.ui.apps 34 | content-package 35 | my-aem-project - UI apps 36 | UI apps package for my-aem-project 37 | 38 | 44 | 45 | 46 | 47 | 48 | 49 | src/main/content/jcr_root 50 | 51 | 52 | 53 | 54 | 55 | org.apache.jackrabbit 56 | filevault-package-maven-plugin 57 | true 58 | 59 | My AEM Project - com.surajkamdi 60 | 61 | 62 | com.surajkamdi-aem-project 63 | my-aem-project.core 64 | /apps/my-aem-project/install 65 | 66 | 67 | 68 | 69 | com.adobe.cq 70 | core.wcm.components.all 71 | true 72 | 73 | 74 | com.adobe.cq 75 | core.wcm.components.examples 76 | true 77 | 78 | 79 | 80 | 81 | 82 | com.day.jcr.vault 83 | content-package-maven-plugin 84 | true 85 | 86 | true 87 | true 88 | 89 | 90 | 91 | 92 | org.apache.sling 93 | htl-maven-plugin 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | com.surajkamdi-aem-project 104 | my-aem-project.core 105 | 1.0-SNAPSHOT 106 | 107 | 108 | 109 | com.adobe.aem 110 | uber-jar 111 | apis 112 | 113 | 114 | 115 | com.adobe.cq 116 | core.wcm.components.all 117 | zip 118 | 119 | 120 | com.adobe.cq 121 | core.wcm.components.examples 122 | zip 123 | 124 | 125 | javax.jcr 126 | jcr 127 | 128 | 129 | 130 | javax.servlet 131 | javax.servlet-api 132 | 133 | 134 | 135 | com.day.cq.wcm 136 | cq-wcm-taglib 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/META-INF/vault/filter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs/clientlib-base/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs/clientlib-base/css.txt: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright 2017 Adobe Systems Incorporated 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | ############################################################################### -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs/clientlib-base/js.txt: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright 2017 Adobe Systems Incorporated 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | ############################################################################### -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs/clientlib-site/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs/clientlib-site/css.txt: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright 2018 Adobe Systems Incorporated 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | ############################################################################### 16 | 17 | less/grid.less -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs/clientlib-site/less/grid.less: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Adobe Systems Incorporated 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | @import (once) "/libs/wcm/foundation/clientlibs/grid/grid_base.less"; 18 | 19 | /* maximum amount of grid cells to be provided */ 20 | @max_col: 12; 21 | 22 | /* default breakpoint */ 23 | .aem-Grid { 24 | .generate-grid(default, @max_col); 25 | } 26 | 27 | /* phone breakpoint */ 28 | @media (max-width: 650px) { 29 | .aem-Grid { 30 | .generate-grid(phone, @max_col); 31 | } 32 | } 33 | 34 | /* tablet breakpoint */ 35 | @media (min-width: 651px) and (max-width: 1200px) { 36 | .aem-Grid { 37 | .generate-grid(tablet, @max_col); 38 | } 39 | } -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs/react-app/.content.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs/react-app/css.txt: -------------------------------------------------------------------------------- 1 | #base=css 2 | 3 | main.963feb16.chunk.css -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs/react-app/css/main.963feb16.chunk.css: -------------------------------------------------------------------------------- 1 | .react-aem-page{margin:0 auto;padding:0}.heading .red-color{color:#fc0b03}.heading .green-color{color:#39fc03}.heading .blue-color{color:#2403fc}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace} 2 | /*# sourceMappingURL=main.963feb16.chunk.css.map */ -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs/react-app/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | 2.6550cedb.chunk.js 4 | main.36b4d8cb.chunk.js 5 | runtime~main.2a9f8c0c.js -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs/react-app/js/main.36b4d8cb.chunk.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonpmy-aem-react-app"]=window["webpackJsonpmy-aem-react-app"]||[]).push([[0],{20:function(t,e,n){t.exports=n(41)},34:function(t,e,n){n(42),n(38)},37:function(t,e,n){},38:function(t,e,n){"use strict";n.r(e),n.d(e,"default",(function(){return h}));var a=n(2),c=n(3),r=n(4),o=n(1),i=n(5),s=n(0),p=n.n(s),u=n(6);n(39);var h=function(t){function e(){return Object(a.a)(this,e),Object(r.a)(this,Object(o.a)(e).apply(this,arguments))}return Object(i.a)(e,t),Object(c.a)(e,[{key:"render",value:function(){var t=this.props.headingType?p.a.createElement(this.props.headingType,{className:this.props.headingColor},this.props.heading):"";return p.a.createElement("div",{className:"heading"}," ",t," ")}}]),e}(s.Component);Object(u.MapTo)("my-aem-project/components/content/custom-heading")(h,{emptyLabel:"Custom Heading",isEmpty:function(t){return!t.heading||t.heading.trim().length<1}})},39:function(t,e,n){},40:function(t,e,n){},41:function(t,e,n){"use strict";n.r(e);var a=n(0),c=n.n(a),r=n(15),o=n.n(r),i=n(7),s=n(2),p=n(3),u=n(4),h=n(1),l=n(5),m=n(6),O=function(t){function e(){return Object(s.a)(this,e),Object(u.a)(this,Object(h.a)(e).apply(this,arguments))}return Object(l.a)(e,t),Object(p.a)(e,[{key:"render",value:function(){return c.a.createElement("div",{className:"App"},this.childComponents,this.childPages)}}]),e}(m.Page),b=Object(m.withModel)(O);n(34),n(40);i.ModelManager.initialize({path:Object({NODE_ENV:"production",PUBLIC_URL:""}).AEM_REACT_APP_PAGE_MODEL_PATH}).then((function(t){o.a.render(c.a.createElement(b,{cqChildren:t[i.Constants.CHILDREN_PROP],cqItems:t[i.Constants.ITEMS_PROP],cqItemsOrder:t[i.Constants.ITEMS_ORDER_PROP],cqPath:i.ModelManager.rootPath,locationPathname:window.location.pathname}),document.getElementById("root"))}))},42:function(t,e,n){"use strict";n.r(e);var a=n(2),c=n(3),r=n(4),o=n(1),i=n(19),s=n(5),p=n(6),u=n(0),h=n.n(u),l=n(18),m=function(t){function e(){return Object(a.a)(this,e),Object(r.a)(this,Object(o.a)(e).apply(this,arguments))}return Object(s.a)(e,t),Object(c.a)(e,[{key:"componentDidUpdate",value:function(t){this.props.location!==t.location&&window.scrollTo(0,0)}},{key:"render",value:function(){return this.props.children}}]),e}(u.Component);Object(l.b)(m);n(37);var O,b,d=function(t){function e(){return Object(a.a)(this,e),Object(r.a)(this,Object(o.a)(e).apply(this,arguments))}return Object(s.a)(e,t),Object(c.a)(e,[{key:"containerProps",get:function(){var t=Object(i.a)(Object(o.a)(e.prototype),"containerProps",this);return t.className=(t.className||"")+" react-aem-page "+(this.props.cssClassNames||""),t}}]),e}(p.Page);Object(p.MapTo)("my-aem-project/components/structure/page")(Object(p.withComponentMappingContext)((O=d,function(t){function e(){return Object(a.a)(this,e),Object(r.a)(this,Object(o.a)(e).apply(this,arguments))}return Object(s.a)(e,t),Object(c.a)(e,[{key:"render",value:function(){var t=this,e=this.props.cqPath;return e?(b=b||"html",h.a.createElement(l.a,{key:e,path:"(.*)"+e+"."+b,render:function(e){return h.a.createElement(O,Object.assign({},t.props,e))}})):h.a.createElement(O,this.props)}}]),e}(u.Component))))}},[[20,1,2]]]); 2 | //# sourceMappingURL=main.36b4d8cb.chunk.js.map -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/clientlibs/react-app/js/runtime~main.2a9f8c0c.js: -------------------------------------------------------------------------------- 1 | !function(e){function r(r){for(var n,a,p=r[0],l=r[1],f=r[2],c=0,s=[];c 2 | 6 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/components/content/custom-heading/_cq_dialog/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 12 | 16 | 17 | 22 | 23 | 27 | 28 | 31 | 32 | 38 | 43 | 44 |

48 |

52 |

56 | 57 | 58 | 63 | 64 | 68 | 72 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/components/structure/page/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/components/structure/page/body.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/components/structure/page/customfooterlibs.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/components/structure/page/customheaderlibs.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 23 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/config.author/com.day.cq.wcm.mobile.core.impl.MobileEmulatorProvider-my-aem-project.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/config/org.apache.sling.commons.log.LogManager.factory.config-my-aem-project.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/i18n/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/i18n/fr.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/templates/page-content/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 14 | 17 | <topnav 18 | jcr:primaryType="nt:unstructured" 19 | sling:resourceType="my-aem-project/components/structure/topnav"/> 20 | <par 21 | jcr:primaryType="nt:unstructured" 22 | sling:resourceType="wcm/foundation/components/parsys"> 23 | <text 24 | jcr:primaryType="nt:unstructured" 25 | sling:resourceType="my-aem-project/components/content/text" 26 | text="<p>This is a content page</p>" 27 | textIsRich="true"/> 28 | </par> 29 | </jcr:content> 30 | </jcr:root> 31 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/my-aem-project/templates/page-home/.content.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" 3 | jcr:description="Template for initial or main page of the site." 4 | jcr:primaryType="cq:Template" 5 | jcr:title="my-aem-project Home Page" 6 | allowedPaths="[/content/my-aem-project]" 7 | ranking="{Long}100"> 8 | <jcr:content 9 | jcr:primaryType="cq:PageContent" 10 | sling:resourceType="my-aem-project/components/structure/page"> 11 | <logo 12 | jcr:primaryType="nt:unstructured" 13 | sling:resourceType="my-aem-project/components/structure/logo"/> 14 | <title 15 | jcr:primaryType="nt:unstructured" 16 | sling:resourceType="my-aem-project/components/content/title"/> 17 | <topnav 18 | jcr:primaryType="nt:unstructured" 19 | sling:resourceType="my-aem-project/components/structure/topnav"/> 20 | <par 21 | jcr:primaryType="nt:unstructured" 22 | sling:resourceType="wcm/foundation/components/parsys"> 23 | <text 24 | jcr:primaryType="nt:unstructured" 25 | sling:resourceType="my-aem-project/components/content/text" 26 | text="<p>This is a home page</p>" 27 | textIsRich="true"/> 28 | </par> 29 | </jcr:content> 30 | </jcr:root> 31 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/sling/servlet/errorhandler/404.html: -------------------------------------------------------------------------------- 1 | <!--/* 2 | Copyright 2015 Adobe Systems Incorporated 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */--> 16 | <html data-sly-use.responseStatus="apps.sling.servlet.errorhandler.ResponseStatus"> 17 | <head> 18 | <title>File not found 19 | 20 | 21 |

A custom errorhandler for 404 responses

22 | 23 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/sling/servlet/errorhandler/ResponseStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Adobe Systems Incorporated 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package apps.sling.servlet.errorhandler; 17 | 18 | import com.adobe.cq.sightly.WCMUsePojo; 19 | 20 | public class ResponseStatus extends WCMUsePojo { 21 | 22 | @Override 23 | public void activate() throws Exception { 24 | getResponse().setStatus(404); 25 | getResponse().setContentType("text/html"); 26 | } 27 | } -------------------------------------------------------------------------------- /ui.content/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | 21 | 22 | 23 | 24 | com.surajkamdi-aem-project 25 | my-aem-project 26 | 1.0-SNAPSHOT 27 | ../pom.xml 28 | 29 | 30 | 31 | 32 | 33 | my-aem-project.ui.content 34 | content-package 35 | my-aem-project - UI content 36 | UI content package for my-aem-project 37 | 38 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.apache.jackrabbit 55 | filevault-package-maven-plugin 56 | true 57 | 58 | merge_preserve 59 | My AEM Project - com.surajkamdi 60 | 61 | 62 | 63 | com.day.jcr.vault 64 | content-package-maven-plugin 65 | true 66 | 67 | true 68 | true 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | com.surajkamdi-aem-project 80 | my-aem-project.core 81 | 1.0-SNAPSHOT 82 | 83 | 84 | 85 | com.adobe.aem 86 | uber-jar 87 | apis 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ui.content/src/main/content/META-INF/vault/filter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/policies/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 12 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/policies/_rep_policy.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 12 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/_rep_policy.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/empty-page/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/empty-page/initial/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/empty-page/policies/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/empty-page/structure/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 11 | 12 | 13 | 17 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/empty-page/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerficientDigital/my-aem-project/ab12ce3576ec3eac4206fefd35fb794fbde96b3f/ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/empty-page/thumbnail.png -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/empty-page/thumbnail.png.dir/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/empty-page/thumbnail.png.dir/_jcr_content/_dam_thumbnails/_dam_thumbnail_300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerficientDigital/my-aem-project/ab12ce3576ec3eac4206fefd35fb794fbde96b3f/ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/empty-page/thumbnail.png.dir/_jcr_content/_dam_thumbnails/_dam_thumbnail_300.png -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/empty-page/thumbnail.png.dir/_jcr_content/_dam_thumbnails/_dam_thumbnail_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerficientDigital/my-aem-project/ab12ce3576ec3eac4206fefd35fb794fbde96b3f/ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/template-types/empty-page/thumbnail.png.dir/_jcr_content/_dam_thumbnails/_dam_thumbnail_48.png -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/_rep_policy.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 12 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/content-page/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/content-page/initial/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/content-page/policies/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/content-page/structure/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 13 | 14 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/content-page/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerficientDigital/my-aem-project/ab12ce3576ec3eac4206fefd35fb794fbde96b3f/ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/content-page/thumbnail.png -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/content-page/thumbnail.png.dir/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/content-page/thumbnail.png.dir/_jcr_content/_dam_thumbnails/_dam_thumbnail_300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerficientDigital/my-aem-project/ab12ce3576ec3eac4206fefd35fb794fbde96b3f/ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/content-page/thumbnail.png.dir/_jcr_content/_dam_thumbnails/_dam_thumbnail_300.png -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/content-page/thumbnail.png.dir/_jcr_content/_dam_thumbnails/_dam_thumbnail_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerficientDigital/my-aem-project/ab12ce3576ec3eac4206fefd35fb794fbde96b3f/ui.content/src/main/content/jcr_root/conf/my-aem-project/settings/wcm/templates/content-page/thumbnail.png.dir/_jcr_content/_dam_thumbnails/_dam_thumbnail_48.png -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/content/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/content/my-aem-project/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ui.content/src/main/content/jcr_root/content/my-aem-project/blog-page/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 11 | 16 | 17 | 18 | --------------------------------------------------------------------------------