[TASK] Split FormEngine.js 08/58608/22
authorAndreas Fernandez <a.fernandez@scripting-base.de>
Wed, 10 Oct 2018 17:41:02 +0000 (19:41 +0200)
committerFrank Naegler <frank.naegler@typo3.org>
Thu, 14 Mar 2019 08:03:44 +0000 (09:03 +0100)
This patch splits the FormEngine.js into smaller, logically separated
parts. This increases readability and maintainability and has a positive
effect on the client's performance as only the required code is loaded.

Not every aspect of the FormEngine JavaScript is handled here yet, since
other areas, e.g. IRRE, need refactoring as well.

Resolves: #87324
Releases: master
Change-Id: I6704445254a524f8ed3152ab6b0b7105fb97d65a
Reviewed-on: https://review.typo3.org/c/58608
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: André Schließer <andy.schliesser@gmail.com>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Frank Naegler <frank.naegler@typo3.org>
Reviewed-by: André Schließer <andy.schliesser@gmail.com>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
34 files changed:
Build/types/TYPO3/index.d.ts
typo3/sysext/backend/Classes/Form/Element/GroupElement.php
typo3/sysext/backend/Classes/Form/Element/InputDateTimeElement.php
typo3/sysext/backend/Classes/Form/Element/InputLinkElement.php
typo3/sysext/backend/Classes/Form/Element/SelectCheckBoxElement.php
typo3/sysext/backend/Classes/Form/Element/SelectMultipleSideBySideElement.php
typo3/sysext/backend/Classes/Form/Element/TextElement.php
typo3/sysext/backend/Classes/Form/Element/TextTableElement.php
typo3/sysext/backend/Classes/Form/FieldWizard/LocalizationStateSelector.php
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/AbstractSortableSelectItems.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/Extra/SelectBoxFilter.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/GroupElement.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/InputDateTimeElement.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/InputLinkElement.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/Modifier/Resizable.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/Modifier/Tabbable.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/SelectCheckBoxElement.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/SelectMultipleSideBySideElement.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/TextElement.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/TextTableElement.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/FieldWizard/LocalizationStateSelector.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine.js
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/AbstractSortableSelectItems.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/Extra/SelectBoxFilter.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/GroupElement.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/InputDateTimeElement.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/InputLinkElement.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/Modifier/Resizable.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/Modifier/Tabbable.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SelectCheckBoxElement.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SelectMultipleSideBySideElement.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/TextElement.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/TextTableElement.js [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/FieldWizard/LocalizationStateSelector.js [new file with mode: 0644]

index f542594..278b244 100644 (file)
@@ -36,6 +36,9 @@ declare namespace TYPO3 {
 
       export class FormEngine {
         public readonly Validation: FormEngineValidation;
+        public legacyFieldChangedCb(): void;
+        public getFieldElement(fieldName: string, appendix?: string, noFallback?: boolean): JQuery;
+        public updateHiddenFieldValueFromSelect(selectFieldEl: HTMLElement, originalFieldEl: HTMLElement): void;
         public preventFollowLinkIfNotSaved(href: string): boolean;
         public setSelectOptionFromExternalSource(
           fieldName: string,
index 2c4e949..64a818a 100644 (file)
@@ -255,10 +255,13 @@ class GroupElement extends AbstractFormElement
             $deleteControlOnClick = 'inline.revertUnique(' . GeneralUtility::quoteJSvalue($objectPrefix) . ',null,' . GeneralUtility::quoteJSvalue($row['uid']) . ');';
         }
 
+        $fieldId = StringUtility::getUniqueId('tceforms-multiselect-');
+
         $selectorAttributes = [
-            'id' => StringUtility::getUniqueId('tceforms-multiselect-'),
+            'id' => $fieldId,
             'data-formengine-input-name' => htmlspecialchars($elementName),
             'data-formengine-validation-rules' => $this->getValidationDataAsJsonString($config),
+            'data-maxitems' => $maxItems,
             'size' => $size,
         ];
         $selectorClasses = [
@@ -321,7 +324,7 @@ class GroupElement extends AbstractFormElement
         $html[] =           '<div class="btn-group-vertical">';
         if ($maxItems > 1 && $size >=5 && $showMoveIcons) {
             $html[] =           '<a href="#"';
-            $html[] =               ' class="btn btn-default t3js-btn-moveoption-top"';
+            $html[] =               ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-top"';
             $html[] =               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
             $html[] =               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_to_top')) . '"';
             $html[] =           '>';
@@ -330,14 +333,14 @@ class GroupElement extends AbstractFormElement
         }
         if ($maxItems > 1 && $size > 1 && $showMoveIcons) {
             $html[] =           '<a href="#"';
-            $html[] =               ' class="btn btn-default t3js-btn-moveoption-up"';
+            $html[] =               ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-up"';
             $html[] =               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
             $html[] =               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_up')) . '"';
             $html[] =           '>';
             $html[] =               $this->iconFactory->getIcon('actions-move-up', Icon::SIZE_SMALL)->render();
             $html[] =           '</a>';
             $html[] =           '<a href="#"';
-            $html[] =               ' class="btn btn-default t3js-btn-moveoption-down"';
+            $html[] =               ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-down"';
             $html[] =               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
             $html[] =               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_down')) . '"';
             $html[] =           '>';
@@ -346,7 +349,7 @@ class GroupElement extends AbstractFormElement
         }
         if ($maxItems > 1 && $size >= 5 && $showMoveIcons) {
             $html[] =           '<a href="#"';
-            $html[] =               ' class="btn btn-default t3js-btn-moveoption-bottom"';
+            $html[] =               ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-bottom"';
             $html[] =               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
             $html[] =               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_to_bottom')) . '"';
             $html[] =           '>';
@@ -355,7 +358,7 @@ class GroupElement extends AbstractFormElement
         }
         if ($showDeleteControl) {
             $html[] =           '<a href="#"';
-            $html[] =               ' class="btn btn-default t3js-btn-removeoption"';
+            $html[] =               ' class="btn btn-default t3js-btn-option t3js-btn-removeoption"';
             $html[] =               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
             $html[] =               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.remove_selected')) . '"';
             $html[] =               ' onClick="' . $deleteControlOnClick . '"';
@@ -379,6 +382,12 @@ class GroupElement extends AbstractFormElement
         $html[] =   '<input type="hidden" name="' . htmlspecialchars($elementName) . '" value="' . htmlspecialchars(implode(',', $listOfSelectedValues)) . '" />';
         $html[] = '</div>';
 
+        $resultArray['requireJsModules'][] = ['TYPO3/CMS/Backend/FormEngine/Element/GroupElement' => '
+            function(GroupElement) {
+                new GroupElement(' . GeneralUtility::quoteJSvalue($fieldId) . ');
+            }'
+        ];
+
         $resultArray['html'] = implode(LF, $html);
         return $resultArray;
     }
index a777d9a..b92fddb 100644 (file)
@@ -270,6 +270,7 @@ class InputDateTimeElement extends AbstractFormElement
             $fullElement = implode(LF, $fullElement);
         }
 
+        $resultArray['requireJsModules'][] = 'TYPO3/CMS/Backend/FormEngine/Element/InputDateTimeElement';
         $resultArray['html'] = '<div class="formengine-field-item t3js-formengine-field-item">' . $fieldInformationHtml . $fullElement . '</div>';
         return $resultArray;
     }
index d5ca4b9..fb2080f 100644 (file)
@@ -147,9 +147,11 @@ class InputLinkElement extends AbstractFormElement
             }
         }
 
+        $fieldId = StringUtility::getUniqueId('formengine-input-');
+
         $attributes = [
             'value' => '',
-            'id' => StringUtility::getUniqueId('formengine-input-'),
+            'id' => $fieldId,
             'class' => implode(' ', [
                 'form-control',
                 't3js-clearable',
@@ -302,6 +304,11 @@ class InputLinkElement extends AbstractFormElement
             $fullElement = implode(LF, $fullElement);
         }
 
+        $resultArray['requireJsModules'][] = ['TYPO3/CMS/Backend/FormEngine/Element/InputLinkElement' => '
+            function(InputLinkElement) {
+                new InputLinkElement(' . GeneralUtility::quoteJSvalue($fieldId) . ');
+            }'
+        ];
         $resultArray['html'] = '<div class="formengine-field-item t3js-formengine-field-item">' . $fieldInformationHtml . $fullElement . '</div>';
         return $resultArray;
     }
index c2f8af8..81253de 100644 (file)
@@ -237,6 +237,12 @@ class SelectCheckBoxElement extends AbstractFormElement
                     if (is_array($group['header'])) {
                         $html[] = '</div>';
                     }
+
+                    $resultArray['requireJsModules'][] = ['TYPO3/CMS/Backend/FormEngine/Element/SelectCheckBoxElement' => '
+                        function(SelectCheckBoxElement) {
+                            new SelectCheckBoxElement(' . GeneralUtility::quoteJSvalue($checkboxId) . ');
+                        }'
+                    ];
                 }
                 $html[] = '</div>';
             }
index c1aa368..902cafd 100644 (file)
@@ -217,6 +217,9 @@ class SelectMultipleSideBySideElement extends AbstractFormElement
         $fieldWizardHtml = $fieldWizardResult['html'];
         $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
 
+        $selectedOptionsFieldId = StringUtility::getUniqueId('tceforms-multiselect-');
+        $availableOptionsFieldId = StringUtility::getUniqueId('tceforms-multiselect-');
+
         $html = [];
         $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
         $html[] =   $fieldInformationHtml;
@@ -231,7 +234,7 @@ class SelectMultipleSideBySideElement extends AbstractFormElement
         $html[] =                   '<div class="form-wizards-wrap form-wizards-aside">';
         $html[] =                       '<div class="form-wizards-element">';
         $html[] =                           '<select';
-        $html[] =                               ' id="' . StringUtility::getUniqueId('tceforms-multiselect-') . '"';
+        $html[] =                               ' id="' . $selectedOptionsFieldId . '"';
         $html[] =                               ' size="' . $size . '"';
         $html[] =                               ' class="' . implode(' ', $classes) . '"';
         $html[] =                               $multipleAttribute;
@@ -244,7 +247,7 @@ class SelectMultipleSideBySideElement extends AbstractFormElement
         $html[] =                           '<div class="btn-group-vertical">';
         if ($maxItems > 1 && $size >= 5) {
             $html[] =                           '<a href="#"';
-            $html[] =                               ' class="btn btn-default t3js-btn-moveoption-top"';
+            $html[] =                               ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-top"';
             $html[] =                               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
             $html[] =                               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_to_top')) . '"';
             $html[] =                           '>';
@@ -253,14 +256,14 @@ class SelectMultipleSideBySideElement extends AbstractFormElement
         }
         if ($maxItems > 1) {
             $html[] =                           '<a href="#"';
-            $html[] =                               ' class="btn btn-default t3js-btn-moveoption-up"';
+            $html[] =                               ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-up"';
             $html[] =                               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
             $html[] =                               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_up')) . '"';
             $html[] =                           '>';
             $html[] =                               $this->iconFactory->getIcon('actions-move-up', Icon::SIZE_SMALL)->render();
             $html[] =                           '</a>';
             $html[] =                           '<a href="#"';
-            $html[] =                               ' class="btn btn-default t3js-btn-moveoption-down"';
+            $html[] =                               ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-down"';
             $html[] =                               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
             $html[] =                               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_down')) . '"';
             $html[] =                           '>';
@@ -269,7 +272,7 @@ class SelectMultipleSideBySideElement extends AbstractFormElement
         }
         if ($maxItems > 1 && $size >= 5) {
             $html[] =                           '<a href="#"';
-            $html[] =                               ' class="btn btn-default t3js-btn-moveoption-bottom"';
+            $html[] =                               ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-bottom"';
             $html[] =                               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
             $html[] =                               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_to_bottom')) . '"';
             $html[] =                           '>';
@@ -277,7 +280,7 @@ class SelectMultipleSideBySideElement extends AbstractFormElement
             $html[] =                           '</a>';
         }
         $html[] =                               '<a href="#"';
-        $html[] =                                   ' class="btn btn-default t3js-btn-removeoption"';
+        $html[] =                                   ' class="btn btn-default t3js-btn-option t3js-btn-removeoption"';
         $html[] =                                   ' data-fieldname="' . htmlspecialchars($elementName) . '"';
         $html[] =                                   ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.remove_selected')) . '"';
         $html[] =                               '>';
@@ -297,7 +300,7 @@ class SelectMultipleSideBySideElement extends AbstractFormElement
         $html[] =                           '<select';
         $html[] =                               ' data-relatedfieldname="' . htmlspecialchars($elementName) . '"';
         $html[] =                               ' data-exclusivevalues="' . htmlspecialchars($config['exclusiveKeys']) . '"';
-        $html[] =                               ' id="' . StringUtility::getUniqueId('tceforms-multiselect-') . '"';
+        $html[] =                               ' id="' . $availableOptionsFieldId . '"';
         $html[] =                               ' data-formengine-input-name="' . htmlspecialchars($elementName) . '"';
         $html[] =                               ' class="form-control t3js-formengine-select-itemstoselect"';
         $html[] =                               ' size="' . $size . '"';
@@ -327,6 +330,12 @@ class SelectMultipleSideBySideElement extends AbstractFormElement
         $html[] =   '</div>';
         $html[] = '</div>';
 
+        $resultArray['requireJsModules'][] = ['TYPO3/CMS/Backend/FormEngine/Element/SelectMultipleSideBySideElement' => '
+            function(SelectMultipleSideBySideElement) {
+                new SelectMultipleSideBySideElement(' . GeneralUtility::quoteJSvalue($selectedOptionsFieldId) . ', ' . GeneralUtility::quoteJSvalue($availableOptionsFieldId) . ');
+            }'
+        ];
+
         $resultArray['html'] = implode(LF, $html);
         return $resultArray;
     }
index 13a08cd..026451f 100644 (file)
@@ -146,8 +146,10 @@ class TextElement extends AbstractFormElement
             }
         }
 
+        $fieldId = StringUtility::getUniqueId('formengine-textarea-');
+
         $attributes = [
-            'id' => StringUtility::getUniqueId('formengine-textarea-'),
+            'id' => $fieldId,
             'name' => htmlspecialchars($parameterArray['itemFormElName']),
             'data-formengine-validation-rules' => $this->getValidationDataAsJsonString($config),
             'data-formengine-input-name' => htmlspecialchars($parameterArray['itemFormElName']),
@@ -301,6 +303,11 @@ class TextElement extends AbstractFormElement
             $fullElement = implode(LF, $fullElement);
         }
 
+        $resultArray['requireJsModules'][] = ['TYPO3/CMS/Backend/FormEngine/Element/TextElement' => '
+            function(TextElement) {
+                new TextElement(' . GeneralUtility::quoteJSvalue($fieldId) . ');
+            }'
+        ];
         $resultArray['html'] = '<div class="formengine-field-item t3js-formengine-field-item">' . $fieldInformationHtml . $fullElement . '</div>';
         return $resultArray;
     }
index 446807b..b451a64 100644 (file)
@@ -151,8 +151,10 @@ class TextTableElement extends AbstractFormElement
             }
         }
 
+        $fieldId = StringUtility::getUniqueId('formengine-textarea-');
+
         $attributes = [
-            'id' => StringUtility::getUniqueId('formengine-textarea-'),
+            'id' => $fieldId,
             'name' => htmlspecialchars($parameterArray['itemFormElName']),
             'data-formengine-validation-rules' => $this->getValidationDataAsJsonString($config),
             'data-formengine-input-name' => htmlspecialchars($parameterArray['itemFormElName']),
@@ -216,6 +218,11 @@ class TextTableElement extends AbstractFormElement
         $html[] =   '</div>';
         $html[] = '</div>';
 
+        $resultArray['requireJsModules'][] = ['TYPO3/CMS/Backend/FormEngine/Element/TextTableElement' => '
+            function(TextTableElement) {
+                new TextTableElement(' . GeneralUtility::quoteJSvalue($fieldId) . ');
+            }'
+        ];
         $resultArray['html'] = implode(LF, $html);
         return $resultArray;
     }
index f708591..c4edaac 100644 (file)
@@ -18,6 +18,7 @@ namespace TYPO3\CMS\Backend\Form\FieldWizard;
 use TYPO3\CMS\Backend\Form\AbstractNode;
 use TYPO3\CMS\Core\DataHandling\Localization\State;
 use TYPO3\CMS\Core\Localization\LanguageService;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Allows to define the localization state per field.
@@ -127,6 +128,11 @@ class LocalizationStateSelector extends AbstractNode
         }
         $html[] = '</div>';
 
+        $result['requireJsModules'][] = ['TYPO3/CMS/Backend/FormEngine/FieldWizard/LocalizationStateSelector' => '
+            function(LocalizationStateSelector) {
+                new LocalizationStateSelector(' . GeneralUtility::quoteJSvalue($fieldElementName) . ');
+            }'
+        ];
         $result['html'] = implode(LF, $html);
         return $result;
     }
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/AbstractSortableSelectItems.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/AbstractSortableSelectItems.ts
new file mode 100644 (file)
index 0000000..680b814
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+import * as $ from 'jquery';
+import FormEngine = require('TYPO3/CMS/Backend/FormEngine');
+import FormEngineValidation = require('TYPO3/CMS/Backend/FormEngineValidation');
+
+export abstract class AbstractSortableSelectItems {
+
+  /**
+   * Moves currently selected options from a select field to the very top,
+   * can be multiple entries as well
+   *
+   * @param {HTMLSelectElement} fieldElement
+   */
+  private static moveOptionToTop(fieldElement: HTMLSelectElement): void {
+    Array.from(fieldElement.querySelectorAll(':checked')).reverse().forEach((optionEl: HTMLOptionElement): void => {
+      fieldElement.insertBefore(optionEl, fieldElement.firstElementChild);
+    });
+  }
+
+  /**
+   * Moves currently selected options from a select field as the very last entries
+   *
+   * @param {HTMLSelectElement} fieldElement
+   */
+  private static moveOptionToBottom(fieldElement: HTMLSelectElement): void {
+    Array.from(fieldElement.querySelectorAll(':checked')).forEach((optionEl: HTMLOptionElement): void => {
+      fieldElement.insertBefore(optionEl, null);
+    });
+  }
+
+  /**
+   * Moves currently selected options from a select field up by one position,
+   * can be multiple entries as well
+   *
+   * @param {HTMLSelectElement} fieldElement
+   */
+  private static moveOptionUp(fieldElement: HTMLSelectElement): void {
+    const allChildren = Array.from(fieldElement.children);
+    const selectedOptions = Array.from(fieldElement.querySelectorAll(':checked'));
+    for (let optionEl of selectedOptions) {
+      if (allChildren.indexOf(optionEl) === 0 && optionEl.previousElementSibling === null) {
+        break;
+      }
+
+      fieldElement.insertBefore(optionEl, optionEl.previousElementSibling);
+    }
+  }
+
+  /**
+   * Moves currently selected options from a select field up by one position,
+   * can be multiple entries as well
+   *
+   * @param {HTMLSelectElement} fieldElement
+   */
+  private static moveOptionDown(fieldElement: HTMLSelectElement): void {
+    const allChildren = Array.from(fieldElement.children).reverse();
+    const selectedOptions = Array.from(fieldElement.querySelectorAll(':checked')).reverse();
+    for (let optionEl of selectedOptions) {
+      if (allChildren.indexOf(optionEl) === 0 && optionEl.nextElementSibling === null) {
+        break;
+      }
+
+      fieldElement.insertBefore(optionEl, optionEl.nextElementSibling.nextElementSibling);
+    }
+  }
+
+  /**
+   * Removes currently selected options from a select field
+   *
+   * @param {HTMLSelectElement} fieldElement
+   * @param {HTMLSelectElement} availableFieldElement
+   */
+  private static removeOption(fieldElement: HTMLSelectElement, availableFieldElement: HTMLSelectElement): void {
+    Array.from(fieldElement.querySelectorAll(':checked')).forEach((option: HTMLOptionElement): void => {
+      const originalOption = <HTMLOptionElement>availableFieldElement.querySelector('option[value="' + option.value + '"]');
+      originalOption.classList.remove('hidden');
+      originalOption.disabled = false;
+
+      fieldElement.removeChild(option);
+    });
+  }
+
+  /**
+   * @param {HTMLSelectElement} fieldElement
+   */
+  protected registerSortableEventHandler = (fieldElement: HTMLSelectElement): void => {
+    const aside = fieldElement.closest('.form-wizards-wrap').querySelector('.form-wizards-items-aside');
+    if (aside === null) {
+      return;
+    }
+
+    aside.addEventListener('click', (e): void => {
+      let target: HTMLAnchorElement;
+
+      if ((target = <HTMLAnchorElement>(<Element>e.target).closest('.t3js-btn-option')) === null) {
+        if ((<Element>e.target).matches('.t3js-btn-option')) {
+          target = <HTMLAnchorElement>e.target;
+        }
+
+        return;
+      }
+
+      e.preventDefault();
+
+      const relatedFieldName = target.dataset.fieldname;
+
+      if (target.classList.contains('t3js-btn-moveoption-top')) {
+        AbstractSortableSelectItems.moveOptionToTop(fieldElement);
+      } else if (target.classList.contains('t3js-btn-moveoption-up')) {
+        AbstractSortableSelectItems.moveOptionUp(fieldElement);
+      } else if (target.classList.contains('t3js-btn-moveoption-down')) {
+        AbstractSortableSelectItems.moveOptionDown(fieldElement);
+      } else if (target.classList.contains('t3js-btn-moveoption-bottom')) {
+        AbstractSortableSelectItems.moveOptionToBottom(fieldElement);
+      } else if (target.classList.contains('t3js-btn-removeoption')) {
+        AbstractSortableSelectItems.removeOption(
+          fieldElement,
+          <HTMLSelectElement>FormEngine.getFieldElement(relatedFieldName, '_avail').get(0)
+        );
+      }
+
+      FormEngine.updateHiddenFieldValueFromSelect(fieldElement, FormEngine.getFieldElement(relatedFieldName).get(0));
+      FormEngine.legacyFieldChangedCb();
+      FormEngineValidation.markFieldAsChanged($(fieldElement));
+      FormEngineValidation.validate();
+    });
+  }
+}
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/Extra/SelectBoxFilter.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/Extra/SelectBoxFilter.ts
new file mode 100644 (file)
index 0000000..f5b1139
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+import * as $ from 'jquery';
+
+enum Selectors {
+  fieldContainerSelector = '.t3js-formengine-field-group',
+  filterTextFieldSelector = '.t3js-formengine-multiselect-filter-textfield',
+  filterSelectFieldSelector = '.t3js-formengine-multiselect-filter-dropdown'
+}
+
+/**
+ * Select field filter functions, see TCA option "enableMultiSelectFilterTextfield"
+ * and "multiSelectFilterItems"
+ */
+class SelectBoxFilter {
+  private selectElement: HTMLSelectElement = null;
+  private filterText: string = '';
+  private $availableOptions: JQuery = null;
+
+  constructor(selectElement: HTMLSelectElement) {
+    this.selectElement = selectElement;
+
+    this.initializeEvents();
+  }
+
+  private initializeEvents(): void {
+    const wizardsElement = this.selectElement.closest('.form-wizards-element');
+    if (wizardsElement === null) {
+      return;
+    }
+
+    wizardsElement.addEventListener('keyup', (e: Event): void => {
+      if ((<HTMLElement>e.target).matches(Selectors.filterTextFieldSelector)) {
+        this.filter((<HTMLInputElement>e.target).value);
+      }
+    });
+    wizardsElement.addEventListener('change', (e: Event): void => {
+      if ((<HTMLElement>e.target).matches(Selectors.filterSelectFieldSelector)) {
+        this.filter((<HTMLInputElement>e.target).value);
+      }
+    });
+  }
+
+  /**
+   * Filter the actual items
+   *
+   * @param {string} filterText
+   */
+  private filter(filterText: string): void {
+    this.filterText = filterText;
+    if (!this.$availableOptions) {
+      this.$availableOptions = $(this.selectElement).find('option').clone();
+    }
+
+    this.selectElement.innerHTML = '';
+    const matchFilter = new RegExp(filterText, 'i');
+
+    this.$availableOptions.each((i, el): void => {
+      if (filterText.length === 0 || el.textContent.match(matchFilter)) {
+        this.selectElement.appendChild(el);
+      }
+    });
+  }
+}
+
+export = SelectBoxFilter;
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/GroupElement.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/GroupElement.ts
new file mode 100644 (file)
index 0000000..ebe2b5d
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+import {AbstractSortableSelectItems} from './AbstractSortableSelectItems';
+import * as $ from 'jquery';
+import FormEngineSuggest = require('../../FormEngineSuggest');
+
+class GroupElement extends AbstractSortableSelectItems {
+  private element: HTMLSelectElement = null;
+
+  constructor(elementId: string) {
+    super();
+
+    $((): void => {
+      this.element = <HTMLSelectElement>document.querySelector('#' + elementId);
+      this.registerEventHandler();
+      this.registerSuggest();
+    });
+  }
+
+  private registerEventHandler(): void {
+    this.registerSortableEventHandler(this.element);
+  }
+
+  private registerSuggest(): void {
+    let suggestContainer;
+    if ((suggestContainer = <HTMLElement>this.element.closest('.t3js-formengine-field-item').querySelector('.t3-form-suggest')) !== null) {
+      // tslint:disable-next-line:no-unused-expression
+      new FormEngineSuggest(suggestContainer);
+    }
+  }
+}
+
+export = GroupElement;
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/InputDateTimeElement.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/InputDateTimeElement.ts
new file mode 100644 (file)
index 0000000..d91597b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+import * as $ from 'jquery';
+import FormEngine = require('TYPO3/CMS/Backend/FormEngine');
+
+class InputDateTimeElement {
+  constructor() {
+    $((): void => {
+      this.registerEventHandler();
+
+      if (document.querySelectorAll('.t3js-datetimepicker').length) {
+        require(['../../DateTimePicker']);
+      }
+    });
+  }
+
+  private registerEventHandler(): void {
+    $(document).on('formengine.dp.change', (event: JQueryEventObject, $field: JQuery): void => {
+      FormEngine.Validation.validate();
+      FormEngine.Validation.markFieldAsChanged($field);
+      $('.module-docheader-bar .btn').removeClass('disabled').prop('disabled', false);
+    });
+  }
+}
+
+export = new InputDateTimeElement();
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/InputLinkElement.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/InputLinkElement.ts
new file mode 100644 (file)
index 0000000..9e65f4c
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+import * as $ from 'jquery';
+
+enum Selectors {
+  toggleSelector = '.t3js-form-field-inputlink-explanation-toggle',
+  inputFieldSelector = '.t3js-form-field-inputlink-input',
+  explanationSelector = '.t3js-form-field-inputlink-explanation'
+}
+
+class InputLinkElement {
+  private element: HTMLSelectElement = null;
+  private container: HTMLElement = null;
+  private explanationField: HTMLInputElement = null;
+
+  constructor(elementId: string) {
+    $((): void => {
+      this.element = <HTMLSelectElement>document.querySelector('#' + elementId);
+      this.container = <HTMLElement>this.element.closest('.t3js-form-field-inputlink');
+      this.explanationField = <HTMLInputElement>this.container.querySelector(Selectors.explanationSelector);
+
+      this.toggleVisibility(this.explanationField.value === '');
+      this.registerEventHandler();
+    });
+  }
+
+  /**
+   * @param {boolean} explanationShown
+   */
+  private toggleVisibility(explanationShown: boolean): void {
+    this.explanationField.classList.toggle('hidden', explanationShown);
+    this.element.classList.toggle('hidden', !explanationShown);
+    const clearable = this.container.querySelector('.form-control-clearable button.close');
+    if (clearable !== null) {
+      clearable.classList.toggle('hidden', !explanationShown);
+    }
+  }
+
+  private registerEventHandler(): void {
+    this.container.querySelector(Selectors.toggleSelector).addEventListener('click', (e: Event): void => {
+      e.preventDefault();
+
+      const explanationShown = !this.explanationField.classList.contains('hidden');
+      this.toggleVisibility(explanationShown);
+    });
+
+    this.container.querySelector(Selectors.inputFieldSelector).addEventListener('change', (): void => {
+      const explanationShown = !this.explanationField.classList.contains('hidden');
+      if (explanationShown) {
+        this.toggleVisibility(explanationShown);
+      }
+    });
+  }
+}
+
+export = InputLinkElement;
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/Modifier/Resizable.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/Modifier/Resizable.ts
new file mode 100644 (file)
index 0000000..5ef7608
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Convert textarea so they grow when it is typed in.
+ */
+export class Resizable {
+
+  /**
+   * @param {HTMLTextAreaElement} textarea
+   */
+  public static enable(textarea: HTMLTextAreaElement): void {
+    if (TYPO3.settings.Textarea && TYPO3.settings.Textarea.autosize) {
+      require(['autosize'], (autosize: Function): void => {
+        autosize(textarea);
+      });
+    }
+  }
+}
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/Modifier/Tabbable.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/Modifier/Tabbable.ts
new file mode 100644 (file)
index 0000000..8fc94f8
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Convert textarea to enable tab
+ */
+export class Tabbable {
+
+  /**
+   * @param {HTMLTextAreaElement} textarea
+   */
+  public static enable(textarea: HTMLTextAreaElement): void {
+    if (textarea.classList.contains('t3js-enable-tab')) {
+      require(['taboverride'], (taboverride: any): void => {
+        taboverride.set(textarea);
+      });
+    }
+  }
+}
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/SelectCheckBoxElement.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/SelectCheckBoxElement.ts
new file mode 100644 (file)
index 0000000..4c44ee0
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+import * as $ from 'jquery';
+import FormEngine = require('TYPO3/CMS/Backend/FormEngine');
+
+enum Identifier {
+  toggleAll = '.t3js-toggle-checkboxes',
+  singleItem = '.t3js-checkbox'
+}
+
+class SelectCheckBoxElement {
+  private checkBoxId: string = '';
+  private $table: JQuery = null;
+
+  /**
+   * Determines whether all available checkboxes are checked
+   *
+   * @param {JQuery} $checkBoxes
+   * @return {boolean}
+   */
+  private static allCheckBoxesAreChecked($checkBoxes: JQuery): boolean {
+    return $checkBoxes.length === $checkBoxes.filter(':checked').length;
+  }
+
+  /**
+   * @param {string} checkBoxId
+   */
+  constructor(checkBoxId: string) {
+    this.checkBoxId = checkBoxId;
+    $((): void => {
+      this.$table = $('#' + checkBoxId).closest('table');
+
+      this.enableTriggerCheckBox();
+      this.registerEventHandler();
+    });
+  }
+
+  /**
+   * Registers the events for clicking the "Toggle all" and the single item checkboxes
+   */
+  private registerEventHandler(): void {
+    $(this.$table).on('change', Identifier.toggleAll, (e: JQueryEventObject): void => {
+      const $me = $(e.currentTarget);
+      const $checkBoxes = this.$table.find(Identifier.singleItem);
+      const checkIt = !SelectCheckBoxElement.allCheckBoxesAreChecked($checkBoxes);
+
+      $checkBoxes.prop('checked', checkIt);
+      $me.prop('checked', checkIt);
+      FormEngine.Validation.markFieldAsChanged($me);
+    }).on('change', Identifier.singleItem, (): void => {
+      const $checkBoxes = this.$table.find(Identifier.singleItem);
+      const checkIt = SelectCheckBoxElement.allCheckBoxesAreChecked($checkBoxes);
+
+      this.$table.find(Identifier.toggleAll).prop('checked', checkIt);
+    });
+  }
+
+  /**
+   * Enables the "Toggle all" checkbox on document load if all child checkboxes are checked
+   */
+  private enableTriggerCheckBox(): void {
+    const $checkBoxes = this.$table.find(Identifier.singleItem);
+    const checkIt = SelectCheckBoxElement.allCheckBoxesAreChecked($checkBoxes);
+    $('#' + this.checkBoxId).prop('checked', checkIt);
+  }
+}
+
+export = SelectCheckBoxElement;
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/SelectMultipleSideBySideElement.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/SelectMultipleSideBySideElement.ts
new file mode 100644 (file)
index 0000000..980a5c7
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+import {AbstractSortableSelectItems} from './AbstractSortableSelectItems';
+import * as $ from 'jquery';
+import FormEngine = require('TYPO3/CMS/Backend/FormEngine');
+import SelectBoxFilter = require('./Extra/SelectBoxFilter');
+
+class SelectMultipleSideBySideElement extends AbstractSortableSelectItems {
+  private selectedOptionsElement: HTMLSelectElement = null;
+  private availableOptionsElement: HTMLSelectElement = null;
+
+  constructor(selectedOptionsElementId: string, availableOptionsElementId: string) {
+    super();
+
+    $((): void => {
+      this.selectedOptionsElement = <HTMLSelectElement>document.querySelector('#' + selectedOptionsElementId);
+      this.availableOptionsElement = <HTMLSelectElement>document.querySelector('#' + availableOptionsElementId);
+      this.registerEventHandler();
+    });
+  }
+
+  private registerEventHandler(): void {
+    this.registerSortableEventHandler(this.selectedOptionsElement);
+
+    this.availableOptionsElement.addEventListener('click', (e: Event): void => {
+      const el = <HTMLSelectElement>e.currentTarget;
+      const fieldName = el.dataset.relatedfieldname;
+      if (fieldName) {
+        const exclusiveValues = el.dataset.exclusiveValues;
+        const selectedOptions = el.querySelectorAll('option:checked'); // Yep, :checked finds selected options
+        if (selectedOptions.length > 0) {
+          Array.from(selectedOptions).forEach((optionElement: HTMLOptionElement): void => {
+            FormEngine.setSelectOptionFromExternalSource(
+              fieldName,
+              optionElement.value,
+              optionElement.textContent,
+              optionElement.getAttribute('title'),
+              exclusiveValues,
+              $(optionElement)
+            );
+          });
+        }
+      }
+    });
+
+    // tslint:disable-next-line:no-unused-expression
+    new SelectBoxFilter(this.availableOptionsElement);
+  }
+}
+
+export = SelectMultipleSideBySideElement;
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/TextElement.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/TextElement.ts
new file mode 100644 (file)
index 0000000..2b82509
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+import {Resizable} from './Modifier/Resizable';
+import {Tabbable} from './Modifier/Tabbable';
+import * as $ from 'jquery';
+
+class TextElement {
+  private element: HTMLTextAreaElement = null;
+
+  constructor(elementId: string) {
+    $((): void => {
+      this.element = <HTMLTextAreaElement>document.querySelector('#' + elementId);
+
+      Resizable.enable(this.element);
+      Tabbable.enable(this.element);
+    });
+  }
+}
+
+export = TextElement;
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/TextTableElement.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/Element/TextTableElement.ts
new file mode 100644 (file)
index 0000000..e5a7d84
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+import {Resizable} from './Modifier/Resizable';
+import {Tabbable} from './Modifier/Tabbable';
+import * as $ from 'jquery';
+
+class TextTableElement {
+  private element: HTMLTextAreaElement = null;
+
+  constructor(elementId: string) {
+    $((): void => {
+      this.element = <HTMLTextAreaElement>document.querySelector('#' + elementId);
+
+      Resizable.enable(this.element);
+      Tabbable.enable(this.element);
+    });
+  }
+}
+
+export = TextTableElement;
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/FieldWizard/LocalizationStateSelector.ts b/typo3/sysext/backend/Resources/Private/TypeScript/FormEngine/FieldWizard/LocalizationStateSelector.ts
new file mode 100644 (file)
index 0000000..2c7d9a8
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+import * as $ from 'jquery';
+
+enum States {
+  CUSTOM = 'custom'
+}
+
+class LocalizationStateSelector {
+  constructor(fieldName: string) {
+    $((): void => {
+      this.registerEventHandler(fieldName);
+    });
+  }
+
+  /**
+   * @param {string} fieldName
+   */
+  private registerEventHandler(fieldName: string): void {
+    $(document).on(
+      'change',
+      '.t3js-l10n-state-container input[type="radio"][name="' + fieldName + '"]',
+      (e: JQueryEventObject): void => {
+        const $me = $(e.currentTarget);
+        const $input = $me.closest('.t3js-formengine-field-item').find('[data-formengine-input-name]');
+
+        if ($input.length === 0) {
+          return;
+        }
+
+        const lastState = $input.data('last-l10n-state') || false;
+        const currentState = $me.val();
+
+        if (lastState && currentState === lastState) {
+          return;
+        }
+
+        if (currentState === States.CUSTOM) {
+          if (lastState) {
+            $me.attr('data-original-language-value', $input.val());
+          }
+          $input.removeAttr('disabled');
+        } else {
+          if (lastState === States.CUSTOM) {
+            $me.closest('.t3js-l10n-state-container')
+              .find('.t3js-l10n-state-custom')
+              .attr('data-original-language-value', $input.val());
+          }
+          $input.attr('disabled', 'disabled');
+        }
+
+        $input.val($me.attr('data-original-language-value')).trigger('change');
+        $input.data('last-l10n-state', $me.val());
+      }
+    );
+  }
+}
+
+export = LocalizationStateSelector;
index 6fa597b..a12fca0 100644 (file)
@@ -469,7 +469,7 @@ define(['jquery',
    * @returns {*|HTMLElement}
    */
   FormEngine.getFieldElement = function(fieldName, appendix, noFallback) {
-    var $formEl = FormEngine.getFormElement();
+    var $formEl = $('form[name="' + FormEngine.formName + '"]:first');
 
     // if an appendix is set, return the field with the appendix (like _mul or _list)
     if (appendix) {
@@ -494,106 +494,6 @@ define(['jquery',
     return $(':input[name="' + fieldName + '"]', $formEl);
   };
 
-
-  /**************************************************
-   * manipulate existing options in a select field
-   **************************************************/
-
-  /**
-   * Moves currently selected options from a select field to the very top,
-   * can be multiple entries as well
-   *
-   * @param {Object} $fieldEl a jQuery object, containing the select field
-   */
-  FormEngine.moveOptionToTop = function($fieldEl) {
-    // remove the selected options
-    var selectedOptions = $fieldEl.find(':selected').detach();
-    // and add them on first position again
-    $fieldEl.prepend(selectedOptions);
-  };
-
-
-  /**
-   * moves currently selected options from a select field up by one position,
-   * can be multiple entries as well
-   *
-   * @param {Object} $fieldEl a jQuery object, containing the select field
-   */
-  FormEngine.moveOptionUp = function($fieldEl) {
-    // remove the selected options and add it before the previous sibling
-    $.each($fieldEl.find(':selected'), function(k, optionEl) {
-      var $optionEl = $(optionEl)
-        , $optionBefore = $optionEl.prev();
-
-      // stop if first option to move is already the first one
-      if (k == 0 && $optionBefore.length === 0) {
-        return false;
-      }
-
-      $optionBefore.before($optionEl.detach());
-    });
-  };
-
-
-  /**
-   * moves currently selected options from a select field down one position,
-   * can be multiple entries as well
-   *
-   * @param {Object} $fieldEl a jQuery object, containing the select field
-   */
-  FormEngine.moveOptionDown = function($fieldEl) {
-    // remove the selected options and add it after the next sibling
-    // however, this time, we need to go from the last to the first
-    var selectedOptions = $fieldEl.find(':selected');
-    selectedOptions = $.makeArray(selectedOptions);
-    selectedOptions.reverse();
-    $.each(selectedOptions, function(k, optionEl) {
-      var $optionEl = $(optionEl)
-        , $optionAfter = $optionEl.next();
-
-      // stop if first option to move is already the last one
-      if (k == 0 && $optionAfter.length === 0) {
-        return false;
-      }
-
-      $optionAfter.after($optionEl.detach());
-    });
-  };
-
-
-  /**
-   * moves currently selected options from a select field as the very last entries
-   *
-   * @param {Object} $fieldEl a jQuery object, containing the select field
-   */
-  FormEngine.moveOptionToBottom = function($fieldEl) {
-    // remove the selected options
-    var selectedOptions = $fieldEl.find(':selected').detach();
-    // and add them on last position again
-    $fieldEl.append(selectedOptions);
-  };
-
-  /**
-   * removes currently selected options from a select field
-   *
-   * @param {Object} $fieldEl a jQuery object, containing the select field
-   * @param {Object} $availableFieldEl a jQuery object, containing all available value
-   */
-  FormEngine.removeOption = function($fieldEl, $availableFieldEl) {
-    var $selected = $fieldEl.find(':selected');
-
-    $selected.each(function() {
-      $availableFieldEl
-        .find('option[value="' + $.escapeSelector($(this).attr('value')) + '"]')
-        .removeClass('hidden')
-        .prop('disabled', false);
-    });
-
-    // remove the selected options
-    $selected.remove();
-  };
-
-
   /**
    * Initialize events for all form engine relevant tasks.
    * This function only needs to be called once on page load,
@@ -606,51 +506,7 @@ define(['jquery',
         top.TYPO3.Backend.consumerScope.detach(FormEngine);
       });
     }
-    $(document).on('click', '.t3js-btn-moveoption-top, .t3js-btn-moveoption-up, .t3js-btn-moveoption-down, .t3js-btn-moveoption-bottom, .t3js-btn-removeoption', function(evt) {
-      evt.preventDefault();
-
-      // track the arrows "Up", "Down", "Clear" etc in multi-select boxes
-      var $el = $(this)
-        , fieldName = $el.data('fieldname')
-        , $listFieldEl = FormEngine.getFieldElement(fieldName, '_list');
-
-      if ($listFieldEl.length > 0) {
-
-        if ($el.hasClass('t3js-btn-moveoption-top')) {
-          FormEngine.moveOptionToTop($listFieldEl);
-        } else if ($el.hasClass('t3js-btn-moveoption-up')) {
-          FormEngine.moveOptionUp($listFieldEl);
-        } else if ($el.hasClass('t3js-btn-moveoption-down')) {
-          FormEngine.moveOptionDown($listFieldEl);
-        } else if ($el.hasClass('t3js-btn-moveoption-bottom')) {
-          FormEngine.moveOptionToBottom($listFieldEl);
-        } else if ($el.hasClass('t3js-btn-removeoption')) {
-          var $availableFieldEl = FormEngine.getFieldElement(fieldName, '_avail');
-          FormEngine.removeOption($listFieldEl, $availableFieldEl);
-        }
-
-        // make sure to update the hidden field value when modifying the select value
-        FormEngine.updateHiddenFieldValueFromSelect($listFieldEl, FormEngine.getFieldElement(fieldName));
-        FormEngine.legacyFieldChangedCb();
-        if (typeof FormEngine.Validation !== 'undefined' && typeof FormEngine.Validation.validate === 'function') {
-          FormEngine.Validation.markFieldAsChanged($listFieldEl);
-          FormEngine.Validation.validate();
-        }
-      }
-    }).on('click', '.t3js-formengine-select-itemstoselect', function(evt) {
-      // in multi-select environments with two (e.g. "Access"), on click the item from the right should go to the left
-      var $el = $(this)
-        , fieldName = $el.data('relatedfieldname')
-        , exclusiveValues = $el.data('exclusivevalues');
-
-      if (fieldName) {
-        // try to add each selected field to the "left" select field
-        $el.find(':selected').each(function() {
-          var $optionEl = $(this);
-          FormEngine.setSelectOptionFromExternalSource(fieldName, $optionEl.prop('value'), $optionEl.text(), $optionEl.prop('title'), exclusiveValues, $optionEl);
-        });
-      }
-    }).on('click', '.t3js-editform-close', function(e) {
+    $(document).on('click', '.t3js-editform-close', function(e) {
         e.preventDefault();
         FormEngine.preventExitIfNotSaved(
             FormEngine.preventExitIfNotSavedCallback
@@ -706,38 +562,6 @@ define(['jquery',
       $(this).closest('.t3js-formengine-field-item').toggleClass('disabled');
     }).on('change', '.t3js-form-field-eval-null-placeholder-checkbox input[type="checkbox"]', function(e) {
       FormEngine.toggleCheckboxField($(this));
-    }).on('change', '.t3js-l10n-state-container input[type=radio]', function(event) {
-      // Change handler for "l10n_state" field changes
-      var $me = $(this);
-      var $input = $me.closest('.t3js-formengine-field-item').find('[data-formengine-input-name]');
-
-      if ($input.length > 0) {
-        var lastState = $input.data('last-l10n-state') || false,
-          currentState = $(this).val();
-
-        if (lastState && currentState === lastState) {
-          return;
-        }
-
-        if (currentState === 'custom') {
-          if (lastState) {
-            $(this).attr('data-original-language-value', $input.val());
-          }
-          $input.attr('disabled', false);
-        } else {
-          if (lastState === 'custom') {
-            $(this).closest('.t3js-l10n-state-container').find('.t3js-l10n-state-custom').attr('data-original-language-value', $input.val());
-          }
-          $input.attr('disabled', 'disabled');
-        }
-
-        $input.val($(this).attr('data-original-language-value')).trigger('change');
-        $input.data('last-l10n-state', $(this).val());
-      }
-    }).on('formengine.dp.change', function(event, $field) {
-      FormEngine.Validation.validate();
-      FormEngine.Validation.markFieldAsChanged($field);
-      $('.module-docheader-bar .btn').removeClass('disabled').prop('disabled', false);
     }).on('change', function(event) {
       $('.module-docheader-bar .btn').removeClass('disabled').prop('disabled', false);
     });
@@ -818,44 +642,6 @@ define(['jquery',
   };
 
   /**
-   * Initialize select checkbox element checkboxes
-   */
-  FormEngine.initializeSelectCheckboxes = function() {
-    $('.t3js-toggle-checkboxes').each(function() {
-      var $checkbox = $(this);
-      var $table = $checkbox.closest('table');
-      var $checkboxes = $table.find('.t3js-checkbox');
-      var checkIt = $checkboxes.length === $table.find('.t3js-checkbox:checked').length;
-      $checkbox.prop('checked', checkIt);
-    });
-    $(document).on('change', '.t3js-toggle-checkboxes', function(e) {
-      e.preventDefault();
-      var $checkbox = $(this);
-      var $table = $checkbox.closest('table');
-      var $checkboxes = $table.find('.t3js-checkbox');
-      var checkIt = $checkboxes.length !== $table.find('.t3js-checkbox:checked').length;
-      $checkboxes.prop('checked', checkIt);
-      $checkbox.prop('checked', checkIt);
-      FormEngine.Validation.markFieldAsChanged($checkbox);
-    });
-    $(document).on('change', '.t3js-checkbox', function(e) {
-      FormEngine.updateCheckboxState(this);
-    });
-  };
-
-  /**
-   *
-   * @param {HTMLElement} source
-   */
-  FormEngine.updateCheckboxState = function(source) {
-    var $sourceElement = $(source);
-    var $table = $sourceElement.closest('table');
-    var $checkboxes = $table.find('.t3js-checkbox');
-    var checkIt = $checkboxes.length === $table.find('.t3js-checkbox:checked').length;
-    $table.find('.t3js-toggle-checkboxes').prop('checked', checkIt);
-  };
-
-  /**
    * Get the properties required for proper rendering of the character counter
    *
    * @param {Object} $field
@@ -885,99 +671,6 @@ define(['jquery',
   };
 
   /**
-   * Select field filter functions, see TCA option "enableMultiSelectFilterTextfield"
-   * and "multiSelectFilterItems"
-   */
-  FormEngine.SelectBoxFilter = {
-    options: {
-      fieldContainerSelector: '.t3js-formengine-field-group',
-      filterContainerSelector: '.t3js-formengine-multiselect-filter-container',
-      filterTextFieldSelector: '.t3js-formengine-multiselect-filter-textfield',
-      filterSelectFieldSelector: '.t3js-formengine-multiselect-filter-dropdown',
-      itemsToSelectElementSelector: '.t3js-formengine-select-itemstoselect'
-    }
-  };
-
-  /**
-   * Make sure that all selectors and input filters are recognized
-   * note: this also works on elements that are loaded asynchronously via AJAX, no need to call this method
-   * after an AJAX load.
-   */
-  FormEngine.SelectBoxFilter.initializeEvents = function() {
-    $(document).on('keyup', FormEngine.SelectBoxFilter.options.filterTextFieldSelector, function() {
-      var $selectElement = FormEngine.SelectBoxFilter.getSelectElement($(this));
-      FormEngine.SelectBoxFilter.filter($selectElement, $(this).val());
-    }).on('change', FormEngine.SelectBoxFilter.options.filterSelectFieldSelector, function() {
-      var $selectElement = FormEngine.SelectBoxFilter.getSelectElement($(this));
-      FormEngine.SelectBoxFilter.filter($selectElement, $(this).val());
-    });
-  };
-
-  /**
-   * Fetch the "itemstoselect" select element where a filter item is attached to
-   *
-   * @param {Object} $relativeElement
-   * @returns {*}
-   */
-  FormEngine.SelectBoxFilter.getSelectElement = function($relativeElement) {
-    var $containerElement = $relativeElement.closest(FormEngine.SelectBoxFilter.options.fieldContainerSelector);
-    return $containerElement.find(FormEngine.SelectBoxFilter.options.itemsToSelectElementSelector);
-  };
-
-  /**
-   * Filter the actual items
-   *
-   * @param {Object} $selectElement
-   * @param {String} filterText
-   */
-  FormEngine.SelectBoxFilter.filter = function($selectElement, filterText) {
-    var $allOptionElements;
-    if (!$selectElement.data('alloptions')) {
-      $allOptionElements = $selectElement.find('option').clone();
-      $selectElement.data('alloptions', $allOptionElements);
-    } else {
-      $allOptionElements = $selectElement.data('alloptions');
-    }
-
-    if (filterText.length > 0) {
-      var matchFilter = new RegExp(filterText, 'i');
-      $selectElement.html('');
-      $allOptionElements.each(function() {
-        var $item = $(this);
-        if ($item.text().match(matchFilter)) {
-          $selectElement.append($item.clone());
-        }
-      });
-    } else {
-      $selectElement.html($allOptionElements);
-    }
-  };
-
-  /**
-   * convert all textareas so they grow when it is typed in.
-   */
-  FormEngine.convertTextareasResizable = function() {
-    var $elements = $('.t3js-formengine-textarea');
-    if (TYPO3.settings.Textarea && TYPO3.settings.Textarea.autosize && $elements.length) {
-      require(['autosize'], function(autosize) {
-        autosize($elements);
-      });
-    }
-  };
-
-  /**
-   * convert all textareas to enable tab
-   */
-  FormEngine.convertTextareasEnableTab = function() {
-    var $elements = $('.t3js-enable-tab');
-    if ($elements.length) {
-      require(['taboverride'], function(taboverride) {
-        taboverride.set($elements);
-      });
-    }
-  };
-
-  /**
    * Initialize input / text field "null" checkbox CSS overlay if no placeholder is set.
    */
   FormEngine.initializeNullNoPlaceholderCheckboxes = function() {
@@ -1030,25 +723,9 @@ define(['jquery',
         $('.t3js-clearable').clearable();
       });
     }
-    if ($('.t3-form-suggest').length) {
-      require(['TYPO3/CMS/Backend/FormEngineSuggest'], function(Suggest) {
-        $('.t3-form-suggest').each(function(index, suggestElement) {
-          new Suggest(suggestElement);
-        });
-      });
-    }
-    // Apply DatePicker to all date time fields
-    if ($('.t3js-datetimepicker').length) {
-      require(['TYPO3/CMS/Backend/DateTimePicker'], function(DateTimePicker) {
-        DateTimePicker.initialize();
-      });
-    }
 
-    FormEngine.convertTextareasResizable();
-    FormEngine.convertTextareasEnableTab();
     FormEngine.initializeNullNoPlaceholderCheckboxes();
     FormEngine.initializeNullWithPlaceholderCheckboxes();
-    FormEngine.initializeInputLinkToggle();
     FormEngine.initializeLocalizationStateSelector();
     FormEngine.initializeRemainingCharacterViews();
   };
@@ -1067,56 +744,6 @@ define(['jquery',
   };
 
   /**
-   * Toggle for input link explanation
-   */
-  FormEngine.initializeInputLinkToggle = function() {
-    var toggleClass = '.t3js-form-field-inputlink-explanation-toggle',
-      inputFieldClass = '.t3js-form-field-inputlink-input',
-      explanationClass = '.t3js-form-field-inputlink-explanation';
-
-    // if empty, show input field
-    $(explanationClass).filter(function() {
-      return !$.trim($(this).val());
-    }).each(function() {
-      var $group = $(this).closest('.t3js-form-field-inputlink'),
-        $inputField = $group.find(inputFieldClass),
-        $explanationField = $group.find(explanationClass);
-      $explanationField.toggleClass('hidden', true);
-      $inputField.toggleClass('hidden', false);
-      $group.find('.form-control-clearable button.close').toggleClass('hidden', false)
-    });
-
-    $(document).on('click', toggleClass, function(e) {
-      e.preventDefault();
-
-      var $group = $(this).closest('.t3js-form-field-inputlink'),
-        $inputField = $group.find(inputFieldClass),
-        $explanationField = $group.find(explanationClass),
-        explanationShown;
-
-      explanationShown = !$explanationField.hasClass('hidden');
-      $explanationField.toggleClass('hidden', explanationShown);
-      $inputField.toggleClass('hidden', !explanationShown);
-      $group.find('.form-control-clearable button.close').toggleClass('hidden', !explanationShown)
-    });
-
-    $(inputFieldClass).on('change', function() {
-      var $group = $(this).closest('.t3js-form-field-inputlink'),
-        $inputField = $group.find(inputFieldClass),
-        $explanationField = $group.find(explanationClass),
-        explanationShown;
-
-      if (!$explanationField.hasClass('hidden')) {
-
-        explanationShown = !$explanationField.hasClass('hidden');
-        $explanationField.toggleClass('hidden', explanationShown);
-        $inputField.toggleClass('hidden', !explanationShown);
-        $group.find('.form-control-clearable button.close').toggleClass('hidden', !explanationShown)
-      }
-    });
-  };
-
-  /**
    * @return {boolean}
    */
   FormEngine.hasChange = function() {
@@ -1605,8 +1232,6 @@ define(['jquery',
 
     $(function() {
       FormEngine.initializeEvents();
-      FormEngine.SelectBoxFilter.initializeEvents();
-      FormEngine.initializeSelectCheckboxes();
       FormEngine.Validation.initialize();
       FormEngine.reinitialize();
       $('#t3js-ui-block').remove();
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/AbstractSortableSelectItems.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/AbstractSortableSelectItems.js
new file mode 100644 (file)
index 0000000..f1b5e45
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+var __values=this&&this.__values||function(e){var t="function"==typeof Symbol&&e[Symbol.iterator],n=0;return t?t.call(e):{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}}};define(["require","exports","jquery","TYPO3/CMS/Backend/FormEngine","TYPO3/CMS/Backend/FormEngineValidation"],function(e,t,n,r,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(){this.registerSortableEventHandler=function(t){var i=t.closest(".form-wizards-wrap").querySelector(".form-wizards-items-aside");null!==i&&i.addEventListener("click",function(i){var l;if(null!==(l=i.target.closest(".t3js-btn-option"))){i.preventDefault();var a=l.dataset.fieldname;l.classList.contains("t3js-btn-moveoption-top")?e.moveOptionToTop(t):l.classList.contains("t3js-btn-moveoption-up")?e.moveOptionUp(t):l.classList.contains("t3js-btn-moveoption-down")?e.moveOptionDown(t):l.classList.contains("t3js-btn-moveoption-bottom")?e.moveOptionToBottom(t):l.classList.contains("t3js-btn-removeoption")&&e.removeOption(t,r.getFieldElement(a,"_avail").get(0)),r.updateHiddenFieldValueFromSelect(t,r.getFieldElement(a).get(0)),r.legacyFieldChangedCb(),o.markFieldAsChanged(n(t)),o.validate()}else i.target.matches(".t3js-btn-option")&&(l=i.target)})}}return e.moveOptionToTop=function(e){Array.from(e.querySelectorAll(":checked")).reverse().forEach(function(t){e.insertBefore(t,e.firstElementChild)})},e.moveOptionToBottom=function(e){Array.from(e.querySelectorAll(":checked")).forEach(function(t){e.insertBefore(t,null)})},e.moveOptionUp=function(e){var t,n,r=Array.from(e.children),o=Array.from(e.querySelectorAll(":checked"));try{for(var i=__values(o),l=i.next();!l.done;l=i.next()){var a=l.value;if(0===r.indexOf(a)&&null===a.previousElementSibling)break;e.insertBefore(a,a.previousElementSibling)}}catch(e){t={error:e}}finally{try{l&&!l.done&&(n=i.return)&&n.call(i)}finally{if(t)throw t.error}}},e.moveOptionDown=function(e){var t,n,r=Array.from(e.children).reverse(),o=Array.from(e.querySelectorAll(":checked")).reverse();try{for(var i=__values(o),l=i.next();!l.done;l=i.next()){var a=l.value;if(0===r.indexOf(a)&&null===a.nextElementSibling)break;e.insertBefore(a,a.nextElementSibling.nextElementSibling)}}catch(e){t={error:e}}finally{try{l&&!l.done&&(n=i.return)&&n.call(i)}finally{if(t)throw t.error}}},e.removeOption=function(e,t){Array.from(e.querySelectorAll(":checked")).forEach(function(n){var r=t.querySelector('option[value="'+n.value+'"]');r.classList.remove("hidden"),r.disabled=!1,e.removeChild(n)})},e}();t.AbstractSortableSelectItems=i});
\ No newline at end of file
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/Extra/SelectBoxFilter.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/Extra/SelectBoxFilter.js
new file mode 100644 (file)
index 0000000..f119b1c
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+define(["require","exports","jquery"],function(e,t,i){"use strict";var l,n;return(n=l||(l={})).fieldContainerSelector=".t3js-formengine-field-group",n.filterTextFieldSelector=".t3js-formengine-multiselect-filter-textfield",n.filterSelectFieldSelector=".t3js-formengine-multiselect-filter-dropdown",function(){function e(e){this.selectElement=null,this.filterText="",this.$availableOptions=null,this.selectElement=e,this.initializeEvents()}return e.prototype.initializeEvents=function(){var e=this,t=this.selectElement.closest(".form-wizards-element");null!==t&&(t.addEventListener("keyup",function(t){t.target.matches(l.filterTextFieldSelector)&&e.filter(t.target.value)}),t.addEventListener("change",function(t){t.target.matches(l.filterSelectFieldSelector)&&e.filter(t.target.value)}))},e.prototype.filter=function(e){var t=this;this.filterText=e,this.$availableOptions||(this.$availableOptions=i(this.selectElement).find("option").clone()),this.selectElement.innerHTML="";var l=new RegExp(e,"i");this.$availableOptions.each(function(i,n){(0===e.length||n.textContent.match(l))&&t.selectElement.appendChild(n)})},e}()});
\ No newline at end of file
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/GroupElement.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/GroupElement.js
new file mode 100644 (file)
index 0000000..9c52e3a
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+var __extends=this&&this.__extends||function(){var e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])};return function(t,r){function n(){this.constructor=t}e(t,r),t.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();define(["require","exports","./AbstractSortableSelectItems","jquery","../../FormEngineSuggest"],function(e,t,r,n,o){"use strict";return function(e){function t(t){var r=e.call(this)||this;return r.element=null,n(function(){r.element=document.querySelector("#"+t),r.registerEventHandler(),r.registerSuggest()}),r}return __extends(t,e),t.prototype.registerEventHandler=function(){this.registerSortableEventHandler(this.element)},t.prototype.registerSuggest=function(){var e;null!==(e=this.element.closest(".t3js-formengine-field-item").querySelector(".t3-form-suggest"))&&new o(e)},t}(r.AbstractSortableSelectItems)});
\ No newline at end of file
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/InputDateTimeElement.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/InputDateTimeElement.js
new file mode 100644 (file)
index 0000000..62e83ca
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+define(["require","exports","jquery","TYPO3/CMS/Backend/FormEngine"],function(e,n,t,r){"use strict";return new(function(){function n(){var n=this;t(function(){n.registerEventHandler(),document.querySelectorAll(".t3js-datetimepicker").length&&e(["../../DateTimePicker"])})}return n.prototype.registerEventHandler=function(){t(document).on("formengine.dp.change",function(e,n){r.Validation.validate(),r.Validation.markFieldAsChanged(n),t(".module-docheader-bar .btn").removeClass("disabled").prop("disabled",!1)})},n}())});
\ No newline at end of file
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/InputLinkElement.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/InputLinkElement.js
new file mode 100644 (file)
index 0000000..acbc345
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+define(["require","exports","jquery"],function(e,t,i){"use strict";var n,l;return(l=n||(n={})).toggleSelector=".t3js-form-field-inputlink-explanation-toggle",l.inputFieldSelector=".t3js-form-field-inputlink-input",l.explanationSelector=".t3js-form-field-inputlink-explanation",function(){function e(e){var t=this;this.element=null,this.container=null,this.explanationField=null,i(function(){t.element=document.querySelector("#"+e),t.container=t.element.closest(".t3js-form-field-inputlink"),t.explanationField=t.container.querySelector(n.explanationSelector),t.toggleVisibility(""===t.explanationField.value),t.registerEventHandler()})}return e.prototype.toggleVisibility=function(e){this.explanationField.classList.toggle("hidden",e),this.element.classList.toggle("hidden",!e);var t=this.container.querySelector(".form-control-clearable button.close");null!==t&&t.classList.toggle("hidden",!e)},e.prototype.registerEventHandler=function(){var e=this;this.container.querySelector(n.toggleSelector).addEventListener("click",function(t){t.preventDefault();var i=!e.explanationField.classList.contains("hidden");e.toggleVisibility(i)}),this.container.querySelector(n.inputFieldSelector).addEventListener("change",function(){var t=!e.explanationField.classList.contains("hidden");t&&e.toggleVisibility(t)})},e}()});
\ No newline at end of file
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/Modifier/Resizable.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/Modifier/Resizable.js
new file mode 100644 (file)
index 0000000..e08a986
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+define(["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function t(){}return t.enable=function(t){TYPO3.settings.Textarea&&TYPO3.settings.Textarea.autosize&&e(["autosize"],function(e){e(t)})},t}();t.Resizable=n});
\ No newline at end of file
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/Modifier/Tabbable.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/Modifier/Tabbable.js
new file mode 100644 (file)
index 0000000..39345c0
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+define(["require","exports"],function(e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var t=function(){function n(){}return n.enable=function(n){n.classList.contains("t3js-enable-tab")&&e(["taboverride"],function(e){e.set(n)})},n}();n.Tabbable=t});
\ No newline at end of file
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SelectCheckBoxElement.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SelectCheckBoxElement.js
new file mode 100644 (file)
index 0000000..f0a3da9
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+define(["require","exports","jquery","TYPO3/CMS/Backend/FormEngine"],function(e,t,n,c){"use strict";var l,r;return(r=l||(l={})).toggleAll=".t3js-toggle-checkboxes",r.singleItem=".t3js-checkbox",function(){function e(e){var t=this;this.checkBoxId="",this.$table=null,this.checkBoxId=e,n(function(){t.$table=n("#"+e).closest("table"),t.enableTriggerCheckBox(),t.registerEventHandler()})}return e.allCheckBoxesAreChecked=function(e){return e.length===e.filter(":checked").length},e.prototype.registerEventHandler=function(){var t=this;n(this.$table).on("change",l.toggleAll,function(r){var i=n(r.currentTarget),o=t.$table.find(l.singleItem),h=!e.allCheckBoxesAreChecked(o);o.prop("checked",h),i.prop("checked",h),c.Validation.markFieldAsChanged(i)}).on("change",l.singleItem,function(){var n=t.$table.find(l.singleItem),c=e.allCheckBoxesAreChecked(n);t.$table.find(l.toggleAll).prop("checked",c)})},e.prototype.enableTriggerCheckBox=function(){var t=this.$table.find(l.singleItem),c=e.allCheckBoxesAreChecked(t);n("#"+this.checkBoxId).prop("checked",c)},e}()});
\ No newline at end of file
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SelectMultipleSideBySideElement.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SelectMultipleSideBySideElement.js
new file mode 100644 (file)
index 0000000..b0e3e5b
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+var __extends=this&&this.__extends||function(){var e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();define(["require","exports","./AbstractSortableSelectItems","jquery","TYPO3/CMS/Backend/FormEngine","./Extra/SelectBoxFilter"],function(e,t,n,r,o,i){"use strict";return function(e){function t(t,n){var o=e.call(this)||this;return o.selectedOptionsElement=null,o.availableOptionsElement=null,r(function(){o.selectedOptionsElement=document.querySelector("#"+t),o.availableOptionsElement=document.querySelector("#"+n),o.registerEventHandler()}),o}return __extends(t,e),t.prototype.registerEventHandler=function(){this.registerSortableEventHandler(this.selectedOptionsElement),this.availableOptionsElement.addEventListener("click",function(e){var t=e.currentTarget,n=t.dataset.relatedfieldname;if(n){var i=t.dataset.exclusiveValues,l=t.querySelectorAll("option:checked");l.length>0&&Array.from(l).forEach(function(e){o.setSelectOptionFromExternalSource(n,e.value,e.textContent,e.getAttribute("title"),i,r(e))})}}),new i(this.availableOptionsElement)},t}(n.AbstractSortableSelectItems)});
\ No newline at end of file
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/TextElement.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/TextElement.js
new file mode 100644 (file)
index 0000000..b15975f
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+define(["require","exports","./Modifier/Resizable","./Modifier/Tabbable","jquery"],function(e,n,t,i,l){"use strict";return function(e){var n=this;this.element=null,l(function(){n.element=document.querySelector("#"+e),t.Resizable.enable(n.element),i.Tabbable.enable(n.element)})}});
\ No newline at end of file
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/TextTableElement.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/TextTableElement.js
new file mode 100644 (file)
index 0000000..b15975f
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+define(["require","exports","./Modifier/Resizable","./Modifier/Tabbable","jquery"],function(e,n,t,i,l){"use strict";return function(e){var n=this;this.element=null,l(function(){n.element=document.querySelector("#"+e),t.Resizable.enable(n.element),i.Tabbable.enable(n.element)})}});
\ No newline at end of file
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/FieldWizard/LocalizationStateSelector.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/FieldWizard/LocalizationStateSelector.js
new file mode 100644 (file)
index 0000000..f9820b6
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+define(["require","exports","jquery"],function(t,a,e){"use strict";var n;return(n||(n={})).CUSTOM="custom",function(){function t(t){var a=this;e(function(){a.registerEventHandler(t)})}return t.prototype.registerEventHandler=function(t){e(document).on("change",'.t3js-l10n-state-container input[type="radio"][name="'+t+'"]',function(t){var a=e(t.currentTarget),r=a.closest(".t3js-formengine-field-item").find("[data-formengine-input-name]");if(0!==r.length){var i=r.data("last-l10n-state")||!1,l=a.val();i&&l===i||(l===n.CUSTOM?(i&&a.attr("data-original-language-value",r.val()),r.removeAttr("disabled")):(i===n.CUSTOM&&a.closest(".t3js-l10n-state-container").find(".t3js-l10n-state-custom").attr("data-original-language-value",r.val()),r.attr("disabled","disabled")),r.val(a.attr("data-original-language-value")).trigger("change"),r.data("last-l10n-state",a.val()))}})},t}()});
\ No newline at end of file