From 8d064f0fc44455380c06a626da50eca79718e2b8 Mon Sep 17 00:00:00 2001
From: Andreas Kienast <a.fernandez@scripting-base.de>
Date: Tue, 20 Feb 2024 10:42:34 +0100
Subject: [PATCH] [TASK] Remove `then()` callback hell in EXT:form wizard

The code of the form creation wizard is cleaned up a bit. The nested
`then()` callback hell is replaced with proper async/await statements to
make the code more readable.

Resolves: #103156
Releases: main
Change-Id: I144d6be0c3608f7d412dbefd031dd4d0ce4a3a42
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/83041
Tested-by: Benjamin Franzke <ben@bnf.dev>
Tested-by: Andreas Nedbal <andy@pixelde.su>
Reviewed-by: Benjamin Franzke <ben@bnf.dev>
Reviewed-by: Andreas Kienast <a.fernandez@scripting-base.de>
Reviewed-by: Andreas Nedbal <andy@pixelde.su>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Andreas Kienast <a.fernandez@scripting-base.de>
---
 .../form/backend/form-manager/view-model.ts   | 470 +++++++++---------
 .../backend/form-manager/view-model.js        |   2 +-
 2 files changed, 232 insertions(+), 240 deletions(-)

diff --git a/Build/Sources/TypeScript/form/backend/form-manager/view-model.ts b/Build/Sources/TypeScript/form/backend/form-manager/view-model.ts
index e4eb2ec6a038..b10b66f82928 100644
--- a/Build/Sources/TypeScript/form/backend/form-manager/view-model.ts
+++ b/Build/Sources/TypeScript/form/backend/form-manager/view-model.ts
@@ -61,80 +61,78 @@ function newFormSetup(formManagerApp: FormManager): void {
     /**
      * Wizard step 1
      */
-    MultiStepWizard.addSlide('new-form-step-1', TYPO3.lang['formManager.newFormWizard.step1.title'], '', Severity.info, TYPO3.lang['formManager.newFormWizard.step1.progressLabel'], function(slide) {
-      Icons.getIcon('actions-plus', Icons.sizes.small).then(function (addIconMarkup) {
-        Icons.getIcon('form-page', Icons.sizes.large).then(function (duplicateIconMarkup) {
-          Icons.getIcon('apps-pagetree-page-default', Icons.sizes.large).then(function (blankIconMarkup) {
-            let html;
-            const modal = MultiStepWizard.setup.$carousel.closest('.modal');
-            const nextButton = modal.find('.modal-footer').find('button[name="next"]');
-
-            MultiStepWizard.blurCancelStep();
-            MultiStepWizard.lockNextStep();
-            MultiStepWizard.lockPrevStep();
-
-            const folders = formManagerApp.getAccessibleFormStorageFolders();
-            if (folders.length === 0) {
-              html = '<div class="new-form-modal">'
-                + '<div class="row">'
-                + '<label class="col col-form-label">' + TYPO3.lang['formManager.newFormWizard.step1.noStorages'] + '</label>'
-                + '</div>'
-                + '</div>';
-
-              slide.html(html);
-              formManagerApp.assert(false, 'No accessible form storage folders', 1477506500);
-            }
-
-            html = '<div class="new-form-modal">'
-
-            html += '<div class="card-container">'
-              + '<div class="card card-size-medium">'
-              + '<div class="card-header">'
-              + '<div class="card-icon">' + blankIconMarkup + '</div>'
-              + '<div class="card-header-body">'
-              + '<h2 class="card-title">' + TYPO3.lang['formManager.blankForm.label'] + '</h2>'
-              + '<span class="card-subtitle">' + TYPO3.lang['formManager.blankForm.subtitle'] + '</span>'
-              + '</div>'
-              + '</div>'
-              + '<div class="card-body">'
-              + '<p class="card-text">' + TYPO3.lang['formManager.blankForm.description'] + '</p>'
-              + '</div>'
-              + '<div class="card-footer">'
-              + '<button type="button" class="btn btn-success" data-inline="1" value="blank" data-identifier="newFormModeButton">' + addIconMarkup + ' ' + TYPO3.lang['formManager.blankForm.label'] + '</button>'
-              + '</div>'
-              + '</div>'
-              + '<div class="card card-size-medium">'
-              + '<div class="card-header">'
-              + '<div class="card-icon">' + duplicateIconMarkup + '</div>'
-              + '<div class="card-header-body">'
-              + '<h2 class="card-title">' + TYPO3.lang['formManager.predefinedForm.label'] + '</h2>'
-              + '<span class="card-subtitle">' + TYPO3.lang['formManager.predefinedForm.subtitle'] + '</span>'
-              + '</div>'
-              + '</div>'
-              + '<div class="card-body">'
-              + '<p class="card-text">' + TYPO3.lang['formManager.predefinedForm.description'] + '</p>'
-              + '</div>'
-              + '<div class="card-footer">'
-              + '<button type="button" class="btn btn-success" data-inline="1" value="predefined" data-identifier="newFormModeButton">' + addIconMarkup + ' ' + TYPO3.lang['formManager.predefinedForm.label'] + '</button>'
-              + '</div>'
-              + '</div>';
-
-            html += '</div>';
-
-            slide.html(html);
-
-            $(Identifiers.newFormModeButton, modal).on('click', function (e: Event) {
-              MultiStepWizard.set('newFormMode', $(e.currentTarget).val());
-              MultiStepWizard.unlockNextStep().get(0).click();
-            });
-
-            nextButton.on('click', function() {
-              Icons.getIcon('spinner-circle', Icons.sizes.default, null, null).then(function(markup) {
-                slide.html($('<div />', { class: 'text-center' }).append(markup).prop('outerHTML'));
-              });
-            });
-          });
-        });
+    MultiStepWizard.addSlide('new-form-step-1', TYPO3.lang['formManager.newFormWizard.step1.title'], '', Severity.info, TYPO3.lang['formManager.newFormWizard.step1.progressLabel'], async function(slide) {
+      const addIconMarkup = await Icons.getIcon('actions-plus', Icons.sizes.small);
+      const duplicateIconMarkup = await Icons.getIcon('form-page', Icons.sizes.large);
+      const blankIconMarkup = await Icons.getIcon('apps-pagetree-page-default', Icons.sizes.large);
+
+      let html;
+      const modal = MultiStepWizard.setup.$carousel.closest('.modal');
+      const nextButton = modal.find('.modal-footer').find('button[name="next"]');
+
+      MultiStepWizard.blurCancelStep();
+      MultiStepWizard.lockNextStep();
+      MultiStepWizard.lockPrevStep();
+
+      const folders = formManagerApp.getAccessibleFormStorageFolders();
+      if (folders.length === 0) {
+        html = '<div class="new-form-modal">'
+          + '<div class="row">'
+          + '<label class="col col-form-label">' + TYPO3.lang['formManager.newFormWizard.step1.noStorages'] + '</label>'
+          + '</div>'
+          + '</div>';
+
+        slide.html(html);
+        formManagerApp.assert(false, 'No accessible form storage folders', 1477506500);
+      }
+
+      html = '<div class="new-form-modal">'
+
+      html += '<div class="card-container">'
+        + '<div class="card card-size-medium">'
+        + '<div class="card-header">'
+        + '<div class="card-icon">' + blankIconMarkup + '</div>'
+        + '<div class="card-header-body">'
+        + '<h2 class="card-title">' + TYPO3.lang['formManager.blankForm.label'] + '</h2>'
+        + '<span class="card-subtitle">' + TYPO3.lang['formManager.blankForm.subtitle'] + '</span>'
+        + '</div>'
+        + '</div>'
+        + '<div class="card-body">'
+        + '<p class="card-text">' + TYPO3.lang['formManager.blankForm.description'] + '</p>'
+        + '</div>'
+        + '<div class="card-footer">'
+        + '<button type="button" class="btn btn-success" data-inline="1" value="blank" data-identifier="newFormModeButton">' + addIconMarkup + ' ' + TYPO3.lang['formManager.blankForm.label'] + '</button>'
+        + '</div>'
+        + '</div>'
+        + '<div class="card card-size-medium">'
+        + '<div class="card-header">'
+        + '<div class="card-icon">' + duplicateIconMarkup + '</div>'
+        + '<div class="card-header-body">'
+        + '<h2 class="card-title">' + TYPO3.lang['formManager.predefinedForm.label'] + '</h2>'
+        + '<span class="card-subtitle">' + TYPO3.lang['formManager.predefinedForm.subtitle'] + '</span>'
+        + '</div>'
+        + '</div>'
+        + '<div class="card-body">'
+        + '<p class="card-text">' + TYPO3.lang['formManager.predefinedForm.description'] + '</p>'
+        + '</div>'
+        + '<div class="card-footer">'
+        + '<button type="button" class="btn btn-success" data-inline="1" value="predefined" data-identifier="newFormModeButton">' + addIconMarkup + ' ' + TYPO3.lang['formManager.predefinedForm.label'] + '</button>'
+        + '</div>'
+        + '</div>';
+
+      html += '</div>';
+
+      slide.html(html);
+
+      $(Identifiers.newFormModeButton, modal).on('click', function (e: Event) {
+        MultiStepWizard.set('newFormMode', $(e.currentTarget).val());
+        MultiStepWizard.unlockNextStep().get(0).click();
+      });
+
+      nextButton.on('click', async function() {
+        slide.html($('<div />', { class: 'text-center' })
+          .append(await Icons.getIcon('spinner-circle', Icons.sizes.default, null, null))
+          .prop('outerHTML'));
       });
     });
 
@@ -330,94 +328,90 @@ function newFormSetup(formManagerApp: FormManager): void {
         MultiStepWizard.set('templatePathName', $(Identifiers.newFormTemplate + ' option:selected', modal).text());
       }
 
-      nextButton.on('click', function() {
+      nextButton.on('click', async function() {
         MultiStepWizard.setup.forceSelection = false;
-        Icons.getIcon('spinner-circle', Icons.sizes.default, null, null).then(function(markup) {
-          slide.html($('<div />', { class: 'text-center' }).append(markup).prop('outerHTML'));
-        });
+        slide.html($('<div />', { class: 'text-center' })
+          .append(await Icons.getIcon('spinner-circle', Icons.sizes.default, null, null))
+          .prop('outerHTML'));
       });
     });
 
     /**
      * Wizard step 3
      */
-    MultiStepWizard.addSlide('new-form-step-3', TYPO3.lang['formManager.newFormWizard.step3.title'], '', Severity.info, TYPO3.lang['formManager.newFormWizard.step3.progressLabel'], function(slide, settings) {
-      Icons.getIcon('actions-cog', Icons.sizes.small).then(function (formPrototypeIconMarkup) {
-        Icons.getIcon('actions-file-t3d', Icons.sizes.small).then(function (formTemplateIconMarkup) {
-          Icons.getIcon('actions-tag', Icons.sizes.small).then(function (formNameIconMarkup) {
-            Icons.getIcon('actions-database', Icons.sizes.small).then(function (formStorageMarkup) {
-              const modal = MultiStepWizard.setup.$carousel.closest('.modal');
-              const nextButton = modal.find('.modal-footer').find('button[name="next"]');
-
-              let html = '<div class="new-form-modal">';
-
-              html += '<div class="mb-3">'
-                + '<h5 class="form-section-headline">' + TYPO3.lang['formManager.newFormWizard.step3.check'] + '</h5>'
-                + '<p>' + TYPO3.lang['formManager.newFormWizard.step3.message'] + '</p>'
-                + '</div>'
-                + '<div class="alert alert-notice">'
-                + '<div class="alert-body mt-1">'
-
-              if (settings.prototypeNameName) {
-                html += '<div class="row my-1">'
-                  + '<div class="col col-sm-6">'
-                  + formPrototypeIconMarkup + ' '
-                  + TYPO3.lang['formManager.form_prototype']
-                  + '</div>'
-                  + '<div class="col">'
-                  + securityUtility.encodeHtml(settings.prototypeNameName)
-                  + '</div>'
-                  + '</div>';
-              }
-
-              if (settings.templatePathName) {
-                html += '<div class="row my-1">'
-                  + '<div class="col col-sm-6">'
-                  + formTemplateIconMarkup + ' '
-                  + TYPO3.lang['formManager.form_template']
-                  + '</div>'
-                  + '<div class="col">'
-                  + securityUtility.encodeHtml(settings.templatePathName)
-                  + '</div>'
-                  + '</div>';
-              }
-
-              html += '<div class="row my-1">'
-                + '<div class="col col-sm-6">'
-                + formNameIconMarkup + ' '
-                + TYPO3.lang['formManager.form_name']
-                + '</div>'
-                + '<div class="col">'
-                + securityUtility.encodeHtml(settings.formName)
-                + '</div>'
-                + '</div>'
-                + '<div class="row my-1">'
-                + '<div class="col col-sm-6">'
-                + formStorageMarkup + ' '
-                + TYPO3.lang['formManager.form_save_path']
-                + '</div>'
-                + '<div class="col">'
-                + securityUtility.encodeHtml(settings.savePathName)
-                + '</div>'
-                + '</div>';
-
-              html += '</div>'
-                + '</div>'
-                + '</div>';
-
-              slide.html(html);
-
-              nextButton.focus();
-
-              nextButton.on('click', function() {
-                MultiStepWizard.setup.forceSelection = false;
-                Icons.getIcon('spinner-circle', Icons.sizes.default, null, null).then(function(markup) {
-                  slide.html($('<div />', { class: 'text-center' }).append(markup).prop('outerHTML'));
-                });
-              });
-            });
-          });
-        });
+    MultiStepWizard.addSlide('new-form-step-3', TYPO3.lang['formManager.newFormWizard.step3.title'], '', Severity.info, TYPO3.lang['formManager.newFormWizard.step3.progressLabel'], async function(slide, settings) {
+      const formPrototypeIconMarkup = await Icons.getIcon('actions-cog', Icons.sizes.small);
+      const formTemplateIconMarkup = await Icons.getIcon('actions-file-t3d', Icons.sizes.small);
+      const formNameIconMarkup = await Icons.getIcon('actions-tag', Icons.sizes.small);
+      const formStorageMarkup = await Icons.getIcon('actions-database', Icons.sizes.small);
+      const modal = MultiStepWizard.setup.$carousel.closest('.modal');
+      const nextButton = modal.find('.modal-footer').find('button[name="next"]');
+
+      let html = '<div class="new-form-modal">';
+
+      html += '<div class="mb-3">'
+        + '<h5 class="form-section-headline">' + TYPO3.lang['formManager.newFormWizard.step3.check'] + '</h5>'
+        + '<p>' + TYPO3.lang['formManager.newFormWizard.step3.message'] + '</p>'
+        + '</div>'
+        + '<div class="alert alert-notice">'
+        + '<div class="alert-body mt-1">'
+
+      if (settings.prototypeNameName) {
+        html += '<div class="row my-1">'
+          + '<div class="col col-sm-6">'
+          + formPrototypeIconMarkup + ' '
+          + TYPO3.lang['formManager.form_prototype']
+          + '</div>'
+          + '<div class="col">'
+          + securityUtility.encodeHtml(settings.prototypeNameName)
+          + '</div>'
+          + '</div>';
+      }
+
+      if (settings.templatePathName) {
+        html += '<div class="row my-1">'
+          + '<div class="col col-sm-6">'
+          + formTemplateIconMarkup + ' '
+          + TYPO3.lang['formManager.form_template']
+          + '</div>'
+          + '<div class="col">'
+          + securityUtility.encodeHtml(settings.templatePathName)
+          + '</div>'
+          + '</div>';
+      }
+
+      html += '<div class="row my-1">'
+        + '<div class="col col-sm-6">'
+        + formNameIconMarkup + ' '
+        + TYPO3.lang['formManager.form_name']
+        + '</div>'
+        + '<div class="col">'
+        + securityUtility.encodeHtml(settings.formName)
+        + '</div>'
+        + '</div>'
+        + '<div class="row my-1">'
+        + '<div class="col col-sm-6">'
+        + formStorageMarkup + ' '
+        + TYPO3.lang['formManager.form_save_path']
+        + '</div>'
+        + '<div class="col">'
+        + securityUtility.encodeHtml(settings.savePathName)
+        + '</div>'
+        + '</div>';
+
+      html += '</div>'
+        + '</div>'
+        + '</div>';
+
+      slide.html(html);
+
+      nextButton.focus();
+
+      nextButton.on('click', async function() {
+        MultiStepWizard.setup.forceSelection = false;
+        slide.html($('<div />', { class: 'text-center' })
+          .append(await Icons.getIcon('spinner-circle', Icons.sizes.default, null, null))
+          .prop('outerHTML'));
       });
     });
 
@@ -567,99 +561,97 @@ function duplicateFormSetup(formManagerApp: FormManager): void {
         }
       });
 
-      nextButton.on('click', function() {
+      nextButton.on('click', async function() {
         MultiStepWizard.setup.forceSelection = false;
-        Icons.getIcon('spinner-circle', Icons.sizes.default, null, null).then(function(markup) {
-          MultiStepWizard.set('confirmationDuplicateFormName', that.data('formName'));
-
-          if (folders.length > 1) {
-            MultiStepWizard.set('savePath', $(Identifiers.duplicateFormSavePath + ' option:selected', modal).val());
-            MultiStepWizard.set('confirmationDuplicateFormSavePath', $(Identifiers.duplicateFormSavePath + ' option:selected', modal).text());
-          } else {
-            MultiStepWizard.set('savePath', folders[0].value);
-            MultiStepWizard.set('confirmationDuplicateFormSavePath', folders[0].label);
-          }
+        MultiStepWizard.set('confirmationDuplicateFormName', that.data('formName'));
 
-          slide.html($('<div />', { class: 'text-center' }).append(markup).prop('outerHTML'));
-        });
+        if (folders.length > 1) {
+          MultiStepWizard.set('savePath', $(Identifiers.duplicateFormSavePath + ' option:selected', modal).val());
+          MultiStepWizard.set('confirmationDuplicateFormSavePath', $(Identifiers.duplicateFormSavePath + ' option:selected', modal).text());
+        } else {
+          MultiStepWizard.set('savePath', folders[0].value);
+          MultiStepWizard.set('confirmationDuplicateFormSavePath', folders[0].label);
+        }
+
+        slide.html($('<div />', { class: 'text-center' })
+          .append(await Icons.getIcon('spinner-circle', Icons.sizes.default, null, null))
+          .prop('outerHTML'));
       });
     });
 
     /**
      * Wizard step 2
      */
-    MultiStepWizard.addSlide('duplicate-form-step-2', TYPO3.lang['formManager.duplicateFormWizard.step2.title'], '', Severity.info, TYPO3.lang['formManager.duplicateFormWizard.step2.progressLabel'], function(slide, settings) {
-      Icons.getIcon('actions-file-t3d', Icons.sizes.small).then(function (formTemplateIconMarkup) {
-        Icons.getIcon('actions-tag', Icons.sizes.small).then(function (formNameIconMarkup) {
-          Icons.getIcon('actions-database', Icons.sizes.small).then(function (formStorageMarkup) {
-            MultiStepWizard.unlockPrevStep();
-            MultiStepWizard.unlockNextStep();
+    MultiStepWizard.addSlide('duplicate-form-step-2', TYPO3.lang['formManager.duplicateFormWizard.step2.title'], '', Severity.info, TYPO3.lang['formManager.duplicateFormWizard.step2.progressLabel'], async function(slide, settings) {
+      const formTemplateIconMarkup = await Icons.getIcon('actions-file-t3d', Icons.sizes.small);
+      const formNameIconMarkup = await Icons.getIcon('actions-tag', Icons.sizes.small);
+      const formStorageMarkup = await Icons.getIcon('actions-database', Icons.sizes.small);
 
-            const modal = MultiStepWizard.setup.$carousel.closest('.modal');
-            const nextButton = modal.find('.modal-footer').find('button[name="next"]');
-
-            let html = '<div class="new-form-modal">'
-              + '<div class="row">'
-              + '<div class="col">';
-
-            html += '<div class="mb-3">'
-              + '<h5 class="form-section-headline">' + TYPO3.lang['formManager.duplicateFormWizard.step2.check'] + '</h5>'
-              + '<p>' + TYPO3.lang['formManager.newFormWizard.step3.message'] + '</p>'
-              + '</div>'
-              + '<div class="alert alert-notice">'
-              + '<div class="alert-body mt-1">'
-              + '<div class="dropdown-table-row">'
-              + '<div class="dropdown-table-column dropdown-table-icon">'
-              + formTemplateIconMarkup
-              + '</div>'
-              + '<div class="dropdown-table-column dropdown-table-title">'
-              + TYPO3.lang['formManager.form_copied']
-              + '</div>'
-              + '<div class="dropdown-table-column dropdown-table-value">'
-              + securityUtility.encodeHtml(settings.confirmationDuplicateFormName)
-              + '</div>'
-              + '</div>'
-              + '<div class="dropdown-table-row">'
-              + '<div class="dropdown-table-column dropdown-table-icon">'
-              + formNameIconMarkup
-              + '</div>'
-              + '<div class="dropdown-table-column dropdown-table-title">'
-              + TYPO3.lang['formManager.form_name']
-              + '</div>'
-              + '<div class="dropdown-table-column dropdown-table-value">'
-              + securityUtility.encodeHtml(settings.formName)
-              + '</div>'
-              + '</div>'
-              + '<div class="dropdown-table-row">'
-              + '<div class="dropdown-table-column dropdown-table-icon">'
-              + formStorageMarkup
-              + '</div>'
-              + '<div class="dropdown-table-column dropdown-table-title">'
-              + TYPO3.lang['formManager.form_save_path']
-              + '</div>'
-              + '<div class="dropdown-table-column dropdown-table-value">'
-              + securityUtility.encodeHtml(settings.confirmationDuplicateFormSavePath)
-              + '</div>'
-              + '</div>'
-              + '</div>'
-              + '</div>';
-
-            html += '</div>'
-              + '</div>'
-              + '</div>';
-
-            slide.html(html);
-
-            nextButton.focus();
-
-            nextButton.on('click', function() {
-              MultiStepWizard.setup.forceSelection = false;
-              Icons.getIcon('spinner-circle', Icons.sizes.default, null, null).then(function(markup) {
-                slide.html($('<div />', { class: 'text-center' }).append(markup).prop('outerHTML'));
-              });
-            });
-          });
-        });
+      MultiStepWizard.unlockPrevStep();
+      MultiStepWizard.unlockNextStep();
+
+      const modal = MultiStepWizard.setup.$carousel.closest('.modal');
+      const nextButton = modal.find('.modal-footer').find('button[name="next"]');
+
+      let html = '<div class="new-form-modal">'
+        + '<div class="row">'
+        + '<div class="col">';
+
+      html += '<div class="mb-3">'
+        + '<h5 class="form-section-headline">' + TYPO3.lang['formManager.duplicateFormWizard.step2.check'] + '</h5>'
+        + '<p>' + TYPO3.lang['formManager.newFormWizard.step3.message'] + '</p>'
+        + '</div>'
+        + '<div class="alert alert-notice">'
+        + '<div class="alert-body mt-1">'
+        + '<div class="dropdown-table-row">'
+        + '<div class="dropdown-table-column dropdown-table-icon">'
+        + formTemplateIconMarkup
+        + '</div>'
+        + '<div class="dropdown-table-column dropdown-table-title">'
+        + TYPO3.lang['formManager.form_copied']
+        + '</div>'
+        + '<div class="dropdown-table-column dropdown-table-value">'
+        + securityUtility.encodeHtml(settings.confirmationDuplicateFormName)
+        + '</div>'
+        + '</div>'
+        + '<div class="dropdown-table-row">'
+        + '<div class="dropdown-table-column dropdown-table-icon">'
+        + formNameIconMarkup
+        + '</div>'
+        + '<div class="dropdown-table-column dropdown-table-title">'
+        + TYPO3.lang['formManager.form_name']
+        + '</div>'
+        + '<div class="dropdown-table-column dropdown-table-value">'
+        + securityUtility.encodeHtml(settings.formName)
+        + '</div>'
+        + '</div>'
+        + '<div class="dropdown-table-row">'
+        + '<div class="dropdown-table-column dropdown-table-icon">'
+        + formStorageMarkup
+        + '</div>'
+        + '<div class="dropdown-table-column dropdown-table-title">'
+        + TYPO3.lang['formManager.form_save_path']
+        + '</div>'
+        + '<div class="dropdown-table-column dropdown-table-value">'
+        + securityUtility.encodeHtml(settings.confirmationDuplicateFormSavePath)
+        + '</div>'
+        + '</div>'
+        + '</div>'
+        + '</div>';
+
+      html += '</div>'
+        + '</div>'
+        + '</div>';
+
+      slide.html(html);
+
+      nextButton.focus();
+
+      nextButton.on('click', async function() {
+        MultiStepWizard.setup.forceSelection = false;
+        slide.html($('<div />', { class: 'text-center' })
+          .append(await Icons.getIcon('spinner-circle', Icons.sizes.default, null, null))
+          .prop('outerHTML'));
       });
     });
 
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/backend/form-manager/view-model.js b/typo3/sysext/form/Resources/Public/JavaScript/backend/form-manager/view-model.js
index 568b275afbee..d050ba341412 100644
--- a/typo3/sysext/form/Resources/Public/JavaScript/backend/form-manager/view-model.js
+++ b/typo3/sysext/form/Resources/Public/JavaScript/backend/form-manager/view-model.js
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-import $ from"jquery";import Modal from"@typo3/backend/modal.js";import Severity from"@typo3/backend/severity.js";import MultiStepWizard from"@typo3/backend/multi-step-wizard.js";import Icons from"@typo3/backend/icons.js";import Notification from"@typo3/backend/notification.js";import SecurityUtility from"@typo3/core/security-utility.js";import{selector}from"@typo3/core/literals.js";const securityUtility=new SecurityUtility;var Identifiers;function newFormSetup(e){$(Identifiers.newFormModalTrigger).on("click",(function(t){t.preventDefault(),MultiStepWizard.addSlide("new-form-step-1",TYPO3.lang["formManager.newFormWizard.step1.title"],"",Severity.info,TYPO3.lang["formManager.newFormWizard.step1.progressLabel"],(function(t){Icons.getIcon("actions-plus",Icons.sizes.small).then((function(a){Icons.getIcon("form-page",Icons.sizes.large).then((function(r){Icons.getIcon("apps-pagetree-page-default",Icons.sizes.large).then((function(o){let i;const n=MultiStepWizard.setup.$carousel.closest(".modal"),l=n.find(".modal-footer").find('button[name="next"]');MultiStepWizard.blurCancelStep(),MultiStepWizard.lockNextStep(),MultiStepWizard.lockPrevStep();0===e.getAccessibleFormStorageFolders().length&&(i='<div class="new-form-modal"><div class="row"><label class="col col-form-label">'+TYPO3.lang["formManager.newFormWizard.step1.noStorages"]+"</label></div></div>",t.html(i),e.assert(!1,"No accessible form storage folders",1477506500)),i='<div class="new-form-modal">',i+='<div class="card-container"><div class="card card-size-medium"><div class="card-header"><div class="card-icon">'+o+'</div><div class="card-header-body"><h2 class="card-title">'+TYPO3.lang["formManager.blankForm.label"]+'</h2><span class="card-subtitle">'+TYPO3.lang["formManager.blankForm.subtitle"]+'</span></div></div><div class="card-body"><p class="card-text">'+TYPO3.lang["formManager.blankForm.description"]+'</p></div><div class="card-footer"><button type="button" class="btn btn-success" data-inline="1" value="blank" data-identifier="newFormModeButton">'+a+" "+TYPO3.lang["formManager.blankForm.label"]+'</button></div></div><div class="card card-size-medium"><div class="card-header"><div class="card-icon">'+r+'</div><div class="card-header-body"><h2 class="card-title">'+TYPO3.lang["formManager.predefinedForm.label"]+'</h2><span class="card-subtitle">'+TYPO3.lang["formManager.predefinedForm.subtitle"]+'</span></div></div><div class="card-body"><p class="card-text">'+TYPO3.lang["formManager.predefinedForm.description"]+'</p></div><div class="card-footer"><button type="button" class="btn btn-success" data-inline="1" value="predefined" data-identifier="newFormModeButton">'+a+" "+TYPO3.lang["formManager.predefinedForm.label"]+"</button></div></div>",i+="</div>",t.html(i),$(Identifiers.newFormModeButton,n).on("click",(function(e){MultiStepWizard.set("newFormMode",$(e.currentTarget).val()),MultiStepWizard.unlockNextStep().get(0).click()})),l.on("click",(function(){Icons.getIcon("spinner-circle",Icons.sizes.default,null,null).then((function(e){t.html($("<div />",{class:"text-center"}).append(e).prop("outerHTML"))}))}))}))}))}))})),MultiStepWizard.addSlide("new-form-step-2",TYPO3.lang["formManager.newFormWizard.step2.title"],"",Severity.info,top.TYPO3.lang["wizard.progressStep.configure"],(function(t,a){let r,o;MultiStepWizard.lockNextStep(),MultiStepWizard.unlockPrevStep();const i=MultiStepWizard.setup.$carousel.closest(".modal"),n=i.find(".modal-footer").find('button[name="next"]'),l=e.getAccessibleFormStorageFolders();if(a.savePath||(MultiStepWizard.set("savePath",l[0].value),MultiStepWizard.set("savePathName",l[0].label)),l.length>1){o=$('<select class="new-form-save-path form-select" id="new-form-save-path" data-identifier="newFormSavePath" />');for(let e=0,t=l.length;e<t;++e){const t=new Option(l[e].label,l[e].value);$(o).append(t)}}const s=e.getPrototypes();e.assert(s.length>0,"No prototypes available",1477506501),a.prototypeName||(MultiStepWizard.set("prototypeName",s[0].value),MultiStepWizard.set("prototypeNameName",s[0].label));const d=$('<select class="new-form-prototype-name form-select" id="new-form-prototype-name" data-identifier="newFormPrototypeName" />');for(let e=0,t=s.length;e<t;++e){const t=new Option(s[e].label,s[e].value);$(d).append(t)}let c=e.getTemplatesForPrototype(s[0].value);e.assert(c.length>0,"No templates available",1477506502),a.templatePath||(MultiStepWizard.set("templatePath",c[0].value),MultiStepWizard.set("templatePathName",c[0].label));const m=$('<select class="new-form-template form-select" id="new-form-template" data-identifier="newFormTemplate" />');for(let e=0,t=c.length;e<t;++e){const t=new Option(c[e].label,c[e].value);$(m).append(t)}r='<div class="new-form-modal">',"blank"===a.newFormMode?(r+='<h5 class="form-section-headline">'+TYPO3.lang["formManager.blankForm.label"]+"</h5>",MultiStepWizard.set("templatePath","EXT:form/Resources/Private/Backend/Templates/FormEditor/Yaml/NewForms/BlankForm.yaml"),MultiStepWizard.set("templatePathName",TYPO3.lang["formManager.blankForm.label"])):(r+='<h5 class="form-section-headline">'+TYPO3.lang["formManager.predefinedForm.label"]+"</h5>",s.length>1&&(r+='<div class="mb-3"><label for="new-form-prototype-name"><strong>'+TYPO3.lang["formManager.form_prototype"]+'</strong></label><div class="formengine-field-item t3js-formengine-field-item"><div class="form-control-wrap">'+$(d)[0].outerHTML+"</div></div></div>"),c.length>1&&(r+='<div class="mb-3"><label for="new-form-template"><strong>'+TYPO3.lang["formManager.form_template"]+'</strong></label><div class="formengine-field-item t3js-formengine-field-item"><div class="form-description">'+TYPO3.lang["formManager.form_template_description"]+'</div><div class="form-control-wrap">'+$(m)[0].outerHTML+"</div></div></div>")),r+='<div class="mb-3"><label for="new-form-name"><strong>'+TYPO3.lang["formManager.form_name"]+'</strong></label><div class="formengine-field-item t3js-formengine-field-item"><div class="form-description">'+TYPO3.lang["formManager.form_name_description"]+'</div><div class="form-control-wrap">',a.formName?(r+='<input class="form-control" id="new-form-name" data-identifier="newFormName" value="'+securityUtility.encodeHtml(a.formName)+'" />',setTimeout((function(){MultiStepWizard.unlockNextStep()}),200)):r+='<input class="form-control has-error" id="new-form-name" data-identifier="newFormName" />',r+="</div></div></div>",o&&(r+='<div class="mb-3"><label for="new-form-save-path"><strong>'+TYPO3.lang["formManager.form_save_path"]+'</strong></label><div class="formengine-field-item t3js-formengine-field-item"><div class="form-description">'+TYPO3.lang["formManager.form_save_path_description"]+'</div><div class="form-control-wrap">'+$(o)[0].outerHTML+"</div></div></div>"),r+="</div>",t.html(r),a.savePath&&$(Identifiers.newFormSavePath,i).val(a.savePath),a.templatePath&&$(Identifiers.newFormTemplate,i).val(a.templatePath),s.length>1?$(Identifiers.newFormPrototypeName,i).focus():c.length>1&&$(Identifiers.newFormTemplate,i).focus();const p=function(){$(Identifiers.newFormTemplate,i).on("change",(function(){MultiStepWizard.set("templatePath",$(Identifiers.newFormTemplate+" option:selected",i).val()),MultiStepWizard.set("templatePathName",$(Identifiers.newFormTemplate+" option:selected",i).text()),MultiStepWizard.set("templatePathOnPrev",$(Identifiers.newFormTemplate+" option:selected",i).val())}))};$(Identifiers.newFormPrototypeName,i).on("change",(function(t){MultiStepWizard.set("prototypeName",$(Identifiers.newFormPrototypeName+" option:selected",i).val()),MultiStepWizard.set("prototypeNameName",$(Identifiers.newFormPrototypeName+" option:selected",i).text()),c=e.getTemplatesForPrototype($(t.currentTarget).val()),$(Identifiers.newFormTemplate,i).off().empty();for(let e=0,t=c.length;e<t;++e){const t=new Option(c[e].label,c[e].value);$(Identifiers.newFormTemplate,i).append(t),MultiStepWizard.set("templatePath",c[0].value),MultiStepWizard.set("templatePathName",c[0].label)}p()})),p(),a.prototypeName&&($(Identifiers.newFormPrototypeName,i).val(a.prototypeName),$(Identifiers.newFormPrototypeName,i).trigger("change"),a.templatePathOnPrev&&($(Identifiers.newFormTemplate,i).find(selector`option[value="${a.templatePathOnPrev}"]`).prop("selected",!0),$(Identifiers.newFormTemplate,i).trigger("change"))),$(Identifiers.newFormName,i).focus(),$(Identifiers.newFormName,i).on("keyup paste",(function(e){$(e.currentTarget).val().length>0?($(e.currentTarget).removeClass("has-error"),MultiStepWizard.unlockNextStep(),MultiStepWizard.set("formName",$(e.currentTarget).val()),"code"in e&&"Enter"===e.code&&MultiStepWizard.triggerStepButton("next")):($(e.currentTarget).addClass("has-error"),MultiStepWizard.lockNextStep())})),$(Identifiers.newFormSavePath,i).on("change",(function(){MultiStepWizard.set("savePath",$(Identifiers.newFormSavePath+" option:selected",i).val()),MultiStepWizard.set("savePathName",$(Identifiers.newFormSavePath+" option:selected",i).text())})),"blank"===a.newFormMode||a.templatePathName||MultiStepWizard.set("templatePathName",$(Identifiers.newFormTemplate+" option:selected",i).text()),n.on("click",(function(){MultiStepWizard.setup.forceSelection=!1,Icons.getIcon("spinner-circle",Icons.sizes.default,null,null).then((function(e){t.html($("<div />",{class:"text-center"}).append(e).prop("outerHTML"))}))}))})),MultiStepWizard.addSlide("new-form-step-3",TYPO3.lang["formManager.newFormWizard.step3.title"],"",Severity.info,TYPO3.lang["formManager.newFormWizard.step3.progressLabel"],(function(e,t){Icons.getIcon("actions-cog",Icons.sizes.small).then((function(a){Icons.getIcon("actions-file-t3d",Icons.sizes.small).then((function(r){Icons.getIcon("actions-tag",Icons.sizes.small).then((function(o){Icons.getIcon("actions-database",Icons.sizes.small).then((function(i){const n=MultiStepWizard.setup.$carousel.closest(".modal").find(".modal-footer").find('button[name="next"]');let l='<div class="new-form-modal">';l+='<div class="mb-3"><h5 class="form-section-headline">'+TYPO3.lang["formManager.newFormWizard.step3.check"]+"</h5><p>"+TYPO3.lang["formManager.newFormWizard.step3.message"]+'</p></div><div class="alert alert-notice"><div class="alert-body mt-1">',t.prototypeNameName&&(l+='<div class="row my-1"><div class="col col-sm-6">'+a+" "+TYPO3.lang["formManager.form_prototype"]+'</div><div class="col">'+securityUtility.encodeHtml(t.prototypeNameName)+"</div></div>"),t.templatePathName&&(l+='<div class="row my-1"><div class="col col-sm-6">'+r+" "+TYPO3.lang["formManager.form_template"]+'</div><div class="col">'+securityUtility.encodeHtml(t.templatePathName)+"</div></div>"),l+='<div class="row my-1"><div class="col col-sm-6">'+o+" "+TYPO3.lang["formManager.form_name"]+'</div><div class="col">'+securityUtility.encodeHtml(t.formName)+'</div></div><div class="row my-1"><div class="col col-sm-6">'+i+" "+TYPO3.lang["formManager.form_save_path"]+'</div><div class="col">'+securityUtility.encodeHtml(t.savePathName)+"</div></div>",l+="</div></div></div>",e.html(l),n.focus(),n.on("click",(function(){MultiStepWizard.setup.forceSelection=!1,Icons.getIcon("spinner-circle",Icons.sizes.default,null,null).then((function(t){e.html($("<div />",{class:"text-center"}).append(t).prop("outerHTML"))}))}))}))}))}))}))})),MultiStepWizard.addFinalProcessingSlide((function(){$.post(e.getAjaxEndpoint("create"),{formName:MultiStepWizard.setup.settings.formName,templatePath:MultiStepWizard.setup.settings.templatePath,prototypeName:MultiStepWizard.setup.settings.prototypeName,savePath:MultiStepWizard.setup.settings.savePath},(function(e){"success"===e.status?document.location=e.url:Notification.error(TYPO3.lang["formManager.newFormWizard.step4.errorTitle"],TYPO3.lang["formManager.newFormWizard.step4.errorMessage"]+" "+e.message),MultiStepWizard.dismiss()})).fail((function(e,t,a){const r=(new DOMParser).parseFromString(e.responseText,"text/html"),o=$(r.body);Notification.error(t,a,2),MultiStepWizard.dismiss(),$(Identifiers.t3Logo,o).remove(),$(Identifiers.t3Footer,o).remove(),$(Identifiers.moduleBody).html(o.html())}))})).then((function(){MultiStepWizard.show()}))}))}function removeFormSetup(e){$(Identifiers.removeFormModalTrigger).on("click",(function(t){const a=[];t.preventDefault();const r=$(t.currentTarget);a.push({text:TYPO3.lang["formManager.cancel"],active:!0,btnClass:"btn-default",name:"cancel",trigger:function(e,t){t.hideModal()}}),a.push({text:TYPO3.lang["formManager.remove_form"],active:!0,btnClass:"btn-warning",name:"createform",trigger:function(t,a){document.location=e.getAjaxEndpoint("delete")+"&formPersistenceIdentifier="+r.data("formPersistenceIdentifier"),a.hideModal()}}),Modal.show(TYPO3.lang["formManager.remove_form_title"],TYPO3.lang["formManager.remove_form_message"],Severity.warning,a)}))}function duplicateFormSetup(e){$(Identifiers.duplicateFormModalTrigger).on("click",(function(t){t.preventDefault();const a=$(t.currentTarget);MultiStepWizard.addSlide("duplicate-form-step-1",TYPO3.lang["formManager.duplicateFormWizard.step1.title"].replace("{0}",a.data("formName")),"",Severity.info,top.TYPO3.lang["wizard.progressStep.configure"],(function(t){let r,o;MultiStepWizard.lockPrevStep(),MultiStepWizard.lockNextStep();const i=MultiStepWizard.setup.$carousel.closest(".modal"),n=i.find(".modal-footer").find('button[name="next"]'),l=e.getAccessibleFormStorageFolders();if(e.assert(l.length>0,"No accessible form storage folders",1477649539),MultiStepWizard.set("formPersistenceIdentifier",a.data("formPersistenceIdentifier")),MultiStepWizard.set("savePath",l[0].value),l.length>1){o=$('<select id="duplicate-form-save-path" class="form-select" data-identifier="duplicateFormSavePath" />');for(let e=0,t=l.length;e<t;++e){const t=new Option(l[e].label,l[e].value);$(o).append(t)}}r='<div class="duplicate-form-modal"><h5 class="form-section-headline">'+TYPO3.lang["formManager.new_form_name"]+'</h5><div class="mb-3"><label for="duplicate-form-name"><strong>'+TYPO3.lang["formManager.form_name"]+'</strong></label><div class="formengine-field-item t3js-formengine-field-item"><div class="form-description">'+TYPO3.lang["formManager.form_name_description"]+'</div><div class="form-control-wrap"><input id="duplicate-form-name" class="form-control has-error" data-identifier="duplicateFormName" /></div></div></div>',o&&(r+='<div class="mb-3"><label for="duplicate-form-save-path"><strong>'+TYPO3.lang["formManager.form_save_path"]+'</strong></label><div class="formengine-field-item t3js-formengine-field-item"><div class="form-description">'+TYPO3.lang["formManager.form_save_path_description"]+'</div><div class="form-control-wrap">'+$(o)[0].outerHTML+"</div></div></div>"),r+="</div>",t.html(r),$(Identifiers.duplicateFormName,i).focus(),$(Identifiers.duplicateFormName,i).on("keyup paste",(function(e){const t=$(event.currentTarget);t.val().length>0?(t.removeClass("has-error"),MultiStepWizard.unlockNextStep(),MultiStepWizard.set("formName",t.val()),"code"in e&&"Enter"===e.code&&MultiStepWizard.triggerStepButton("next")):(t.addClass("has-error"),MultiStepWizard.lockNextStep())})),n.on("click",(function(){MultiStepWizard.setup.forceSelection=!1,Icons.getIcon("spinner-circle",Icons.sizes.default,null,null).then((function(e){MultiStepWizard.set("confirmationDuplicateFormName",a.data("formName")),l.length>1?(MultiStepWizard.set("savePath",$(Identifiers.duplicateFormSavePath+" option:selected",i).val()),MultiStepWizard.set("confirmationDuplicateFormSavePath",$(Identifiers.duplicateFormSavePath+" option:selected",i).text())):(MultiStepWizard.set("savePath",l[0].value),MultiStepWizard.set("confirmationDuplicateFormSavePath",l[0].label)),t.html($("<div />",{class:"text-center"}).append(e).prop("outerHTML"))}))}))})),MultiStepWizard.addSlide("duplicate-form-step-2",TYPO3.lang["formManager.duplicateFormWizard.step2.title"],"",Severity.info,TYPO3.lang["formManager.duplicateFormWizard.step2.progressLabel"],(function(e,t){Icons.getIcon("actions-file-t3d",Icons.sizes.small).then((function(a){Icons.getIcon("actions-tag",Icons.sizes.small).then((function(r){Icons.getIcon("actions-database",Icons.sizes.small).then((function(o){MultiStepWizard.unlockPrevStep(),MultiStepWizard.unlockNextStep();const i=MultiStepWizard.setup.$carousel.closest(".modal").find(".modal-footer").find('button[name="next"]');let n='<div class="new-form-modal"><div class="row"><div class="col">';n+='<div class="mb-3"><h5 class="form-section-headline">'+TYPO3.lang["formManager.duplicateFormWizard.step2.check"]+"</h5><p>"+TYPO3.lang["formManager.newFormWizard.step3.message"]+'</p></div><div class="alert alert-notice"><div class="alert-body mt-1"><div class="dropdown-table-row"><div class="dropdown-table-column dropdown-table-icon">'+a+'</div><div class="dropdown-table-column dropdown-table-title">'+TYPO3.lang["formManager.form_copied"]+'</div><div class="dropdown-table-column dropdown-table-value">'+securityUtility.encodeHtml(t.confirmationDuplicateFormName)+'</div></div><div class="dropdown-table-row"><div class="dropdown-table-column dropdown-table-icon">'+r+'</div><div class="dropdown-table-column dropdown-table-title">'+TYPO3.lang["formManager.form_name"]+'</div><div class="dropdown-table-column dropdown-table-value">'+securityUtility.encodeHtml(t.formName)+'</div></div><div class="dropdown-table-row"><div class="dropdown-table-column dropdown-table-icon">'+o+'</div><div class="dropdown-table-column dropdown-table-title">'+TYPO3.lang["formManager.form_save_path"]+'</div><div class="dropdown-table-column dropdown-table-value">'+securityUtility.encodeHtml(t.confirmationDuplicateFormSavePath)+"</div></div></div></div>",n+="</div></div></div>",e.html(n),i.focus(),i.on("click",(function(){MultiStepWizard.setup.forceSelection=!1,Icons.getIcon("spinner-circle",Icons.sizes.default,null,null).then((function(t){e.html($("<div />",{class:"text-center"}).append(t).prop("outerHTML"))}))}))}))}))}))})),MultiStepWizard.addFinalProcessingSlide((function(){$.post(e.getAjaxEndpoint("duplicate"),{formName:MultiStepWizard.setup.settings.formName,formPersistenceIdentifier:MultiStepWizard.setup.settings.formPersistenceIdentifier,savePath:MultiStepWizard.setup.settings.savePath},(function(e){"success"===e.status?document.location=e.url:Notification.error(TYPO3.lang["formManager.duplicateFormWizard.step3.errorTitle"],TYPO3.lang["formManager.duplicateFormWizard.step3.errorMessage"]+" "+e.message),MultiStepWizard.dismiss()})).fail((function(e,t,a){const r=(new DOMParser).parseFromString(e.responseText,"text/html"),o=$(r.body);Notification.error(t,a,2),MultiStepWizard.dismiss(),$(Identifiers.t3Logo,o).remove(),$(Identifiers.t3Footer,o).remove(),$(Identifiers.moduleBody).html(o.html())}))})).then((function(){MultiStepWizard.show()}))}))}function showReferencesSetup(e){$(Identifiers.showReferences).on("click",(t=>{t.preventDefault();const a=$(t.currentTarget),r=e.getAjaxEndpoint("references")+"&formPersistenceIdentifier="+a.data("formPersistenceIdentifier");$.get(r,(function(e){let t;const r=[];r.push({text:TYPO3.lang["formManager.cancel"],active:!0,btnClass:"btn-default",name:"cancel",trigger:function(e,t){t.hideModal()}});if(e.references.length>0){t="<div><h3>"+TYPO3.lang["formManager.references.headline"].replace("{0}",a.data("formName"))+'</h3></div><div class="table-fit"><table id="forms" class="table table-striped table-sm"><thead><tr><th>'+TYPO3.lang["formManager.page"]+"</th><th>"+TYPO3.lang["formManager.record"]+"</th></tr></thead><tbody>";for(let a=0,r=e.references.length;a<r;++a)t+="<tr><td>"+e.references[a].recordPageTitle+"</td><td>"+e.references[a].recordIcon+'<a href="'+e.references[a].recordEditUrl+'" data-identifier="referenceLink">'+e.references[a].recordTitle+" (uid: "+e.references[a].recordUid+")</a></td></tr>";t+="</tbody></table></div>"}else t="<div><h1>"+TYPO3.lang["formManager.references.title"].replace("{0}",e.formPersistenceIdentifier)+"</h1></div><div>"+TYPO3.lang["formManager.no_references"]+"</div>";t=$(t),$(Identifiers.referenceLink,t).on("click",(function(e){e.preventDefault(),Modal.currentModal.hideModal(),document.location=$(e.currentTarget).prop("href")})),Modal.show(TYPO3.lang["formManager.references.title"],t,Severity.info,r)})).fail((function(e,t,a){0!==e.status&&Notification.error(t,a,2)}))}))}!function(e){e.newFormModalTrigger='[data-identifier="newForm"]',e.duplicateFormModalTrigger='[data-identifier="duplicateForm"]',e.removeFormModalTrigger='[data-identifier="removeForm"]',e.newFormModeButton='[data-identifier="newFormModeButton"]',e.newFormName='[data-identifier="newFormName"]',e.newFormSavePath='[data-identifier="newFormSavePath"]',e.newFormPrototypeName='[data-identifier="newFormPrototypeName"]',e.newFormTemplate='[data-identifier="newFormTemplate"]',e.duplicateFormName='[data-identifier="duplicateFormName"]',e.duplicateFormSavePath='[data-identifier="duplicateFormSavePath"]',e.showReferences='[data-identifier="showReferences"]',e.referenceLink='[data-identifier="referenceLink"]',e.moduleBody=".module-body.t3js-module-body",e.t3Logo=".t3-message-page-logo",e.t3Footer="#t3-footer"}(Identifiers||(Identifiers={}));export function bootstrap(e){removeFormSetup(e),newFormSetup(e),duplicateFormSetup(e),showReferencesSetup(e)}
\ No newline at end of file
+import $ from"jquery";import Modal from"@typo3/backend/modal.js";import Severity from"@typo3/backend/severity.js";import MultiStepWizard from"@typo3/backend/multi-step-wizard.js";import Icons from"@typo3/backend/icons.js";import Notification from"@typo3/backend/notification.js";import SecurityUtility from"@typo3/core/security-utility.js";import{selector}from"@typo3/core/literals.js";const securityUtility=new SecurityUtility;var Identifiers;function newFormSetup(e){$(Identifiers.newFormModalTrigger).on("click",(function(t){t.preventDefault(),MultiStepWizard.addSlide("new-form-step-1",TYPO3.lang["formManager.newFormWizard.step1.title"],"",Severity.info,TYPO3.lang["formManager.newFormWizard.step1.progressLabel"],(async function(t){const a=await Icons.getIcon("actions-plus",Icons.sizes.small),r=await Icons.getIcon("form-page",Icons.sizes.large),i=await Icons.getIcon("apps-pagetree-page-default",Icons.sizes.large);let o;const n=MultiStepWizard.setup.$carousel.closest(".modal"),l=n.find(".modal-footer").find('button[name="next"]');MultiStepWizard.blurCancelStep(),MultiStepWizard.lockNextStep(),MultiStepWizard.lockPrevStep();0===e.getAccessibleFormStorageFolders().length&&(o='<div class="new-form-modal"><div class="row"><label class="col col-form-label">'+TYPO3.lang["formManager.newFormWizard.step1.noStorages"]+"</label></div></div>",t.html(o),e.assert(!1,"No accessible form storage folders",1477506500)),o='<div class="new-form-modal">',o+='<div class="card-container"><div class="card card-size-medium"><div class="card-header"><div class="card-icon">'+i+'</div><div class="card-header-body"><h2 class="card-title">'+TYPO3.lang["formManager.blankForm.label"]+'</h2><span class="card-subtitle">'+TYPO3.lang["formManager.blankForm.subtitle"]+'</span></div></div><div class="card-body"><p class="card-text">'+TYPO3.lang["formManager.blankForm.description"]+'</p></div><div class="card-footer"><button type="button" class="btn btn-success" data-inline="1" value="blank" data-identifier="newFormModeButton">'+a+" "+TYPO3.lang["formManager.blankForm.label"]+'</button></div></div><div class="card card-size-medium"><div class="card-header"><div class="card-icon">'+r+'</div><div class="card-header-body"><h2 class="card-title">'+TYPO3.lang["formManager.predefinedForm.label"]+'</h2><span class="card-subtitle">'+TYPO3.lang["formManager.predefinedForm.subtitle"]+'</span></div></div><div class="card-body"><p class="card-text">'+TYPO3.lang["formManager.predefinedForm.description"]+'</p></div><div class="card-footer"><button type="button" class="btn btn-success" data-inline="1" value="predefined" data-identifier="newFormModeButton">'+a+" "+TYPO3.lang["formManager.predefinedForm.label"]+"</button></div></div>",o+="</div>",t.html(o),$(Identifiers.newFormModeButton,n).on("click",(function(e){MultiStepWizard.set("newFormMode",$(e.currentTarget).val()),MultiStepWizard.unlockNextStep().get(0).click()})),l.on("click",(async function(){t.html($("<div />",{class:"text-center"}).append(await Icons.getIcon("spinner-circle",Icons.sizes.default,null,null)).prop("outerHTML"))}))})),MultiStepWizard.addSlide("new-form-step-2",TYPO3.lang["formManager.newFormWizard.step2.title"],"",Severity.info,top.TYPO3.lang["wizard.progressStep.configure"],(function(t,a){let r,i;MultiStepWizard.lockNextStep(),MultiStepWizard.unlockPrevStep();const o=MultiStepWizard.setup.$carousel.closest(".modal"),n=o.find(".modal-footer").find('button[name="next"]'),l=e.getAccessibleFormStorageFolders();if(a.savePath||(MultiStepWizard.set("savePath",l[0].value),MultiStepWizard.set("savePathName",l[0].label)),l.length>1){i=$('<select class="new-form-save-path form-select" id="new-form-save-path" data-identifier="newFormSavePath" />');for(let e=0,t=l.length;e<t;++e){const t=new Option(l[e].label,l[e].value);$(i).append(t)}}const s=e.getPrototypes();e.assert(s.length>0,"No prototypes available",1477506501),a.prototypeName||(MultiStepWizard.set("prototypeName",s[0].value),MultiStepWizard.set("prototypeNameName",s[0].label));const d=$('<select class="new-form-prototype-name form-select" id="new-form-prototype-name" data-identifier="newFormPrototypeName" />');for(let e=0,t=s.length;e<t;++e){const t=new Option(s[e].label,s[e].value);$(d).append(t)}let c=e.getTemplatesForPrototype(s[0].value);e.assert(c.length>0,"No templates available",1477506502),a.templatePath||(MultiStepWizard.set("templatePath",c[0].value),MultiStepWizard.set("templatePathName",c[0].label));const m=$('<select class="new-form-template form-select" id="new-form-template" data-identifier="newFormTemplate" />');for(let e=0,t=c.length;e<t;++e){const t=new Option(c[e].label,c[e].value);$(m).append(t)}r='<div class="new-form-modal">',"blank"===a.newFormMode?(r+='<h5 class="form-section-headline">'+TYPO3.lang["formManager.blankForm.label"]+"</h5>",MultiStepWizard.set("templatePath","EXT:form/Resources/Private/Backend/Templates/FormEditor/Yaml/NewForms/BlankForm.yaml"),MultiStepWizard.set("templatePathName",TYPO3.lang["formManager.blankForm.label"])):(r+='<h5 class="form-section-headline">'+TYPO3.lang["formManager.predefinedForm.label"]+"</h5>",s.length>1&&(r+='<div class="mb-3"><label for="new-form-prototype-name"><strong>'+TYPO3.lang["formManager.form_prototype"]+'</strong></label><div class="formengine-field-item t3js-formengine-field-item"><div class="form-control-wrap">'+$(d)[0].outerHTML+"</div></div></div>"),c.length>1&&(r+='<div class="mb-3"><label for="new-form-template"><strong>'+TYPO3.lang["formManager.form_template"]+'</strong></label><div class="formengine-field-item t3js-formengine-field-item"><div class="form-description">'+TYPO3.lang["formManager.form_template_description"]+'</div><div class="form-control-wrap">'+$(m)[0].outerHTML+"</div></div></div>")),r+='<div class="mb-3"><label for="new-form-name"><strong>'+TYPO3.lang["formManager.form_name"]+'</strong></label><div class="formengine-field-item t3js-formengine-field-item"><div class="form-description">'+TYPO3.lang["formManager.form_name_description"]+'</div><div class="form-control-wrap">',a.formName?(r+='<input class="form-control" id="new-form-name" data-identifier="newFormName" value="'+securityUtility.encodeHtml(a.formName)+'" />',setTimeout((function(){MultiStepWizard.unlockNextStep()}),200)):r+='<input class="form-control has-error" id="new-form-name" data-identifier="newFormName" />',r+="</div></div></div>",i&&(r+='<div class="mb-3"><label for="new-form-save-path"><strong>'+TYPO3.lang["formManager.form_save_path"]+'</strong></label><div class="formengine-field-item t3js-formengine-field-item"><div class="form-description">'+TYPO3.lang["formManager.form_save_path_description"]+'</div><div class="form-control-wrap">'+$(i)[0].outerHTML+"</div></div></div>"),r+="</div>",t.html(r),a.savePath&&$(Identifiers.newFormSavePath,o).val(a.savePath),a.templatePath&&$(Identifiers.newFormTemplate,o).val(a.templatePath),s.length>1?$(Identifiers.newFormPrototypeName,o).focus():c.length>1&&$(Identifiers.newFormTemplate,o).focus();const p=function(){$(Identifiers.newFormTemplate,o).on("change",(function(){MultiStepWizard.set("templatePath",$(Identifiers.newFormTemplate+" option:selected",o).val()),MultiStepWizard.set("templatePathName",$(Identifiers.newFormTemplate+" option:selected",o).text()),MultiStepWizard.set("templatePathOnPrev",$(Identifiers.newFormTemplate+" option:selected",o).val())}))};$(Identifiers.newFormPrototypeName,o).on("change",(function(t){MultiStepWizard.set("prototypeName",$(Identifiers.newFormPrototypeName+" option:selected",o).val()),MultiStepWizard.set("prototypeNameName",$(Identifiers.newFormPrototypeName+" option:selected",o).text()),c=e.getTemplatesForPrototype($(t.currentTarget).val()),$(Identifiers.newFormTemplate,o).off().empty();for(let e=0,t=c.length;e<t;++e){const t=new Option(c[e].label,c[e].value);$(Identifiers.newFormTemplate,o).append(t),MultiStepWizard.set("templatePath",c[0].value),MultiStepWizard.set("templatePathName",c[0].label)}p()})),p(),a.prototypeName&&($(Identifiers.newFormPrototypeName,o).val(a.prototypeName),$(Identifiers.newFormPrototypeName,o).trigger("change"),a.templatePathOnPrev&&($(Identifiers.newFormTemplate,o).find(selector`option[value="${a.templatePathOnPrev}"]`).prop("selected",!0),$(Identifiers.newFormTemplate,o).trigger("change"))),$(Identifiers.newFormName,o).focus(),$(Identifiers.newFormName,o).on("keyup paste",(function(e){$(e.currentTarget).val().length>0?($(e.currentTarget).removeClass("has-error"),MultiStepWizard.unlockNextStep(),MultiStepWizard.set("formName",$(e.currentTarget).val()),"code"in e&&"Enter"===e.code&&MultiStepWizard.triggerStepButton("next")):($(e.currentTarget).addClass("has-error"),MultiStepWizard.lockNextStep())})),$(Identifiers.newFormSavePath,o).on("change",(function(){MultiStepWizard.set("savePath",$(Identifiers.newFormSavePath+" option:selected",o).val()),MultiStepWizard.set("savePathName",$(Identifiers.newFormSavePath+" option:selected",o).text())})),"blank"===a.newFormMode||a.templatePathName||MultiStepWizard.set("templatePathName",$(Identifiers.newFormTemplate+" option:selected",o).text()),n.on("click",(async function(){MultiStepWizard.setup.forceSelection=!1,t.html($("<div />",{class:"text-center"}).append(await Icons.getIcon("spinner-circle",Icons.sizes.default,null,null)).prop("outerHTML"))}))})),MultiStepWizard.addSlide("new-form-step-3",TYPO3.lang["formManager.newFormWizard.step3.title"],"",Severity.info,TYPO3.lang["formManager.newFormWizard.step3.progressLabel"],(async function(e,t){const a=await Icons.getIcon("actions-cog",Icons.sizes.small),r=await Icons.getIcon("actions-file-t3d",Icons.sizes.small),i=await Icons.getIcon("actions-tag",Icons.sizes.small),o=await Icons.getIcon("actions-database",Icons.sizes.small),n=MultiStepWizard.setup.$carousel.closest(".modal").find(".modal-footer").find('button[name="next"]');let l='<div class="new-form-modal">';l+='<div class="mb-3"><h5 class="form-section-headline">'+TYPO3.lang["formManager.newFormWizard.step3.check"]+"</h5><p>"+TYPO3.lang["formManager.newFormWizard.step3.message"]+'</p></div><div class="alert alert-notice"><div class="alert-body mt-1">',t.prototypeNameName&&(l+='<div class="row my-1"><div class="col col-sm-6">'+a+" "+TYPO3.lang["formManager.form_prototype"]+'</div><div class="col">'+securityUtility.encodeHtml(t.prototypeNameName)+"</div></div>"),t.templatePathName&&(l+='<div class="row my-1"><div class="col col-sm-6">'+r+" "+TYPO3.lang["formManager.form_template"]+'</div><div class="col">'+securityUtility.encodeHtml(t.templatePathName)+"</div></div>"),l+='<div class="row my-1"><div class="col col-sm-6">'+i+" "+TYPO3.lang["formManager.form_name"]+'</div><div class="col">'+securityUtility.encodeHtml(t.formName)+'</div></div><div class="row my-1"><div class="col col-sm-6">'+o+" "+TYPO3.lang["formManager.form_save_path"]+'</div><div class="col">'+securityUtility.encodeHtml(t.savePathName)+"</div></div>",l+="</div></div></div>",e.html(l),n.focus(),n.on("click",(async function(){MultiStepWizard.setup.forceSelection=!1,e.html($("<div />",{class:"text-center"}).append(await Icons.getIcon("spinner-circle",Icons.sizes.default,null,null)).prop("outerHTML"))}))})),MultiStepWizard.addFinalProcessingSlide((function(){$.post(e.getAjaxEndpoint("create"),{formName:MultiStepWizard.setup.settings.formName,templatePath:MultiStepWizard.setup.settings.templatePath,prototypeName:MultiStepWizard.setup.settings.prototypeName,savePath:MultiStepWizard.setup.settings.savePath},(function(e){"success"===e.status?document.location=e.url:Notification.error(TYPO3.lang["formManager.newFormWizard.step4.errorTitle"],TYPO3.lang["formManager.newFormWizard.step4.errorMessage"]+" "+e.message),MultiStepWizard.dismiss()})).fail((function(e,t,a){const r=(new DOMParser).parseFromString(e.responseText,"text/html"),i=$(r.body);Notification.error(t,a,2),MultiStepWizard.dismiss(),$(Identifiers.t3Logo,i).remove(),$(Identifiers.t3Footer,i).remove(),$(Identifiers.moduleBody).html(i.html())}))})).then((function(){MultiStepWizard.show()}))}))}function removeFormSetup(e){$(Identifiers.removeFormModalTrigger).on("click",(function(t){const a=[];t.preventDefault();const r=$(t.currentTarget);a.push({text:TYPO3.lang["formManager.cancel"],active:!0,btnClass:"btn-default",name:"cancel",trigger:function(e,t){t.hideModal()}}),a.push({text:TYPO3.lang["formManager.remove_form"],active:!0,btnClass:"btn-warning",name:"createform",trigger:function(t,a){document.location=e.getAjaxEndpoint("delete")+"&formPersistenceIdentifier="+r.data("formPersistenceIdentifier"),a.hideModal()}}),Modal.show(TYPO3.lang["formManager.remove_form_title"],TYPO3.lang["formManager.remove_form_message"],Severity.warning,a)}))}function duplicateFormSetup(e){$(Identifiers.duplicateFormModalTrigger).on("click",(function(t){t.preventDefault();const a=$(t.currentTarget);MultiStepWizard.addSlide("duplicate-form-step-1",TYPO3.lang["formManager.duplicateFormWizard.step1.title"].replace("{0}",a.data("formName")),"",Severity.info,top.TYPO3.lang["wizard.progressStep.configure"],(function(t){let r,i;MultiStepWizard.lockPrevStep(),MultiStepWizard.lockNextStep();const o=MultiStepWizard.setup.$carousel.closest(".modal"),n=o.find(".modal-footer").find('button[name="next"]'),l=e.getAccessibleFormStorageFolders();if(e.assert(l.length>0,"No accessible form storage folders",1477649539),MultiStepWizard.set("formPersistenceIdentifier",a.data("formPersistenceIdentifier")),MultiStepWizard.set("savePath",l[0].value),l.length>1){i=$('<select id="duplicate-form-save-path" class="form-select" data-identifier="duplicateFormSavePath" />');for(let e=0,t=l.length;e<t;++e){const t=new Option(l[e].label,l[e].value);$(i).append(t)}}r='<div class="duplicate-form-modal"><h5 class="form-section-headline">'+TYPO3.lang["formManager.new_form_name"]+'</h5><div class="mb-3"><label for="duplicate-form-name"><strong>'+TYPO3.lang["formManager.form_name"]+'</strong></label><div class="formengine-field-item t3js-formengine-field-item"><div class="form-description">'+TYPO3.lang["formManager.form_name_description"]+'</div><div class="form-control-wrap"><input id="duplicate-form-name" class="form-control has-error" data-identifier="duplicateFormName" /></div></div></div>',i&&(r+='<div class="mb-3"><label for="duplicate-form-save-path"><strong>'+TYPO3.lang["formManager.form_save_path"]+'</strong></label><div class="formengine-field-item t3js-formengine-field-item"><div class="form-description">'+TYPO3.lang["formManager.form_save_path_description"]+'</div><div class="form-control-wrap">'+$(i)[0].outerHTML+"</div></div></div>"),r+="</div>",t.html(r),$(Identifiers.duplicateFormName,o).focus(),$(Identifiers.duplicateFormName,o).on("keyup paste",(function(e){const t=$(event.currentTarget);t.val().length>0?(t.removeClass("has-error"),MultiStepWizard.unlockNextStep(),MultiStepWizard.set("formName",t.val()),"code"in e&&"Enter"===e.code&&MultiStepWizard.triggerStepButton("next")):(t.addClass("has-error"),MultiStepWizard.lockNextStep())})),n.on("click",(async function(){MultiStepWizard.setup.forceSelection=!1,MultiStepWizard.set("confirmationDuplicateFormName",a.data("formName")),l.length>1?(MultiStepWizard.set("savePath",$(Identifiers.duplicateFormSavePath+" option:selected",o).val()),MultiStepWizard.set("confirmationDuplicateFormSavePath",$(Identifiers.duplicateFormSavePath+" option:selected",o).text())):(MultiStepWizard.set("savePath",l[0].value),MultiStepWizard.set("confirmationDuplicateFormSavePath",l[0].label)),t.html($("<div />",{class:"text-center"}).append(await Icons.getIcon("spinner-circle",Icons.sizes.default,null,null)).prop("outerHTML"))}))})),MultiStepWizard.addSlide("duplicate-form-step-2",TYPO3.lang["formManager.duplicateFormWizard.step2.title"],"",Severity.info,TYPO3.lang["formManager.duplicateFormWizard.step2.progressLabel"],(async function(e,t){const a=await Icons.getIcon("actions-file-t3d",Icons.sizes.small),r=await Icons.getIcon("actions-tag",Icons.sizes.small),i=await Icons.getIcon("actions-database",Icons.sizes.small);MultiStepWizard.unlockPrevStep(),MultiStepWizard.unlockNextStep();const o=MultiStepWizard.setup.$carousel.closest(".modal").find(".modal-footer").find('button[name="next"]');let n='<div class="new-form-modal"><div class="row"><div class="col">';n+='<div class="mb-3"><h5 class="form-section-headline">'+TYPO3.lang["formManager.duplicateFormWizard.step2.check"]+"</h5><p>"+TYPO3.lang["formManager.newFormWizard.step3.message"]+'</p></div><div class="alert alert-notice"><div class="alert-body mt-1"><div class="dropdown-table-row"><div class="dropdown-table-column dropdown-table-icon">'+a+'</div><div class="dropdown-table-column dropdown-table-title">'+TYPO3.lang["formManager.form_copied"]+'</div><div class="dropdown-table-column dropdown-table-value">'+securityUtility.encodeHtml(t.confirmationDuplicateFormName)+'</div></div><div class="dropdown-table-row"><div class="dropdown-table-column dropdown-table-icon">'+r+'</div><div class="dropdown-table-column dropdown-table-title">'+TYPO3.lang["formManager.form_name"]+'</div><div class="dropdown-table-column dropdown-table-value">'+securityUtility.encodeHtml(t.formName)+'</div></div><div class="dropdown-table-row"><div class="dropdown-table-column dropdown-table-icon">'+i+'</div><div class="dropdown-table-column dropdown-table-title">'+TYPO3.lang["formManager.form_save_path"]+'</div><div class="dropdown-table-column dropdown-table-value">'+securityUtility.encodeHtml(t.confirmationDuplicateFormSavePath)+"</div></div></div></div>",n+="</div></div></div>",e.html(n),o.focus(),o.on("click",(async function(){MultiStepWizard.setup.forceSelection=!1,e.html($("<div />",{class:"text-center"}).append(await Icons.getIcon("spinner-circle",Icons.sizes.default,null,null)).prop("outerHTML"))}))})),MultiStepWizard.addFinalProcessingSlide((function(){$.post(e.getAjaxEndpoint("duplicate"),{formName:MultiStepWizard.setup.settings.formName,formPersistenceIdentifier:MultiStepWizard.setup.settings.formPersistenceIdentifier,savePath:MultiStepWizard.setup.settings.savePath},(function(e){"success"===e.status?document.location=e.url:Notification.error(TYPO3.lang["formManager.duplicateFormWizard.step3.errorTitle"],TYPO3.lang["formManager.duplicateFormWizard.step3.errorMessage"]+" "+e.message),MultiStepWizard.dismiss()})).fail((function(e,t,a){const r=(new DOMParser).parseFromString(e.responseText,"text/html"),i=$(r.body);Notification.error(t,a,2),MultiStepWizard.dismiss(),$(Identifiers.t3Logo,i).remove(),$(Identifiers.t3Footer,i).remove(),$(Identifiers.moduleBody).html(i.html())}))})).then((function(){MultiStepWizard.show()}))}))}function showReferencesSetup(e){$(Identifiers.showReferences).on("click",(t=>{t.preventDefault();const a=$(t.currentTarget),r=e.getAjaxEndpoint("references")+"&formPersistenceIdentifier="+a.data("formPersistenceIdentifier");$.get(r,(function(e){let t;const r=[];r.push({text:TYPO3.lang["formManager.cancel"],active:!0,btnClass:"btn-default",name:"cancel",trigger:function(e,t){t.hideModal()}});if(e.references.length>0){t="<div><h3>"+TYPO3.lang["formManager.references.headline"].replace("{0}",a.data("formName"))+'</h3></div><div class="table-fit"><table id="forms" class="table table-striped table-sm"><thead><tr><th>'+TYPO3.lang["formManager.page"]+"</th><th>"+TYPO3.lang["formManager.record"]+"</th></tr></thead><tbody>";for(let a=0,r=e.references.length;a<r;++a)t+="<tr><td>"+e.references[a].recordPageTitle+"</td><td>"+e.references[a].recordIcon+'<a href="'+e.references[a].recordEditUrl+'" data-identifier="referenceLink">'+e.references[a].recordTitle+" (uid: "+e.references[a].recordUid+")</a></td></tr>";t+="</tbody></table></div>"}else t="<div><h1>"+TYPO3.lang["formManager.references.title"].replace("{0}",e.formPersistenceIdentifier)+"</h1></div><div>"+TYPO3.lang["formManager.no_references"]+"</div>";t=$(t),$(Identifiers.referenceLink,t).on("click",(function(e){e.preventDefault(),Modal.currentModal.hideModal(),document.location=$(e.currentTarget).prop("href")})),Modal.show(TYPO3.lang["formManager.references.title"],t,Severity.info,r)})).fail((function(e,t,a){0!==e.status&&Notification.error(t,a,2)}))}))}!function(e){e.newFormModalTrigger='[data-identifier="newForm"]',e.duplicateFormModalTrigger='[data-identifier="duplicateForm"]',e.removeFormModalTrigger='[data-identifier="removeForm"]',e.newFormModeButton='[data-identifier="newFormModeButton"]',e.newFormName='[data-identifier="newFormName"]',e.newFormSavePath='[data-identifier="newFormSavePath"]',e.newFormPrototypeName='[data-identifier="newFormPrototypeName"]',e.newFormTemplate='[data-identifier="newFormTemplate"]',e.duplicateFormName='[data-identifier="duplicateFormName"]',e.duplicateFormSavePath='[data-identifier="duplicateFormSavePath"]',e.showReferences='[data-identifier="showReferences"]',e.referenceLink='[data-identifier="referenceLink"]',e.moduleBody=".module-body.t3js-module-body",e.t3Logo=".t3-message-page-logo",e.t3Footer="#t3-footer"}(Identifiers||(Identifiers={}));export function bootstrap(e){removeFormSetup(e),newFormSetup(e),duplicateFormSetup(e),showReferencesSetup(e)}
\ No newline at end of file
-- 
GitLab