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..512e5acdda --- /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/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" +} 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/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/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 new file mode 100644 index 0000000000..46fadaaa24 --- /dev/null +++ b/it/core/src/main/java/com/adobe/cq/forms/core/components/it/service/rewriter/CustomCloudRewriterTransformer.java @@ -0,0 +1,102 @@ +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 + : new AttributesImpl(attributes); + if (isPublish) { + if ("link".equals(localName)) { + replaceLinkPaths(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); + } + + 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) { + 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 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"; + } + } +}