diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/servlets/FormMetaDataDataSourceServlet.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/servlets/FormMetaDataDataSourceServlet.java index 22ab9d1441..369eb92eea 100644 --- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/servlets/FormMetaDataDataSourceServlet.java +++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/servlets/FormMetaDataDataSourceServlet.java @@ -87,7 +87,8 @@ public enum FormMetaDataType { PREFILL_ACTION("prefillServiceProvider"), LANG("lang"), FORMATTERS("formatters"), - SSV_CLOUD_CONFIG("ssvCloudServiceConfiguration"); + SSV_CLOUD_CONFIG("ssvCloudServiceConfiguration"), + FILE_ATTACHMENT_VALIDATOR("fileAttachmentValidator"); private String value; @@ -181,12 +182,13 @@ private List getDataSourceResources(SlingHttpServletRequest request, R FormMetaData formMetaData = resourceResolver.adaptTo(FormMetaData.class); if (formMetaData != null) { Iterator metaDataList = null; + I18n i18n = new I18n(request.getResourceBundle(request.getLocale())); switch (type) { case FORMATTERS: case LANG: ContentPolicy policy = ComponentUtils.getPolicy((String) request.getAttribute(Value.CONTENTPATH_ATTRIBUTE), resourceResolver); - resources.add(getResourceForDropdownDisplay(resourceResolver, "Select", "")); + resources.add(getResourceForDropdownDisplay(resourceResolver, i18n.get("Select"), "")); if (policy != null) { ValueMap props = policy.getProperties(); if (props != null) { @@ -204,7 +206,7 @@ private List getDataSourceResources(SlingHttpServletRequest request, R } } } - resources.add(getResourceForDropdownDisplay(resourceResolver, "Custom", "custom")); + resources.add(getResourceForDropdownDisplay(resourceResolver, i18n.get("Custom"), "custom")); break; case SUBMIT_ACTION: // filter the submit actions by uniqueness and data model @@ -223,7 +225,12 @@ private List getDataSourceResources(SlingHttpServletRequest request, R case PREFILL_ACTION: metaDataList = formMetaData.getPrefillActions(); // Add an explicit empty option so authors can clear an already selected prefill service. - I18n i18n = new I18n(request.getResourceBundle(request.getLocale())); + resources.add(getResourceForDropdownDisplay(resourceResolver, i18n.get("None"), "")); + resources.addAll(this.getResourceListFromComponentDescription(metaDataList, resourceResolver)); + break; + case FILE_ATTACHMENT_VALIDATOR: + metaDataList = formMetaData.getFileAttachmentValidators(); + // Add an explicit empty option so authors can clear an already selected file attachment validator. resources.add(getResourceForDropdownDisplay(resourceResolver, i18n.get("None"), "")); resources.addAll(this.getResourceListFromComponentDescription(metaDataList, resourceResolver)); break; diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/Utils.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/Utils.java index ad6744e94a..a31e7212d5 100644 --- a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/Utils.java +++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/Utils.java @@ -28,6 +28,7 @@ import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; +import org.apache.sling.api.scripting.SlingBindings; import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest; import org.jetbrains.annotations.NotNull; @@ -252,4 +253,22 @@ public static Method getPrivateMethod(Class clazz, String privateMethodName) { return null; } } + + /** + * Removes the request's {@link SlingBindings} attribute so the AF locale-resolution code in + * {@code GuideUtils} takes its {@code bindings == null} branches. + *

+ * Call this in tests that set an AF language parameter before adapting/using a model. Newer + * {@code aem-forms-sdk-api} versions resolve the locale via {@code GuideUtils}, and when a + * {@link SlingBindings} is present they look up services through {@code bindings.getSling()}: + * {@code getSanitizedLocale(...)} fetches the runtime-only Granite {@code ToggleRouter} (absent + * from the test classpath → {@link NoClassDefFoundError}), and {@code getLocaleParamFromRequest(...)} + * fetches {@code GuideLocalizationService} via {@code getSling()} without null-guarding it. Both + * are skipped entirely when the {@code SlingBindings} attribute is absent, and the locale is then + * taken from the {@code afAcceptLang} request parameter (which these tests set) — the same result + * expected in production for that parameter, since no {@code ToggleRouter} is registered in tests. + */ + public static void disableLocaleFeatureToggleLookup(MockSlingHttpServletRequest request) { + request.setAttribute(SlingBindings.class.getName(), null); + } } diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/HCaptchaImplTest.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/HCaptchaImplTest.java index 097e78a012..d8c84db53b 100644 --- a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/HCaptchaImplTest.java +++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/HCaptchaImplTest.java @@ -60,6 +60,11 @@ public String getCustomFunctionUrl(Resource resource) { return null; } + @Override + public String getCustomFunctionFranklinProxyUrl(Resource resource) { + return null; + } + @Override public HCaptchaConfiguration getHCaptchaCloudConfiguration(Resource resource) throws GuideException { return hCaptchaConfiguration; diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/RecaptchaImplTest.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/RecaptchaImplTest.java index 3e47210250..27a72bc697 100644 --- a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/RecaptchaImplTest.java +++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/RecaptchaImplTest.java @@ -61,6 +61,11 @@ public String getCustomFunctionUrl(Resource resource) { return null; } + @Override + public String getCustomFunctionFranklinProxyUrl(Resource resource) { + return null; + } + @Override public HCaptchaConfiguration getHCaptchaCloudConfiguration(Resource resource) throws GuideException { return null; diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TitleImplTest.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TitleImplTest.java index 405ec23c99..8f7f99ac1b 100644 --- a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TitleImplTest.java +++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TitleImplTest.java @@ -170,6 +170,7 @@ void testTitleWithLocale() throws Exception { Map paramMap = new HashMap<>(); paramMap.put(GuideConstants.AF_LANGUAGE_PARAMETER, "de"); request.setParameterMap(paramMap); + Utils.disableLocaleFeatureToggleLookup(request); Title title = request.adaptTo(Title.class); assertEquals("Title", title.getText()); } diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TurnstileImplTest.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TurnstileImplTest.java index d54786385b..692f693b2f 100644 --- a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TurnstileImplTest.java +++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/TurnstileImplTest.java @@ -59,6 +59,11 @@ public String getCustomFunctionUrl(Resource resource) { return null; } + @Override + public String getCustomFunctionFranklinProxyUrl(Resource resource) { + return null; + } + @Override public HCaptchaConfiguration getHCaptchaCloudConfiguration(Resource resource) throws GuideException { return null; diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/FormContainerImplTest.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/FormContainerImplTest.java index 3fb34c9baf..22ef247eb0 100644 --- a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/FormContainerImplTest.java +++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/FormContainerImplTest.java @@ -485,6 +485,7 @@ private FormContainer getFormContainerWithLocaleUnderTest(String resourcePath) t Map paramMap = new HashMap<>(); paramMap.put(GuideConstants.AF_LANGUAGE_PARAMETER, "de"); request.setParameterMap(paramMap); + Utils.disableLocaleFeatureToggleLookup(request); context.currentResource().adaptTo(FormContainer.class); return request.adaptTo(FormContainer.class); } @@ -507,6 +508,7 @@ private FormContainer getFormContainerWithRTLLocaleUnderTest(String resourcePath Map paramMap = new HashMap<>(); paramMap.put(GuideConstants.AF_LANGUAGE_PARAMETER, "ar-ae"); request.setParameterMap(paramMap); + Utils.disableLocaleFeatureToggleLookup(request); context.currentResource().adaptTo(FormContainer.class); return request.adaptTo(FormContainer.class); } diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/TitleImplV2Test.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/TitleImplV2Test.java index e62908a127..713339d9ce 100644 --- a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/TitleImplV2Test.java +++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/TitleImplV2Test.java @@ -197,6 +197,7 @@ void testTitleWithLocale() throws Exception { Map paramMap = new HashMap<>(); paramMap.put(GuideConstants.AF_LANGUAGE_PARAMETER, "de"); request.setParameterMap(paramMap); + Utils.disableLocaleFeatureToggleLookup(request); FormTitle title = request.adaptTo(FormTitle.class); assertEquals("Title", title.getText()); } diff --git a/parent/pom.xml b/parent/pom.xml index 008698915f..40835611ca 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -1136,7 +1136,7 @@ com.adobe.aem aem-forms-sdk-api - 2024.09.08.00-240800 + 2026.06.27.00-260700 diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/_cq_dialog/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/_cq_dialog/.content.xml index 9ce011f785..7ce0ab65c4 100644 --- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/_cq_dialog/.content.xml +++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/_cq_dialog/.content.xml @@ -372,6 +372,26 @@ + + + +