From cef99dd290b88169bcceaafdeef358e3cccdf9f3 Mon Sep 17 00:00:00 2001
From: Andreas Fernandez <a.fernandez@scripting-base.de>
Date: Sun, 8 Mar 2020 15:06:30 +0100
Subject: [PATCH] [BUGFIX] Bind onChange alert to field again

The change of #88665 aimed to centralize the onchange behavior for all
FormEngine fields. The result of this change is that this didn't work
for all field types. Due to the fact the FormEngine rendering is rather
cluttered (e.g. sometimes there are hidden fields that hold the actual
value) and it's not possible to bind a global event delegation to such
fields right now, this patch now uses the onchange handling again which
was tried to be replaced.

Resolves: #90672
Related: #88665
Releases: master
Change-Id: I17d54edfc45dd39735bcc53ed0fd92e9fa061f13
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/63621
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Susanne Moog <look@susi.dev>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: Susanne Moog <look@susi.dev>
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
---
 .../Container/FlexFormElementContainer.php    | 28 +++++++----
 .../Form/Container/SingleFieldContainer.php   | 48 +++++++++++--------
 2 files changed, 48 insertions(+), 28 deletions(-)

diff --git a/typo3/sysext/backend/Classes/Form/Container/FlexFormElementContainer.php b/typo3/sysext/backend/Classes/Form/Container/FlexFormElementContainer.php
index 88cc6da04b4a..1046593d6bbe 100644
--- a/typo3/sysext/backend/Classes/Form/Container/FlexFormElementContainer.php
+++ b/typo3/sysext/backend/Classes/Form/Container/FlexFormElementContainer.php
@@ -18,7 +18,6 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * The container handles single elements.
@@ -85,6 +84,25 @@ class FlexFormElementContainer extends AbstractContainer
                     $fakeParameterArray['fieldConf']['description'] = $flexFormFieldArray['description'];
                 }
 
+                $alertMsgOnChange = '';
+                if (isset($fakeParameterArray['fieldConf']['onChange']) && $fakeParameterArray['fieldConf']['onChange'] === 'reload') {
+                    if ($this->getBackendUserAuthentication()->jsConfirmation(JsConfirmation::TYPE_CHANGE)) {
+                        $alertMsgOnChange = 'Modal.confirm('
+                            . 'TYPO3.lang["FormEngine.refreshRequiredTitle"],'
+                            . ' TYPO3.lang["FormEngine.refreshRequiredContent"]'
+                            . ')'
+                            . '.on('
+                            . '"button.clicked",'
+                            . ' function(e) { if (e.target.name == "ok") { FormEngine.saveDocument(); } Modal.dismiss(); }'
+                            . ');';
+                    } else {
+                        $alertMsgOnChange = 'FormEngine.saveDocument();';
+                    }
+                }
+                if ($alertMsgOnChange) {
+                    $fakeParameterArray['fieldChangeFunc']['alert'] = 'require([\'TYPO3/CMS/Backend/FormEngine\', \'TYPO3/CMS/Backend/Modal\'], function (FormEngine, Modal) {' . $alertMsgOnChange . '});';
+                }
+
                 $originalFieldName = $parameterArray['itemFormElName'];
                 $fakeParameterArray['itemFormElName'] = $parameterArray['itemFormElName'] . $flexFormFormPrefix . '[' . $flexFormFieldName . '][vDEF]';
                 if ($fakeParameterArray['itemFormElName'] !== $originalFieldName) {
@@ -120,14 +138,6 @@ class FlexFormElementContainer extends AbstractContainer
                 }
                 $childResult = $this->nodeFactory->create($options)->render();
 
-                // Create a JavaScript code line which will ask the user to save/update the form due to changing the element.
-                // This is used for eg. "type" fields and others configured with "onChange"
-                if (isset($fakeParameterArray['fieldConf']['onChange']) && $fakeParameterArray['fieldConf']['onChange'] === 'reload') {
-                    $showConfirmation = $this->getBackendUserAuthentication()->jsConfirmation(JsConfirmation::TYPE_CHANGE) ? 'true' : 'false';
-
-                    $resultArray['requireJsModules'][] = ['TYPO3/CMS/Backend/FormEngine' => 'function (FormEngine) {FormEngine.requestConfirmationOnFieldChange(' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ', ' . $showConfirmation . ');}'];
-                }
-
                 if (!empty($childResult['html'])) {
                     // Possible line breaks in the label through xml: \n => <br/>, usage of nl2br() not possible, so it's done through str_replace (?!)
                     $processedTitle = str_replace('\\n', '<br />', htmlspecialchars($fakeParameterArray['fieldConf']['label']));
diff --git a/typo3/sysext/backend/Classes/Form/Container/SingleFieldContainer.php b/typo3/sysext/backend/Classes/Form/Container/SingleFieldContainer.php
index ab2ab44f90f8..22f461ecc0f7 100644
--- a/typo3/sysext/backend/Classes/Form/Container/SingleFieldContainer.php
+++ b/typo3/sysext/backend/Classes/Form/Container/SingleFieldContainer.php
@@ -110,6 +110,32 @@ class SingleFieldContainer extends AbstractContainer
             $parameterArray['itemFormElValue'] = $this->data['defaultLanguageRow'][$fieldName];
         }
 
+        if (strpos($this->data['processedTca']['ctrl']['type'], ':') === false) {
+            $typeField = $this->data['processedTca']['ctrl']['type'];
+        } else {
+            $typeField = substr($this->data['processedTca']['ctrl']['type'], 0, strpos($this->data['processedTca']['ctrl']['type'], ':'));
+        }
+        // Create a JavaScript code line which will ask the user to save/update the form due to changing the element.
+        // This is used for eg. "type" fields and others configured with "onChange"
+        if (!empty($this->data['processedTca']['ctrl']['type']) && $fieldName === $typeField
+            || isset($parameterArray['fieldConf']['onChange']) && $parameterArray['fieldConf']['onChange'] === 'reload'
+        ) {
+            if ($backendUser->jsConfirmation(JsConfirmation::TYPE_CHANGE)) {
+                $alertMsgOnChange = 'Modal.confirm('
+                    . 'TYPO3.lang["FormEngine.refreshRequiredTitle"],'
+                    . ' TYPO3.lang["FormEngine.refreshRequiredContent"]'
+                    . ')'
+                    . '.on('
+                    . '"button.clicked",'
+                    . ' function(e) { if (e.target.name == "ok") { FormEngine.saveDocument(); } Modal.dismiss(); }'
+                    . ');';
+            } else {
+                $alertMsgOnChange = 'FormEngine.saveDocument();';
+            }
+        } else {
+            $alertMsgOnChange = '';
+        }
+
         // JavaScript code for event handlers:
         $parameterArray['fieldChangeFunc'] = [];
         $parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'TBE_EDITOR.fieldChanged('
@@ -118,6 +144,9 @@ class SingleFieldContainer extends AbstractContainer
             . GeneralUtility::quoteJSvalue($fieldName) . ','
             . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName'])
             . ');';
+        if ($alertMsgOnChange) {
+            $parameterArray['fieldChangeFunc']['alert'] = 'require([\'TYPO3/CMS/Backend/FormEngine\', \'TYPO3/CMS/Backend/Modal\'], function (FormEngine, Modal) {' . $alertMsgOnChange . '});';
+        }
 
         // Based on the type of the item, call a render function on a child element
         $options = $this->data;
@@ -130,25 +159,6 @@ class SingleFieldContainer extends AbstractContainer
             $options['renderType'] = $parameterArray['fieldConf']['config']['type'];
         }
         $resultArray = $this->nodeFactory->create($options)->render();
-
-        if (strpos($this->data['processedTca']['ctrl']['type'], ':') === false) {
-            $typeField = $this->data['processedTca']['ctrl']['type'];
-        } else {
-            $typeField = substr($this->data['processedTca']['ctrl']['type'], 0, strpos($this->data['processedTca']['ctrl']['type'], ':'));
-        }
-
-        // Create a JavaScript code line which will ask the user to save/update the form due to changing the element.
-        // This is used for eg. "type" fields and others configured with "onChange"
-        if ((!empty($this->data['processedTca']['ctrl']['type']) && $fieldName === $typeField)
-            || (isset($parameterArray['fieldConf']['onChange']) && $parameterArray['fieldConf']['onChange'] === 'reload')
-        ) {
-            $showConfirmation = $backendUser->jsConfirmation(JsConfirmation::TYPE_CHANGE) ? 'true' : 'false';
-
-            $resultArray['requireJsModules'][] = ['TYPO3/CMS/Backend/FormEngine' => 'function (FormEngine) {'
-                . 'FormEngine.requestConfirmationOnFieldChange(' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ', ' . $showConfirmation . ');'
-                . '}'];
-        }
-
         return $resultArray;
     }
 
-- 
GitLab