From 4d3b8454c03262d5704f432621e608c9bc54addc Mon Sep 17 00:00:00 2001 From: Barshat Rai Date: Thu, 7 Nov 2024 11:57:23 +0530 Subject: [PATCH 1/5] support to embed forms in different sites --- .../main/content/META-INF/vault/filter.xml | 1 + .../config/rewriter/.content.xml | 3 + .../rewriter/custom-linkrewriter/.content.xml | 14 +++ .../sites/formsembed/.content.xml | 5 + .../sites/formsembed/README.md | 1 + .../sites/formsembed/_cq_dialog/.content.xml | 23 +++++ .../sites/formsembed/formsembed.html | 57 +++++++++++ .../it/models/embed/FormsEmbed.java | 10 ++ .../it/models/embed/FormsEmbedImpl.java | 35 +++++++ .../CustomCloudRewriterTransformer.java | 99 +++++++++++++++++++ .../it/service/rewriter/CustomRunMode.java | 11 +++ .../rewriter/CustomRunModeConfiguration.java | 25 +++++ 12 files changed, 284 insertions(+) create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/.content.xml create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/custom-linkrewriter/.content.xml create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/.content.xml create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/README.md create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/formsembed.html create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbed.java create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbedImpl.java create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunMode.java create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunModeConfiguration.java diff --git a/it/apps/src/main/content/META-INF/vault/filter.xml b/it/apps/src/main/content/META-INF/vault/filter.xml index a9c91e0f86..2f5660e047 100644 --- a/it/apps/src/main/content/META-INF/vault/filter.xml +++ b/it/apps/src/main/content/META-INF/vault/filter.xml @@ -2,5 +2,6 @@ + diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/.content.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/.content.xml new file mode 100644 index 0000000000..6d97bc0e2f --- /dev/null +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/.content.xml @@ -0,0 +1,3 @@ + + diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/custom-linkrewriter/.content.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/custom-linkrewriter/.content.xml new file mode 100644 index 0000000000..5af7a1c4d0 --- /dev/null +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/custom-linkrewriter/.content.xml @@ -0,0 +1,14 @@ + + + + diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/.content.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/.content.xml new file mode 100644 index 0000000000..f4c23add8e --- /dev/null +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/.content.xml @@ -0,0 +1,5 @@ + + diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/README.md b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/README.md new file mode 100644 index 0000000000..bb05396426 --- /dev/null +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/README.md @@ -0,0 +1 @@ +## This component should be deployed in the Sites' instance where we need to embed the form diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml new file mode 100644 index 0000000000..c8daf3e681 --- /dev/null +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/formsembed.html b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/formsembed.html new file mode 100644 index 0000000000..151ad4223c --- /dev/null +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/formsembed.html @@ -0,0 +1,57 @@ +
+ +
+
+ +
+
+ Your Form Will Appear Here +
+
+
+
+
+ +
+
diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbed.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbed.java new file mode 100644 index 0000000000..bb751dc19b --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbed.java @@ -0,0 +1,10 @@ +package com.adobe.cq.forms.core.components.it.models.embed; + +import com.adobe.cq.wcm.core.components.models.Component; +import org.osgi.annotation.versioning.ConsumerType; + +@ConsumerType +public interface FormsEmbed extends Component { + + String getFormsUrl(); +} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbedImpl.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbedImpl.java new file mode 100644 index 0000000000..9a0d0628e2 --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbedImpl.java @@ -0,0 +1,35 @@ +package com.adobe.cq.forms.core.components.it.models.embed; + +import com.adobe.cq.export.json.ComponentExporter; +import com.adobe.cq.export.json.ExporterConstants; +import com.drew.lang.annotations.Nullable; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.models.annotations.Exporter; +import org.apache.sling.models.annotations.Model; +import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy; +import org.apache.sling.models.annotations.injectorspecific.ValueMapValue; + +@Model( + adaptables = SlingHttpServletRequest.class, + adapters = {FormsEmbed.class, ComponentExporter.class}, + resourceType = FormsEmbedImpl.RESOURCE_TYPE +) +@Exporter( + name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, + extensions = ExporterConstants.SLING_MODEL_EXTENSION +) +public class FormsEmbedImpl implements FormsEmbed { + + // TODO replace app name + public static final String RESOURCE_TYPE = "forms-core-component-it/components/formsembed"; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL) + @Nullable + protected String formsUrl; + + + @Override + public String getFormsUrl() { + return formsUrl; + } +} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java new file mode 100644 index 0000000000..a9ecb55c06 --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java @@ -0,0 +1,99 @@ +package com.adobe.cq.forms.core.components.it.service.rewriter; + +import org.apache.sling.rewriter.DefaultTransformer; +import org.apache.sling.rewriter.TransformerFactory; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +@Component( + service = TransformerFactory.class, + property = { + "pipeline.type=" + CustomCloudRewriterTransformer.TYPE, + } +) +public class CustomCloudRewriterTransformer implements TransformerFactory { + + private static final Logger log = LoggerFactory.getLogger(CustomCloudRewriterTransformer.class); + + public static final String TYPE = "custom-linkrewriter"; + + public static final String PATH_PREFIX = "custom"; + + + @Reference + private CustomRunModeConfiguration customRunModeConfiguration; + + @Override + public TransformerImpl createTransformer() { + String runmode = customRunModeConfiguration.getRunMode(); + log.info("current runmode = " + runmode); + boolean isPublish = "publish".equals(runmode); + return new TransformerImpl(isPublish); + } + + + protected static class TransformerImpl extends DefaultTransformer { + + private final boolean isPublish; + + public TransformerImpl(boolean isPublish) { + super(); + this.isPublish = isPublish; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + AttributesImpl mutableAttributes = + attributes instanceof AttributesImpl ? (AttributesImpl) attributes + : null; + if (isPublish) { + if ("link".equals(localName)) { + mutableAttributes = mutableAttributes != null ? mutableAttributes : new AttributesImpl(attributes); + replaceLinkPaths(mutableAttributes); + } else if ("script".equals(localName)) { + mutableAttributes = mutableAttributes != null ? mutableAttributes : new AttributesImpl(attributes); + replaceScriptPaths(mutableAttributes); + } + } + super.startElement(uri, localName, qName, + mutableAttributes != null ? mutableAttributes : attributes); + } + + private void replaceLinkPaths(AttributesImpl attributes) { + if (attributes.getIndex("href") >= 0 && attributes.getIndex("rel") >= 0) { + String rel = attributes.getValue("rel"); + if ("preload stylesheet".equals(rel) || "stylesheet".equals(rel)) { + int index = attributes.getIndex("href"); + String value = attributes.getValue(index); + setAttribute(attributes, index, addPathPrefix(value)); + } + } + } + + private void replaceScriptPaths(AttributesImpl attributes) { + if (attributes.getIndex("src") >= 0) { + int index = attributes.getIndex("src"); + String value = attributes.getValue(index); + setAttribute(attributes, index, addPathPrefix(value)); + } + } + + private String addPathPrefix(String url) { + return "/" + PATH_PREFIX + url; + } + + private void setAttribute(AttributesImpl attributes, int index, String value) { + String attrUri = attributes.getURI(index); + String attrLocalName = attributes.getLocalName(index); + String attrQName = attributes.getQName(index); + String attrType = attributes.getType(index); + attributes.setAttribute(index, attrUri, attrLocalName, attrQName, attrType, value); + } + } +} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunMode.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunMode.java new file mode 100644 index 0000000000..a5137d99f1 --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunMode.java @@ -0,0 +1,11 @@ +package com.adobe.cq.forms.core.components.it.service.rewriter; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition(name = "Runmode OSGI Configuration", description = "Configuration for Identifying Run Mode") +public @interface CustomRunMode { + + @AttributeDefinition(name = "Runmode Information", description = "Runmode Info") + String runmode_info() default "default"; +} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunModeConfiguration.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunModeConfiguration.java new file mode 100644 index 0000000000..98bdf28543 --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunModeConfiguration.java @@ -0,0 +1,25 @@ +package com.adobe.cq.forms.core.components.it.service.rewriter; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; + +@Component( + service = CustomRunModeConfiguration.class +) +public class CustomRunModeConfiguration { + + private CustomRunMode customRunMode; + + @Activate + public void activate(CustomRunMode customRunMode) { + this.customRunMode = customRunMode; + } + + public String getRunMode() { + if (customRunMode != null) { + return customRunMode.runmode_info(); + } else { + return "default"; + } + } +} From 3e18571426c35965bf45fef0ed977f2f86eb5c4b Mon Sep 17 00:00:00 2001 From: Barshat Rai Date: Mon, 2 Dec 2024 12:13:17 +0530 Subject: [PATCH 2/5] custom form container model for prefix path for prefill, custom functions and submit custom form container model for prefix path for prefill, custom functions and submit custom form container model for prefix path for prefill, custom functions and submit custom form container model for prefix path for prefill, custom functions and submit --- .../sites/formsembed/_cq_dialog/.content.xml | 2 +- it/core/pom.xml | 2 +- .../formcontainer/CustomFormContainer.java | 421 ++++++++++++++++++ .../formcontainer/ReservedProperties.java | 172 +++++++ .../CustomCloudRewriterTransformer.java | 31 +- 5 files changed, 612 insertions(+), 16 deletions(-) create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/CustomFormContainer.java create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/ReservedProperties.java diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml index c8daf3e681..512e5acdda 100644 --- a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml @@ -14,7 +14,7 @@ diff --git a/it/core/pom.xml b/it/core/pom.xml index 3ef2cf1334..88c9879226 100644 --- a/it/core/pom.xml +++ b/it/core/pom.xml @@ -161,7 +161,7 @@ Import-Package: javax.annotation;version=0.0.0,* com.adobe.aem core-forms-components-af-core - 3.0.70 + ${project.version} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/CustomFormContainer.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/CustomFormContainer.java new file mode 100644 index 0000000000..e4ca0cc94c --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/CustomFormContainer.java @@ -0,0 +1,421 @@ +package com.adobe.cq.forms.core.components.it.models.formcontainer; + +import com.adobe.aemds.guide.common.GuideContainer; +import com.adobe.aemds.guide.service.CoreComponentCustomPropertiesProvider; +import com.adobe.aemds.guide.service.GuideSchemaType; +import com.adobe.aemds.guide.utils.GuideConstants; +import com.adobe.aemds.guide.utils.GuideUtils; +import com.adobe.aemds.guide.utils.GuideWCMUtils; +import com.adobe.cq.export.json.ComponentExporter; +import com.adobe.cq.export.json.ContainerExporter; +import com.adobe.cq.export.json.ExporterConstants; +import com.adobe.cq.forms.core.components.internal.form.FormConstants; +import com.adobe.cq.forms.core.components.it.service.rewriter.CustomRunModeConfiguration; +import com.adobe.cq.forms.core.components.models.form.AutoSaveConfiguration; +import com.adobe.cq.forms.core.components.models.form.Container; +import com.adobe.cq.forms.core.components.models.form.FieldType; +import com.adobe.cq.forms.core.components.models.form.FormClientLibManager; +import com.adobe.cq.forms.core.components.models.form.FormContainer; +import com.adobe.cq.forms.core.components.models.form.FormMetaData; +import com.adobe.cq.forms.core.components.models.form.ThankYouOption; +import com.adobe.cq.forms.core.components.util.AbstractContainerImpl; +import com.adobe.cq.forms.core.components.util.ComponentUtils; +import com.day.cq.commons.LanguageUtil; +import com.day.cq.commons.jcr.JcrConstants; +import com.day.cq.wcm.api.Page; +import com.day.cq.wcm.api.PageManager; +import com.drew.lang.annotations.Nullable; +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Consumer; +import javax.annotation.PostConstruct; +import org.apache.commons.lang3.StringUtils; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.models.annotations.Default; +import org.apache.sling.models.annotations.Exporter; +import org.apache.sling.models.annotations.Model; +import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy; +import org.apache.sling.models.annotations.injectorspecific.OSGiService; +import org.apache.sling.models.annotations.injectorspecific.Self; +import org.apache.sling.models.annotations.injectorspecific.SlingObject; +import org.apache.sling.models.annotations.injectorspecific.ValueMapValue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Model( + adaptables = { SlingHttpServletRequest.class, Resource.class }, + adapters = { FormContainer.class, ContainerExporter.class, ComponentExporter.class }, + resourceType = { CustomFormContainer.RESOURCE_TYPE }) +@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION) +public class CustomFormContainer extends AbstractContainerImpl implements FormContainer { + protected static final String RESOURCE_TYPE = "/components/adaptiveForm/formcontainer"; + + private static final Logger logger = LoggerFactory.getLogger(CustomFormContainer.class); + private static final String DOR_TYPE = "dorType"; + private static final String DOR_TEMPLATE_REF = "dorTemplateRef"; + private static final String DOR_TEMPLATE_TYPE = "dorTemplateType"; + private static final String FD_SCHEMA_TYPE = "fd:schemaType"; + private static final String FD_SCHEMA_REF = "fd:schemaRef"; + private static final String FD_IS_HAMBURGER_MENU_ENABLED = "fd:isHamburgerMenuEnabled"; + public static final String FD_FORM_DATA_ENABLED = "fd:formDataEnabled"; + public static final String FD_ROLE_ATTRIBUTE = "fd:roleAttribute"; + private static final String FD_CUSTOM_FUNCTIONS_URL = "fd:customFunctionsUrl"; + private static final String FD_DATA_URL = "fd:dataUrl"; + + @OSGiService(injectionStrategy = InjectionStrategy.OPTIONAL) + private CoreComponentCustomPropertiesProvider coreComponentCustomPropertiesProvider; + + @SlingObject(injectionStrategy = InjectionStrategy.OPTIONAL) + @Nullable + private SlingHttpServletRequest request; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_THANK_YOU_MSG_V2) + @Nullable + private String thankYouMessage; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_THANK_YOU_OPTION) + @Nullable + private String thankYouOption; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_CLIENTLIB_REF) + @Nullable + private String clientLibRef; + + @ValueMapValue(name = FD_IS_HAMBURGER_MENU_ENABLED, injectionStrategy = InjectionStrategy.OPTIONAL) + private Boolean isHamburgerMenuEnabled = false; + + protected String contextPath = StringUtils.EMPTY; + private boolean formDataEnabled = false; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_TITLE) + @Nullable + private String title; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_REDIRECT) + @Nullable + private String redirect; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_PREFILL_SERVICE) + @Nullable + private String prefillService; + + @ValueMapValue(name = FD_ROLE_ATTRIBUTE, injectionStrategy = InjectionStrategy.OPTIONAL) + @Nullable + private String roleAttribute; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_DATA) + @Nullable + private String data; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_SPEC_VERSION) + @Default(values = DEFAULT_FORMS_SPEC_VERSION) + private String specVersion; + + @Self(injectionStrategy = InjectionStrategy.OPTIONAL) + private AutoSaveConfiguration autoSaveConfig; + + @OSGiService + private CustomRunModeConfiguration runModeConfigService; + + @Override + public String getFieldType() { + return super.getFieldType(FieldType.FORM); + } + + private static final String PREFIX_PATH = "/custom"; + + @PostConstruct + protected void initFormContainerModel() { + if (request != null) { + contextPath = request.getContextPath(); + request.setAttribute("formContainerPath", this.getPath()); + + Page currentPage = getCurrentPage(); + if (currentPage != null) { + PageManager pageManager = currentPage.getPageManager(); + Page resourcePage = pageManager.getContainingPage(resource); + if (resourcePage != null && !StringUtils.equals(currentPage.getPath(), resourcePage.getPath())) { + request.setAttribute(FormConstants.REQ_ATTR_REFERENCED_PATH, resourcePage.getPath()); + } + } + FormClientLibManager formClientLibManager = request.adaptTo(FormClientLibManager.class); + if (formClientLibManager != null && clientLibRef != null) { + formClientLibManager.addClientLibRef(clientLibRef); + } + } + } + + @Override + public void setContextPath(String contextPath) { + this.contextPath = contextPath; + } + + @JsonIgnore + public String getContextPath() { + return contextPath != null ? contextPath : StringUtils.EMPTY; + } + + @Override + @Nullable + @JsonIgnore + public String getThankYouMessage() { + return translate("thankYouMessage", thankYouMessage); + } + + @Override + @Nullable + @JsonIgnore + public ThankYouOption getThankYouOption() { + return ThankYouOption.fromString(thankYouOption); + } + + @Override + public String getAdaptiveFormVersion() { + return specVersion; + } + + @Override + @Nullable + public String getClientLibRef() { + return clientLibRef; + } + + @Override + @Nullable + public String getSchemaRef() { + return GuideContainer.from(resource).getSchemaRef(); + } + + @Override + @Nullable + public GuideSchemaType getSchemaType() { + return GuideContainer.from(resource).getSchema(); + } + + @Override + public FormMetaData getMetaData() { + return new FormMetaData() { + @Override + public String getVersion() { + return FormMetaData.super.getVersion(); + } + }; + } + + @Override + @Nullable + public String getTitle() { + return title; + } + + @Override + @Nullable + public String getFormData() { + return data; + } + + @Override + @JsonIgnore + public String getEncodedCurrentPagePath() { + if (getCurrentPage() != null) { + return getId(); + } else { + return null; + } + } + + @Override + public String getId() { + String parentPagePath = getParentPagePath(); + if (GuideWCMUtils.isForms(parentPagePath)) { + return ComponentUtils.getEncodedPath(parentPagePath); + } else { + // handling use-case when AF is used in iframe mode inside embed form component + if (request != null && request.getAttribute("formRenderingInsideEmbedContainer") != null) { + return ComponentUtils.getEncodedPath(StringUtils.replace(getPath(), "/" + JcrConstants.JCR_CONTENT + "/" + + GuideConstants.GUIDE_CONTAINER_NODE_NAME, "")); + } + return ComponentUtils.getEncodedPath(getPath()); + } + } + + @JsonIgnore + @Nullable + public String getRedirectUrl() { + String redirectURL = GuideUtils.getRedirectUrl(redirect, getPath()); + // Only do this if redirect configured to relative URL, that is, page hosted on same AEM + if (StringUtils.isNotEmpty(redirectURL) && redirectURL.startsWith("/")) { + redirectURL = getContextPath() + redirectURL; + } + return redirectURL; + } + + @JsonIgnore + @Nullable + public String getPrefillService() { + return prefillService; + } + + public Boolean getIsHamburgerMenuEnabled() { + return isHamburgerMenuEnabled; + } + + @Override + public String getRoleAttribute() { + return roleAttribute; + } + + @Override + public String getAction() { + String action; + if ("publish".equals(runModeConfigService.getRunMode())) { + action = getContextPath() + PREFIX_PATH + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/submit/" + getId(); + } else { + action = getContextPath() + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/submit/" + getId(); + } + return action; + } + + @Override + @JsonIgnore + public String getDataUrl() { + String dataUrl; + if ("publish".equals(runModeConfigService.getRunMode())) { + dataUrl = getContextPath() + PREFIX_PATH + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/data/" + getId(); + } else { + dataUrl = getContextPath() + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/data/" + getId(); + } + return dataUrl; + } + + @Override + public String getLang() { + // todo: uncomment once forms sdk is released + if (request != null) { + return GuideUtils.getAcceptLang(request); + } else { + return FormContainer.super.getLang(); + } + } + + @Override + public String getContainingPageLang() { + // todo: right now it is copy of aem form because app is part of far, and af-apps is not pare of far + if (request != null) { + Page currentPage = getCurrentPage(); + if (!GuideWCMUtils.isForms(currentPage.getPath())) { + String pagePath = currentPage.getPath(), pageLocaleRoot = LanguageUtil.getLanguageRoot(pagePath), locale = ""; + if (StringUtils.isNotBlank(pageLocaleRoot)) { + int localeStartIndex = StringUtils.lastIndexOf(pageLocaleRoot, '/'); + locale = StringUtils.substring(pageLocaleRoot, localeStartIndex + 1); + } + return locale; + } else { + return FormContainer.super.getContainingPageLang(); + } + } else { + return FormContainer.super.getContainingPageLang(); + } + } + + @Override + public String getLanguageDirection() { + return GuideUtils.getLanguageDirection(getLang()); + } + + @Override + public Map getProperties() { + Map properties = new LinkedHashMap<>(); + if (coreComponentCustomPropertiesProvider != null) { + Map customProperties = coreComponentCustomPropertiesProvider.getProperties(); + if (customProperties != null) { + properties.putAll(customProperties); + } + } + properties.putAll(super.getProperties()); + if (getSchemaType() != null) { + properties.put(FD_SCHEMA_TYPE, getSchemaType()); + } + if (StringUtils.isNotBlank(getSchemaRef())) { + properties.put(FD_SCHEMA_REF, getSchemaRef()); + } + properties.put(FD_IS_HAMBURGER_MENU_ENABLED, getIsHamburgerMenuEnabled()); + // adding a custom property to know if form data is enabled + // this is done so that an extra API call from the client can be avoided + if (StringUtils.isNotBlank(getPrefillService()) || + (request != null && StringUtils.isNotBlank(request.getParameter(GuideConstants.AF_DATA_REF)))) { + formDataEnabled = true; + } + properties.put(FD_ROLE_ATTRIBUTE, getRoleAttribute()); + properties.put(FD_FORM_DATA_ENABLED, formDataEnabled); + properties.put(ReservedProperties.FD_AUTO_SAVE_PROPERTY_WRAPPER, this.autoSaveConfig); + properties.put(FD_CUSTOM_FUNCTIONS_URL, getCustomFunctionUrl()); + properties.put(FD_DATA_URL, getDataUrl()); + + return properties; + } + + @Override + @JsonIgnore + public Map getDorProperties() { + Map customDorProperties = new LinkedHashMap<>(); + if (dorType != null) { + customDorProperties.put(DOR_TYPE, dorType); + } + if (dorTemplateRef != null) { + customDorProperties.put(DOR_TEMPLATE_REF, dorTemplateRef); + } + if (dorTemplateType != null) { + customDorProperties.put(DOR_TEMPLATE_TYPE, dorTemplateType); + } + return customDorProperties; + } + + @JsonIgnore + @Override + public void visit(Consumer callback) throws Exception { + traverseChild(this, callback); + } + + private void traverseChild(Container container, Consumer callback) throws Exception { + for (ComponentExporter component : container.getItems()) { + callback.accept(component); + + if (component instanceof Container) { + traverseChild((Container) component, callback); + } + } + } + + @Override + @JsonIgnore + public String getParentPagePath() { + if (resource != null) { + PageManager pm = resource.getResourceResolver().adaptTo(PageManager.class); + if (pm != null) { + Page page = pm.getContainingPage(resource); + return page != null ? page.getPath() : StringUtils.EMPTY; + } + } + return StringUtils.EMPTY; + } + + @Override + public String getName() { + return FormContainer.super.getName(); + } + + @Override + public String getCustomFunctionUrl() { + String customFunctionUrl; + if ("publish".equals(runModeConfigService.getRunMode())) { + customFunctionUrl = getContextPath() + PREFIX_PATH + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/customfunctions/" + getId(); + } else { + customFunctionUrl = getContextPath() + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/customfunctions/" + getId(); + } + return customFunctionUrl; + } + +} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/ReservedProperties.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/ReservedProperties.java new file mode 100644 index 0000000000..13f7d5ae21 --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/ReservedProperties.java @@ -0,0 +1,172 @@ +package com.adobe.cq.forms.core.components.it.models.formcontainer; + +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.adobe.cq.forms.core.components.models.form.FormContainer; +import com.adobe.cq.wcm.core.components.models.Component; +import com.adobe.cq.wcm.core.components.models.Title; + +public final class ReservedProperties { + private ReservedProperties() { + // NOOP + } + + private static final Logger logger = LoggerFactory.getLogger(ReservedProperties.class); + + public static final String PN_ID = Component.PN_ID; + public static final String PN_VIEWTYPE = "fd:viewType"; + public static final String PN_FIELDTYPE = "fieldType"; + public static final String PN_DATAREF = "dataRef"; + public static final String PN_NAME = "name"; + public static final String PN_VALUE = "value"; + public static final String PN_ICON = "icon"; + public static final String PN_DATA = "data"; + public static final String PN_SIZE = "size"; + public static final String PN_VISIBLE = "visible"; + public static final String PN_UNBOUND_FORM_ELEMENT = "unboundFormElement"; + public static final String PN_DOR_EXCLUSION = "dorExclusion"; + public static final String PN_DOR_COLSPAN = "dorColspan"; + public static final String PN_DOR_BINDREF = "dorBindRef"; + public static final String PN_DOR_EXCLUDE_TITLE = "dorExcludeTitle"; + public static final String PN_DOR_EXCLUDE_DESC = "dorExcludeDescription"; + public static final String PN_DOR_NUM_COLS = "dorNumCols"; + public static final String PN_DOR_LAYOUT_TYPE = "dorLayoutType"; + public static final String PN_DESCRIPTION = "description"; + public static final String PN_TOOLTIP = "tooltip"; + public static final String PN_DOR_TEMPLATE_TYPE = "fd:formType"; + public static final String PN_TOOLTIP_VISIBLE = "tooltipVisible"; + public static final String PN_TYPE = "type"; + public static final String PN_DOR_TEMPLATE_REF = "dorTemplateRef"; + public static final String PN_DOR_TYPE = "dorType"; + public static final String PN_VALIDATION_EXPRESSION = "validationExpression"; + public static final String PN_REQUIRED = "required"; + public static final String PN_AUTOCOMPLETE = "autocomplete"; + public static final String PN_ASSIST_PRIORITY = "assistPriority"; + public static final String PN_CUSTOM = "custom"; + public static final String PN_ENABLED = "enabled"; + public static final String PN_REPEATABLE = "repeatable"; + public static final String PN_MIN_OCCUR = "minOccur"; + public static final String PN_MAX_OCCUR = "maxOccur"; + public static final String PN_MIN_ITEMS = "minItems"; + public static final String PN_MAX_ITEMS = "maxItems"; + public static final String PN_LANG = "lang"; + public static final String PN_LANG_DISPLAY_VALUE = "langDisplayValue"; + public static final String PN_PLACEHOLDER = "placeholder"; + public static final String PN_READ_ONLY = "readOnly"; + public static final String PN_DEFAULT_VALUE = "default"; + public static final String PN_FORMAT = "format"; + public static final String PN_DISPLAY_FORMAT = "displayFormat"; + public static final String PN_EDIT_FORMAT = "editFormat"; + public static final String PN_DISPLAY_VALUE_EXPRESSION = "displayValueExpression"; + public static final String PN_DATA_FORMAT = "dataFormat"; + public static final String PN_MIN_LENGTH = "minLength"; + public static final String PN_MAX_LENGTH = "maxLength"; + public static final String PN_MINIMUM_DATE = "minimumDate"; + public static final String PN_MAXIMUM_DATE = "maximumDate"; + public static final String PN_MAXIMUM = "maximum"; + public static final String PN_MINIMUM = "minimum"; + public static final String PN_EXCLUSIVE_MINIMUM = "exclusiveMinimum"; + public static final String PN_EXCLUSIVE_MAXIMUM = "exclusiveMaximum"; + public static final String PN_EXCLUDE_MINIMUM = "excludeMinimum"; + public static final String PN_EXCLUDE_MAXIMUM = "excludeMaximum"; + public static final String PN_EXCLUDE_MINIMUM_CHECK = "excludeMinimumCheck"; + public static final String PN_EXCLUDE_MAXIMUM_CHECK = "excludeMaximumCheck"; + public static final String PN_ENFORCE_ENUM = "enforceEnum"; + public static final String PN_ENUM = "enum"; + public static final String PN_ENUM_NAMES = "enumNames"; + public static final String PN_TITLE = "title"; + public static final String PN_HIDE_TITLE = "hideTitle"; + public static final String PN_IS_TITLE_RICH_TEXT = "isTitleRichText"; + public static final String PN_ORIENTATION = "orientation"; + public static final String PN_TYPE_MESSAGE = "typeMessage"; + public static final String PN_REQUIRED_MESSAGE = "mandatoryMessage"; // reusing the same property name as in foundation + public static final String PN_MINIMUM_MESSAGE = "minimumMessage"; + public static final String PN_MAXIMUM_MESSAGE = "maximumMessage"; + public static final String PN_MINLENGTH_MESSAGE = "minLengthMessage"; + public static final String PN_MAXLENGTH_MESSAGE = "maxLengthMessage"; + public static final String PN_MAX_FILE_SIZE_MESSAGE = "maxFileSizeMessage"; // for fileInput min, max number of files, maximum file size + // and accept of file type messages + public static final String PN_ACCEPT_MESSAGE = "acceptMessage"; + public static final String PN_STEP_MESSAGE = "stepMessage"; + public static final String PN_FORMAT_MESSAGE = "formatMessage"; + public static final String PN_PATTERN = "pattern"; + public static final String PN_PATTERN_MESSAGE = "validatePictureClauseMessage"; // reusing the same property name as in foundation + public static final String PN_MINITEMS_MESSAGE = "minItemsMessage"; + public static final String PN_MAXITEMS_MESSAGE = "maxItemsMessage"; + public static final String PN_UNIQUE_ITEMS_MESSAGE = "uniqueItemsMessage"; + public static final String PN_ENFORCE_ENUM_MESSAGE = "enforceEnumMessage"; + public static final String PN_VALIDATION_EXPRESSION_MESSAGE = "validateExpMessage"; // reusing the same property name as in foundation + public static final String PN_MULTISELECT = "multiSelect"; + public static final String PN_MULTISELECTION = "multiSelection"; + public static final String PN_ENABLE_UNCHECKED_VALUE = "enableUncheckedValue"; + public static final String PN_CHECKED_VALUE = "checkedValue"; + public static final String PN_UNCHECKED_VALUE = "uncheckedValue"; + public static final String PN_MAX_FILE_SIZE = "maxFileSize"; + public static final String PN_FILE_ACCEPT = "accept"; + public static final String PN_BUTTON_TEXT = "buttonText"; + public static final String PN_WRAP_DATA = "wrapData"; + public static final String PN_FRAGMENT_PATH = "fragmentPath"; + public static final String PN_BUTTON_TYPE = "buttonType"; + public static final String PN_THANK_YOU_MSG_V1 = "thankyouMessage"; + public static final String PN_THANK_YOU_MSG_V2 = "thankYouMessage"; + public static final String PN_THANK_YOU_OPTION = "thankYouOption"; + public static final String PN_RUNTIME_DOCUMENT_PATH = FormContainer.PN_RUNTIME_DOCUMENT_PATH; + public static final String PN_CLOUD_SERVICE_PATH = "cloudServicePath"; + public static final String PN_RECAPTCHA_CLOUD_SERVICE_PATH = "rcCloudServicePath"; + public static final String PN_RECAPTCHA_SIZE = "recaptchaSize"; + public static final String PN_BREAK_BEFORE_TEXT = "breakBeforeText"; + public static final String PN_BREAK_AFTER_TEXT = "breakAfterText"; + public static final String PN_OVERFLOW_TEXT = "overflowText"; + public static final String PN_ALT_TEXT = "altText"; + public static final String PN_IMAGE_SRC = "imageSrc"; + public static final String PN_FILE_REF = "fileReference"; + public static final String PN_SHOW_APPROVAL_OPTION = "showApprovalOption"; + public static final String PN_SHOW_LINK = "showLink"; + public static final String PN_SHOW_AS_POPUP = "showAsPopup"; + public static final String PN_TEXT_IS_RICH = "textIsRich"; + public static final String PN_MULTILINE = "multiLine"; + public static final String PN_DESIGN_DEFAULT_TYPE = Title.PN_DESIGN_DEFAULT_TYPE; + public static final String PN_TITLE_LINK_DISABLED = Title.PN_TITLE_LINK_DISABLED; + public static final String PN_DRAG_DROP_TEXT = "dragDropText"; + public static final String PN_DRAG_DROP_TEXT_V3 = "fd:dragDropText"; + public static final String PN_CLIENTLIB_REF = "clientLibRef"; + public static final String PN_REDIRECT = "redirect"; + public static final String PN_PREFILL_SERVICE = "prefillService"; + public static final String PN_SPEC_VERSION = "specVersion"; + public static final String PN_RICH_TEXT = "richText"; + public static final String PN_OPTIONS_RICH_TEXT = "areOptionsRichText"; + public static final String PN_EXCLUDE_FROM_DOR = "excludeFromDor"; + public static final String PN_MANDATORY = "mandatory"; + public static final String PN_HTML_ELEMENT_TYPE_V2 = "fd:htmlelementType"; + public static final String FD_AUTO_SAVE_PROPERTY_WRAPPER = "fd:autoSave"; + public static final String FD_ENABLE_AUTO_SAVE = "fd:enableAutoSave"; + public static final String FD_AUTO_SAVE_STRATEGY_TYPE = "fd:autoSaveStrategyType"; + public static final String FD_AUTO_SAVE_INTERVAL = "fd:autoSaveInterval"; + private static final Set reservedProperties = aggregateReservedProperties(); + + private static Set aggregateReservedProperties() { + Set reservedProperties = new HashSet<>(); + Field[] fields = ReservedProperties.class.getDeclaredFields(); + + for (Field field : fields) { + if (field.getType().equals(String.class)) { + try { + reservedProperties.add((String) field.get(null)); + } catch (IllegalAccessException e) { + logger.error("[AF] Error while accessing field: {}", field.getName(), e); + } + } + } + + return reservedProperties; + } + + public static Set getReservedProperties() { + return reservedProperties; + } +} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java index a9ecb55c06..46fadaaa24 100644 --- a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java @@ -51,18 +51,29 @@ public void startElement(String uri, String localName, String qName, Attributes throws SAXException { AttributesImpl mutableAttributes = attributes instanceof AttributesImpl ? (AttributesImpl) attributes - : null; + : new AttributesImpl(attributes); if (isPublish) { if ("link".equals(localName)) { - mutableAttributes = mutableAttributes != null ? mutableAttributes : new AttributesImpl(attributes); replaceLinkPaths(mutableAttributes); - } else if ("script".equals(localName)) { - mutableAttributes = mutableAttributes != null ? mutableAttributes : new AttributesImpl(attributes); - replaceScriptPaths(mutableAttributes); + } else if ("script".equals(localName) || "img".equals(localName)) { + replaceAttributePaths(mutableAttributes, "src"); + } else if ("form".equals(localName)) { + replaceAttributePaths(mutableAttributes, "data-cmp-path"); + } else if ("div".equals(localName)) { + replaceAttributePaths(mutableAttributes, "data-cmp-adaptiveformcontainer-path"); } } + super.startElement(uri, localName, qName, - mutableAttributes != null ? mutableAttributes : attributes); + mutableAttributes); + } + + private void replaceAttributePaths(AttributesImpl attributes, String attributeName) { + if (attributes.getIndex(attributeName) >= 0) { + int index = attributes.getIndex(attributeName); + String value = attributes.getValue(index); + setAttribute(attributes, index, addPathPrefix(value)); + } } private void replaceLinkPaths(AttributesImpl attributes) { @@ -76,14 +87,6 @@ private void replaceLinkPaths(AttributesImpl attributes) { } } - private void replaceScriptPaths(AttributesImpl attributes) { - if (attributes.getIndex("src") >= 0) { - int index = attributes.getIndex("src"); - String value = attributes.getValue(index); - setAttribute(attributes, index, addPathPrefix(value)); - } - } - private String addPathPrefix(String url) { return "/" + PATH_PREFIX + url; } From 9bb509ceb26cde00e39f693c2c6e4015f19f1231 Mon Sep 17 00:00:00 2001 From: Barshat Rai Date: Thu, 7 Nov 2024 11:57:23 +0530 Subject: [PATCH 3/5] support to embed forms in different sites --- .../main/content/META-INF/vault/filter.xml | 1 + .../config/rewriter/.content.xml | 3 + .../rewriter/custom-linkrewriter/.content.xml | 14 +++ .../sites/formsembed/.content.xml | 5 + .../sites/formsembed/README.md | 1 + .../sites/formsembed/_cq_dialog/.content.xml | 23 +++++ .../sites/formsembed/formsembed.html | 57 +++++++++++ .../it/models/embed/FormsEmbed.java | 10 ++ .../it/models/embed/FormsEmbedImpl.java | 35 +++++++ .../CustomCloudRewriterTransformer.java | 99 +++++++++++++++++++ .../it/service/rewriter/CustomRunMode.java | 11 +++ .../rewriter/CustomRunModeConfiguration.java | 25 +++++ 12 files changed, 284 insertions(+) create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/.content.xml create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/custom-linkrewriter/.content.xml create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/.content.xml create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/README.md create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml create mode 100644 it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/formsembed.html create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbed.java create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbedImpl.java create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunMode.java create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunModeConfiguration.java diff --git a/it/apps/src/main/content/META-INF/vault/filter.xml b/it/apps/src/main/content/META-INF/vault/filter.xml index a9c91e0f86..2f5660e047 100644 --- a/it/apps/src/main/content/META-INF/vault/filter.xml +++ b/it/apps/src/main/content/META-INF/vault/filter.xml @@ -2,5 +2,6 @@ + diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/.content.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/.content.xml new file mode 100644 index 0000000000..6d97bc0e2f --- /dev/null +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/.content.xml @@ -0,0 +1,3 @@ + + diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/custom-linkrewriter/.content.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/custom-linkrewriter/.content.xml new file mode 100644 index 0000000000..5af7a1c4d0 --- /dev/null +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/config/rewriter/custom-linkrewriter/.content.xml @@ -0,0 +1,14 @@ + + + + diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/.content.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/.content.xml new file mode 100644 index 0000000000..f4c23add8e --- /dev/null +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/.content.xml @@ -0,0 +1,5 @@ + + diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/README.md b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/README.md new file mode 100644 index 0000000000..bb05396426 --- /dev/null +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/README.md @@ -0,0 +1 @@ +## This component should be deployed in the Sites' instance where we need to embed the form diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml new file mode 100644 index 0000000000..c8daf3e681 --- /dev/null +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/formsembed.html b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/formsembed.html new file mode 100644 index 0000000000..151ad4223c --- /dev/null +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/formsembed.html @@ -0,0 +1,57 @@ +
+ +
+
+ +
+
+ Your Form Will Appear Here +
+
+
+
+
+ +
+
diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbed.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbed.java new file mode 100644 index 0000000000..bb751dc19b --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbed.java @@ -0,0 +1,10 @@ +package com.adobe.cq.forms.core.components.it.models.embed; + +import com.adobe.cq.wcm.core.components.models.Component; +import org.osgi.annotation.versioning.ConsumerType; + +@ConsumerType +public interface FormsEmbed extends Component { + + String getFormsUrl(); +} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbedImpl.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbedImpl.java new file mode 100644 index 0000000000..9a0d0628e2 --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/embed/FormsEmbedImpl.java @@ -0,0 +1,35 @@ +package com.adobe.cq.forms.core.components.it.models.embed; + +import com.adobe.cq.export.json.ComponentExporter; +import com.adobe.cq.export.json.ExporterConstants; +import com.drew.lang.annotations.Nullable; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.models.annotations.Exporter; +import org.apache.sling.models.annotations.Model; +import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy; +import org.apache.sling.models.annotations.injectorspecific.ValueMapValue; + +@Model( + adaptables = SlingHttpServletRequest.class, + adapters = {FormsEmbed.class, ComponentExporter.class}, + resourceType = FormsEmbedImpl.RESOURCE_TYPE +) +@Exporter( + name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, + extensions = ExporterConstants.SLING_MODEL_EXTENSION +) +public class FormsEmbedImpl implements FormsEmbed { + + // TODO replace app name + public static final String RESOURCE_TYPE = "forms-core-component-it/components/formsembed"; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL) + @Nullable + protected String formsUrl; + + + @Override + public String getFormsUrl() { + return formsUrl; + } +} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java new file mode 100644 index 0000000000..a9ecb55c06 --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java @@ -0,0 +1,99 @@ +package com.adobe.cq.forms.core.components.it.service.rewriter; + +import org.apache.sling.rewriter.DefaultTransformer; +import org.apache.sling.rewriter.TransformerFactory; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +@Component( + service = TransformerFactory.class, + property = { + "pipeline.type=" + CustomCloudRewriterTransformer.TYPE, + } +) +public class CustomCloudRewriterTransformer implements TransformerFactory { + + private static final Logger log = LoggerFactory.getLogger(CustomCloudRewriterTransformer.class); + + public static final String TYPE = "custom-linkrewriter"; + + public static final String PATH_PREFIX = "custom"; + + + @Reference + private CustomRunModeConfiguration customRunModeConfiguration; + + @Override + public TransformerImpl createTransformer() { + String runmode = customRunModeConfiguration.getRunMode(); + log.info("current runmode = " + runmode); + boolean isPublish = "publish".equals(runmode); + return new TransformerImpl(isPublish); + } + + + protected static class TransformerImpl extends DefaultTransformer { + + private final boolean isPublish; + + public TransformerImpl(boolean isPublish) { + super(); + this.isPublish = isPublish; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + AttributesImpl mutableAttributes = + attributes instanceof AttributesImpl ? (AttributesImpl) attributes + : null; + if (isPublish) { + if ("link".equals(localName)) { + mutableAttributes = mutableAttributes != null ? mutableAttributes : new AttributesImpl(attributes); + replaceLinkPaths(mutableAttributes); + } else if ("script".equals(localName)) { + mutableAttributes = mutableAttributes != null ? mutableAttributes : new AttributesImpl(attributes); + replaceScriptPaths(mutableAttributes); + } + } + super.startElement(uri, localName, qName, + mutableAttributes != null ? mutableAttributes : attributes); + } + + private void replaceLinkPaths(AttributesImpl attributes) { + if (attributes.getIndex("href") >= 0 && attributes.getIndex("rel") >= 0) { + String rel = attributes.getValue("rel"); + if ("preload stylesheet".equals(rel) || "stylesheet".equals(rel)) { + int index = attributes.getIndex("href"); + String value = attributes.getValue(index); + setAttribute(attributes, index, addPathPrefix(value)); + } + } + } + + private void replaceScriptPaths(AttributesImpl attributes) { + if (attributes.getIndex("src") >= 0) { + int index = attributes.getIndex("src"); + String value = attributes.getValue(index); + setAttribute(attributes, index, addPathPrefix(value)); + } + } + + private String addPathPrefix(String url) { + return "/" + PATH_PREFIX + url; + } + + private void setAttribute(AttributesImpl attributes, int index, String value) { + String attrUri = attributes.getURI(index); + String attrLocalName = attributes.getLocalName(index); + String attrQName = attributes.getQName(index); + String attrType = attributes.getType(index); + attributes.setAttribute(index, attrUri, attrLocalName, attrQName, attrType, value); + } + } +} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunMode.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunMode.java new file mode 100644 index 0000000000..a5137d99f1 --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunMode.java @@ -0,0 +1,11 @@ +package com.adobe.cq.forms.core.components.it.service.rewriter; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition(name = "Runmode OSGI Configuration", description = "Configuration for Identifying Run Mode") +public @interface CustomRunMode { + + @AttributeDefinition(name = "Runmode Information", description = "Runmode Info") + String runmode_info() default "default"; +} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunModeConfiguration.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunModeConfiguration.java new file mode 100644 index 0000000000..98bdf28543 --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomRunModeConfiguration.java @@ -0,0 +1,25 @@ +package com.adobe.cq.forms.core.components.it.service.rewriter; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; + +@Component( + service = CustomRunModeConfiguration.class +) +public class CustomRunModeConfiguration { + + private CustomRunMode customRunMode; + + @Activate + public void activate(CustomRunMode customRunMode) { + this.customRunMode = customRunMode; + } + + public String getRunMode() { + if (customRunMode != null) { + return customRunMode.runmode_info(); + } else { + return "default"; + } + } +} From f846958567589adf349c0eebd8d83e19c3dd0508 Mon Sep 17 00:00:00 2001 From: Barshat Rai Date: Mon, 2 Dec 2024 12:13:17 +0530 Subject: [PATCH 4/5] custom form container model for prefix path for prefill, custom functions and submit custom form container model for prefix path for prefill, custom functions and submit custom form container model for prefix path for prefill, custom functions and submit custom form container model for prefix path for prefill, custom functions and submit --- .../sites/formsembed/_cq_dialog/.content.xml | 2 +- it/core/pom.xml | 2 +- .../formcontainer/CustomFormContainer.java | 421 ++++++++++++++++++ .../formcontainer/ReservedProperties.java | 172 +++++++ .../CustomCloudRewriterTransformer.java | 31 +- 5 files changed, 612 insertions(+), 16 deletions(-) create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/CustomFormContainer.java create mode 100644 it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/ReservedProperties.java diff --git a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml index c8daf3e681..512e5acdda 100644 --- a/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml +++ b/it/apps/src/main/content/jcr_root/apps/forms-core-components-it/sites/formsembed/_cq_dialog/.content.xml @@ -14,7 +14,7 @@ diff --git a/it/core/pom.xml b/it/core/pom.xml index 3ef2cf1334..88c9879226 100644 --- a/it/core/pom.xml +++ b/it/core/pom.xml @@ -161,7 +161,7 @@ Import-Package: javax.annotation;version=0.0.0,* com.adobe.aem core-forms-components-af-core - 3.0.70 + ${project.version} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/CustomFormContainer.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/CustomFormContainer.java new file mode 100644 index 0000000000..e4ca0cc94c --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/CustomFormContainer.java @@ -0,0 +1,421 @@ +package com.adobe.cq.forms.core.components.it.models.formcontainer; + +import com.adobe.aemds.guide.common.GuideContainer; +import com.adobe.aemds.guide.service.CoreComponentCustomPropertiesProvider; +import com.adobe.aemds.guide.service.GuideSchemaType; +import com.adobe.aemds.guide.utils.GuideConstants; +import com.adobe.aemds.guide.utils.GuideUtils; +import com.adobe.aemds.guide.utils.GuideWCMUtils; +import com.adobe.cq.export.json.ComponentExporter; +import com.adobe.cq.export.json.ContainerExporter; +import com.adobe.cq.export.json.ExporterConstants; +import com.adobe.cq.forms.core.components.internal.form.FormConstants; +import com.adobe.cq.forms.core.components.it.service.rewriter.CustomRunModeConfiguration; +import com.adobe.cq.forms.core.components.models.form.AutoSaveConfiguration; +import com.adobe.cq.forms.core.components.models.form.Container; +import com.adobe.cq.forms.core.components.models.form.FieldType; +import com.adobe.cq.forms.core.components.models.form.FormClientLibManager; +import com.adobe.cq.forms.core.components.models.form.FormContainer; +import com.adobe.cq.forms.core.components.models.form.FormMetaData; +import com.adobe.cq.forms.core.components.models.form.ThankYouOption; +import com.adobe.cq.forms.core.components.util.AbstractContainerImpl; +import com.adobe.cq.forms.core.components.util.ComponentUtils; +import com.day.cq.commons.LanguageUtil; +import com.day.cq.commons.jcr.JcrConstants; +import com.day.cq.wcm.api.Page; +import com.day.cq.wcm.api.PageManager; +import com.drew.lang.annotations.Nullable; +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Consumer; +import javax.annotation.PostConstruct; +import org.apache.commons.lang3.StringUtils; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.models.annotations.Default; +import org.apache.sling.models.annotations.Exporter; +import org.apache.sling.models.annotations.Model; +import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy; +import org.apache.sling.models.annotations.injectorspecific.OSGiService; +import org.apache.sling.models.annotations.injectorspecific.Self; +import org.apache.sling.models.annotations.injectorspecific.SlingObject; +import org.apache.sling.models.annotations.injectorspecific.ValueMapValue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Model( + adaptables = { SlingHttpServletRequest.class, Resource.class }, + adapters = { FormContainer.class, ContainerExporter.class, ComponentExporter.class }, + resourceType = { CustomFormContainer.RESOURCE_TYPE }) +@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION) +public class CustomFormContainer extends AbstractContainerImpl implements FormContainer { + protected static final String RESOURCE_TYPE = "/components/adaptiveForm/formcontainer"; + + private static final Logger logger = LoggerFactory.getLogger(CustomFormContainer.class); + private static final String DOR_TYPE = "dorType"; + private static final String DOR_TEMPLATE_REF = "dorTemplateRef"; + private static final String DOR_TEMPLATE_TYPE = "dorTemplateType"; + private static final String FD_SCHEMA_TYPE = "fd:schemaType"; + private static final String FD_SCHEMA_REF = "fd:schemaRef"; + private static final String FD_IS_HAMBURGER_MENU_ENABLED = "fd:isHamburgerMenuEnabled"; + public static final String FD_FORM_DATA_ENABLED = "fd:formDataEnabled"; + public static final String FD_ROLE_ATTRIBUTE = "fd:roleAttribute"; + private static final String FD_CUSTOM_FUNCTIONS_URL = "fd:customFunctionsUrl"; + private static final String FD_DATA_URL = "fd:dataUrl"; + + @OSGiService(injectionStrategy = InjectionStrategy.OPTIONAL) + private CoreComponentCustomPropertiesProvider coreComponentCustomPropertiesProvider; + + @SlingObject(injectionStrategy = InjectionStrategy.OPTIONAL) + @Nullable + private SlingHttpServletRequest request; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_THANK_YOU_MSG_V2) + @Nullable + private String thankYouMessage; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_THANK_YOU_OPTION) + @Nullable + private String thankYouOption; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_CLIENTLIB_REF) + @Nullable + private String clientLibRef; + + @ValueMapValue(name = FD_IS_HAMBURGER_MENU_ENABLED, injectionStrategy = InjectionStrategy.OPTIONAL) + private Boolean isHamburgerMenuEnabled = false; + + protected String contextPath = StringUtils.EMPTY; + private boolean formDataEnabled = false; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_TITLE) + @Nullable + private String title; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_REDIRECT) + @Nullable + private String redirect; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_PREFILL_SERVICE) + @Nullable + private String prefillService; + + @ValueMapValue(name = FD_ROLE_ATTRIBUTE, injectionStrategy = InjectionStrategy.OPTIONAL) + @Nullable + private String roleAttribute; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_DATA) + @Nullable + private String data; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_SPEC_VERSION) + @Default(values = DEFAULT_FORMS_SPEC_VERSION) + private String specVersion; + + @Self(injectionStrategy = InjectionStrategy.OPTIONAL) + private AutoSaveConfiguration autoSaveConfig; + + @OSGiService + private CustomRunModeConfiguration runModeConfigService; + + @Override + public String getFieldType() { + return super.getFieldType(FieldType.FORM); + } + + private static final String PREFIX_PATH = "/custom"; + + @PostConstruct + protected void initFormContainerModel() { + if (request != null) { + contextPath = request.getContextPath(); + request.setAttribute("formContainerPath", this.getPath()); + + Page currentPage = getCurrentPage(); + if (currentPage != null) { + PageManager pageManager = currentPage.getPageManager(); + Page resourcePage = pageManager.getContainingPage(resource); + if (resourcePage != null && !StringUtils.equals(currentPage.getPath(), resourcePage.getPath())) { + request.setAttribute(FormConstants.REQ_ATTR_REFERENCED_PATH, resourcePage.getPath()); + } + } + FormClientLibManager formClientLibManager = request.adaptTo(FormClientLibManager.class); + if (formClientLibManager != null && clientLibRef != null) { + formClientLibManager.addClientLibRef(clientLibRef); + } + } + } + + @Override + public void setContextPath(String contextPath) { + this.contextPath = contextPath; + } + + @JsonIgnore + public String getContextPath() { + return contextPath != null ? contextPath : StringUtils.EMPTY; + } + + @Override + @Nullable + @JsonIgnore + public String getThankYouMessage() { + return translate("thankYouMessage", thankYouMessage); + } + + @Override + @Nullable + @JsonIgnore + public ThankYouOption getThankYouOption() { + return ThankYouOption.fromString(thankYouOption); + } + + @Override + public String getAdaptiveFormVersion() { + return specVersion; + } + + @Override + @Nullable + public String getClientLibRef() { + return clientLibRef; + } + + @Override + @Nullable + public String getSchemaRef() { + return GuideContainer.from(resource).getSchemaRef(); + } + + @Override + @Nullable + public GuideSchemaType getSchemaType() { + return GuideContainer.from(resource).getSchema(); + } + + @Override + public FormMetaData getMetaData() { + return new FormMetaData() { + @Override + public String getVersion() { + return FormMetaData.super.getVersion(); + } + }; + } + + @Override + @Nullable + public String getTitle() { + return title; + } + + @Override + @Nullable + public String getFormData() { + return data; + } + + @Override + @JsonIgnore + public String getEncodedCurrentPagePath() { + if (getCurrentPage() != null) { + return getId(); + } else { + return null; + } + } + + @Override + public String getId() { + String parentPagePath = getParentPagePath(); + if (GuideWCMUtils.isForms(parentPagePath)) { + return ComponentUtils.getEncodedPath(parentPagePath); + } else { + // handling use-case when AF is used in iframe mode inside embed form component + if (request != null && request.getAttribute("formRenderingInsideEmbedContainer") != null) { + return ComponentUtils.getEncodedPath(StringUtils.replace(getPath(), "/" + JcrConstants.JCR_CONTENT + "/" + + GuideConstants.GUIDE_CONTAINER_NODE_NAME, "")); + } + return ComponentUtils.getEncodedPath(getPath()); + } + } + + @JsonIgnore + @Nullable + public String getRedirectUrl() { + String redirectURL = GuideUtils.getRedirectUrl(redirect, getPath()); + // Only do this if redirect configured to relative URL, that is, page hosted on same AEM + if (StringUtils.isNotEmpty(redirectURL) && redirectURL.startsWith("/")) { + redirectURL = getContextPath() + redirectURL; + } + return redirectURL; + } + + @JsonIgnore + @Nullable + public String getPrefillService() { + return prefillService; + } + + public Boolean getIsHamburgerMenuEnabled() { + return isHamburgerMenuEnabled; + } + + @Override + public String getRoleAttribute() { + return roleAttribute; + } + + @Override + public String getAction() { + String action; + if ("publish".equals(runModeConfigService.getRunMode())) { + action = getContextPath() + PREFIX_PATH + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/submit/" + getId(); + } else { + action = getContextPath() + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/submit/" + getId(); + } + return action; + } + + @Override + @JsonIgnore + public String getDataUrl() { + String dataUrl; + if ("publish".equals(runModeConfigService.getRunMode())) { + dataUrl = getContextPath() + PREFIX_PATH + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/data/" + getId(); + } else { + dataUrl = getContextPath() + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/data/" + getId(); + } + return dataUrl; + } + + @Override + public String getLang() { + // todo: uncomment once forms sdk is released + if (request != null) { + return GuideUtils.getAcceptLang(request); + } else { + return FormContainer.super.getLang(); + } + } + + @Override + public String getContainingPageLang() { + // todo: right now it is copy of aem form because app is part of far, and af-apps is not pare of far + if (request != null) { + Page currentPage = getCurrentPage(); + if (!GuideWCMUtils.isForms(currentPage.getPath())) { + String pagePath = currentPage.getPath(), pageLocaleRoot = LanguageUtil.getLanguageRoot(pagePath), locale = ""; + if (StringUtils.isNotBlank(pageLocaleRoot)) { + int localeStartIndex = StringUtils.lastIndexOf(pageLocaleRoot, '/'); + locale = StringUtils.substring(pageLocaleRoot, localeStartIndex + 1); + } + return locale; + } else { + return FormContainer.super.getContainingPageLang(); + } + } else { + return FormContainer.super.getContainingPageLang(); + } + } + + @Override + public String getLanguageDirection() { + return GuideUtils.getLanguageDirection(getLang()); + } + + @Override + public Map getProperties() { + Map properties = new LinkedHashMap<>(); + if (coreComponentCustomPropertiesProvider != null) { + Map customProperties = coreComponentCustomPropertiesProvider.getProperties(); + if (customProperties != null) { + properties.putAll(customProperties); + } + } + properties.putAll(super.getProperties()); + if (getSchemaType() != null) { + properties.put(FD_SCHEMA_TYPE, getSchemaType()); + } + if (StringUtils.isNotBlank(getSchemaRef())) { + properties.put(FD_SCHEMA_REF, getSchemaRef()); + } + properties.put(FD_IS_HAMBURGER_MENU_ENABLED, getIsHamburgerMenuEnabled()); + // adding a custom property to know if form data is enabled + // this is done so that an extra API call from the client can be avoided + if (StringUtils.isNotBlank(getPrefillService()) || + (request != null && StringUtils.isNotBlank(request.getParameter(GuideConstants.AF_DATA_REF)))) { + formDataEnabled = true; + } + properties.put(FD_ROLE_ATTRIBUTE, getRoleAttribute()); + properties.put(FD_FORM_DATA_ENABLED, formDataEnabled); + properties.put(ReservedProperties.FD_AUTO_SAVE_PROPERTY_WRAPPER, this.autoSaveConfig); + properties.put(FD_CUSTOM_FUNCTIONS_URL, getCustomFunctionUrl()); + properties.put(FD_DATA_URL, getDataUrl()); + + return properties; + } + + @Override + @JsonIgnore + public Map getDorProperties() { + Map customDorProperties = new LinkedHashMap<>(); + if (dorType != null) { + customDorProperties.put(DOR_TYPE, dorType); + } + if (dorTemplateRef != null) { + customDorProperties.put(DOR_TEMPLATE_REF, dorTemplateRef); + } + if (dorTemplateType != null) { + customDorProperties.put(DOR_TEMPLATE_TYPE, dorTemplateType); + } + return customDorProperties; + } + + @JsonIgnore + @Override + public void visit(Consumer callback) throws Exception { + traverseChild(this, callback); + } + + private void traverseChild(Container container, Consumer callback) throws Exception { + for (ComponentExporter component : container.getItems()) { + callback.accept(component); + + if (component instanceof Container) { + traverseChild((Container) component, callback); + } + } + } + + @Override + @JsonIgnore + public String getParentPagePath() { + if (resource != null) { + PageManager pm = resource.getResourceResolver().adaptTo(PageManager.class); + if (pm != null) { + Page page = pm.getContainingPage(resource); + return page != null ? page.getPath() : StringUtils.EMPTY; + } + } + return StringUtils.EMPTY; + } + + @Override + public String getName() { + return FormContainer.super.getName(); + } + + @Override + public String getCustomFunctionUrl() { + String customFunctionUrl; + if ("publish".equals(runModeConfigService.getRunMode())) { + customFunctionUrl = getContextPath() + PREFIX_PATH + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/customfunctions/" + getId(); + } else { + customFunctionUrl = getContextPath() + ADOBE_GLOBAL_API_ROOT + FORMS_RUNTIME_API_GLOBAL_ROOT + "/customfunctions/" + getId(); + } + return customFunctionUrl; + } + +} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/ReservedProperties.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/ReservedProperties.java new file mode 100644 index 0000000000..13f7d5ae21 --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/models/formcontainer/ReservedProperties.java @@ -0,0 +1,172 @@ +package com.adobe.cq.forms.core.components.it.models.formcontainer; + +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.adobe.cq.forms.core.components.models.form.FormContainer; +import com.adobe.cq.wcm.core.components.models.Component; +import com.adobe.cq.wcm.core.components.models.Title; + +public final class ReservedProperties { + private ReservedProperties() { + // NOOP + } + + private static final Logger logger = LoggerFactory.getLogger(ReservedProperties.class); + + public static final String PN_ID = Component.PN_ID; + public static final String PN_VIEWTYPE = "fd:viewType"; + public static final String PN_FIELDTYPE = "fieldType"; + public static final String PN_DATAREF = "dataRef"; + public static final String PN_NAME = "name"; + public static final String PN_VALUE = "value"; + public static final String PN_ICON = "icon"; + public static final String PN_DATA = "data"; + public static final String PN_SIZE = "size"; + public static final String PN_VISIBLE = "visible"; + public static final String PN_UNBOUND_FORM_ELEMENT = "unboundFormElement"; + public static final String PN_DOR_EXCLUSION = "dorExclusion"; + public static final String PN_DOR_COLSPAN = "dorColspan"; + public static final String PN_DOR_BINDREF = "dorBindRef"; + public static final String PN_DOR_EXCLUDE_TITLE = "dorExcludeTitle"; + public static final String PN_DOR_EXCLUDE_DESC = "dorExcludeDescription"; + public static final String PN_DOR_NUM_COLS = "dorNumCols"; + public static final String PN_DOR_LAYOUT_TYPE = "dorLayoutType"; + public static final String PN_DESCRIPTION = "description"; + public static final String PN_TOOLTIP = "tooltip"; + public static final String PN_DOR_TEMPLATE_TYPE = "fd:formType"; + public static final String PN_TOOLTIP_VISIBLE = "tooltipVisible"; + public static final String PN_TYPE = "type"; + public static final String PN_DOR_TEMPLATE_REF = "dorTemplateRef"; + public static final String PN_DOR_TYPE = "dorType"; + public static final String PN_VALIDATION_EXPRESSION = "validationExpression"; + public static final String PN_REQUIRED = "required"; + public static final String PN_AUTOCOMPLETE = "autocomplete"; + public static final String PN_ASSIST_PRIORITY = "assistPriority"; + public static final String PN_CUSTOM = "custom"; + public static final String PN_ENABLED = "enabled"; + public static final String PN_REPEATABLE = "repeatable"; + public static final String PN_MIN_OCCUR = "minOccur"; + public static final String PN_MAX_OCCUR = "maxOccur"; + public static final String PN_MIN_ITEMS = "minItems"; + public static final String PN_MAX_ITEMS = "maxItems"; + public static final String PN_LANG = "lang"; + public static final String PN_LANG_DISPLAY_VALUE = "langDisplayValue"; + public static final String PN_PLACEHOLDER = "placeholder"; + public static final String PN_READ_ONLY = "readOnly"; + public static final String PN_DEFAULT_VALUE = "default"; + public static final String PN_FORMAT = "format"; + public static final String PN_DISPLAY_FORMAT = "displayFormat"; + public static final String PN_EDIT_FORMAT = "editFormat"; + public static final String PN_DISPLAY_VALUE_EXPRESSION = "displayValueExpression"; + public static final String PN_DATA_FORMAT = "dataFormat"; + public static final String PN_MIN_LENGTH = "minLength"; + public static final String PN_MAX_LENGTH = "maxLength"; + public static final String PN_MINIMUM_DATE = "minimumDate"; + public static final String PN_MAXIMUM_DATE = "maximumDate"; + public static final String PN_MAXIMUM = "maximum"; + public static final String PN_MINIMUM = "minimum"; + public static final String PN_EXCLUSIVE_MINIMUM = "exclusiveMinimum"; + public static final String PN_EXCLUSIVE_MAXIMUM = "exclusiveMaximum"; + public static final String PN_EXCLUDE_MINIMUM = "excludeMinimum"; + public static final String PN_EXCLUDE_MAXIMUM = "excludeMaximum"; + public static final String PN_EXCLUDE_MINIMUM_CHECK = "excludeMinimumCheck"; + public static final String PN_EXCLUDE_MAXIMUM_CHECK = "excludeMaximumCheck"; + public static final String PN_ENFORCE_ENUM = "enforceEnum"; + public static final String PN_ENUM = "enum"; + public static final String PN_ENUM_NAMES = "enumNames"; + public static final String PN_TITLE = "title"; + public static final String PN_HIDE_TITLE = "hideTitle"; + public static final String PN_IS_TITLE_RICH_TEXT = "isTitleRichText"; + public static final String PN_ORIENTATION = "orientation"; + public static final String PN_TYPE_MESSAGE = "typeMessage"; + public static final String PN_REQUIRED_MESSAGE = "mandatoryMessage"; // reusing the same property name as in foundation + public static final String PN_MINIMUM_MESSAGE = "minimumMessage"; + public static final String PN_MAXIMUM_MESSAGE = "maximumMessage"; + public static final String PN_MINLENGTH_MESSAGE = "minLengthMessage"; + public static final String PN_MAXLENGTH_MESSAGE = "maxLengthMessage"; + public static final String PN_MAX_FILE_SIZE_MESSAGE = "maxFileSizeMessage"; // for fileInput min, max number of files, maximum file size + // and accept of file type messages + public static final String PN_ACCEPT_MESSAGE = "acceptMessage"; + public static final String PN_STEP_MESSAGE = "stepMessage"; + public static final String PN_FORMAT_MESSAGE = "formatMessage"; + public static final String PN_PATTERN = "pattern"; + public static final String PN_PATTERN_MESSAGE = "validatePictureClauseMessage"; // reusing the same property name as in foundation + public static final String PN_MINITEMS_MESSAGE = "minItemsMessage"; + public static final String PN_MAXITEMS_MESSAGE = "maxItemsMessage"; + public static final String PN_UNIQUE_ITEMS_MESSAGE = "uniqueItemsMessage"; + public static final String PN_ENFORCE_ENUM_MESSAGE = "enforceEnumMessage"; + public static final String PN_VALIDATION_EXPRESSION_MESSAGE = "validateExpMessage"; // reusing the same property name as in foundation + public static final String PN_MULTISELECT = "multiSelect"; + public static final String PN_MULTISELECTION = "multiSelection"; + public static final String PN_ENABLE_UNCHECKED_VALUE = "enableUncheckedValue"; + public static final String PN_CHECKED_VALUE = "checkedValue"; + public static final String PN_UNCHECKED_VALUE = "uncheckedValue"; + public static final String PN_MAX_FILE_SIZE = "maxFileSize"; + public static final String PN_FILE_ACCEPT = "accept"; + public static final String PN_BUTTON_TEXT = "buttonText"; + public static final String PN_WRAP_DATA = "wrapData"; + public static final String PN_FRAGMENT_PATH = "fragmentPath"; + public static final String PN_BUTTON_TYPE = "buttonType"; + public static final String PN_THANK_YOU_MSG_V1 = "thankyouMessage"; + public static final String PN_THANK_YOU_MSG_V2 = "thankYouMessage"; + public static final String PN_THANK_YOU_OPTION = "thankYouOption"; + public static final String PN_RUNTIME_DOCUMENT_PATH = FormContainer.PN_RUNTIME_DOCUMENT_PATH; + public static final String PN_CLOUD_SERVICE_PATH = "cloudServicePath"; + public static final String PN_RECAPTCHA_CLOUD_SERVICE_PATH = "rcCloudServicePath"; + public static final String PN_RECAPTCHA_SIZE = "recaptchaSize"; + public static final String PN_BREAK_BEFORE_TEXT = "breakBeforeText"; + public static final String PN_BREAK_AFTER_TEXT = "breakAfterText"; + public static final String PN_OVERFLOW_TEXT = "overflowText"; + public static final String PN_ALT_TEXT = "altText"; + public static final String PN_IMAGE_SRC = "imageSrc"; + public static final String PN_FILE_REF = "fileReference"; + public static final String PN_SHOW_APPROVAL_OPTION = "showApprovalOption"; + public static final String PN_SHOW_LINK = "showLink"; + public static final String PN_SHOW_AS_POPUP = "showAsPopup"; + public static final String PN_TEXT_IS_RICH = "textIsRich"; + public static final String PN_MULTILINE = "multiLine"; + public static final String PN_DESIGN_DEFAULT_TYPE = Title.PN_DESIGN_DEFAULT_TYPE; + public static final String PN_TITLE_LINK_DISABLED = Title.PN_TITLE_LINK_DISABLED; + public static final String PN_DRAG_DROP_TEXT = "dragDropText"; + public static final String PN_DRAG_DROP_TEXT_V3 = "fd:dragDropText"; + public static final String PN_CLIENTLIB_REF = "clientLibRef"; + public static final String PN_REDIRECT = "redirect"; + public static final String PN_PREFILL_SERVICE = "prefillService"; + public static final String PN_SPEC_VERSION = "specVersion"; + public static final String PN_RICH_TEXT = "richText"; + public static final String PN_OPTIONS_RICH_TEXT = "areOptionsRichText"; + public static final String PN_EXCLUDE_FROM_DOR = "excludeFromDor"; + public static final String PN_MANDATORY = "mandatory"; + public static final String PN_HTML_ELEMENT_TYPE_V2 = "fd:htmlelementType"; + public static final String FD_AUTO_SAVE_PROPERTY_WRAPPER = "fd:autoSave"; + public static final String FD_ENABLE_AUTO_SAVE = "fd:enableAutoSave"; + public static final String FD_AUTO_SAVE_STRATEGY_TYPE = "fd:autoSaveStrategyType"; + public static final String FD_AUTO_SAVE_INTERVAL = "fd:autoSaveInterval"; + private static final Set reservedProperties = aggregateReservedProperties(); + + private static Set aggregateReservedProperties() { + Set reservedProperties = new HashSet<>(); + Field[] fields = ReservedProperties.class.getDeclaredFields(); + + for (Field field : fields) { + if (field.getType().equals(String.class)) { + try { + reservedProperties.add((String) field.get(null)); + } catch (IllegalAccessException e) { + logger.error("[AF] Error while accessing field: {}", field.getName(), e); + } + } + } + + return reservedProperties; + } + + public static Set getReservedProperties() { + return reservedProperties; + } +} diff --git a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java index a9ecb55c06..46fadaaa24 100644 --- a/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java @@ -51,18 +51,29 @@ public void startElement(String uri, String localName, String qName, Attributes throws SAXException { AttributesImpl mutableAttributes = attributes instanceof AttributesImpl ? (AttributesImpl) attributes - : null; + : new AttributesImpl(attributes); if (isPublish) { if ("link".equals(localName)) { - mutableAttributes = mutableAttributes != null ? mutableAttributes : new AttributesImpl(attributes); replaceLinkPaths(mutableAttributes); - } else if ("script".equals(localName)) { - mutableAttributes = mutableAttributes != null ? mutableAttributes : new AttributesImpl(attributes); - replaceScriptPaths(mutableAttributes); + } else if ("script".equals(localName) || "img".equals(localName)) { + replaceAttributePaths(mutableAttributes, "src"); + } else if ("form".equals(localName)) { + replaceAttributePaths(mutableAttributes, "data-cmp-path"); + } else if ("div".equals(localName)) { + replaceAttributePaths(mutableAttributes, "data-cmp-adaptiveformcontainer-path"); } } + super.startElement(uri, localName, qName, - mutableAttributes != null ? mutableAttributes : attributes); + mutableAttributes); + } + + private void replaceAttributePaths(AttributesImpl attributes, String attributeName) { + if (attributes.getIndex(attributeName) >= 0) { + int index = attributes.getIndex(attributeName); + String value = attributes.getValue(index); + setAttribute(attributes, index, addPathPrefix(value)); + } } private void replaceLinkPaths(AttributesImpl attributes) { @@ -76,14 +87,6 @@ private void replaceLinkPaths(AttributesImpl attributes) { } } - private void replaceScriptPaths(AttributesImpl attributes) { - if (attributes.getIndex("src") >= 0) { - int index = attributes.getIndex("src"); - String value = attributes.getValue(index); - setAttribute(attributes, index, addPathPrefix(value)); - } - } - private String addPathPrefix(String url) { return "/" + PATH_PREFIX + url; } From ac781890b932688631f624ad79a7e0f83cd945c0 Mon Sep 17 00:00:00 2001 From: Barshat Rai Date: Wed, 2 Apr 2025 14:33:02 +0530 Subject: [PATCH 5/5] osgi config for rewriter --- ...nts.it.service.rewriter.CustomRunModeConfiguration.cfg.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 it/config/src/main/content/jcr_root/apps/system/config/com.adobe.cq.forms.core.components.it.service.rewriter.CustomRunModeConfiguration.cfg.json diff --git a/it/config/src/main/content/jcr_root/apps/system/config/com.adobe.cq.forms.core.components.it.service.rewriter.CustomRunModeConfiguration.cfg.json b/it/config/src/main/content/jcr_root/apps/system/config/com.adobe.cq.forms.core.components.it.service.rewriter.CustomRunModeConfiguration.cfg.json new file mode 100644 index 0000000000..19be39d8ff --- /dev/null +++ b/it/config/src/main/content/jcr_root/apps/system/config/com.adobe.cq.forms.core.components.it.service.rewriter.CustomRunModeConfiguration.cfg.json @@ -0,0 +1,3 @@ +{ + "runmode.info": "publish" +}