diff --git a/.circleci/config.yml b/.circleci/config.yml index c10d4918fa..fb1179c3a5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -121,6 +121,9 @@ executors: forms_executor_java8: docker: - image: cimg/openjdk:8.0-browsers + forms_executor_java21: + docker: + - image: cimg/openjdk:21.0-browsers test_executor_cloudready: docker: - image: docker-adobe-cif-release.dr-uw2.adobeitc.com/circleci-qp:6.4.6-openjdk11 @@ -137,7 +140,7 @@ executors: docker: - image: docker-adobe-cif-release.dr-uw2.adobeitc.com/circleci-qp:6.4.6-openjdk11 <<: *docker_auth - - image: docker-adobe-cif-release.dr-uw2.adobeitc.com/circleci-aem:6.5.24-load4-openjdk11 + - image: docker-adobe-cif-release.dr-uw2.adobeitc.com/circleci-aem:6.5.24.0-openjdk11 <<: *docker_auth jobs: @@ -185,6 +188,30 @@ jobs: conf: .circleci/codecov.yml flags: unittests + build-java-21: + executor: forms_executor_java21 + working_directory: /home/circleci/build + steps: + - checkout + - restore_cache: + keys: + - maven-repo-java21-v1-{{ checksum "pom.xml" }} + - maven-repo-java21-v1- + - run: + name: Update permissions + command: sudo chown -R circleci /usr/local/lib/node_modules + - run: + name: Build with Java 21 + command: node .circleci/ci/build.js + - save_cache: + paths: + - ~/.m2 + key: maven-repo-java21-v1-{{ .Branch }}-{{ checksum "pom.xml" }} + - store_test_results: + path: bundles/core/target/surefire-reports + - store_artifacts: + path: bundles/core/target/surefire-reports + build-java-8: executor: forms_executor_java8 working_directory: /home/circleci/build @@ -416,6 +443,10 @@ workflows: filters: tags: only: /.*/ + - build-java-21: + filters: + tags: + only: /.*/ - build-java-8: filters: tags: diff --git a/bundles/af-core/pom.xml b/bundles/af-core/pom.xml index 6f69c7b346..f42a1f43c1 100644 --- a/bundles/af-core/pom.xml +++ b/bundles/af-core/pom.xml @@ -573,7 +573,7 @@ org.junit.platform junit-platform-commons - 1.5.2 + 1.10.2 test + + net.bytebuddy + byte-buddy + 1.14.17 + org.powermock powermock-api-mockito2 diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml index cb940073d0..c484806166 100644 --- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml +++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml @@ -5,4 +5,4 @@ cssProcessor="[default:none,min:none]" jsProcessor="[default:none,min:none]" categories="[core.forms.components.runtime.all]" - embed="[core.forms.components.runtime.base,core.forms.components.container.v2.runtime,core.forms.components.datePicker.v1.runtime,core.forms.components.textinput.v1.runtime,core.forms.components.numberinput.v1.runtime,core.forms.components.panelcontainer.v1.runtime,core.forms.components.radiobutton.v1.runtime,core.forms.components.text.v1.runtime,core.forms.components.checkboxgroup.v1.runtime,core.forms.components.button.v1.runtime,core.forms.components.image.v1.runtime,core.forms.components.dropdown.v1.runtime,core.forms.components.fileinput.v4.runtime,core.forms.components.accordion.v1.runtime,core.forms.components.tabs.v1.runtime,core.forms.components.wizard.v1.runtime,core.forms.components.verticaltabs.v1.runtime,core.forms.components.recaptcha.v1.runtime,core.forms.components.checkbox.v1.runtime,core.forms.components.fragment.v1.runtime,core.forms.components.switch.v1.runtime,core.forms.components.termsandconditions.v1.runtime, core.forms.components.review.v1.runtime,core.forms.components.scribble.v1.runtime, core.forms.components.datetime.v1.runtime]"/> + embed="[core.forms.components.runtime.base,core.forms.components.container.v2.runtime,core.forms.components.datePicker.v1.runtime,core.forms.components.textinput.v1.runtime,core.forms.components.numberinput.v1.runtime,core.forms.components.panelcontainer.v1.runtime,core.forms.components.radiobutton.v2.runtime,core.forms.components.text.v1.runtime,core.forms.components.checkboxgroup.v1.runtime,core.forms.components.button.v1.runtime,core.forms.components.image.v1.runtime,core.forms.components.dropdown.v1.runtime,core.forms.components.fileinput.v4.runtime,core.forms.components.accordion.v1.runtime,core.forms.components.tabs.v1.runtime,core.forms.components.wizard.v1.runtime,core.forms.components.verticaltabs.v1.runtime,core.forms.components.recaptcha.v1.runtime,core.forms.components.checkbox.v1.runtime,core.forms.components.fragment.v1.runtime,core.forms.components.switch.v1.runtime,core.forms.components.termsandconditions.v1.runtime,core.forms.components.review.v1.runtime,core.forms.components.scribble.v1.runtime,core.forms.components.datetime.v1.runtime]"/> diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/af-commons/v1/fieldTemplates/legend.html b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/af-commons/v1/fieldTemplates/legend.html new file mode 100644 index 0000000000..83174f3118 --- /dev/null +++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/af-commons/v1/fieldTemplates/legend.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/actions/submit/v1/submit/README.md b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/actions/submit/v1/submit/README.md index 3ed57c1e5b..1901b3eed3 100644 --- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/actions/submit/v1/submit/README.md +++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/actions/submit/v1/submit/README.md @@ -23,6 +23,7 @@ Adaptive Form Submit Button component written in HTL. * Custom description/tooltip for help * Out of the box Submit rule in the button to submit the form * Allows replacing this component with other component (as mentioned below). +* Shows a loader on the form container during submission ### Use Object The submit button component uses the `com.adobe.cq.forms.core.components.models.form.Button` Sling Model for its Use-object. @@ -41,6 +42,14 @@ The button has a default property of `buttonType` set to `submit` which is used The component provides a `core.forms.components.button.v1.runtime` client library category that contains the Javascript runtime for the component. It should be added to a relevant site client library using the `embed` property. +### Loader behavior on submit + +When the Submit button is activated and the form begins submission, the form container gets a loading state so users receive visual feedback: + +- The form element `form.cmp-adaptiveform-container` toggles the CSS class `cmp-adaptiveform-container--submitting` for the duration of the network request. +- The loading class is removed and the loader hides when validation fails, the submission succeeds, or an error occurs. + + ## BEM Description ``` BLOCK cmp-adaptiveform-button @@ -83,7 +92,4 @@ We support replace feature that allows replacing Reset Button component to any o * **Vendor**: Adobe * **Version**: v1 * **Compatibility**: Cloud -* **Status**: production-ready - - - +* **Status**: production-ready \ No newline at end of file diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/button/v1/button/clientlibs/site/js/buttonview.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/button/v1/button/clientlibs/site/js/buttonview.js index dc7512fc63..bcda72d280 100644 --- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/button/v1/button/clientlibs/site/js/buttonview.js +++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/button/v1/button/clientlibs/site/js/buttonview.js @@ -36,6 +36,50 @@ tooltipDiv: `.${Button.bemBlock}__shortdescription` }; + constructor(params) { + super(params); + const formModel = this.formContainer?.getModel?.(); + if (!formModel) { return; } + + formModel.subscribe((action) => { // hide loader if validation fails (no submit performed) + const errors = action?.payload; + if (Array.isArray(errors) && errors.length > 0) { + this._hideLoader(); + } + }, 'validationComplete'); + + formModel.subscribe(() => { // hide loader on submit success + this._hideLoader(); + }, 'submitSuccess'); + + formModel.subscribe(() => { // hide loader on submit error + this._hideLoader(); + }, 'submitError'); + } + + _container = null; + + _getContainer() { + if (this._container) return this._container; + const container = this.formContainer?.getFormElement?.(); + if (container) this._container = container; + return this._container; + } + + _showLoader() { + const container = this._getContainer(); + if (container) { + container.classList.add('cmp-adaptiveform-container--submitting'); + } + } + + _hideLoader() { + const container = this._getContainer(); + if (container) { + container.classList.remove('cmp-adaptiveform-container--submitting'); + } + } + getQuestionMarkDiv() { return this.element.querySelector(Button.selectors.qm); } @@ -70,6 +114,9 @@ if (this.widget.type === 'submit' || this.widget.type === 'reset') { event.preventDefault(); } + if (this.widget.type === 'submit') { + this._showLoader(); + } this._model.dispatch(new FormView.Actions.Click()); }); } @@ -79,4 +126,4 @@ return new Button({element, formContainer}) }, Button.selectors.self); -})(); +})(); \ No newline at end of file diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/checkbox/v1/checkbox/clientlibs/editor/js/editDialog.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/checkbox/v1/checkbox/clientlibs/editor/js/editDialog.js index 5b1ba091f4..67a6ff0c58 100644 --- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/checkbox/v1/checkbox/clientlibs/editor/js/editDialog.js +++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/checkbox/v1/checkbox/clientlibs/editor/js/editDialog.js @@ -79,17 +79,29 @@ function handleDataTypeSelectionAndValidation(dialog) { var dataTypeSelect = dialog.find(DATA_TYPE + " coral-select"); var preselectedDataType = dataTypeSelect[0].selectedItem ? dataTypeSelect[0].selectedItem.value : ''; - if (preselectedDataType == 'boolean') { - dialog.find(ENUMS).hide(); + var checkedValueSelector = 'input[name="./checkedValue"]'; + + function applyCheckedValueBehavior(dataType) { // function which applies checked value behavior based for boolean data type + var checkedValueInput = document.querySelector(checkedValueSelector); + if (!checkedValueInput) { + return; + } + if (dataType === 'boolean') { + checkedValueInput.value = 'true'; + checkedValueInput.setAttribute('readonly', 'readonly'); + } else { + checkedValueInput.removeAttribute('readonly'); + } } + // Apply initial behavior based on preselected type + applyCheckedValueBehavior(preselectedDataType); + dataTypeSelect.on('change', function() { var selectedDataType = dataTypeSelect[0].selectedItem ? dataTypeSelect[0].selectedItem.value : ''; - if (selectedDataType == 'boolean') { - dialog.find(ENUMS).hide(); - } else { - dialog.find(ENUMS).show(); - } + dialog.find(ENUMS).show(); // Keep enums visible for all data types (including boolean) + + applyCheckedValueBehavior(selectedDataType); // Toggle checked value input behavior based on data type }); var registerValidator = function(selector, validate) { diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/checkboxgroup/v1/checkboxgroup/checkboxgroup.html b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/checkboxgroup/v1/checkboxgroup/checkboxgroup.html index 96c0ceafe7..3c524e065c 100644 --- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/checkboxgroup/v1/checkboxgroup/checkboxgroup.html +++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/checkboxgroup/v1/checkboxgroup/checkboxgroup.html @@ -13,7 +13,6 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/--> -