[!!!][TASK] Improve FormEngine and sub classes separation 65/37265/6
authorChristian Kuhn <lolli@schwarzbu.ch>
Sat, 7 Feb 2015 20:19:13 +0000 (21:19 +0100)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Sat, 28 Feb 2015 16:24:32 +0000 (17:24 +0100)
This patch improves the separation of FormEngine and its sub
classes. Currently, all sub classes like single element and wizard
classes get an instance of the parent object to call various methods
and properties on them. This is very hard to refactor and the mesh
of call trees must be simplified to ease further refactoring and
improve maintainability of code.

This patch follows a divide & conquer approach:
* Methods only used by sub elements are moved to AbstractFormElement
* Properties FormEngine "knows" that are needed by element classes
  are given down in a data array during element instatiation to have
  a clear definition of what element classes know.
* Methods used by both FormEngine and sub classes that do not need
  an instance of FormEngine are moved to a static helper for now to
  reduce the amount of code in FormEngine and to mark certain areas
  as stateless.
* Class instances are not created on a global level anymore but
  created only in the scope where they are used
* Class instances injected by outer code are created internally
  for enabling the using code to be moved around.

All in all, this patch is mostly a preparation of defining a
fully separated structure with defined concerns for every sub class.

Most methods are moved around "as is" without changing functionality.
The only area that is refactored codewise is renderWizards().

There is still a nasty circular dependency between FormEngine,
FlexFormElement and InlineElement. This is not resolved by the patch,
but the surrounding code is now separated enough that this structure
could be refactored to a tree. This may follow with other patches.

This patch evolved on catharsis in branch formengine with 53 single
patches. Details can be looked up there, all single patches are
prefixed with [FormEngine].
https://github.com/lolli42/TYPO3.CMS-Catharsis/tree/formengine

Change-Id: I332ad51f5e94c09555480099e3a8a0257bed378f
Releases: master
Resolves: #65357
Resolves: #63848
Resolves: #63849
Resolves: #63851
Resolves: #63853
Resolves: #63855
Resolves: #63857
Resolves: #63867
Resolves: #63868
Resolves: #63869
Resolves: #63870
Resolves: #63871
Resolves: #63872
Resolves: #63873
Resolves: #63874
Resolves: #63875
Resolves: #63877
Resolves: #63879
Resolves: #63880
Resolves: #63884
Resolves: #63885
Resolves: #63886
Resolves: #63887
Resolves: #63888
Resolves: #63890
Resolves: #63892
Reviewed-on: http://review.typo3.org/37265
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Benjamin Mack <benni@typo3.org>
Tested-by: Benjamin Mack <benni@typo3.org>
46 files changed:
typo3/sysext/backend/Classes/Controller/EditDocumentController.php
typo3/sysext/backend/Classes/Controller/PageLayoutController.php
typo3/sysext/backend/Classes/Controller/SimpleDataHandlerController.php
typo3/sysext/backend/Classes/Controller/Wizard/RteController.php
typo3/sysext/backend/Classes/Form/DataPreprocessor.php
typo3/sysext/backend/Classes/Form/DatabaseFileIconsHookInterface.php
typo3/sysext/backend/Classes/Form/Element/AbstractFormElement.php
typo3/sysext/backend/Classes/Form/Element/CheckboxElement.php
typo3/sysext/backend/Classes/Form/Element/FlexElement.php
typo3/sysext/backend/Classes/Form/Element/GroupElement.php
typo3/sysext/backend/Classes/Form/Element/InlineElement.php
typo3/sysext/backend/Classes/Form/Element/InputElement.php
typo3/sysext/backend/Classes/Form/Element/NoneElement.php
typo3/sysext/backend/Classes/Form/Element/RadioElement.php
typo3/sysext/backend/Classes/Form/Element/SelectElement.php
typo3/sysext/backend/Classes/Form/Element/SuggestDefaultReceiver.php [deleted file]
typo3/sysext/backend/Classes/Form/Element/SuggestElement.php [deleted file]
typo3/sysext/backend/Classes/Form/Element/TextElement.php
typo3/sysext/backend/Classes/Form/Element/TreeElement.php
typo3/sysext/backend/Classes/Form/Element/UnknownElement.php
typo3/sysext/backend/Classes/Form/Element/ValueSlider.php [deleted file]
typo3/sysext/backend/Classes/Form/FlexFormsHelper.php
typo3/sysext/backend/Classes/Form/FormEngine.php
typo3/sysext/backend/Classes/Form/FrontendFormEngine.php
typo3/sysext/backend/Classes/Form/Utility/FormEngineUtility.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Form/Wizard/SuggestWizard.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Form/Wizard/SuggestWizardDefaultReceiver.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Form/Wizard/ValueSliderWizard.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Utility/BackendUtility.php
typo3/sysext/backend/Classes/View/BackendLayoutView.php
typo3/sysext/backend/Classes/View/PageLayoutView.php
typo3/sysext/backend/Migrations/Code/ClassAliasMap.php [new file with mode: 0644]
typo3/sysext/backend/Tests/Unit/Form/Element/InlineElementTest.php
typo3/sysext/backend/Tests/Unit/Form/Element/NoneElementTest.php [new file with mode: 0644]
typo3/sysext/backend/Tests/Unit/Form/FormEngineTest.php [deleted file]
typo3/sysext/compatibility6/Migrations/Code/ClassAliasMap.php
typo3/sysext/compatibility6/Migrations/Code/LegacyClassesForIde.php
typo3/sysext/core/Classes/Authentication/BackendUserAuthentication.php
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/core/Documentation/Changelog/master/Breaking-65357-DependenciesToFormEngine.rst [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Deprecation-65357-DependenciesToFormEngine.rst [new file with mode: 0644]
typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php
typo3/sysext/rtehtmlarea/Classes/Controller/FrontendRteController.php
typo3/sysext/rtehtmlarea/Classes/RteHtmlAreaBase.php
typo3/sysext/sys_action/Classes/ActionTask.php
typo3/sysext/t3editor/Classes/FormWizard.php

index 523b068..c21b509 100644 (file)
@@ -174,6 +174,7 @@ class EditDocumentController {
         * Disable help... ?
         *
         * @var bool
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
         */
        public $disHelp;
 
@@ -523,7 +524,6 @@ class EditDocumentController {
                        $tce->neverHideAtCopy = 1;
                }
                $tce->debug = 0;
-               $tce->disableRTE = !$GLOBALS['BE_USER']->isRTE();
                // Loading TCEmain with data:
                $tce->start($this->data, $this->cmd);
                if (is_array($this->mirror)) {
@@ -628,7 +628,6 @@ class EditDocumentController {
                $this->viewUrl = GeneralUtility::_GP('viewUrl');
                $this->editRegularContentFromId = GeneralUtility::_GP('editRegularContentFromId');
                $this->recTitle = GeneralUtility::_GP('recTitle');
-               $this->disHelp = GeneralUtility::_GP('disHelp');
                $this->noView = GeneralUtility::_GP('noView');
                $this->perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
                // Set other internal variables:
@@ -714,16 +713,6 @@ class EditDocumentController {
                        // text,media is keywords defined in TYPO3 Core API..., see "l10n_cat"
                        $this->tceforms->returnUrl = $this->R_URI;
                        $this->tceforms->palettesCollapsed = !$this->MOD_SETTINGS['showPalettes'];
-                       $this->tceforms->disableRTE = !$GLOBALS['BE_USER']->isRTE();
-                       $this->tceforms->enableClickMenu = TRUE;
-                       $this->tceforms->enableTabMenu = TRUE;
-                       // Clipboard is initialized:
-                       // Start clipboard
-                       $this->tceforms->clipObj = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Clipboard\Clipboard::class);
-                       // Initialize - reads the clipboard content from the user session
-                       $this->tceforms->clipObj->initializeClipboard();
-                       // Setting external variables:
-                       $this->tceforms->edit_showFieldHelp = $GLOBALS['BE_USER']->uc['edit_showFieldHelp'];
                        if ($this->editRegularContentFromId) {
                                $this->editRegularContentFromId();
                        }
@@ -743,7 +732,6 @@ class EditDocumentController {
                                $body .= $this->compileForm($editForm);
                                $body .= $this->tceforms->printNeededJSFunctions();
                                $body .= $this->functionMenus();
-                               $body .= $this->tceformMessages();
                        }
                }
                // Access check...
@@ -891,7 +879,6 @@ class EditDocumentController {
                                                                $trData->addRawData = TRUE;
                                                                $trData->defVals = $this->defVals;
                                                                $trData->lockRecords = 1;
-                                                               $trData->disableRTE = !$GLOBALS['BE_USER']->isRTE();
                                                                $trData->prevPageID = $prevPageID;
                                                                // 'new'
                                                                $trData->fetchRecord($table, $theUid, $cmd == 'new' ? 'new' : '');
@@ -916,7 +903,6 @@ class EditDocumentController {
                                                                        }
                                                                        // Setting variables in TCEforms object:
                                                                        $this->tceforms->hiddenFieldList = '';
-                                                                       $this->tceforms->globalShowHelp = !$this->disHelp;
                                                                        if (is_array($this->overrideVals) && is_array($this->overrideVals[$table])) {
                                                                                $this->tceforms->hiddenFieldListArr = array_keys($this->overrideVals[$table]);
                                                                        }
@@ -1144,7 +1130,7 @@ class EditDocumentController {
                if ($this->returnUrl == 'close.html' || !$GLOBALS['BE_USER']->mayMakeShortcut()) {
                        return '';
                }
-               return $this->doc->makeShortcutIcon('returnUrl,edit,defVals,overrideVals,columnsOnly,returnNewPageId,editRegularContentFromId,disHelp,noView', implode(',', array_keys($this->MOD_MENU)), $this->MCONF['name'], 1);
+               return $this->doc->makeShortcutIcon('returnUrl,edit,defVals,overrideVals,columnsOnly,returnNewPageId,editRegularContentFromId,noView', implode(',', array_keys($this->MOD_MENU)), $this->MCONF['name'], 1);
        }
 
        /**
@@ -1163,17 +1149,12 @@ class EditDocumentController {
        /**
         * Reads comment messages from TCEforms and prints them in a HTML comment in the bottom of the page.
         *
-        * @return void
+        * @return string
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
         */
        public function tceformMessages() {
-               if (count($this->tceforms->commentMessages)) {
-                       $tceformMessages = '
-                               <!-- TCEFORM messages
-                               ' . htmlspecialchars(implode(LF, $this->tceforms->commentMessages)) . '
-                               -->
-                       ';
-               }
-               return $tceformMessages;
+               GeneralUtility::logDeprecatedFunction();
+               return '';
        }
 
        /***************************
@@ -1429,7 +1410,7 @@ class EditDocumentController {
         * @see makeDocSel()
         */
        public function compileStoreDat() {
-               $this->storeArray = GeneralUtility::compileSelectedGetVarsFromArray('edit,defVals,overrideVals,columnsOnly,disHelp,noView,editRegularContentFromId,workspace', $this->R_URL_getvars);
+               $this->storeArray = GeneralUtility::compileSelectedGetVarsFromArray('edit,defVals,overrideVals,columnsOnly,noView,editRegularContentFromId,workspace', $this->R_URL_getvars);
                $this->storeUrl = GeneralUtility::implodeArrayForUrl('', $this->storeArray);
                $this->storeUrlMd5 = md5($this->storeUrl);
        }
index 3a3aaa6..0b35614 100644 (file)
@@ -302,7 +302,6 @@ class PageLayoutController {
                        'tt_content_showHidden' => '',
                        'showPalettes' => '',
                        'showDescriptions' => '',
-                       'disableRTE' => '',
                        'function' => array(
                                0 => $GLOBALS['LANG']->getLL('m_function_0'),
                                1 => $GLOBALS['LANG']->getLL('m_function_1'),
@@ -774,7 +773,6 @@ class PageLayoutController {
                                'colPos' => (int)$ex_colPos,
                                'sys_language_uid' => (int)$this->current_sys_language
                        );
-                       $trData->disableRTE = $this->MOD_SETTINGS['disableRTE'];
                        $trData->lockRecords = 1;
                        // 'new'
                        $trData->fetchRecord($this->eRParts[0], $uidVal == 'new' ? $this->id : $uidVal, $uidVal);
@@ -798,18 +796,9 @@ class PageLayoutController {
                                // If the record is an array (which it will always be... :-)
                                // Create instance of TCEforms, setting defaults:
                                $tceforms = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\FormEngine::class);
-                               $tceforms->backPath = $GLOBALS['BACK_PATH'];
                                $tceforms->initDefaultBEMode();
                                $tceforms->fieldOrder = $this->modTSconfig['properties']['tt_content.']['fieldOrder'];
                                $tceforms->palettesCollapsed = !$this->MOD_SETTINGS['showPalettes'];
-                               $tceforms->disableRTE = $this->MOD_SETTINGS['disableRTE'];
-                               $tceforms->enableClickMenu = TRUE;
-                               $tceforms->enableTabMenu = TRUE;
-                               // Clipboard is initialized:
-                               // Start clipboard
-                               $tceforms->clipObj = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Clipboard\Clipboard::class);
-                               // Initialize - reads the clipboard content from the user session
-                               $tceforms->clipObj->initializeClipboard();
                                // Render form, wrap it:
                                $panel = '';
                                $panel .= $tceforms->getMainFields($this->eRParts[0], $rec);
@@ -821,7 +810,6 @@ class PageLayoutController {
                                }
                                $theCode .= '
                                        <input type="hidden" name="_serialNumber" value="' . md5(microtime()) . '" />
-                                       <input type="hidden" name="_disableRTE" value="' . $tceforms->disableRTE . '" />
                                        <input type="hidden" name="edit_record" value="' . $edit_record . '" />
                                        <input type="hidden" name="redirect" value="' . htmlspecialchars(($uidVal == 'new' ? BackendUtility::getModuleUrl(
                                                'web_layout',
@@ -875,14 +863,6 @@ class PageLayoutController {
                                '</label>' .
                                '</div>';
                }
-               if ($GLOBALS['BE_USER']->isRTE()) {
-                       $h_func_b .= '<div class="checkbox">' .
-                               '<label for="checkDisableRTE">' .
-                               BackendUtility::getFuncCheck($this->id, 'SET[disableRTE]', $this->MOD_SETTINGS['disableRTE'], '', '', 'id="checkDisableRTE"') .
-                               $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.disableRTE', TRUE) .
-                               '</label>' .
-                               '</div>';
-               }
                // Add the function menus to bottom:
                $content .= $this->doc->section('', $h_func_b, 0, 0);
                $content .= $this->doc->spacer(10);
@@ -899,14 +879,6 @@ class PageLayoutController {
                        $content .= $this->doc->section($GLOBALS['LANG']->getLL('CEonThisPage'), $HTMLcode, 0, 1);
                        $content .= $this->doc->spacer(20);
                }
-               // Finally, if comments were generated in TCEforms object, print these as a HTML comment:
-               if (count($tceforms->commentMessages)) {
-                       $content .= '
-       <!-- TCEFORM messages
-       ' . htmlspecialchars(implode(LF, $tceforms->commentMessages)) . '
-       -->
-       ';
-               }
                return $content;
        }
 
index b24cbd5..f136ae4 100644 (file)
@@ -136,7 +136,6 @@ class SimpleDataHandlerController {
                $this->cacheCmd = GeneralUtility::_GP('cacheCmd');
                $this->redirect = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('redirect'));
                $this->prErr = GeneralUtility::_GP('prErr');
-               $this->_disableRTE = GeneralUtility::_GP('_disableRTE');
                $this->CB = GeneralUtility::_GP('CB');
                $this->vC = GeneralUtility::_GP('vC');
                $this->uPT = GeneralUtility::_GP('uPT');
index 72088ac..645d00a 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Backend\Controller\Wizard;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -148,7 +149,7 @@ class RteController extends AbstractWizardController {
                        $rec['uid'] = $this->P['uid'];
                        $rec['pid'] = $rawRec['pid'];
                        // TSconfig, setting width:
-                       $fieldTSConfig = $tceforms->setTSconfig($this->P['table'], $rec, $this->P['field']);
+                       $fieldTSConfig = FormEngineUtility::getTSconfigForTableRow($this->P['table'], $rec, $this->P['field']);
                        if ((string)$fieldTSConfig['RTEfullScreenWidth'] !== '') {
                                $width = $fieldTSConfig['RTEfullScreenWidth'];
                        } else {
index eea8987..54f5281 100644 (file)
@@ -19,6 +19,8 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
 use TYPO3\CMS\Lang\LanguageService;
 use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
+use TYPO3\CMS\Core\Messaging\FlashMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessageService;
 
 /**
  * Class for getting and transforming data for display in backend forms (TCEforms)
@@ -38,6 +40,7 @@ class DataPreprocessor {
         * Is set externally if RTE is disabled.
         *
         * @var int
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
         */
        public $disableRTE = 0;
 
@@ -854,6 +857,7 @@ class DataPreprocessor {
         * @see procesItemArray()
         */
        public function procItems($items, $itemsProcFuncTSconfig, $config, $table, $row, $field) {
+               $languageService = $this->getLanguageService();
                $params = array();
                $params['items'] = &$items;
                $params['config'] = $config;
@@ -861,7 +865,33 @@ class DataPreprocessor {
                $params['table'] = $table;
                $params['row'] = $row;
                $params['field'] = $field;
-               GeneralUtility::callUserFunction($config['itemsProcFunc'], $params, $this);
+               // The itemsProcFunc method may throw an exception.
+               // If it does display an error message and return items unchanged.
+               try {
+                       GeneralUtility::callUserFunction($config['itemsProcFunc'], $params, $this);
+               } catch (\Exception $exception) {
+                       $fieldLabel = $field;
+                       if (isset($GLOBALS['TCA'][$table]['columns'][$field]['label'])) {
+                               $fieldLabel = $languageService->sL($GLOBALS['TCA'][$table]['columns'][$field]['label']);
+                       }
+                       $message = sprintf(
+                               $languageService->sL('LLL:EXT:lang/locallang_core.xlf:error.items_proc_func_error'),
+                               $fieldLabel,
+                               $exception->getMessage()
+                       );
+                       /** @var FlashMessage $flashMessage */
+                       $flashMessage = GeneralUtility::makeInstance(
+                               FlashMessage::class,
+                               htmlspecialchars($message),
+                               '',
+                               FlashMessage::ERROR,
+                               TRUE
+                       );
+                       /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
+                       $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
+                       $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
+                       $defaultFlashMessageQueue->enqueue($flashMessage);
+               }
                return $items;
        }
 
index aa83652..8e6102e 100644 (file)
@@ -33,9 +33,9 @@ interface DatabaseFileIconsHookInterface {
         * @param string $fName Form element name
         * @param array $uidList The array of item-uids. Have a look at \TYPO3\CMS\Backend\Form\FormEngine::dbFileIcons parameter "$itemArray
         * @param array $additionalParams Array with additional parameters which are be available at method call. Includes $mode, $allowed, $itemArray, $onFocus, $table, $field, $uid. For more information have a look at PHPDoc-Comment of \TYPO3\CMS\Backend\Form\FormEngine::dbFileIcons
-        * @param \TYPO3\CMS\Backend\Form\FormEngine $parentObject Parent object
+        * @param object $parentObject Parent object
         * @return void
         */
-       public function dbFileIcons_postProcess(array &$params, &$selector, &$thumbnails, array &$icons, &$rightbox, &$fName, array &$uidList, array $additionalParams, \TYPO3\CMS\Backend\Form\FormEngine $parentObject);
+       public function dbFileIcons_postProcess(array &$params, &$selector, &$thumbnails, array &$icons, &$rightbox, &$fName, array &$uidList, array $additionalParams, $parentObject);
 
 }
index 6acb7b8..3625081 100644 (file)
@@ -15,10 +15,21 @@ namespace TYPO3\CMS\Backend\Form\Element;
  */
 
 use TYPO3\CMS\Backend\Form\FormEngine;
+use TYPO3\CMS\Backend\Form\DataPreprocessor;
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\DatabaseConnection;
 use TYPO3\CMS\Lang\LanguageService;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
+use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Backend\Utility\IconUtility;
+use TYPO3\CMS\Backend\Form\Wizard\SuggestWizard;
+use TYPO3\CMS\Backend\Form\Wizard\ValueSliderWizard;
+use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Backend\Form\DatabaseFileIconsHookInterface;
+use TYPO3\CMS\Backend\Clipboard\Clipboard;
 
 /**
  * Base class for form elements of FormEngine
@@ -31,9 +42,37 @@ abstract class AbstractFormElement {
        protected $formEngine;
 
        /**
-        * @var bool If TRUE, the element will not be editable
+        * A list of global options given from FormEngine to child elements
+        *
+        * @var array
+        */
+       protected $globalOptions = array();
+
+       /**
+        * Default width value for a couple of elements like text
+        *
+        * @var int
+        */
+       protected $defaultInputWidth = 30;
+
+       /**
+        * Minimum width value for a couple of elements like text
+        *
+        * @var int
+        */
+       protected $minimumInputWidth = 10;
+
+       /**
+        * Maximum width value for a couple of elements like text
+        *
+        * @var int
         */
-       protected $renderReadonly = FALSE;
+       protected $maxInputWidth = 50;
+
+       /**
+        * @var \TYPO3\CMS\Backend\Clipboard\Clipboard|NULL
+        */
+       protected $clipboard = NULL;
 
        /**
         * Constructor function, setting the FormEngine
@@ -45,20 +84,13 @@ abstract class AbstractFormElement {
        }
 
        /**
-        * @return bool TRUE if field is set to read only
-        */
-       public function isRenderReadonly() {
-               return $this->renderReadonly;
-       }
-
-       /**
-        * Set render read only state
+        * Set global options from parent FormEngine instance
         *
-        * @param bool $renderReadonly
+        * @param array $globalOptions Global options like 'readonly' for all elements
         * @return AbstractFormElement
         */
-       public function setRenderReadonly($renderReadonly) {
-               $this->renderReadonly = (bool)$renderReadonly;
+       public function setGlobalOptions(array $globalOptions) {
+               $this->globalOptions = $globalOptions;
                return $this;
        }
 
@@ -74,6 +106,802 @@ abstract class AbstractFormElement {
        abstract public function render($table, $field, $row, &$additionalInformation);
 
        /**
+        * @return bool TRUE if field is set to read only
+        */
+       protected function isGlobalReadonly() {
+               return !empty($this->globalOptions['renderReadonly']);
+       }
+
+       /**
+        * @return bool TRUE if wizards are disabled on a global level
+        */
+       protected function isWizardsDisabled() {
+               return !empty($this->globalOptions['disabledWizards']);
+       }
+
+       /**
+        * @return string URL to return to this entry script
+        */
+       protected function getReturnUrl() {
+               return isset($this->globalOptions['returnUrl']) ? $this->globalOptions['returnUrl'] : '';
+       }
+
+       /**
+        * Returns the max width in pixels for a elements like input and text
+        *
+        * @param int $size The abstract size value (1-48)
+        * @return int Maximum width in pixels
+        */
+       protected function formMaxWidth($size = 48) {
+               $compensationForLargeDocuments = 1.33;
+               $compensationForFormFields = 12;
+
+               $size = round($size * $compensationForLargeDocuments);
+               return ceil($size * $compensationForFormFields);
+       }
+
+       /**
+        * Rendering wizards for form fields.
+        *
+        * @param array $itemKinds Array with the real item in the first value, and an alternative item in the second value.
+        * @param array $wizConf The "wizard" key from the config array for the field (from TCA)
+        * @param string $table Table name
+        * @param array $row The record array
+        * @param string $field The field name
+        * @param array $PA Additional configuration array.
+        * @param string $itemName The field name
+        * @param array $specConf Special configuration if available.
+        * @param bool $RTE Whether the RTE could have been loaded.
+        * @return string The new item value.
+        */
+       protected function renderWizards($itemKinds, $wizConf, $table, $row, $field, $PA, $itemName, $specConf, $RTE = FALSE) {
+               // Return not changed main item directly if wizards are disabled
+               if (!is_array($wizConf) || $this->isWizardsDisabled()) {
+                       return $itemKinds[0];
+               }
+
+               $languageService = $this->getLanguageService();
+
+               $fieldChangeFunc = $PA['fieldChangeFunc'];
+               $item = $itemKinds[0];
+               $fName = '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
+               $md5ID = 'ID' . GeneralUtility::shortmd5($itemName);
+               $fieldConfig = $PA['fieldConf']['config'];
+               $prefixOfFormElName = 'data[' . $table . '][' . $row['uid'] . '][' . $field . ']';
+               $flexFormPath = '';
+               if (GeneralUtility::isFirstPartOfStr($PA['itemFormElName'], $prefixOfFormElName)) {
+                       $flexFormPath = str_replace('][', '/', substr($PA['itemFormElName'], strlen($prefixOfFormElName) + 1, -1));
+               }
+
+               // Manipulate the field name (to be the TRUE form field name) and remove
+               // a suffix-value if the item is a selector box with renderMode "singlebox":
+               $listFlag = '_list';
+               if ($PA['fieldConf']['config']['form_type'] == 'select') {
+                       // Single select situation:
+                       if ($PA['fieldConf']['config']['maxitems'] <= 1) {
+                               $listFlag = '';
+                       } elseif ($PA['fieldConf']['config']['renderMode'] == 'singlebox') {
+                               $itemName .= '[]';
+                               $listFlag = '';
+                       }
+               }
+
+               // Contains wizard identifiers enabled for this record type, see "special configuration" docs
+               $wizardsEnabledByType = $specConf['wizards']['parameters'];
+
+               $buttonWizards = array();
+               $otherWizards = array();
+               foreach ($wizConf as $wizardIdentifier => $wizardConfiguration) {
+                       // If an identifier starts with "_", this is a configuration option like _POSITION and not a wizard
+                       if ($wizardIdentifier[0] === '_') {
+                               continue;
+                       }
+
+                       // Sanitize wizard type
+                       $wizardConfiguration['type'] = (string)$wizardConfiguration['type'];
+
+                       // Wizards can be shown based on selected "type" of record. If this is the case, the wizard configuration
+                       // is set to enableByTypeConfig = 1, and the wizardIdentifier is found in $wizardsEnabledByType
+                       $wizardIsEnabled = TRUE;
+                       if (
+                               isset($wizardConfiguration['enableByTypeConfig'])
+                               && (bool)$wizardConfiguration['enableByTypeConfig']
+                               && (!is_array($wizardsEnabledByType) || !in_array($wizardIdentifier, $wizardsEnabledByType))
+                       ) {
+                               $wizardIsEnabled = FALSE;
+                       }
+                       // Disable if wizard is for RTE fields only and the handled field is no RTE field or RTE can not be loaded
+                       if (isset($wizardConfiguration['RTEonly']) && (bool)$wizardConfiguration['RTEonly'] && !$RTE) {
+                               $wizardIsEnabled = FALSE;
+                       }
+                       // Disable if wizard is for not-new records only and we're handling a new record
+                       if (isset($wizardConfiguration['notNewRecords']) && $wizardConfiguration['notNewRecords'] && !MathUtility::canBeInterpretedAsInteger($row['uid'])) {
+                               $wizardIsEnabled = FALSE;
+                       }
+                       // Wizard types script, colorbox and popup must contain a module name configuration
+                       if (!isset($wizardConfiguration['module']['name']) && in_array($wizardConfiguration['type'], array('script', 'colorbox', 'popup'), TRUE)) {
+                               $wizardIsEnabled = FALSE;
+                       }
+
+                       if (!$wizardIsEnabled) {
+                               continue;
+                       }
+
+                       // Title / icon:
+                       $iTitle = htmlspecialchars($languageService->sL($wizardConfiguration['title']));
+                       if (isset($wizardConfiguration['icon'])) {
+                               $icon = FormEngineUtility::getIconHtml($wizardConfiguration['icon'], $iTitle, $iTitle);
+                       } else {
+                               $icon = $iTitle;
+                       }
+
+                       switch ($wizardConfiguration['type']) {
+                               case 'userFunc':
+                                       $params = array();
+                                       $params['fieldConfig'] = $fieldConfig;
+                                       $params['params'] = $wizardConfiguration['params'];
+                                       $params['exampleImg'] = $wizardConfiguration['exampleImg'];
+                                       $params['table'] = $table;
+                                       $params['uid'] = $row['uid'];
+                                       $params['pid'] = $row['pid'];
+                                       $params['field'] = $field;
+                                       $params['flexFormPath'] = $flexFormPath;
+                                       $params['md5ID'] = $md5ID;
+                                       $params['returnUrl'] = $this->getReturnUrl();
+
+                                       $params['formName'] = 'editform';
+                                       $params['itemName'] = $itemName;
+                                       $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js');
+                                       $params['fieldChangeFunc'] = $fieldChangeFunc;
+                                       $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc));
+
+                                       $params['item'] = &$item;
+                                       $params['icon'] = $icon;
+                                       $params['iTitle'] = $iTitle;
+                                       $params['wConf'] = $wizardConfiguration;
+                                       $params['row'] = $row;
+                                       $formEngineDummy = new FormEngine;
+                                       $otherWizards[] = GeneralUtility::callUserFunction($wizardConfiguration['userFunc'], $params, $formEngineDummy);
+                                       break;
+
+                               case 'script':
+                                       $params = array();
+                                       // Including the full fieldConfig from TCA may produce too long an URL
+                                       if ($wizardIdentifier != 'RTE') {
+                                               $params['fieldConfig'] = $fieldConfig;
+                                       }
+                                       $params['params'] = $wizardConfiguration['params'];
+                                       $params['exampleImg'] = $wizardConfiguration['exampleImg'];
+                                       $params['table'] = $table;
+                                       $params['uid'] = $row['uid'];
+                                       $params['pid'] = $row['pid'];
+                                       $params['field'] = $field;
+                                       $params['flexFormPath'] = $flexFormPath;
+                                       $params['md5ID'] = $md5ID;
+                                       $params['returnUrl'] = $this->getReturnUrl();
+
+                                       // Resolving script filename and setting URL.
+                                       $urlParameters = array();
+                                       if (isset($wizardConfiguration['module']['urlParameters']) && is_array($wizardConfiguration['module']['urlParameters'])) {
+                                               $urlParameters = $wizardConfiguration['module']['urlParameters'];
+                                       }
+                                       $wScript = BackendUtility::getModuleUrl($wizardConfiguration['module']['name'], $urlParameters, '');
+                                       $url = $wScript . (strstr($wScript, '?') ? '' : '?') . GeneralUtility::implodeArrayForUrl('', array('P' => $params));
+                                       $buttonWizards[] =
+                                               '<a class="btn btn-default" href="' . htmlspecialchars($url) . '" onclick="this.blur(); return !TBE_EDITOR.isFormChanged();">'
+                                                       . $icon .
+                                               '</a>';
+                                       break;
+
+                               case 'popup':
+                                       $params = array();
+                                       $params['fieldConfig'] = $fieldConfig;
+                                       $params['params'] = $wizardConfiguration['params'];
+                                       $params['exampleImg'] = $wizardConfiguration['exampleImg'];
+                                       $params['table'] = $table;
+                                       $params['uid'] = $row['uid'];
+                                       $params['pid'] = $row['pid'];
+                                       $params['field'] = $field;
+                                       $params['flexFormPath'] = $flexFormPath;
+                                       $params['md5ID'] = $md5ID;
+                                       $params['returnUrl'] = $this->getReturnUrl();
+
+                                       $params['formName'] = 'editform';
+                                       $params['itemName'] = $itemName;
+                                       $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js');
+                                       $params['fieldChangeFunc'] = $fieldChangeFunc;
+                                       $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc));
+
+                                       // Resolving script filename and setting URL.
+                                       $urlParameters = array();
+                                       if (isset($wizardConfiguration['module']['urlParameters']) && is_array($wizardConfiguration['module']['urlParameters'])) {
+                                               $urlParameters = $wizardConfiguration['module']['urlParameters'];
+                                       }
+                                       $wScript = BackendUtility::getModuleUrl($wizardConfiguration['module']['name'], $urlParameters, '');
+                                       $url = $wScript . (strstr($wScript, '?') ? '' : '?') . GeneralUtility::implodeArrayForUrl('', array('P' => $params));
+
+                                       $onlyIfSelectedJS = '';
+                                       if (isset($wizardConfiguration['popup_onlyOpenIfSelected']) && $wizardConfiguration['popup_onlyOpenIfSelected']) {
+                                               $notSelectedText = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.noSelItemForEdit');
+                                               $onlyIfSelectedJS =
+                                                       'if (!TBE_EDITOR.curSelected(\'' . $itemName . $listFlag . '\')){' .
+                                                               'alert(' . GeneralUtility::quoteJSvalue($notSelectedText) . ');' .
+                                                               'return false; .
+                                                       }';
+                                       }
+                                       $aOnClick =
+                                               'this.blur();' .
+                                               $onlyIfSelectedJS .
+                                               'vHWin=window.open(' .
+                                                       '\'' . $url  . '\'+\'&P[currentValue]=\'+TBE_EDITOR.rawurlencode(' .
+                                                               'document.editform[\'' . $itemName . '\'].value,200' .
+                                                       ')' .
+                                                       '+\'&P[currentSelectedValues]=\'+TBE_EDITOR.curSelected(\'' . $itemName . $listFlag . '\'),' .
+                                                       '\'popUp' . $md5ID . '\',' .
+                                                       '\'' . $wizardConfiguration['JSopenParams'] . '\'' .
+                                               ');' .
+                                               'vHWin.focus();' .
+                                               'return false;';
+
+                                       $buttonWizards[] =
+                                               '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($aOnClick) . '">' .
+                                                       $icon .
+                                               '</a>';
+                                       break;
+
+                               case 'colorbox':
+                                       $params = array();
+                                       $params['fieldConfig'] = $fieldConfig;
+                                       $params['params'] = $wizardConfiguration['params'];
+                                       $params['exampleImg'] = $wizardConfiguration['exampleImg'];
+                                       $params['table'] = $table;
+                                       $params['uid'] = $row['uid'];
+                                       $params['pid'] = $row['pid'];
+                                       $params['field'] = $field;
+                                       $params['flexFormPath'] = $flexFormPath;
+                                       $params['md5ID'] = $md5ID;
+                                       $params['returnUrl'] = $this->getReturnUrl();
+
+                                       $params['formName'] = 'editform';
+                                       $params['itemName'] = $itemName;
+                                       $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js');
+                                       $params['fieldChangeFunc'] = $fieldChangeFunc;
+                                       $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc));
+
+                                       // Resolving script filename and setting URL.
+                                       $urlParameters = array();
+                                       if (isset($wizardConfiguration['module']['urlParameters']) && is_array($wizardConfiguration['module']['urlParameters'])) {
+                                               $urlParameters = $wizardConfiguration['module']['urlParameters'];
+                                       }
+                                       $wScript = BackendUtility::getModuleUrl($wizardConfiguration['module']['name'], $urlParameters, '');
+                                       $url = $wScript . (strstr($wScript, '?') ? '' : '?') . GeneralUtility::implodeArrayForUrl('', array('P' => $params));
+
+                                       $aOnClick =
+                                               'this.blur();' .
+                                               'vHWin=window.open(' .
+                                                       '\'' . $url  . '\'+\'&P[currentValue]=\'+TBE_EDITOR.rawurlencode(' .
+                                                       'document.editform[\'' . $itemName . '\'].value,200' .
+                                                       ')' .
+                                                       '+\'&P[currentSelectedValues]=\'+TBE_EDITOR.curSelected(\'' . $itemName . $listFlag . '\'),' .
+                                                       '\'popUp' . $md5ID . '\',' .
+                                                       '\'' . $wizardConfiguration['JSopenParams'] . '\'' .
+                                               ');' .
+                                               'vHWin.focus();' .
+                                               'return false;';
+
+                                       $dim = GeneralUtility::intExplode('x', $wizardConfiguration['dim']);
+                                       $dX = MathUtility::forceIntegerInRange($dim[0], 1, 200, 20);
+                                       $dY = MathUtility::forceIntegerInRange($dim[1], 1, 200, 20);
+                                       $color = $PA['itemFormElValue'] ? ' bgcolor="' . htmlspecialchars($PA['itemFormElValue']) . '"' : '';
+                                       $skinImg = IconUtility::skinImg(
+                                               '',
+                                               $PA['itemFormElValue'] === '' ? 'gfx/colorpicker_empty.png' : 'gfx/colorpicker.png',
+                                               'width="' . $dX . '" height="' . $dY . '"' . BackendUtility::titleAltAttrib(trim($iTitle . ' ' . $PA['itemFormElValue'])) . ' border="0"'
+                                       );
+                                       $otherWizards[] =
+                                               '<table border="0" id="' . $md5ID . '"' . $color . ' style="' . htmlspecialchars($wizardConfiguration['tableStyle']) . '">' .
+                                                       '<tr>' .
+                                                               '<td>' .
+                                                                       '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . '<img ' . $skinImg . '>' . '</a>' .
+                                                               '</td>' .
+                                                       '</tr>' .
+                                               '</table>';
+                                       break;
+
+                               case 'slider':
+                                       $params = array();
+                                       $params['fieldConfig'] = $fieldConfig;
+                                       $params['field'] = $field;
+                                       $params['flexFormPath'] = $flexFormPath;
+                                       $params['md5ID'] = $md5ID;
+                                       $params['itemName'] = $itemName;
+                                       $params['fieldChangeFunc'] = $fieldChangeFunc;
+                                       $params['wConf'] = $wizardConfiguration;
+                                       $params['row'] = $row;
+
+                                       /** @var ValueSliderWizard $wizard */
+                                       $wizard = GeneralUtility::makeInstance(ValueSliderWizard::class);
+                                       $otherWizards[] = $wizard->renderWizard($params);
+                                       break;
+
+                               case 'select':
+                                       $fieldValue = array('config' => $wizardConfiguration);
+                                       $TSconfig = FormEngineUtility::getTSconfigForTableRow($table, $row);
+                                       $TSconfig[$field] = $TSconfig[$field]['wizards.'][$wizardIdentifier . '.'];
+                                       $selItems = FormEngineUtility::addSelectOptionsToItemArray(FormEngineUtility::initItemArray($fieldValue), $fieldValue, $TSconfig, $field);
+                                       // Process items by a user function:
+                                       if (!empty($wizardConfiguration['itemsProcFunc'])) {
+                                               $funcConfig = !empty($wizardConfiguration['itemsProcFunc.']) ? $wizardConfiguration['itemsProcFunc.'] : array();
+                                               $dataPreprocessor = GeneralUtility::makeInstance(DataPreprocessor::class);
+                                               $selItems = $dataPreprocessor->procItems($selItems, $funcConfig, $wizardConfiguration, $table, $row, $field);
+                                       }
+                                       $options = array();
+                                       $options[] = '<option>' . $iTitle . '</option>';
+                                       foreach ($selItems as $p) {
+                                               $options[] = '<option value="' . htmlspecialchars($p[1]) . '">' . htmlspecialchars($p[0]) . '</option>';
+                                       }
+                                       if ($wizardConfiguration['mode'] == 'append') {
+                                               $assignValue = 'document.editform[\'' . $itemName . '\'].value=\'\'+this.options[this.selectedIndex].value+document.editform[\'' . $itemName . '\'].value';
+                                       } elseif ($wizardConfiguration['mode'] == 'prepend') {
+                                               $assignValue = 'document.editform[\'' . $itemName . '\'].value+=\'\'+this.options[this.selectedIndex].value';
+                                       } else {
+                                               $assignValue = 'document.editform[\'' . $itemName . '\'].value=this.options[this.selectedIndex].value';
+                                       }
+                                       $otherWizards[] =
+                                               '<select' .
+                                                       ' id="' . str_replace('.', '', uniqid('tceforms-select-', TRUE)) . '"' .
+                                                       ' class="form-control tceforms-select tceforms-wizardselect"' .
+                                                       ' name="_WIZARD' . $fName . '"' .
+                                                       ' onchange="' . htmlspecialchars($assignValue . ';this.blur();this.selectedIndex=0;' . implode('', $fieldChangeFunc)) . '"'.
+                                               '>' .
+                                                       implode('', $options) .
+                                               '</select>';
+                                       break;
+                               case 'suggest':
+                                       if (!empty($PA['fieldTSConfig']['suggest.']['default.']['hide'])) {
+                                               break;
+                                       }
+                                       /** @var SuggestWizard $suggestWizard */
+                                       $suggestWizard = GeneralUtility::makeInstance(SuggestWizard::class);
+                                       $otherWizards[] = $suggestWizard->renderSuggestSelector($PA['itemFormElName'], $table, $field, $row, $PA);
+                                       break;
+                       }
+
+                       // Hide the real form element?
+                       if (is_array($wizardConfiguration['hideParent']) || $wizardConfiguration['hideParent']) {
+                               // Setting the item to a hidden-field.
+                               $item = $itemKinds[1];
+                               if (is_array($wizardConfiguration['hideParent'])) {
+                                       // NoneElement does not access formEngine properties, use a dummy for decoupling
+                                       $formEngineDummy = new FormEngine;
+                                       /** @var NoneElement $noneElement */
+                                       $noneElement = GeneralUtility::makeInstance(NoneElement::class, $formEngineDummy);
+                                       $elementConfiguration = array(
+                                               'fieldConf' => array(
+                                                       'config' => $wizardConfiguration['hideParent'],
+                                               ),
+                                               'itemFormElValue' => $PA['itemFormElValue'],
+                                       );
+                                       $item .= $noneElement->render('', '', '', $elementConfiguration);
+                               }
+                       }
+               }
+
+               // For each rendered wizard, put them together around the item.
+               if (!empty($buttonWizards) || !empty($otherWizards)) {
+                       if ($wizConf['_HIDDENFIELD']) {
+                               $item = $itemKinds[1];
+                       }
+
+                       $innerContent = '';
+                       if (!empty($buttonWizards)) {
+                               $innerContent .= '<div class="btn-group' . ($wizConf['_VERTICAL'] ? ' btn-group-vertical' : '') . '">' . implode('', $buttonWizards) . '</div>';
+                       }
+                       $innerContent .= implode(' ', $otherWizards);
+
+                       // Position
+                       $classes = array('form-wizards-wrap');
+                       if ($wizConf['_POSITION'] === 'left') {
+                               $classes[] = 'form-wizards-aside';
+                               $innerContent = '<div class="form-wizards-items">' . $innerContent . '</div><div class="form-wizards-element">' . $item . '</div>';
+                       } elseif ($wizConf['_POSITION'] === 'top') {
+                               $classes[] = 'form-wizards-top';
+                               $innerContent = '<div class="form-wizards-items">' . $innerContent . '</div><div class="form-wizards-element">' . $item . '</div>';
+                       } elseif ($wizConf['_POSITION'] === 'bottom') {
+                               $classes[] = 'form-wizards-bottom';
+                               $innerContent = '<div class="form-wizards-element">' . $item . '</div><div class="form-wizards-items">' . $innerContent . '</div>';
+                       } else {
+                               $classes[] = 'form-wizards-aside';
+                               $innerContent = '<div class="form-wizards-element">' . $item . '</div><div class="form-wizards-items">' . $innerContent . '</div>';
+                       }
+                       $item = '
+                               <div class="' . implode(' ', $classes) . '">
+                                       ' . $innerContent . '
+                               </div>';
+               }
+
+               return $item;
+       }
+
+       /**
+        * Prints the selector box form-field for the db/file/select elements (multiple)
+        *
+        * @param string $fName Form element name
+        * @param string $mode Mode "db", "file" (internal_type for the "group" type) OR blank (then for the "select" type)
+        * @param string $allowed Commalist of "allowed
+        * @param array $itemArray The array of items. For "select" and "group"/"file" this is just a set of value. For "db" its an array of arrays with table/uid pairs.
+        * @param string $selector Alternative selector box.
+        * @param array $params An array of additional parameters, eg: "size", "info", "headers" (array with "selector" and "items"), "noBrowser", "thumbnails
+        * @param string $onFocus On focus attribute string
+        * @param string $table (optional) Table name processing for
+        * @param string $field (optional) Field of table name processing for
+        * @param string $uid (optional) uid of table record processing for
+        * @param array $config (optional) The TCA field config
+        * @return string The form fields for the selection.
+        * @throws \UnexpectedValueException
+        */
+       protected function dbFileIcons($fName, $mode, $allowed, $itemArray, $selector = '', $params = array(), $onFocus = '', $table = '', $field = '', $uid = '', $config = array()) {
+               $languageService = $this->getLanguageService();
+               $disabled = '';
+               if ($this->isGlobalReadonly() || $params['readOnly']) {
+                       $disabled = ' disabled="disabled"';
+               }
+               // INIT
+               $uidList = array();
+               $opt = array();
+               $itemArrayC = 0;
+               // Creating <option> elements:
+               if (is_array($itemArray)) {
+                       $itemArrayC = count($itemArray);
+                       switch ($mode) {
+                               case 'db':
+                                       foreach ($itemArray as $pp) {
+                                               $pRec = BackendUtility::getRecordWSOL($pp['table'], $pp['id']);
+                                               if (is_array($pRec)) {
+                                                       $pTitle = BackendUtility::getRecordTitle($pp['table'], $pRec, FALSE, TRUE);
+                                                       $pUid = $pp['table'] . '_' . $pp['id'];
+                                                       $uidList[] = $pUid;
+                                                       $title = htmlspecialchars($pTitle);
+                                                       $opt[] = '<option value="' . htmlspecialchars($pUid) . '" title="' . $title . '">' . $title . '</option>';
+                                               }
+                                       }
+                                       break;
+                               case 'file_reference':
+
+                               case 'file':
+                                       foreach ($itemArray as $item) {
+                                               $itemParts = explode('|', $item);
+                                               $uidList[] = ($pUid = ($pTitle = $itemParts[0]));
+                                               $title = htmlspecialchars(rawurldecode($itemParts[1]));
+                                               $opt[] = '<option value="' . htmlspecialchars(rawurldecode($itemParts[0])) . '" title="' . $title . '">' . $title . '</option>';
+                                       }
+                                       break;
+                               case 'folder':
+                                       foreach ($itemArray as $pp) {
+                                               $pParts = explode('|', $pp);
+                                               $uidList[] = ($pUid = ($pTitle = $pParts[0]));
+                                               $title = htmlspecialchars(rawurldecode($pParts[0]));
+                                               $opt[] = '<option value="' . htmlspecialchars(rawurldecode($pParts[0])) . '" title="' . $title . '">' . $title . '</option>';
+                                       }
+                                       break;
+                               default:
+                                       foreach ($itemArray as $pp) {
+                                               $pParts = explode('|', $pp, 2);
+                                               $uidList[] = ($pUid = $pParts[0]);
+                                               $pTitle = $pParts[1];
+                                               $title = htmlspecialchars(rawurldecode($pTitle));
+                                               $opt[] = '<option value="' . htmlspecialchars(rawurldecode($pUid)) . '" title="' . $title . '">' . $title . '</option>';
+                                       }
+                       }
+               }
+               // Create selector box of the options
+               $sSize = $params['autoSizeMax']
+                       ? MathUtility::forceIntegerInRange($itemArrayC + 1, MathUtility::forceIntegerInRange($params['size'], 1), $params['autoSizeMax'])
+                       : $params['size'];
+               if (!$selector) {
+                       $isMultiple = $params['maxitems'] != 1 && $params['size'] != 1;
+                       $selector = '<select id="' . str_replace('.', '', uniqid('tceforms-multiselect-', TRUE)) . '" '
+                               . ($params['noList'] ? 'style="display: none"' : 'size="' . $sSize . '" class="form-control tceforms-multiselect"')
+                               . ($isMultiple ? ' multiple="multiple"' : '')
+                               . ' name="' . $fName . '_list" ' . $onFocus . $params['style'] . $disabled . '>' . implode('', $opt)
+                               . '</select>';
+               }
+               $icons = array(
+                       'L' => array(),
+                       'R' => array()
+               );
+               $rOnClickInline = '';
+               if (!$params['readOnly'] && !$params['noList']) {
+                       if (!$params['noBrowser']) {
+                               // Check against inline uniqueness
+                               /** @var InlineElement $inline */
+                               $inline = $this->globalOptions['inline'];
+                               $inlineParent = $inline->getStructureLevel(-1);
+                               $aOnClickInline = '';
+                               if (is_array($inlineParent) && $inlineParent['uid']) {
+                                       if ($inlineParent['config']['foreign_table'] == $table && $inlineParent['config']['foreign_unique'] == $field) {
+                                               $objectPrefix = $inline->inlineNames['object'] . InlineElement::Structure_Separator . $table;
+                                               $aOnClickInline = $objectPrefix . '|inline.checkUniqueElement|inline.setUniqueElement';
+                                               $rOnClickInline = 'inline.revertUnique(\'' . $objectPrefix . '\',null,\'' . $uid . '\');';
+                                       }
+                               }
+                               if (is_array($config['appearance']) && isset($config['appearance']['elementBrowserType'])) {
+                                       $elementBrowserType = $config['appearance']['elementBrowserType'];
+                               } else {
+                                       $elementBrowserType = $mode;
+                               }
+                               if (is_array($config['appearance']) && isset($config['appearance']['elementBrowserAllowed'])) {
+                                       $elementBrowserAllowed = $config['appearance']['elementBrowserAllowed'];
+                               } else {
+                                       $elementBrowserAllowed = $allowed;
+                               }
+                               $aOnClick = 'setFormValueOpenBrowser(\'' . $elementBrowserType . '\',\''
+                                       . ($fName . '|||' . $elementBrowserAllowed . '|' . $aOnClickInline) . '\'); return false;';
+                               $icons['R'][] = '
+                                       <a href="#"
+                                               onclick="' . htmlspecialchars($aOnClick) . '"
+                                               class="btn btn-default"
+                                               title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.browse_' . ($mode == 'db' ? 'db' : 'file'))) . '">
+                                               ' . IconUtility::getSpriteIcon('actions-insert-record') . '
+                                       </a>';
+                       }
+                       if (!$params['dontShowMoveIcons']) {
+                               if ($sSize >= 5) {
+                                       $icons['L'][] = '
+                                               <a href="#"
+                                                       class="btn btn-default t3-btn-moveoption-top"
+                                                       data-fieldname="' . $fName . '"
+                                                       title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.move_to_top')) . '">
+                                                       ' . IconUtility::getSpriteIcon('actions-move-to-top') . '
+                                               </a>';
+
+                               }
+                               $icons['L'][] = '
+                                       <a href="#"
+                                               class="btn btn-default t3-btn-moveoption-up"
+                                               data-fieldname="' . $fName . '"
+                                               title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.move_up')) . '">
+                                               ' . IconUtility::getSpriteIcon('actions-move-up') . '
+                                       </a>';
+                               $icons['L'][] = '
+                                       <a href="#"
+                                               class="btn btn-default t3-btn-moveoption-down"
+                                               data-fieldname="' . $fName . '"
+                                               title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.move_down')) . '">
+                                               ' . IconUtility::getSpriteIcon('actions-move-down') . '
+                                       </a>';
+                               if ($sSize >= 5) {
+                                       $icons['L'][] = '
+                                               <a href="#"
+                                                       class="btn btn-default t3-btn-moveoption-bottom"
+                                                       data-fieldname="' . $fName . '"
+                                                       title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.move_to_bottom')) . '">
+                                                       ' . IconUtility::getSpriteIcon('actions-move-to-bottom') . '
+                                               </a>';
+                               }
+                       }
+                       $clipElements = $this->getClipboardElements($allowed, $mode);
+                       if (count($clipElements)) {
+                               $aOnClick = '';
+                               foreach ($clipElements as $elValue) {
+                                       if ($mode == 'db') {
+                                               list($itemTable, $itemUid) = explode('|', $elValue);
+                                               $recordTitle = BackendUtility::getRecordTitle($itemTable, BackendUtility::getRecordWSOL($itemTable, $itemUid));
+                                               $itemTitle = GeneralUtility::quoteJSvalue($recordTitle);
+                                               $elValue = $itemTable . '_' . $itemUid;
+                                       } else {
+                                               // 'file', 'file_reference' and 'folder' mode
+                                               $itemTitle = 'unescape(\'' . rawurlencode(basename($elValue)) . '\')';
+                                       }
+                                       $aOnClick .= 'setFormValueFromBrowseWin(\'' . $fName . '\',unescape(\''
+                                               . rawurlencode(str_replace('%20', ' ', $elValue)) . '\'),' . $itemTitle . ',' . $itemTitle . ');';
+                               }
+                               $aOnClick .= 'return false;';
+                               $icons['R'][] = '
+                                       <a href="#"
+                                               onclick="' . htmlspecialchars($aOnClick) . '"
+                                               title="' . htmlspecialchars(sprintf($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.clipInsert_' . ($mode == 'db' ? 'db' : 'file')), count($clipElements))) . '">
+                                               ' . IconUtility::getSpriteIcon('actions-document-paste-into') . '
+                                       </a>';
+                       }
+               }
+               if (!$params['readOnly'] && !$params['noDelete']) {
+                       $icons['L'][] = '
+                               <a href="#"
+                                       class="btn btn-default t3-btn-removeoption"
+                                       onClick="' . $rOnClickInline . '"
+                                       data-fieldname="' . $fName . '"
+                                       title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.remove_selected')) . '">
+                                       ' . IconUtility::getSpriteIcon('actions-selection-delete') . '
+                               </a>';
+               }
+
+               // Thumbnails
+               $imagesOnly = FALSE;
+               if ($params['thumbnails'] && $params['allowed']) {
+                       // In case we have thumbnails, check if only images are allowed.
+                       // In this case, render them below the field, instead of to the right
+                       $allowedExtensionList = $params['allowed'];
+                       $imageExtensionList = GeneralUtility::trimExplode(',', strtolower($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']), TRUE);
+                       $imagesOnly = TRUE;
+                       foreach ($allowedExtensionList as $allowedExtension) {
+                               if (!ArrayUtility::inArray($imageExtensionList, $allowedExtension)) {
+                                       $imagesOnly = FALSE;
+                                       break;
+                               }
+                       }
+               }
+               $thumbnails = '';
+               if (is_array($params['thumbnails']) && !empty($params['thumbnails'])) {
+                       if ($imagesOnly) {
+                               $thumbnails .= '<ul class="list-inline">';
+                               foreach ($params['thumbnails'] as $thumbnail) {
+                                       $thumbnails .= '<li><span class="thumbnail">' . $thumbnail['image'] . '</span></li>';
+                               }
+                               $thumbnails .= '</ul>';
+                       } else {
+                               $thumbnails .= '<div class="table-fit"><table class="table table-white"><tbody>';
+                               foreach ($params['thumbnails'] as $thumbnail) {
+                                       $thumbnails .= '
+                                               <tr>
+                                                       <td class="col-icon">
+                                                               ' . ($config['internal_type'] === 'db'
+                                                       ? $this->getControllerDocumentTemplate()->wrapClickMenuOnIcon($thumbnail['image'], $thumbnail['table'], $thumbnail['uid'], 1, '', '+copy,info,edit,view')
+                                                       : $thumbnail['image']) . '
+                                                       </td>
+                                                       <td class="col-title">
+                                                               ' . ($config['internal_type'] === 'db'
+                                                       ? $this->getControllerDocumentTemplate()->wrapClickMenuOnIcon($thumbnail['name'], $thumbnail['table'], $thumbnail['uid'], 1, '', '+copy,info,edit,view')
+                                                       : $thumbnail['name']) . '
+                                                               ' . ($config['internal_type'] === 'db' ? '' : ' <span class="text-muted">[' . $thumbnail['uid'] . ']</span>') . '
+                                                       </td>
+                                               </tr>
+                                               ';
+                               }
+                               $thumbnails .= '</tbody></table></div>';
+                       }
+               }
+
+               // Allowed Tables
+               $allowedTables = '';
+               if (is_array($params['allowedTables']) && !empty($params['allowedTables'])) {
+                       $allowedTables .= '<div class="help-block">';
+                       foreach ($params['allowedTables'] as $key => $item) {
+                               if (is_array($item)) {
+                                       $allowedTables .= '<a href="#" onClick="' . htmlspecialchars($item['onClick']) . '" class="btn btn-default">' . $item['icon'] . ' ' . htmlspecialchars($item['name']) . '</a> ';
+                               } elseif($key === 'name') {
+                                       $allowedTables .= '<span>' . htmlspecialchars($item) . '</span> ';
+                               }
+                       }
+                       $allowedTables .= '</div>';
+               }
+               // Allowed
+               $allowedList = '';
+               if (is_array($params['allowed']) && !empty($params['allowed'])) {
+                       foreach ($params['allowed'] as $item) {
+                               $allowedList .= '<span class="label label-success">' . strtoupper($item) . '</span> ';
+                       }
+               }
+               // Disallowed
+               $disallowedList = '';
+               if (is_array($params['disallowed']) && !empty($params['disallowed'])) {
+                       foreach ($params['disallowed'] as $item) {
+                               $disallowedList .= '<span class="label label-danger">' . strtoupper($item) . '</span> ';
+                       }
+               }
+               // Rightbox
+               $rightbox = ($params['rightbox'] ?: '');
+
+               // Hook: dbFileIcons_postProcess (requested by FAL-team for use with the "fal" extension)
+               if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['dbFileIcons'])) {
+                       foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['dbFileIcons'] as $classRef) {
+                               $hookObject = GeneralUtility::getUserObj($classRef);
+                               if (!$hookObject instanceof DatabaseFileIconsHookInterface) {
+                                       throw new \UnexpectedValueException('$hookObject must implement interface ' . DatabaseFileIconsHookInterface::class, 1290167704);
+                               }
+                               $additionalParams = array(
+                                       'mode' => $mode,
+                                       'allowed' => $allowed,
+                                       'itemArray' => $itemArray,
+                                       'onFocus' => $onFocus,
+                                       'table' => $table,
+                                       'field' => $field,
+                                       'uid' => $uid,
+                                       'config' => $GLOBALS['TCA'][$table]['columns'][$field]
+                               );
+                               $hookObject->dbFileIcons_postProcess($params, $selector, $thumbnails, $icons, $rightbox, $fName, $uidList, $additionalParams, $this);
+                       }
+               }
+
+               // Output
+               $str = '
+                       ' . ($params['headers']['selector'] ? '<label>' . $params['headers']['selector'] . '</label>' : '') . '
+                       <div class="form-wizards-wrap form-wizards-aside">
+                               <div class="form-wizards-element">
+                                       ' . $selector . '
+                                       ' . (!$params['noList'] && !empty($allowedTables) ? $allowedTables : '') . '
+                                       ' . (!$params['noList'] && (!empty($allowedList) || !empty($disallowedList))
+                               ? '<div class="help-block">' . $allowedList . $disallowedList . ' </div>'
+                               : '') . '
+                               </div>
+                               ' . (!empty($icons['L']) ? '<div class="form-wizards-items"><div class="btn-group-vertical">' . implode('', $icons['L']) . '</div></div>' : '' ) . '
+                               ' . (!empty($icons['R']) ? '<div class="form-wizards-items"><div class="btn-group-vertical">' . implode('', $icons['R']) . '</div></div>' : '' ) . '
+                       </div>
+                       ';
+               if ($rightbox) {
+                       $str = '
+                               <div class="form-multigroup-wrap t3js-formengine-field-group">
+                                       <div class="form-multigroup-item form-multigroup-element">' . $str . '</div>
+                                       <div class="form-multigroup-item form-multigroup-element">
+                                               ' . ($params['headers']['items'] ? '<label>' . $params['headers']['items'] . '</label>' : '') . '
+                                               ' . ($params['headers']['selectorbox'] ? '<div class="form-multigroup-item-wizard">' . $params['headers']['selectorbox'] . '</div>' : '') . '
+                                               ' . $rightbox . '
+                                       </div>
+                               </div>
+                               ';
+               }
+               $str .= $thumbnails;
+
+               // Creating the hidden field which contains the actual value as a comma list.
+               $str .= '<input type="hidden" name="' . $fName . '" value="' . htmlspecialchars(implode(',', $uidList)) . '" />';
+               return $str;
+       }
+
+       /**
+        * Returns array of elements from clipboard to insert into GROUP element box.
+        *
+        * @param string $allowed Allowed elements, Eg "pages,tt_content", "gif,jpg,jpeg,png
+        * @param string $mode Mode of relations: "db" or "file
+        * @return array Array of elements in values (keys are insignificant), if none found, empty array.
+        */
+       protected function getClipboardElements($allowed, $mode) {
+               if (!is_object($this->clipboard)) {
+                       $this->clipboard = GeneralUtility::makeInstance(Clipboard::class);
+                       $this->clipboard->initializeClipboard();
+               }
+
+               $output = array();
+               switch ($mode) {
+                       case 'file_reference':
+
+                       case 'file':
+                               $elFromTable = $this->clipboard->elFromTable('_FILE');
+                               $allowedExts = GeneralUtility::trimExplode(',', $allowed, TRUE);
+                               // If there are a set of allowed extensions, filter the content:
+                               if ($allowedExts) {
+                                       foreach ($elFromTable as $elValue) {
+                                               $pI = pathinfo($elValue);
+                                               $ext = strtolower($pI['extension']);
+                                               if (in_array($ext, $allowedExts)) {
+                                                       $output[] = $elValue;
+                                               }
+                                       }
+                               } else {
+                                       // If all is allowed, insert all: (This does NOT respect any disallowed extensions,
+                                       // but those will be filtered away by the backend TCEmain)
+                                       $output = $elFromTable;
+                               }
+                               break;
+                       case 'db':
+                               $allowedTables = GeneralUtility::trimExplode(',', $allowed, TRUE);
+                               // All tables allowed for relation:
+                               if (trim($allowedTables[0]) === '*') {
+                                       $output = $this->clipboard->elFromTable('');
+                               } else {
+                                       // Only some tables, filter them:
+                                       foreach ($allowedTables as $tablename) {
+                                               $elFromTable = $this->clipboard->elFromTable($tablename);
+                                               $output = array_merge($output, $elFromTable);
+                                       }
+                               }
+                               $output = array_keys($output);
+                               break;
+               }
+
+               return $output;
+       }
+
+       /**
         * @return LanguageService
         */
        protected function getLanguageService() {
index 94f9ff2..c8bde24 100644 (file)
@@ -14,6 +14,10 @@ namespace TYPO3\CMS\Backend\Form\Element;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Backend\Form\DataPreprocessor;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
+
 /**
  * Generation of TCEform elements of the type "check"
  */
@@ -32,13 +36,14 @@ class CheckboxElement extends AbstractFormElement {
                $config = $additionalInformation['fieldConf']['config'];
                $item = '';
                $disabled = FALSE;
-               if ($this->isRenderReadonly() || $config['readOnly']) {
+               if ($this->isGlobalReadonly() || $config['readOnly']) {
                        $disabled = TRUE;
                }
                // Traversing the array of items
-               $items = $this->formEngine->initItemArray($additionalInformation['fieldConf']);
+               $items = FormEngineUtility::initItemArray($additionalInformation['fieldConf']);
                if ($config['itemsProcFunc']) {
-                       $items = $this->formEngine->procItems(
+                       $dataPreprocessor = GeneralUtility::makeInstance(DataPreprocessor::class);
+                       $items = $dataPreprocessor->procItems(
                                $items,
                                $additionalInformation['fieldTSConfig']['itemsProcFunc.'],
                                $config,
@@ -180,7 +185,7 @@ class CheckboxElement extends AbstractFormElement {
         * @return string The onclick attribute + possibly the checked-option set.
         */
        protected function checkBoxParams($itemName, $formElementValue, $checkbox, $checkboxesCount, $additionalJavaScript = '') {
-               $elementName = $this->formEngine->elName($itemName);
+               $elementName = 'document.editform[' . Generalutility::quoteJSvalue($itemName) . ']';
                $checkboxPow = pow(2, $checkbox);
                $onClick = $elementName . '.value=this.checked?(' . $elementName . '.value|' . $checkboxPow . '):('
                        . $elementName . '.value&' . (pow(2, $checkboxesCount) - 1 - $checkboxPow) . ');' . $additionalJavaScript;
index d8f44fb..6657514 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Backend\Form\Element;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
@@ -112,7 +113,7 @@ class FlexElement extends AbstractFormElement {
 
                        foreach ($rotateLang as $lKey) {
                                if (!$langChildren && !$langDisabled) {
-                                       $item .= '<strong>' . $this->formEngine->getLanguageIcon($table, $row, ('v' . $lKey)) . $lKey . ':</strong>';
+                                       $item .= '<strong>' . FormEngineUtility::getLanguageIcon($table, $row, ('v' . $lKey)) . $lKey . ':</strong>';
                                }
                                // Default language, other options are "lUK" or whatever country code (independent of system!!!)
                                $lang = 'l' . $lKey;
@@ -510,7 +511,7 @@ class FlexElement extends AbstractFormElement {
                                                                $theTitle = htmlspecialchars($fakePA['fieldConf']['label']);
                                                                if (!in_array('DEF', $rotateLang)) {
                                                                        $defInfo = '<div class="t3-form-original-language">'
-                                                                               . $this->formEngine->getLanguageIcon($table, $row, 0)
+                                                                               . FormEngineUtility::getLanguageIcon($table, $row, 0)
                                                                                . $this->formEngine->previewFieldValue($editData[$key]['vDEF'], $fakePA['fieldConf'], $field)
                                                                                . '&nbsp;</div>';
                                                                } else {
@@ -520,14 +521,14 @@ class FlexElement extends AbstractFormElement {
                                                                        $prLang = $this->formEngine->getAdditionalPreviewLanguages();
                                                                        foreach ($prLang as $prL) {
                                                                                $defInfo .= '<div class="t3-form-original-language">'
-                                                                                       . $this->formEngine->getLanguageIcon($table, $row, ('v' . $prL['ISOcode']))
+                                                                                       . FormEngineUtility::getLanguageIcon($table, $row, ('v' . $prL['ISOcode']))
                                                                                        . $this->formEngine->previewFieldValue($editData[$key][('v' . $prL['ISOcode'])], $fakePA['fieldConf'], $field)
                                                                                        . '&nbsp;</div>';
                                                                        }
                                                                }
                                                                $languageIcon = '';
                                                                if ($vDEFkey != 'vDEF') {
-                                                                       $languageIcon = $this->formEngine->getLanguageIcon($table, $row, $vDEFkey);
+                                                                       $languageIcon = FormEngineUtility::getLanguageIcon($table, $row, $vDEFkey);
                                                                }
                                                                // Put row together
                                                                // possible linebreaks in the label through xml: \n => <br/>, usage of nl2br()
index 2fac409..007b428 100644 (file)
@@ -41,7 +41,7 @@ class GroupElement extends AbstractFormElement {
 
                $config = $additionalInformation['fieldConf']['config'];
                $show_thumbs = $config['show_thumbs'];
-               $size = isset($config['size']) ? (int)$config['size'] : $this->formEngine->minimumInputWidth;
+               $size = isset($config['size']) ? (int)$config['size'] : $this->minimumInputWidth;
                $maxitems = MathUtility::forceIntegerInRange($config['maxitems'], 0);
                if (!$maxitems) {
                        $maxitems = 100000;
@@ -50,7 +50,7 @@ class GroupElement extends AbstractFormElement {
                $thumbnails = array();
                $allowed = GeneralUtility::trimExplode(',', $config['allowed'], TRUE);
                $disallowed = GeneralUtility::trimExplode(',', $config['disallowed'], TRUE);
-               $disabled = ($this->isRenderReadonly() || $config['readOnly']);
+               $disabled = ($this->isGlobalReadonly() || $config['readOnly']);
                $info = array();
                $additionalInformation['itemFormElID_file'] = $additionalInformation['itemFormElID'] . '_files';
 
@@ -144,7 +144,7 @@ class GroupElement extends AbstractFormElement {
                                                                                $rowCopy,
                                                                                $table,
                                                                                $field,
-                                                                               $this->formEngine->backPath,
+                                                                               '',
                                                                                'thumbs.php',
                                                                                $config['uploadfolder'],
                                                                                0,
@@ -178,14 +178,14 @@ class GroupElement extends AbstractFormElement {
                                        'maxitems' => $maxitems,
                                        'style' => isset($config['selectedListStyle'])
                                                ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
-                                               : ' style="' . $this->formEngine->defaultMultipleSelectorStyle . '"',
+                                               : '',
                                        'thumbnails' => $thumbnails,
                                        'readOnly' => $disabled,
                                        'noBrowser' => $noList || isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'browser'),
                                        'noList' => $noList,
                                        'noDelete' => $noDelete
                                );
-                               $item .= $this->formEngine->dbFileIcons(
+                               $item .= $this->dbFileIcons(
                                        $additionalInformation['itemFormElName'],
                                        'file',
                                        implode(',', $allowed),
@@ -199,7 +199,8 @@ class GroupElement extends AbstractFormElement {
                                        $config);
                                if (!$disabled && !(isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'upload'))) {
                                        // Adding the upload field:
-                                       if ($this->formEngine->edit_docModuleUpload && $config['uploadfolder']) {
+                                       $isDirectFileUploadEnabled = (bool)$this->getBackendUserAuthentication()->uc['edit_docModuleUpload'];
+                                       if ($isDirectFileUploadEnabled && $config['uploadfolder']) {
                                                // Insert the multiple attribute to enable HTML5 multiple file upload
                                                $multipleAttribute = '';
                                                $multipleFilenameSuffix = '';
@@ -229,12 +230,12 @@ class GroupElement extends AbstractFormElement {
                                        'maxitems' => $maxitems,
                                        'style' => isset($config['selectedListStyle'])
                                                ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
-                                               : ' style="' . $this->formEngine->defaultMultipleSelectorStyle . '"',
+                                               : '',
                                        'readOnly' => $disabled,
                                        'noBrowser' => $noList || isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'browser'),
                                        'noList' => $noList
                                );
-                               $item .= $this->formEngine->dbFileIcons(
+                               $item .= $this->dbFileIcons(
                                        $additionalInformation['itemFormElName'],
                                        'folder',
                                        '',
@@ -298,7 +299,7 @@ class GroupElement extends AbstractFormElement {
                                        'maxitems' => $maxitems,
                                        'style' => isset($config['selectedListStyle'])
                                                ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
-                                               : ' style="' . $this->formEngine->defaultMultipleSelectorStyle . '"',
+                                               : '',
                                        'info' => $info,
                                        'allowedTables' => $allowedTables,
                                        'thumbnails' => $thumbnails,
@@ -306,7 +307,7 @@ class GroupElement extends AbstractFormElement {
                                        'noBrowser' => $noList || isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'browser'),
                                        'noList' => $noList
                                );
-                               $item .= $this->formEngine->dbFileIcons(
+                               $item .= $this->dbFileIcons(
                                        $additionalInformation['itemFormElName'],
                                        'db',
                                        implode(',', $allowed),
@@ -324,7 +325,7 @@ class GroupElement extends AbstractFormElement {
                // Wizards:
                $altItem = '<input type="hidden" name="' . $additionalInformation['itemFormElName'] . '" value="' . htmlspecialchars($additionalInformation['itemFormElValue']) . '" />';
                if (!$disabled) {
-                       $item = $this->formEngine->renderWizards(
+                       $item = $this->renderWizards(
                                array(
                                        $item,
                                        $altItem
index 12a8181..cf15b30 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Backend\Form\Element;
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
+use TYPO3\CMS\Backend\Form\DataPreprocessor;
 use TYPO3\CMS\Core\Database\DatabaseConnection;
 use TYPO3\CMS\Core\Database\RelationHandler;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
@@ -24,6 +25,8 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Core\Versioning\VersionState;
 use TYPO3\CMS\Lang\LanguageService;
+use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 
 /**
  * The Inline-Relational-Record-Editing (IRRE) functions as part of the FormEngine.
@@ -47,14 +50,15 @@ class InlineElement {
         *
         * @var \TYPO3\CMS\Backend\Form\FormEngine
         */
-       public $fObj;
+       protected $formEngine;
 
        /**
-        * Reference to $fObj->backPath
+        * Reference to $formEngine->backPath
         *
         * @var string
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
         */
-       public $backPath;
+       public $backPath = '';
 
        /**
         * Indicates if a field is rendered upon an AJAX call
@@ -145,10 +149,9 @@ class InlineElement {
         * @return void
         */
        public function init(&$formEngine) {
-               $this->fObj = $formEngine;
-               $this->backPath = &$formEngine->backPath;
-               $this->prependFormFieldNames = &$this->fObj->prependFormFieldNames;
-               $this->prependCmdFieldNames = &$this->fObj->prependCmdFieldNames;
+               $this->formEngine = $formEngine;
+               $this->prependFormFieldNames = &$this->formEngine->prependFormFieldNames;
+               $this->prependCmdFieldNames = &$this->formEngine->prependCmdFieldNames;
                $this->inlineStyles['margin-right'] = '5';
                $this->initHookObjects();
        }
@@ -209,7 +212,7 @@ class InlineElement {
                        $maxitems = 100000;
                }
                // Register the required number of elements:
-               $this->fObj->requiredElements[$PA['itemFormElName']] = array($minitems, $maxitems, 'imgName' => $table . '_' . $row['uid'] . '_' . $field);
+               $this->formEngine->requiredElements[$PA['itemFormElName']] = array($minitems, $maxitems, 'imgName' => $table . '_' . $row['uid'] . '_' . $field);
                // Remember the page id (pid of record) where inline editing started first
                // We need that pid for ajax calls, so that they would know where the action takes place on the page structure
                if (!isset($this->inlineFirstPid)) {
@@ -262,7 +265,7 @@ class InlineElement {
                        ),
                );
                // Set a hint for nested IRRE and tab elements:
-               $this->inlineData['nested'][$nameObject] = $this->fObj->getDynNestedStack(FALSE, $this->isAjaxCall);
+               $this->inlineData['nested'][$nameObject] = $this->formEngine->getDynNestedStack(FALSE, $this->isAjaxCall);
                // If relations are required to be unique, get the uids that have already been used on the foreign side of the relation
                if ($config['foreign_unique']) {
                        // If uniqueness *and* selector are set, they should point to the same field - so, get the configuration of one:
@@ -385,7 +388,7 @@ class InlineElement {
                // Register default localization content:
                $parent = $this->getStructureLevel(-1);
                if (isset($parent['localizationMode']) && $parent['localizationMode'] != FALSE) {
-                       $this->fObj->registerDefaultLanguageData($foreign_table, $rec);
+                       $this->formEngine->registerDefaultLanguageData($foreign_table, $rec);
                }
                // Send a mapping information to the browser via JSON:
                // e.g. data[<curTable>][<curId>][<curField>] => data-<pid>-<parentTable>-<parentId>-<parentField>-<curTable>-<curId>-<curField>
@@ -406,7 +409,7 @@ class InlineElement {
                $appendFormFieldNames = '[' . $foreign_table . '][' . $rec['uid'] . ']';
                $objectId = $nameObject . self::Structure_Separator . $foreign_table . self::Structure_Separator . $rec['uid'];
                // Put the current level also to the dynNestedStack of FormEngine:
-               $this->fObj->pushToDynNestedStack('inline', $objectId);
+               $this->formEngine->pushToDynNestedStack('inline', $objectId);
                $class = '';
                if (!$isVirtualRecord) {
                        // Get configuration:
@@ -483,7 +486,7 @@ class InlineElement {
                                </div>';
                }
                // Remove the current level also from the dynNestedStack of FormEngine:
-               $this->fObj->popFromDynNestedStack();
+               $this->formEngine->popFromDynNestedStack();
                return $out;
        }
 
@@ -497,16 +500,16 @@ class InlineElement {
         */
        protected function renderMainFields($table, array $row, array $overruleTypesArray = array()) {
                // The current render depth of \TYPO3\CMS\Backend\Form\FormEngine
-               $depth = $this->fObj->renderDepth;
+               $depth = $this->formEngine->renderDepth;
                // If there is some information about already rendered palettes of our parent, store this info:
-               if (isset($this->fObj->palettesRendered[$depth][$table])) {
-                       $palettesRendered = $this->fObj->palettesRendered[$depth][$table];
+               if (isset($this->formEngine->palettesRendered[$depth][$table])) {
+                       $palettesRendered = $this->formEngine->palettesRendered[$depth][$table];
                }
                // Render the form:
-               $content = $this->fObj->getMainFields($table, $row, $depth, $overruleTypesArray);
+               $content = $this->formEngine->getMainFields($table, $row, $depth, $overruleTypesArray);
                // If there was some info about rendered palettes stored, write it back for our parent:
                if (isset($palettesRendered)) {
-                       $this->fObj->palettesRendered[$depth][$table] = $palettesRendered;
+                       $this->formEngine->palettesRendered[$depth][$table] = $palettesRendered;
                }
                return $content;
        }
@@ -887,7 +890,7 @@ class InlineElement {
                $PA['fieldConf'] = $GLOBALS['TCA'][$foreign_table]['columns'][$foreign_selector];
                $PA['fieldConf']['config']['form_type'] = $PA['fieldConf']['config']['form_type'] ?: $PA['fieldConf']['config']['type'];
                // Using "form_type" locally in this script
-               $PA['fieldTSConfig'] = $this->fObj->setTSconfig($foreign_table, array(), $foreign_selector);
+               $PA['fieldTSConfig'] = FormEngineUtility::getTSconfigForTableRow($foreign_table, array(), $foreign_selector);
                $config = $PA['fieldConf']['config'];
                // @todo $disabled is not present - should be read from config?
                $disabled = FALSE;
@@ -897,14 +900,14 @@ class InlineElement {
                        $styleAttrValue = '';
                        foreach ($selItems as $p) {
                                if ($config['iconsInOptionTags']) {
-                                       $styleAttrValue = $this->fObj->optionTagStyle($p[2]);
+                                       $styleAttrValue = FormEngineUtility::optionTagStyle($p[2]);
                                }
                                if (!in_array($p[1], $uniqueIds)) {
                                        $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . ' style="' . (in_array($p[1], $uniqueIds) ? '' : '') . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) : '') . '">' . htmlspecialchars($p[0]) . '</option>';
                                }
                        }
                        // Put together the selector box:
-                       $selector_itemListStyle = isset($config['itemListStyle']) ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"' : ' style="' . $this->fObj->defaultMultipleSelectorStyle . '"';
+                       $selector_itemListStyle = isset($config['itemListStyle']) ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"' : '';
                        $size = (int)$conf['size'];
                        $size = $conf['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($selItems) + 1, MathUtility::forceIntegerInRange($size, 1), $conf['autoSizeMax']) : $size;
                        $onChange = 'return inline.importNewRecord(\'' . $this->inlineNames['object'] . self::Structure_Separator . $conf['foreign_table'] . '\')';
@@ -985,7 +988,8 @@ class InlineElement {
                                ' . $createNewRelationText . '
                        </a>';
 
-               if ($showUpload && $this->fObj->edit_docModuleUpload) {
+               $isDirectFileUploadEnabled = (bool)$this->getBackendUserAuthentication()->uc['edit_docModuleUpload'];
+               if ($showUpload && $isDirectFileUploadEnabled) {
                        $folder = $GLOBALS['BE_USER']->getDefaultUploadFolder();
                        if (
                                $folder instanceof \TYPO3\CMS\Core\Resource\Folder
@@ -1101,7 +1105,7 @@ class InlineElement {
         * @return void
         */
        public function addJavaScriptSortable($objectId) {
-               $this->fObj->additionalJS_post[] = '
+               $this->formEngine->additionalJS_post[] = '
                        inline.createDragAndDropSorting("' . $objectId . '");
                ';
        }
@@ -1194,7 +1198,6 @@ class InlineElement {
                $GLOBALS['SOBE']->MOD_MENU = array(
                        'showPalettes' => '',
                        'showDescriptions' => '',
-                       'disableRTE' => ''
                );
                // Setting virtual document name
                $GLOBALS['SOBE']->MCONF['name'] = 'xMOD_alt_doc.php';
@@ -1209,14 +1212,6 @@ class InlineElement {
                $GLOBALS['SOBE']->tceforms->RTEcounter = (int)array_shift($ajaxArguments);
                $GLOBALS['SOBE']->tceforms->initDefaultBEMode();
                $GLOBALS['SOBE']->tceforms->palettesCollapsed = !$GLOBALS['SOBE']->MOD_SETTINGS['showPalettes'];
-               $GLOBALS['SOBE']->tceforms->disableRTE = $GLOBALS['SOBE']->MOD_SETTINGS['disableRTE'];
-               $GLOBALS['SOBE']->tceforms->enableClickMenu = TRUE;
-               $GLOBALS['SOBE']->tceforms->enableTabMenu = TRUE;
-               // Clipboard is initialized:
-               // Start clipboard
-               $GLOBALS['SOBE']->tceforms->clipObj = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Clipboard\Clipboard::class);
-               // Initialize - reads the clipboard content from the user session
-               $GLOBALS['SOBE']->tceforms->clipObj->initializeClipboard();
        }
 
        /**
@@ -1232,14 +1227,14 @@ class InlineElement {
                        $jsonArray['headData'] = $headTags;
                }
                // Add the JavaScript data that would have been added at the bottom of a regular FormEngine call:
-               $jsonArray['scriptCall'][] = $this->fObj->JSbottom($this->fObj->formName, TRUE);
+               $jsonArray['scriptCall'][] = $this->formEngine->JSbottom('editform', TRUE);
                // If script.aculo.us Sortable is used, update the Observer to know the record:
                if ($config['appearance']['useSortable']) {
                        $jsonArray['scriptCall'][] = 'inline.createDragAndDropSorting(\'' . $this->inlineNames['object'] . '_records\');';
                }
                // if FormEngine has some JavaScript code to be executed, just do it
-               if ($this->fObj->extJSCODE) {
-                       $jsonArray['scriptCall'][] = $this->fObj->extJSCODE;
+               if ($this->formEngine->extJSCODE) {
+                       $jsonArray['scriptCall'][] = $this->formEngine->extJSCODE;
                }
                // activate "enable tabs" for textareas
                $jsonArray['scriptCall'][] = 'changeTextareaElements();';
@@ -1282,7 +1277,7 @@ class InlineElement {
                $collapseAll = isset($config['appearance']['collapseAll']) && $config['appearance']['collapseAll'];
                $expandSingle = isset($config['appearance']['expandSingle']) && $config['appearance']['expandSingle'];
                // Put the current level also to the dynNestedStack of FormEngine:
-               $this->fObj->pushToDynNestedStack('inline', $this->inlineNames['object']);
+               $this->formEngine->pushToDynNestedStack('inline', $this->inlineNames['object']);
                // Dynamically create a new record using \TYPO3\CMS\Backend\Form\DataPreprocessor
                if (!$foreignUid || !MathUtility::canBeInterpretedAsInteger($foreignUid) || $config['foreign_selector']) {
                        $record = $this->getNewRecord($this->inlineFirstPid, $current['table']);
@@ -1371,7 +1366,7 @@ class InlineElement {
                // Fade out and fade in the new record in the browser view to catch the user's eye
                $jsonArray['scriptCall'][] = 'inline.fadeOutFadeIn(\'' . $objectId . '_div\');';
                // Remove the current level also from the dynNestedStack of FormEngine:
-               $this->fObj->popFromDynNestedStack();
+               $this->formEngine->popFromDynNestedStack();
                // Return the JSON array:
                return $jsonArray;
        }
@@ -1448,7 +1443,7 @@ class InlineElement {
                $collapseAll = isset($config['appearance']['collapseAll']) && $config['appearance']['collapseAll'];
                $expandSingle = isset($config['appearance']['expandSingle']) && $config['appearance']['expandSingle'];
                // Put the current level also to the dynNestedStack of FormEngine:
-               $this->fObj->pushToDynNestedStack('inline', $this->inlineNames['object']);
+               $this->formEngine->pushToDynNestedStack('inline', $this->inlineNames['object']);
                $record = $this->getRecord($this->inlineFirstPid, $current['table'], $current['uid']);
                // The HTML-object-id's prefix of the dynamically created record
                $objectPrefix = $this->inlineNames['object'] . self::Structure_Separator . $current['table'];
@@ -1472,7 +1467,7 @@ class InlineElement {
                        $jsonArray['scriptCall'][] = 'inline.collapseAllRecords(\'' . $objectId . '\',\'' . $objectPrefix . '\',\'' . $record['uid'] . '\');';
                }
                // Remove the current level also from the dynNestedStack of FormEngine:
-               $this->fObj->popFromDynNestedStack();
+               $this->formEngine->popFromDynNestedStack();
                // Return the JSON array:
                return $jsonArray;
        }
@@ -1755,7 +1750,12 @@ class InlineElement {
                $config = $PA['fieldConf']['config'];
                if ($foreignConfig['type'] == 'select') {
                        // Getting the selector box items from the system
-                       $selItems = $this->fObj->addSelectOptionsToItemArray($this->fObj->initItemArray($PA['fieldConf']), $PA['fieldConf'], $this->fObj->setTSconfig($table, $row), $field);
+                       $selItems = FormEngineUtility::addSelectOptionsToItemArray(
+                               FormEngineUtility::initItemArray($PA['fieldConf']),
+                               $PA['fieldConf'],
+                               FormEngineUtility::getTSconfigForTableRow($table, $row),
+                               $field
+                       );
 
                        // Possibly filter some items:
                        $selItems = ArrayUtility::keepItemsInArray(
@@ -1767,9 +1767,10 @@ class InlineElement {
                        );
 
                        // Possibly add some items:
-                       $selItems = $this->fObj->addItems($selItems, $PA['fieldTSConfig']['addItems.']);
+                       $selItems = FormEngineUtility::addItems($selItems, $PA['fieldTSConfig']['addItems.']);
                        if (isset($config['itemsProcFunc']) && $config['itemsProcFunc']) {
-                               $selItems = $this->fObj->procItems($selItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $field);
+                               $dataPreprocessor = GeneralUtility::makeInstance(DataPreprocessor::class);
+                               $selItems = $dataPreprocessor->procItems($selItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $field);
                        }
                        // Possibly remove some items:
                        $removeItems = GeneralUtility::trimExplode(',', $PA['fieldTSConfig']['removeItems'], TRUE);
@@ -1877,7 +1878,6 @@ class InlineElement {
                $trData = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\DataPreprocessor::class);
                $trData->addRawData = TRUE;
                $trData->lockRecords = 1;
-               $trData->disableRTE = $GLOBALS['SOBE']->MOD_SETTINGS['disableRTE'];
                // If a new record should be created
                $trData->fetchRecord($table, $uid, $cmd === 'new' ? 'new' : '');
                $rec = reset($trData->regTableItems_data);
@@ -2098,10 +2098,10 @@ class InlineElement {
                                        if ($loadConfig) {
                                                $unstable['config'] = $GLOBALS['TCA'][$unstable['table']]['columns'][$unstable['field']]['config'];
                                                // Fetch TSconfig:
-                                               $TSconfig = $this->fObj->setTSconfig($unstable['table'], array('uid' => $unstable['uid'], 'pid' => $this->inlineFirstPid), $unstable['field']);
+                                               $TSconfig = FormEngineUtility::getTSconfigForTableRow($unstable['table'], array('uid' => $unstable['uid'], 'pid' => $this->inlineFirstPid), $unstable['field']);
                                                // Override TCA field config by TSconfig:
                                                if (!$TSconfig['disabled']) {
-                                                       $unstable['config'] = $this->fObj->overrideFieldConf($unstable['config'], $TSconfig);
+                                                       $unstable['config'] = FormEngineUtility::overrideFieldConf($unstable['config'], $TSconfig);
                                                }
                                                $unstable['localizationMode'] = BackendUtility::getInlineLocalizationMode($unstable['table'], $unstable['config']);
                                        }
@@ -2288,8 +2288,8 @@ class InlineElement {
                if ($style) {
                        $style = ' style="' . $style . '"';
                }
-               if (!$tableAttrs['background'] && $this->fObj->borderStyle[2]) {
-                       $tableAttrs['background'] = $this->backPath . $this->borderStyle[2];
+               if (!$tableAttrs['background'] && $this->formEngine->borderStyle[2]) {
+                       $tableAttrs['background'] = $this->borderStyle[2];
                }
                if (!$tableAttrs['class'] && $this->borderStyle[3]) {
                        $tableAttrs['class'] = $this->borderStyle[3];
@@ -2479,7 +2479,7 @@ class InlineElement {
                        }
                        $PA['fieldConf']['config']['form_type'] = $PA['fieldConf']['config']['form_type'] ?: $PA['fieldConf']['config']['type'];
                        // Using "form_type" locally in this script
-                       $PA['fieldTSConfig'] = $this->fObj->setTSconfig($foreign_table, array(), $field);
+                       $PA['fieldTSConfig'] = FormEngineUtility::getTSconfigForTableRow($foreign_table, array(), $field);
                        $config = $PA['fieldConf']['config'];
                        // Determine type of Selector:
                        $type = $this->getPossibleRecordsSelectorType($config);
@@ -2639,7 +2639,7 @@ class InlineElement {
         */
        protected function getHeadTags() {
                $headTags = array();
-               $headDataRaw = $this->fObj->JStop() . $this->getJavaScriptAndStyleSheetsOfPageRenderer();
+               $headDataRaw = $this->formEngine->JStop() . $this->getJavaScriptAndStyleSheetsOfPageRenderer();
                if ($headDataRaw) {
                        // Create instance of the HTML parser:
                        $parseObj = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Html\HtmlParser::class);
@@ -2707,7 +2707,7 @@ class InlineElement {
                $flexFormParts = NULL;
 
                $matches = array();
-               $prefix = preg_quote($this->fObj->prependFormFieldNames, '#');
+               $prefix = preg_quote($this->formEngine->prependFormFieldNames, '#');
 
                if (preg_match('#^' . $prefix . '(?:\[[^]]+\]){3}(\[data\](?:\[[^]]+\]){4,})$#', $formElementName, $matches)) {
                        $flexFormParts = GeneralUtility::trimExplode(
@@ -2733,4 +2733,11 @@ class InlineElement {
                return $GLOBALS['TYPO3_DB'];
        }
 
+       /**
+        * @return BackendUserAuthentication
+        */
+       protected function getBackendUserAuthentication() {
+               return $GLOBALS['BE_USER'];
+       }
+
 }
index 83528da..04f2d54 100644 (file)
@@ -18,6 +18,7 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Backend\Form\FormEngine;
 
 /**
  * Generation of TCEform elements of the type "input"
@@ -39,7 +40,7 @@ class InputElement extends AbstractFormElement {
 
                $config = $additionalInformation['fieldConf']['config'];
                $specConf = BackendUtility::getSpecConfParts($additionalInformation['extra'], $additionalInformation['fieldConf']['defaultExtras']);
-               $size = MathUtility::forceIntegerInRange($config['size'] ?: $this->formEngine->defaultInputWidth, $this->formEngine->minimumInputWidth, $this->formEngine->maxInputWidth);
+               $size = MathUtility::forceIntegerInRange($config['size'] ?: $this->defaultInputWidth, $this->minimumInputWidth, $this->maxInputWidth);
                $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
                $classes = array();
                $attributes = array();
@@ -65,7 +66,7 @@ class InputElement extends AbstractFormElement {
                $dateFormats['datetimesec'] = $dateFormats['timesec'] . ' ' . $dateFormats['date'];
 
                // readonly
-               if ($this->isRenderReadonly() || $config['readOnly']) {
+               if ($this->isGlobalReadonly() || $config['readOnly']) {
                        $itemFormElValue = $additionalInformation['itemFormElValue'];
                        if (in_array('date', $evalList)) {
                                $config['format'] = 'date';
@@ -77,7 +78,15 @@ class InputElement extends AbstractFormElement {
                        if (in_array('password', $evalList)) {
                                $itemFormElValue = $itemFormElValue ? '*********' : '';
                        }
-                       return $this->formEngine->getSingleField_typeNone_render($config, $itemFormElValue);
+                       $formEngineDummy = new FormEngine;
+                       $noneElement = GeneralUtility::makeInstance(NoneElement::class, $formEngineDummy);
+                       $elementConfiguration = array(
+                               'fieldConf' => array(
+                                       'config' => $config,
+                               ),
+                               'itemFormElValue' => $itemFormElValue,
+                       );
+                       return $noneElement->render('', '', '', $elementConfiguration);
                }
 
 
@@ -210,7 +219,7 @@ TBE_EDITOR.customEvalFunctions[\'' . $evalData . '\'] = function(value) {
                        <input type="hidden" name="' . $additionalInformation['itemFormElName'] . '" value="' . htmlspecialchars($additionalInformation['itemFormElValue']) . '" />';
 
                // Wrap a wizard around the item?
-               $item = $this->formEngine->renderWizards(
+               $item = $this->renderWizards(
                        array($item, $altItem),
                        $config['wizards'],
                        $table,
@@ -221,7 +230,7 @@ TBE_EDITOR.customEvalFunctions[\'' . $evalData . '\'] = function(value) {
                );
 
                // Add a wrapper to remain maximum width
-               $width = (int)$this->formEngine->formMaxWidth($size);
+               $width = (int)$this->formMaxWidth($size);
                $item = '<div class="form-control-wrap"' . ($width ? ' style="max-width: ' . $width . 'px"' : '') . '>' . $item . '</div>';
                return $item;
        }
index 13b83ae..30869fa 100644 (file)
@@ -14,6 +14,10 @@ namespace TYPO3\CMS\Backend\Form\Element;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+
 /**
  * Generation of TCEform elements where no rendering could be found
  */
@@ -31,7 +35,139 @@ class NoneElement extends AbstractFormElement {
        public function render($table, $field, $row, &$additionalInformation) {
                $config = $additionalInformation['fieldConf']['config'];
                $itemValue = $additionalInformation['itemFormElValue'];
-               return $this->formEngine->getSingleField_typeNone_render($config, $itemValue);
+
+               if ($config['format']) {
+                       $itemValue = $this->formatValue($config, $itemValue);
+               }
+               if (!$config['pass_content']) {
+                       $itemValue = htmlspecialchars($itemValue);
+               }
+
+               $rows = (int)$config['rows'];
+               // Render as textarea
+               if ($rows > 1 || $config['type'] === 'text') {
+                       if (!$config['pass_content']) {
+                               $itemValue = nl2br($itemValue);
+                       }
+                       $cols = MathUtility::forceIntegerInRange($config['cols'] ?: $this->defaultInputWidth, 5, $this->maxInputWidth);
+                       $width = $this->formMaxWidth($cols);
+                       $item = '
+                               <div class="form-control-wrap"' . ($width ? ' style="max-width: ' . $width . 'px"' : '') . '>
+                                       <textarea class="form-control" rows="' . $rows . '" disabled>' . $itemValue . '</textarea>
+                               </div>';
+               } else {
+                       $cols = $config['cols'] ?: ($config['size'] ?: $this->defaultInputWidth);
+                       $size = MathUtility::forceIntegerInRange($cols ?: $this->defaultInputWidth, 5, $this->maxInputWidth);
+                       $width = $this->formMaxWidth($size);
+                       $item = '
+                               <div class="form-control-wrap"' . ($width ? ' style="max-width: ' . $width . 'px"' : '') . '>
+                                       <input class="form-control" value="'. $itemValue .'" type="text" disabled>
+                               </div>
+                               ' . ((string)$itemValue !== '' ? '<p class="help-block">' . $itemValue . '</p>' : '');
+               }
+               return $item;
+       }
+
+       /**
+        * Format field content if $config['format'] is set to date, filesize, ..., user
+        *
+        * @param array $config Configuration for the display
+        * @param string $itemValue The value to display
+        * @return string Formatted field value
+        */
+       protected function formatValue($config, $itemValue) {
+               $format = trim($config['format']);
+               switch ($format) {
+                       case 'date':
+                               if ($itemValue) {
+                                       $option = trim($config['format.']['option']);
+                                       if ($option) {
+                                               if ($config['format.']['strftime']) {
+                                                       $value = strftime($option, $itemValue);
+                                               } else {
+                                                       $value = date($option, $itemValue);
+                                               }
+                                       } else {
+                                               $value = date('d-m-Y', $itemValue);
+                                       }
+                               } else {
+                                       $value = '';
+                               }
+                               if ($config['format.']['appendAge']) {
+                                       $age = BackendUtility::calcAge(
+                                               $GLOBALS['EXEC_TIME'] - $itemValue,
+                                               $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')
+                                       );
+                                       $value .= ' (' . $age . ')';
+                               }
+                               $itemValue = $value;
+                               break;
+                       case 'datetime':
+                               // compatibility with "eval" (type "input")
+                               if ($itemValue !== '') {
+                                       $itemValue = date('H:i d-m-Y', (int)$itemValue);
+                               }
+                               break;
+                       case 'time':
+                               // compatibility with "eval" (type "input")
+                               if ($itemValue !== '') {
+                                       $itemValue = date('H:i', (int)$itemValue);
+                               }
+                               break;
+                       case 'timesec':
+                               // compatibility with "eval" (type "input")
+                               if ($itemValue !== '') {
+                                       $itemValue = date('H:i:s', (int)$itemValue);
+                               }
+                               break;
+                       case 'year':
+                               // compatibility with "eval" (type "input")
+                               if ($itemValue !== '') {
+                                       $itemValue = date('Y', (int)$itemValue);
+                               }
+                               break;
+                       case 'int':
+                               $baseArr = array('dec' => 'd', 'hex' => 'x', 'HEX' => 'X', 'oct' => 'o', 'bin' => 'b');
+                               $base = trim($config['format.']['base']);
+                               $format = $baseArr[$base] ?: 'd';
+                               $itemValue = sprintf('%' . $format, $itemValue);
+                               break;
+                       case 'float':
+                               $precision = MathUtility::forceIntegerInRange($config['format.']['precision'], 1, 10, 2);
+                               $itemValue = sprintf('%.' . $precision . 'f', $itemValue);
+                               break;
+                       case 'number':
+                               $format = trim($config['format.']['option']);
+                               $itemValue = sprintf('%' . $format, $itemValue);
+                               break;
+                       case 'md5':
+                               $itemValue = md5($itemValue);
+                               break;
+                       case 'filesize':
+                               // We need to cast to int here, otherwise empty values result in empty output,
+                               // but we expect zero.
+                               $value = GeneralUtility::formatSize((int)$itemValue);
+                               if ($config['format.']['appendByteSize']) {
+                                       $value .= ' (' . $itemValue . ')';
+                               }
+                               $itemValue = $value;
+                               break;
+                       case 'user':
+                               $func = trim($config['format.']['userFunc']);
+                               if ($func) {
+                                       $params = array(
+                                               'value' => $itemValue,
+                                               'args' => $config['format.']['userFunc'],
+                                               'config' => $config,
+                                               'pObj' => &$this
+                                       );
+                                       $itemValue = GeneralUtility::callUserFunction($func, $params, $this);
+                               }
+                               break;
+                       default:
+                               // Do nothing e.g. when $format === ''
+               }
+               return $itemValue;
        }
 
 }
index f351973..18e25a6 100644 (file)
@@ -14,6 +14,10 @@ namespace TYPO3\CMS\Backend\Form\Element;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Backend\Form\DataPreprocessor;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
+
 /**
  * Generation of TCEform elements of the type "radio"
  */
@@ -32,14 +36,15 @@ class RadioElement extends AbstractFormElement {
                $config = $additionalInformation['fieldConf']['config'];
                $item = '';
                $disabled = '';
-               if ($this->isRenderReadonly() || $config['readOnly']) {
+               if ($this->isGlobalReadonly() || $config['readOnly']) {
                        $disabled = ' disabled';
                }
 
                // Get items for the array
-               $selectedItems = $this->formEngine->initItemArray($additionalInformation['fieldConf']);
+               $selectedItems = FormEngineUtility::initItemArray($additionalInformation['fieldConf']);
                if ($config['itemsProcFunc']) {
-                       $selectedItems = $this->formEngine->procItems(
+                       $dataPreprocessor = GeneralUtility::makeInstance(DataPreprocessor::class);
+                       $selectedItems = $dataPreprocessor->procItems(
                                $selectedItems,
                                $additionalInformation['fieldTSConfig']['itemsProcFunc.'],
                                $config,
index 6875cb7..ae1ef9d 100644 (file)
@@ -19,6 +19,8 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Backend\Form\DataPreprocessor;
+use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
 
 /**
  * Generation of TCEform elements of the type "select"
@@ -69,7 +71,7 @@ class SelectElement extends AbstractFormElement {
                // Field configuration from TCA:
                $config = $additionalInformation['fieldConf']['config'];
                $disabled = '';
-               if ($this->isRenderReadonly() || $config['readOnly']) {
+               if ($this->isGlobalReadonly() || $config['readOnly']) {
                        $disabled = ' disabled="disabled"';
                }
                // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
@@ -105,7 +107,7 @@ class SelectElement extends AbstractFormElement {
                // Wizards:
                if (!$disabled) {
                        $altItem = '<input type="hidden" name="' . $additionalInformation['itemFormElName'] . '" value="' . htmlspecialchars($additionalInformation['itemFormElValue']) . '" />';
-                       $item = $this->formEngine->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $additionalInformation, $additionalInformation['itemFormElName'], $specConf);
+                       $item = $this->renderWizards(array($item, $altItem), $config['wizards'], $table, $row, $field, $additionalInformation, $additionalInformation['itemFormElName'], $specConf);
                }
                return $item;
        }
@@ -128,7 +130,7 @@ class SelectElement extends AbstractFormElement {
                $languageService = $this->getLanguageService();
                $item = '';
                $disabled = '';
-               if ($this->isRenderReadonly() || $config['readOnly']) {
+               if ($this->isGlobalReadonly() || $config['readOnly']) {
                        $disabled = ' disabled="disabled"';
                }
                // Setting this hidden field (as a flag that JavaScript can read out)
@@ -196,7 +198,7 @@ class SelectElement extends AbstractFormElement {
                        $styleAttrValue = '';
                        foreach ($selItems as $p) {
                                if ($config['iconsInOptionTags']) {
-                                       $styleAttrValue = $this->formEngine->optionTagStyle($p[2]);
+                                       $styleAttrValue = FormEngineUtility::optionTagStyle($p[2]);
                                }
                                $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"'
                                        . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '')
@@ -205,7 +207,7 @@ class SelectElement extends AbstractFormElement {
                        // Put together the selector box:
                        $selector_itemListStyle = isset($config['itemListStyle'])
                                ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"'
-                               : ' style="' . $this->formEngine->defaultMultipleSelectorStyle . '"';
+                               : '';
                        $size = (int)$config['size'];
                        $size = $config['autoSizeMax']
                                ? MathUtility::forceIntegerInRange(count($itemArray) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax'])
@@ -264,7 +266,7 @@ class SelectElement extends AbstractFormElement {
                        'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
                        'style' => isset($config['selectedListStyle'])
                                ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
-                               : ' style="' . $this->formEngine->defaultMultipleSelectorStyle . '"',
+                               : '',
                        'dontShowMoveIcons' => $maxitems <= 1,
                        'maxitems' => $maxitems,
                        'info' => '',
@@ -277,7 +279,7 @@ class SelectElement extends AbstractFormElement {
                        'rightbox' => $itemsToSelect,
                        'readOnly' => $disabled
                );
-               $item .= $this->formEngine->dbFileIcons($PA['itemFormElName'], '', '', $itemArray, '', $params, $PA['onFocus']);
+               $item .= $this->dbFileIcons($PA['itemFormElName'], '', '', $itemArray, '', $params, $PA['onFocus']);
                return $item;
        }
 
@@ -296,10 +298,10 @@ class SelectElement extends AbstractFormElement {
                $config = $PA['fieldConf']['config'];
 
                // Getting the selector box items from the system
-               $selectItems = $this->formEngine->addSelectOptionsToItemArray(
-                       $this->formEngine->initItemArray($PA['fieldConf']),
+               $selectItems = FormEngineUtility::addSelectOptionsToItemArray(
+                       FormEngineUtility::initItemArray($PA['fieldConf']),
                        $PA['fieldConf'],
-                       $this->formEngine->setTSconfig($table, $row),
+                       FormEngineUtility::getTSconfigForTableRow($table, $row),
                        $fieldName
                );
 
@@ -313,11 +315,12 @@ class SelectElement extends AbstractFormElement {
                );
 
                // Possibly add some items:
-               $selectItems = $this->formEngine->addItems($selectItems, $PA['fieldTSConfig']['addItems.']);
+               $selectItems = FormEngineUtility::addItems($selectItems, $PA['fieldTSConfig']['addItems.']);
 
                // Process items by a user function:
                if (isset($config['itemsProcFunc']) && $config['itemsProcFunc']) {
-                       $selectItems = $this->formEngine->procItems($selectItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $fieldName);
+                       $dataPreprocessor = GeneralUtility::makeInstance(DataPreprocessor::class);
+                       $selectItems = $dataPreprocessor->procItems($selectItems, $PA['fieldTSConfig']['itemsProcFunc.'], $config, $table, $row, $fieldName);
                }
 
                // Possibly remove some items:
@@ -409,7 +412,7 @@ class SelectElement extends AbstractFormElement {
                $out = '';
                $options = '';
                $disabled = FALSE;
-               if ($this->isRenderReadonly() || $config['readOnly']) {
+               if ($this->isGlobalReadonly() || $config['readOnly']) {
                        $disabled = TRUE;
                        $onlySelectedIconShown = 1;
                }
@@ -444,12 +447,12 @@ class SelectElement extends AbstractFormElement {
                                }
                                $selectItemGroups[$selectItemGroupCount]['header'] = array(
                                        'title' => $item[0],
-                                       'icon' => (!empty($item[2]) ? $this->formEngine->getIconHtml($item[2]) : '')
+                                       'icon' => (!empty($item[2]) ? FormEngineUtility::getIconHtml($item[2]) : ''),
                                );
                        } else {
                                // IS ITEM
                                $title = htmlspecialchars($item['0'], ENT_COMPAT, 'UTF-8', FALSE);
-                               $icon = (!empty($item[2]) ? $this->formEngine->getIconHtml($item[2], $title, $title) : '');
+                               $icon = !empty($item[2]) ? FormEngineUtility::getIconHtml($item[2], $title, $title) : '';
                                $selected = ((string)$PA['itemFormElValue'] === (string)$item[1] ? 1 : 0);
                                if ($selected) {
                                        $selectedIndex = $selectItemCounter;
@@ -466,10 +469,10 @@ class SelectElement extends AbstractFormElement {
                                );
                                // ICON
                                if ($icon && !$suppressIcons && (!$onlySelectedIconShown || $selected)) {
-                                       $onClick = $this->formEngine->elName($PA['itemFormElName']) . '.selectedIndex=' . $selectItemCounter . ';';
+                                       $onClick = 'document.editform[' . GeneralUtility::quoteJSvalue($PA['itemFormElName']) . '].selectedIndex=' . $selectItemCounter . ';';
                                        if ($config['iconsInOptionTags']) {
                                                $onClick .= 'document.getElementById(\'' . $selectId . '_icon\').innerHTML = '
-                                                       . $this->formEngine->elName($PA['itemFormElName'])
+                                                       . 'document.editform[' . GeneralUtility::quoteJSvalue($PA['itemFormElName']) . ']'
                                                        . '.options[' . $selectItemCounter . '].getAttribute(\'data-icon\'); ';
                                        }
                                        $onClick .= implode('', $PA['fieldChangeFunc']);
@@ -588,12 +591,12 @@ class SelectElement extends AbstractFormElement {
                        return '';
                }
                // Get values in an array (and make unique, which is fine because there can be no duplicates anyway):
-               $itemArray = array_flip($this->formEngine->extractValuesOnlyFromValueLabelList($PA['itemFormElValue']));
+               $itemArray = array_flip(FormEngineUtility::extractValuesOnlyFromValueLabelList($PA['itemFormElValue']));
                $output = '';
 
                // Disabled
                $disabled = 0;
-               if ($this->isRenderReadonly() || $config['readOnly']) {
+               if ($this->isGlobalReadonly() || $config['readOnly']) {
                        $disabled = 1;
                }
                // Traverse the Array of selector box items:
@@ -609,7 +612,7 @@ class SelectElement extends AbstractFormElement {
                                if ($p[1] === '--div--') {
                                        $selIcon = '';
                                        if (isset($p[2]) && $p[2] != 'empty-emtpy') {
-                                               $selIcon = $this->formEngine->getIconHtml($p[2]);
+                                               $selIcon = FormEngineUtility::getIconHtml($p[2]);
                                        }
                                        $currentGroup++;
                                        $groups[$currentGroup]['header'] = array(
@@ -654,7 +657,7 @@ class SelectElement extends AbstractFormElement {
                                                'checked' => $checked,
                                                'disabled' => $disabled,
                                                'class' => '',
-                                               'icon' => (!empty($p[2]) ? $this->formEngine->getIconHtml($p[2]) : IconUtility::getSpriteIcon('empty-empty')),
+                                               'icon' => (!empty($p[2]) ? FormEngineUtility::getIconHtml($p[2]) : IconUtility::getSpriteIcon('empty-empty')),
                                                'title' => htmlspecialchars($p[0], ENT_COMPAT, 'UTF-8', FALSE),
                                                'help' => $help
                                        );
@@ -727,9 +730,9 @@ class SelectElement extends AbstractFormElement {
                                                        <td>' . $item['help'] . '</td>
                                                </tr>
                                                ';
-                                       $checkGroup[] = $this->formEngine->elName($item['name']) . '.checked=1;';
-                                       $uncheckGroup[] = $this->formEngine->elName($item['name']) . '.checked=0;';
-                                       $resetGroup[] = $this->formEngine->elName($item['name']) . '.checked='.$item['checked'] . ';';
+                                       $checkGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked=1;';
+                                       $uncheckGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked=0;';
+                                       $resetGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked='.$item['checked'] . ';';
                                }
 
                                // Build toggle group checkbox
@@ -791,10 +794,10 @@ class SelectElement extends AbstractFormElement {
        public function getSingleField_typeSelect_singlebox($table, $field, $row, &$PA, $config, $selItems, $nMV_label) {
                $languageService = $this->getLanguageService();
                // Get values in an array (and make unique, which is fine because there can be no duplicates anyway):
-               $itemArray = array_flip($this->formEngine->extractValuesOnlyFromValueLabelList($PA['itemFormElValue']));
+               $itemArray = array_flip(FormEngineUtility::extractValuesOnlyFromValueLabelList($PA['itemFormElValue']));
                $item = '';
                $disabled = '';
-               if ($this->isRenderReadonly() || $config['readOnly']) {
+               if ($this->isGlobalReadonly() || $config['readOnly']) {
                        $disabled = ' disabled="disabled"';
                }
                // Traverse the Array of selector box items:
@@ -807,7 +810,7 @@ class SelectElement extends AbstractFormElement {
                        $sM = '';
                        if (isset($itemArray[$p[1]])) {
                                $sM = ' selected="selected"';
-                               $restoreCmd[] = $this->formEngine->elName(($PA['itemFormElName'] . '[]')) . '.options[' . $c . '].selected=1;';
+                               $restoreCmd[] = 'document.editform[' . GeneralUtility::quoteJSvalue($PA['itemFormElName'] . '[]') . '].options[' . $c . '].selected=1;';
                                unset($itemArray[$p[1]]);
                        }
                        // Non-selectable element:
@@ -818,7 +821,7 @@ class SelectElement extends AbstractFormElement {
                        // Icon style for option tag:
                        $styleAttrValue = '';
                        if ($config['iconsInOptionTags']) {
-                               $styleAttrValue = $this->formEngine->optionTagStyle($p[2]);
+                               $styleAttrValue = FormEngineUtility::optionTagStyle($p[2]);
                        }
                        // Compile <option> tag:
                        $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . $sM . $nonSel
@@ -838,7 +841,7 @@ class SelectElement extends AbstractFormElement {
                $sOnChange = implode('', $PA['fieldChangeFunc']);
                $selector_itemListStyle = isset($config['itemListStyle'])
                        ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"'
-                       : ' style="' . $this->formEngine->defaultMultipleSelectorStyle . '"';
+                       : '';
                $size = (int)$config['size'];
                $cssPrefix = $size === 1 ? 'tceforms-select' : 'tceforms-multiselect';
                $size = $config['autoSizeMax']
@@ -856,8 +859,8 @@ class SelectElement extends AbstractFormElement {
                        $item .= '<input type="hidden" name="' . htmlspecialchars($PA['itemFormElName']) . '" value="" />';
                }
                // Put it all into a table:
-               $onClick = htmlspecialchars($this->formEngine->elName(($PA['itemFormElName'] . '[]')) . '.selectedIndex=-1;' . implode('', $restoreCmd) . ' return false;');
-               $width = $this->formEngine->formMaxWidth($this->formEngine->defaultInputWidth);
+               $onClick = htmlspecialchars('document.editform[' . GeneralUtility::quoteJSvalue($PA['itemFormElName'] . '[]') . '].selectedIndex=-1;' . implode('', $restoreCmd) . ' return false;');
+               $width = $this->formMaxWidth($this->defaultInputWidth);
                $item .= '
                        <div class="form-control-wrap" ' . ($width ? ' style="max-width: ' . $width . 'px"' : '') . '>
                                <div class="form-wizards-wrap form-wizards-aside">
@@ -902,8 +905,8 @@ class SelectElement extends AbstractFormElement {
                $PA = array();
                $PA['fieldConf']['config'] = $fieldConfig;
                $PA['fieldConf']['config']['form_type'] = $PA['fieldConf']['config']['form_type'] ? $PA['fieldConf']['config']['form_type'] : $PA['fieldConf']['config']['type'];
-               $PA['fieldTSConfig'] = $this->formEngine->setTSconfig($this->currentTable, $this->currentRow, $fieldName);
-               $PA['fieldConf']['config'] = $this->formEngine->overrideFieldConf($PA['fieldConf']['config'], $PA['fieldTSConfig']);
+               $PA['fieldTSConfig'] = FormEngineUtility::getTSconfigForTableRow($this->currentTable, $this->currentRow, $fieldName);
+               $PA['fieldConf']['config'] = FormEngineUtility::overrideFieldConf($PA['fieldConf']['config'], $PA['fieldTSConfig']);
                $selectItemArray = $this->getSelectItems($this->currentTable, $fieldName, $this->currentRow, $PA);
 
                if ($isTraversable && count($selectItemArray)) {
diff --git a/typo3/sysext/backend/Classes/Form/Element/SuggestDefaultReceiver.php b/typo3/sysext/backend/Classes/Form/Element/SuggestDefaultReceiver.php
deleted file mode 100644 (file)
index cc50e57..0000000
+++ /dev/null
@@ -1,407 +0,0 @@
-<?php
-namespace TYPO3\CMS\Backend\Form\Element;
-
-/*
- * 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!
- */
-
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Backend\Utility\IconUtility;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Lang\LanguageService;
-
-/**
- * Default implementation of a handler class for an ajax record selector.
- *
- * Normally other implementations should be inherited from this one.
- * queryTable() should not be overwritten under normal circumstances.
- *
- * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
- * @author Benjamin Mack <benni@typo3.org>
- */
-class SuggestDefaultReceiver {
-
-       /**
-        * The name of the table to query
-        *
-        * @var string
-        */
-       protected $table = '';
-
-       /**
-        * The name of the foreign table to query (records from this table will be used for displaying instead of the ones
-        * from $table)
-        *
-        * @var string
-        */
-       protected $mmForeignTable = '';
-
-       /**
-        * The select-clause to use when selecting the records (is manipulated and used by different functions, so it has to
-        * be a global var)
-        *
-        * @var string
-        */
-       protected $selectClause = '';
-
-       /**
-        * The statement by which records will be ordered
-        *
-        * @var string
-        */
-       protected $orderByStatement = '';
-
-       /**
-        * Additional WHERE clause to be appended to the SQL
-        *
-        * @var string
-        */
-       protected $addWhere = '';
-
-       /**
-        * Configuration for this selector from TSconfig
-        *
-        * @var array
-        */
-       protected $config = array();
-
-       /**
-        * The list of pages that are allowed to perform the search for records on
-        *
-        * @var array Array of PIDs
-        */
-       protected $allowedPages = array();
-
-       /**
-        * The maximum number of items to select.
-        *
-        * @var int
-        */
-       protected $maxItems = 10;
-
-       /**
-        * @var array
-        */
-       protected $params = array();
-
-       /**
-        * The constructor of this class
-        *
-        * @param string $table The table to query
-        * @param array $config The configuration (TCA overlayed with TSconfig) to use for this selector
-        * @return void
-        */
-       public function __construct($table, $config) {
-               $this->table = $table;
-               $this->config = $config;
-               // get a list of all the pages that should be looked on
-               if (isset($config['pidList'])) {
-                       $allowedPages = ($pageIds = GeneralUtility::trimExplode(',', $config['pidList']));
-                       $depth = (int)$config['pidDepth'];
-                       foreach ($pageIds as $pageId) {
-                               if ($pageId > 0) {
-                                       \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($allowedPages, $this->getAllSubpagesOfPage($pageId, $depth));
-                               }
-                       }
-                       $this->allowedPages = array_unique($allowedPages);
-               }
-               if (isset($config['maxItemsInResultList'])) {
-                       $this->maxItems = $config['maxItemsInResultList'];
-               }
-               if ($this->table == 'pages') {
-                       $this->addWhere = ' AND ' . $GLOBALS['BE_USER']->getPagePermsClause(1);
-               }
-               // if table is versionized, only get the records from the Live Workspace
-               // the overlay itself of WS-records is done below
-               if ($GLOBALS['TCA'][$this->table]['ctrl']['versioningWS'] == TRUE) {
-                       $this->addWhere .= ' AND t3ver_wsid = 0';
-               }
-               if (isset($config['addWhere'])) {
-                       $this->addWhere .= ' ' . $config['addWhere'];
-               }
-       }
-
-       /**
-        * Queries a table for records and completely processes them
-        *
-        * Returns a two-dimensional array of almost finished records; the only need to be put into a <li>-structure
-        *
-        * If you subclass this class, you will most likely only want to overwrite the functions called from here, but not
-        * this function itself
-        *
-        * @param array $params
-        * @param int $ref The parent object
-        * @return array Array of rows or FALSE if nothing found
-        */
-       public function queryTable(&$params, $recursionCounter = 0) {
-               $rows = array();
-               $this->params = &$params;
-               $start = $recursionCounter * 50;
-               $this->prepareSelectStatement();
-               $this->prepareOrderByStatement();
-               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $this->table, $this->selectClause, '', $this->orderByStatement, $start . ', 50');
-               $allRowsCount = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
-               if ($allRowsCount) {
-                       while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                               // check if we already have collected the maximum number of records
-                               if (count($rows) > $this->maxItems) {
-                                       break;
-                               }
-                               $this->manipulateRecord($row);
-                               $this->makeWorkspaceOverlay($row);
-                               // check if the user has access to the record
-                               if (!$this->checkRecordAccess($row, $row['uid'])) {
-                                       continue;
-                               }
-                               $spriteIcon = IconUtility::getSpriteIconForRecord(
-                                       $this->table, $row, array('style' => 'margin: 0 4px 0 -20px; padding: 0;')
-                               );
-                               $uid = $row['t3ver_oid'] > 0 ? $row['t3ver_oid'] : $row['uid'];
-                               $path = $this->getRecordPath($row, $uid);
-                               if (strlen($path) > 30) {
-                                       $languageService = $this->getLanguageService();
-                                       $croppedPath = '<abbr title="' . htmlspecialchars($path) . '">' .
-                                               htmlspecialchars(
-                                                               $languageService->csConvObj->crop($languageService->charSet, $path, 10)
-                                                               . '...'
-                                                               . $languageService->csConvObj->crop($languageService->charSet, $path, -20)
-                                               ) .
-                                               '</abbr>';
-                               } else {
-                                       $croppedPath = htmlspecialchars($path);
-                               }
-                               $label = $this->getLabel($row);
-                               $entry = array(
-                                       'text' => '<span class="suggest-label">' . $label . '</span><span class="suggest-uid">[' . $uid . ']</span><br />
-                                                               <span class="suggest-path">' . $croppedPath . '</span>',
-                                       'table' => $this->mmForeignTable ? $this->mmForeignTable : $this->table,
-                                       'label' => $label,
-                                       'path' => $path,
-                                       'uid' => $uid,
-                                       'style' => '',
-                                       'class' => isset($this->config['cssClass']) ? $this->config['cssClass'] : '',
-                                       'sprite' => $spriteIcon
-                               );
-                               $rows[$this->table . '_' . $uid] = $this->renderRecord($row, $entry);
-                       }
-                       $GLOBALS['TYPO3_DB']->sql_free_result($res);
-                       // if there are less records than we need, call this function again to get more records
-                       if (count($rows) < $this->maxItems && $allRowsCount >= 50 && $recursionCounter < $this->maxItems) {
-                               $tmp = self::queryTable($params, ++$recursionCounter);
-                               $rows = array_merge($tmp, $rows);
-                       }
-               }
-               return $rows;
-       }
-
-       /**
-        * Prepare the statement for selecting the records which will be returned to the selector. May also return some
-        * other records (e.g. from a mm-table) which will be used later on to select the real records
-        *
-        * @return void
-        */
-       protected function prepareSelectStatement() {
-               $searchWholePhrase = $this->config['searchWholePhrase'];
-               $searchString = $this->params['value'];
-               $searchUid = (int)$searchString;
-               if ($searchString !== '') {
-                       $searchString = $GLOBALS['TYPO3_DB']->quoteStr($searchString, $this->table);
-                       $likeCondition = ' LIKE \'' . ($searchWholePhrase ? '%' : '') . $GLOBALS['TYPO3_DB']->escapeStrForLike($searchString, $this->table) . '%\'';
-                       // Search in all fields given by label or label_alt
-                       $selectFieldsList = $GLOBALS['TCA'][$this->table]['ctrl']['label'] . ',' . $GLOBALS['TCA'][$this->table]['ctrl']['label_alt'] . ',' . $this->config['additionalSearchFields'];
-                       $selectFields = GeneralUtility::trimExplode(',', $selectFieldsList, TRUE);
-                       $selectFields = array_unique($selectFields);
-                       $selectParts = array();
-                       foreach ($selectFields as $field) {
-                               $selectParts[] = $field . $likeCondition;
-                       }
-                       $this->selectClause = '(' . implode(' OR ', $selectParts) . ')';
-                       if ($searchUid > 0 && $searchUid == $searchString) {
-                               $this->selectClause = '(' . $this->selectClause . ' OR uid = ' . $searchUid . ')';
-                       }
-               }
-               if (isset($GLOBALS['TCA'][$this->table]['ctrl']['delete'])) {
-                       $this->selectClause .= ' AND ' . $GLOBALS['TCA'][$this->table]['ctrl']['delete'] . ' = 0';
-               }
-               if (count($this->allowedPages)) {
-                       $pidList = $GLOBALS['TYPO3_DB']->cleanIntArray($this->allowedPages);
-                       if (count($pidList)) {
-                               $this->selectClause .= ' AND pid IN (' . implode(', ', $pidList) . ') ';
-                       }
-               }
-               // add an additional search condition comment
-               if (isset($this->config['searchCondition']) && $this->config['searchCondition'] !== '') {
-                       $this->selectClause .= ' AND ' . $this->config['searchCondition'];
-               }
-               // add the global clauses to the where-statement
-               $this->selectClause .= $this->addWhere;
-       }
-
-       /**
-        * Selects all subpages of one page, optionally only up to a certain level
-        *
-        * @param int $uid The uid of the page
-        * @param int $depth The depth to select up to. Defaults to 99
-        * @return array of page IDs
-        */
-       protected function getAllSubpagesOfPage($uid, $depth = 99) {
-               $pageIds = array($uid);
-               $level = 0;
-               $pages = array($uid);
-               // fetch all
-               while ($depth - $level > 0 && !empty($pageIds)) {
-                       ++$level;
-                       $pidList = $GLOBALS['TYPO3_DB']->cleanIntArray($pageIds);
-                       $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid', 'pages', 'pid IN (' . implode(', ', $pidList) . ')', '', '', '', 'uid');
-                       if (count($rows) > 0) {
-                               $pageIds = array_keys($rows);
-                               $pages = array_merge($pages, $pageIds);
-                       } else {
-                               break;
-                       }
-               }
-               return $pages;
-       }
-
-       /**
-        * Prepares the clause by which the result elements are sorted. See description of ORDER BY in
-        * SQL standard for reference.
-        *
-        * @return void
-        */
-       protected function prepareOrderByStatement() {
-               if ($GLOBALS['TCA'][$this->table]['ctrl']['label']) {
-                       $this->orderByStatement = $GLOBALS['TCA'][$this->table]['ctrl']['label'];
-               }
-       }
-
-       /**
-        * Manipulate a record before using it to render the selector; may be used to replace a MM-relation etc.
-        *
-        * @param array $row
-        */
-       protected function manipulateRecord(&$row) {
-
-       }
-
-       /**
-        * Selects whether the logged in Backend User is allowed to read a specific record
-        *
-        * @param array $row
-        * @param int $uid
-        * @return bool
-        */
-       protected function checkRecordAccess($row, $uid) {
-               $retValue = TRUE;
-               $table = $this->mmForeignTable ?: $this->table;
-               if ($table == 'pages') {
-                       if (!BackendUtility::readPageAccess($uid, $GLOBALS['BE_USER']->getPagePermsClause(1))) {
-                               $retValue = FALSE;
-                       }
-               } elseif (isset($GLOBALS['TCA'][$table]['ctrl']['is_static']) && (bool)$GLOBALS['TCA'][$table]['ctrl']['is_static']) {
-                       $retValue = TRUE;
-               } else {
-                       if (!is_array(BackendUtility::readPageAccess($row['pid'], $GLOBALS['BE_USER']->getPagePermsClause(1)))) {
-                               $retValue = FALSE;
-                       }
-               }
-               return $retValue;
-       }
-
-       /**
-        * Overlay the given record with its workspace-version, if any
-        *
-        * @param array The record to get the workspace version for
-        * @return void (passed by reference)
-        */
-       protected function makeWorkspaceOverlay(&$row) {
-               // Check for workspace-versions
-               if ($GLOBALS['BE_USER']->workspace != 0 && $GLOBALS['TCA'][$this->table]['ctrl']['versioningWS'] == TRUE) {
-                       BackendUtility::workspaceOL($this->mmForeignTable ? $this->mmForeignTable : $this->table, $row);
-               }
-       }
-
-       /**
-        * Return the icon for a record - just a wrapper for two functions from \TYPO3\CMS\Backend\Utility\IconUtility
-        *
-        * @param array $row The record to get the icon for
-        * @return string The path to the icon
-        */
-       protected function getIcon($row) {
-               $icon = IconUtility::getIcon($this->mmForeignTable ? $this->mmForeignTable : $this->table, $row);
-               return IconUtility::skinImg('', $icon, '', 1);
-       }
-
-       /**
-        * Returns the path for a record. Is the whole path for all records except pages - for these the last part is cut
-        * off, because it contains the pagetitle itself, which would be double information
-        *
-        * The path is returned uncut, cutting has to be done by calling function.
-        *
-        * @param array $row The row
-        * @param array $record The record
-        * @return string The record-path
-        */
-       protected function getRecordPath(&$row, $uid) {
-               $titleLimit = max($this->config['maxPathTitleLength'], 0);
-               if (($this->mmForeignTable ? $this->mmForeignTable : $this->table) == 'pages') {
-                       $path = BackendUtility::getRecordPath($uid, '', $titleLimit);
-                       // For pages we only want the first (n-1) parts of the path,
-                       // because the n-th part is the page itself
-                       $path = substr($path, 0, strrpos($path, '/', -2)) . '/';
-               } else {
-                       $path = BackendUtility::getRecordPath($row['pid'], '', $titleLimit);
-               }
-               return $path;
-       }
-
-       /**
-        * Returns a label for a given record; usually only a wrapper for \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordTitle
-        *
-        * @param array $row The record to get the label for
-        * @return string The label
-        */
-       protected function getLabel($row) {
-               return BackendUtility::getRecordTitle($this->mmForeignTable ? $this->mmForeignTable : $this->table, $row, TRUE);
-       }
-
-       /**
-        * Calls a user function for rendering the page.
-        *
-        * This user function should manipulate $entry, especially $entry['text'].
-        *
-        * @param array $row The row
-        * @param array $entry The entry to render
-        * @return array The rendered entry (will be put into a <li> later on
-        */
-       protected function renderRecord($row, $entry) {
-               // Call renderlet if available (normal pages etc. usually don't have one)
-               if ($this->config['renderFunc'] != '') {
-                       $params = array(
-                               'table' => $this->table,
-                               'uid' => $row['uid'],
-                               'row' => $row,
-                               'entry' => &$entry
-                       );
-                       GeneralUtility::callUserFunction($this->config['renderFunc'], $params, $this, '');
-               }
-               return $entry;
-       }
-
-       /**
-        * @return LanguageService
-        */
-       protected function getLanguageService() {
-               return $GLOBALS['LANG'];
-       }
-
-}
diff --git a/typo3/sysext/backend/Classes/Form/Element/SuggestElement.php b/typo3/sysext/backend/Classes/Form/Element/SuggestElement.php
deleted file mode 100644 (file)
index 13cca38..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-<?php
-namespace TYPO3\CMS\Backend\Form\Element;
-
-/*
- * 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!
- */
-
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Core\Utility\MathUtility;
-use TYPO3\CMS\Lang\LanguageService;
-
-/**
- * TCEforms wizard for rendering an AJAX selector for records
- *
- * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
- * @author Benjamin Mack <benni@typo3.org>
- */
-class SuggestElement {
-
-       /**
-        * @var int Count the number of ajax selectors used
-        */
-       public $suggestCount = 0;
-
-       /**
-        * @var string
-        */
-       public $cssClass = 'typo3-TCEforms-suggest';
-
-       /**
-        * @var \TYPO3\CMS\Backend\Form\FormEngine
-        */
-       public $TCEformsObj;
-
-       /**
-        * Initialize an instance of SuggestElement
-        *
-        * @param \TYPO3\CMS\Backend\Form\FormEngine $tceForms Reference to an TCEforms instance
-        * @return void
-        */
-       public function init($tceForms) {
-               $this->TCEformsObj = $tceForms;
-       }
-
-       /**
-        * Renders an ajax-enabled text field. Also adds required JS
-        *
-        * @param string $fieldname The fieldname in the form
-        * @param string $table The table we render this selector for
-        * @param string $field The field we render this selector for
-        * @param array $row The row which is currently edited
-        * @param array $config The TSconfig of the field
-        * @return string The HTML code for the selector
-        */
-       public function renderSuggestSelector($fieldname, $table, $field, array $row, array $config) {
-               $languageService = $this->getLanguageService();
-               $this->suggestCount++;
-               $containerCssClass = $this->cssClass . ' ' . $this->cssClass . '-position-right';
-               $suggestId = 'suggest-' . $table . '-' . $field . '-' . $row['uid'];
-               $isFlexFormField = $GLOBALS['TCA'][$table]['columns'][$field]['config']['type'] === 'flex';
-               if ($isFlexFormField) {
-                       $fieldPattern = 'data[' . $table . '][' . $row['uid'] . '][';
-                       $flexformField = str_replace($fieldPattern, '', $fieldname);
-                       $flexformField = substr($flexformField, 0, -1);
-                       $field = str_replace(array(']['), '|', $flexformField);
-               }
-               $selector = '
-               <div class="' . $containerCssClass . '" id="' . $suggestId . '">
-                       <div class="input-group">
-                               <span class="input-group-addon"><i class="fa fa-search"></i></span>
-                               <input type="search" id="' . $fieldname . 'Suggest" value="' . $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.findRecord') . '" class="form-control ' . $this->cssClass . '-search" />
-                               <div class="' . $this->cssClass . '-indicator" style="display: none;" id="' . $fieldname . 'SuggestIndicator">
-                                       <img src="' . $GLOBALS['BACK_PATH'] . 'gfx/spinner.gif" alt="' . $languageService->sL('LLL:EXT:lang/locallang_core.xlf:alttext.suggestSearching') . '" />
-                               </div>
-                               <div class="' . $this->cssClass . '-choices" style="display: none;" id="' . $fieldname . 'SuggestChoices"></div>
-                       </div>
-
-               </div>';
-               // Get minimumCharacters from TCA
-               $minChars = 0;
-               if (isset($config['fieldConf']['config']['wizards']['suggest']['default']['minimumCharacters'])) {
-                       $minChars = (int)$config['fieldConf']['config']['wizards']['suggest']['default']['minimumCharacters'];
-               }
-               // Overwrite it with minimumCharacters from TSConfig (TCEFORM) if given
-               if (isset($config['fieldTSConfig']['suggest.']['default.']['minimumCharacters'])) {
-                       $minChars = (int)$config['fieldTSConfig']['suggest.']['default.']['minimumCharacters'];
-               }
-               $minChars = $minChars > 0 ? $minChars : 2;
-
-               // fetch the TCA field type to hand it over to the JS class
-               $type = '';
-               if (isset($config['fieldConf']['config']['type'])) {
-                       $type = $config['fieldConf']['config']['type'];
-               }
-
-               $jsRow = '';
-               if ($isFlexFormField && !MathUtility::canBeInterpretedAsInteger($row['uid'])) {
-                       // Ff we have a new record, we hand that row over to JS.
-                       // This way we can properly retrieve the configuration of our wizard
-                       // if it is shown in a flexform
-                       $jsRow = serialize($row);
-               }
-
-               // Replace "-" with ucwords for the JS object name
-               $jsObj = str_replace(' ', '', ucwords(str_replace(array('-', '.'), ' ', GeneralUtility::strtolower($suggestId))));
-               $this->TCEformsObj->additionalJS_post[] = '
-                       var ' . $jsObj . ' = new TCEForms.Suggest("' . $fieldname . '", "' . $table . '", "' . $field . '", "' . $row['uid'] . '", ' . $row['pid'] . ', ' . $minChars . ', "' . $type . '", ' . GeneralUtility::quoteJSvalue($jsRow) . ');' . LF
-                               . $jsObj . '.defaultValue = "' . GeneralUtility::slashJS($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.findRecord')) . '";' . LF;
-               return $selector;
-       }
-
-       /**
-        * Search a data structure array recursively -- including within nested
-        * (repeating) elements -- for a particular field config.
-        *
-        * @param array $dataStructure The data structure
-        * @param string $fieldName The field name
-        * @return array
-        */
-       protected function getNestedDsFieldConfig(array $dataStructure, $fieldName) {
-               $fieldConfig = array();
-               $elements = $dataStructure['ROOT']['el'] ? $dataStructure['ROOT']['el'] : $dataStructure['el'];
-               if (is_array($elements)) {
-                       foreach ($elements as $k => $ds) {
-                               if ($k === $fieldName) {
-                                       $fieldConfig = $ds['TCEforms']['config'];
-                                       break;
-                               } elseif (isset($ds['el'][$fieldName]['TCEforms']['config'])) {
-                                       $fieldConfig = $ds['el'][$fieldName]['TCEforms']['config'];
-                                       break;
-                               } else {
-                                       $fieldConfig = $this->getNestedDsFieldConfig($ds, $fieldName);
-                               }
-                       }
-               }
-               return $fieldConfig;
-       }
-
-       /**
-        * Ajax handler for the "suggest" feature in TCEforms.
-        *
-        * @param array $params The parameters from the AJAX call
-        * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj The AJAX object representing the AJAX call
-        * @return void
-        */
-       public function processAjaxRequest($params, &$ajaxObj) {
-               // Get parameters from $_GET/$_POST
-               $search = GeneralUtility::_GP('value');
-               $table = GeneralUtility::_GP('table');
-               $field = GeneralUtility::_GP('field');
-               $uid = GeneralUtility::_GP('uid');
-               $pageId = GeneralUtility::_GP('pid');
-               $newRecordRow = GeneralUtility::_GP('newRecordRow');
-               // If the $uid is numeric, we have an already existing element, so get the
-               // TSconfig of the page itself or the element container (for non-page elements)
-               // otherwise it's a new element, so use given id of parent page (i.e., don't modify it here)
-               $row = NULL;
-               if (is_numeric($uid)) {
-                       $row = BackendUtility::getRecord($table, $uid);
-                       if ($table == 'pages') {
-                               $pageId = $uid;
-                       } else {
-                               $pageId = $row['pid'];
-                       }
-               } else {
-                       $row = unserialize($newRecordRow);
-               }
-               $TSconfig = BackendUtility::getPagesTSconfig($pageId);
-               $queryTables = array();
-               $foreign_table_where = '';
-               $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
-               $parts = explode('|', $field);
-               if ($GLOBALS['TCA'][$table]['columns'][$parts[0]]['config']['type'] === 'flex') {
-                       $flexfieldTCAConfig = $GLOBALS['TCA'][$table]['columns'][$parts[0]]['config'];
-                       $flexformDSArray = BackendUtility::getFlexFormDS($flexfieldTCAConfig, $row, $table, $parts[0]);
-                       $flexformDSArray = GeneralUtility::resolveAllSheetsInDS($flexformDSArray);
-                       $flexformElement = $parts[count($parts) - 2];
-                       $continue = TRUE;
-                       foreach ($flexformDSArray as $sheet) {
-                               foreach ($sheet as $dataStructure) {
-                                       $fieldConfig = $this->getNestedDsFieldConfig($dataStructure, $flexformElement);
-                                       if (count($fieldConfig) > 0) {
-                                               $continue = FALSE;
-                                               break;
-                                       }
-                               }
-                               if (!$continue) {
-                                       break;
-                               }
-                       }
-                       $field = str_replace('|', '][', $field);
-               }
-               $wizardConfig = $fieldConfig['wizards']['suggest'];
-               if (isset($fieldConfig['allowed'])) {
-                       if ($fieldConfig['allowed'] === '*') {
-                               foreach ($GLOBALS['TCA'] as $tableName => $tableConfig) {
-                                       // @todo Refactor function to BackendUtility
-                                       if (empty($tableConfig['ctrl']['hideTable'])
-                                               && ($GLOBALS['BE_USER']->isAdmin()
-                                                       || (empty($tableConfig['ctrl']['adminOnly'])
-                                                               && (empty($tableConfig['ctrl']['rootLevel'])
-                                                                       || !empty($tableConfig['ctrl']['security']['ignoreRootLevelRestriction']))))
-                                       ) {
-                                               $queryTables[] = $tableName;
-                                       }
-                               }
-                               unset($tableName, $tableConfig);
-                       } else {
-                               $queryTables = GeneralUtility::trimExplode(',', $fieldConfig['allowed']);
-                       }
-               } elseif (isset($fieldConfig['foreign_table'])) {
-                       $queryTables = array($fieldConfig['foreign_table']);
-                       $foreign_table_where = $fieldConfig['foreign_table_where'];
-                       // strip ORDER BY clause
-                       $foreign_table_where = trim(preg_replace('/ORDER[[:space:]]+BY.*/i', '', $foreign_table_where));
-               }
-               $resultRows = array();
-               // fetch the records for each query table. A query table is a table from which records are allowed to
-               // be added to the TCEForm selector, originally fetched from the "allowed" config option in the TCA
-               foreach ($queryTables as $queryTable) {
-                       // if the table does not exist, skip it
-                       if (!is_array($GLOBALS['TCA'][$queryTable]) || !count($GLOBALS['TCA'][$queryTable])) {
-                               continue;
-                       }
-                       $config = (array)$wizardConfig['default'];
-                       if (is_array($wizardConfig[$queryTable])) {
-                               \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $wizardConfig[$queryTable]);
-                       }
-                       // merge the configurations of different "levels" to get the working configuration for this table and
-                       // field (i.e., go from the most general to the most special configuration)
-                       if (is_array($TSconfig['TCEFORM.']['suggest.']['default.'])) {
-                               \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $TSconfig['TCEFORM.']['suggest.']['default.']);
-                       }
-                       if (is_array($TSconfig['TCEFORM.']['suggest.'][$queryTable . '.'])) {
-                               \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $TSconfig['TCEFORM.']['suggest.'][$queryTable . '.']);
-                       }
-                       // use $table instead of $queryTable here because we overlay a config
-                       // for the input-field here, not for the queried table
-                       if (is_array($TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.']['default.'])) {
-                               \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.']['default.']);
-                       }
-                       if (is_array($TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'][$queryTable . '.'])) {
-                               \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'][$queryTable . '.']);
-                       }
-                       //process addWhere
-                       if (!isset($config['addWhere']) && $foreign_table_where) {
-                               $config['addWhere'] = $foreign_table_where;
-                       }
-                       if (isset($config['addWhere'])) {
-                               $replacement = array(
-                                       '###THIS_UID###' => (int)$uid,
-                                       '###CURRENT_PID###' => (int)$pageId
-                               );
-                               if (isset($TSconfig['TCEFORM.'][$table . '.'][$field . '.'])) {
-                                       $fieldTSconfig = $TSconfig['TCEFORM.'][$table . '.'][$field . '.'];
-                                       if (isset($fieldTSconfig['PAGE_TSCONFIG_ID'])) {
-                                               $replacement['###PAGE_TSCONFIG_ID###'] = (int)$fieldTSconfig['PAGE_TSCONFIG_ID'];
-                                       }
-                                       if (isset($fieldTSconfig['PAGE_TSCONFIG_IDLIST'])) {
-                                               $replacement['###PAGE_TSCONFIG_IDLIST###'] = $GLOBALS['TYPO3_DB']->cleanIntList($fieldTSconfig['PAGE_TSCONFIG_IDLIST']);
-                                       }
-                                       if (isset($fieldTSconfig['PAGE_TSCONFIG_STR'])) {
-                                               $replacement['###PAGE_TSCONFIG_STR###'] = $GLOBALS['TYPO3_DB']->quoteStr($fieldTSconfig['PAGE_TSCONFIG_STR'], $fieldConfig['foreign_table']);
-                                       }
-                               }
-                               $config['addWhere'] = strtr(' ' . $config['addWhere'], $replacement);
-                       }
-                       // instantiate the class that should fetch the records for this $queryTable
-                       $receiverClassName = $config['receiverClass'];
-                       if (!class_exists($receiverClassName)) {
-                               $receiverClassName = \TYPO3\CMS\Backend\Form\Element\SuggestDefaultReceiver::class;
-                       }
-                       $receiverObj = GeneralUtility::makeInstance($receiverClassName, $queryTable, $config);
-                       $params = array('value' => $search);
-                       $rows = $receiverObj->queryTable($params);
-                       if (empty($rows)) {
-                               continue;
-                       }
-                       $resultRows = $rows + $resultRows;
-                       unset($rows);
-               }
-               $listItems = array();
-               if (count($resultRows) > 0) {
-                       // traverse all found records and sort them
-                       $rowsSort = array();
-                       foreach ($resultRows as $key => $row) {
-                               $rowsSort[$key] = $row['text'];
-                       }
-                       asort($rowsSort);
-                       $rowsSort = array_keys($rowsSort);
-                       // Limit the number of items in the result list
-                       $maxItems = $config['maxItemsInResultList'] ?: 10;
-                       $maxItems = min(count($resultRows), $maxItems);
-                       // put together the selector entry
-                       for ($i = 0; $i < $maxItems; $i++) {
-                               $row = $resultRows[$rowsSort[$i]];
-                               $rowId = $row['table'] . '-' . $row['uid'] . '-' . $table . '-' . $uid . '-' . $field;
-                               $listItems[] = '<li' . ($row['class'] != '' ? ' class="' . $row['class'] . '"' : '') . ' id="' . $rowId . '"' . ($row['style'] != '' ? ' style="' . $row['style'] . '"' : '') . '>' . $row['sprite'] . $row['text'] . '</li>';
-                       }
-               }
-               if (count($listItems) > 0) {
-                       $list = implode('', $listItems);
-               } else {
-                       $list = '<li class="suggest-noresults"><i>' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.noRecordFound') . '</i></li>';
-               }
-               $list = '<ul class="' . $this->cssClass . '-resultlist">' . $list . '</ul>';
-               $ajaxObj->addContent(0, $list);
-       }
-
-       /**
-        * @return LanguageService
-        */
-       protected function getLanguageService() {
-               return $GLOBALS['LANG'];
-       }
-
-}
index 778761c..12b1d4c 100644 (file)
@@ -24,6 +24,14 @@ use TYPO3\CMS\Core\Utility\MathUtility;
 class TextElement extends AbstractFormElement {
 
        /**
+        * The number of chars expected per row when the height of a text area field is
+        * automatically calculated based on the number of characters found in the field content.
+        *
+        * @var int
+        */
+       protected $charactersPerRow = 40;
+
+       /**
         * This will render a <textarea> OR RTE area form field,
         * possibly with various control/validation features
         *
@@ -34,20 +42,22 @@ class TextElement extends AbstractFormElement {
         * @return string The HTML code for the TCEform field
         */
        public function render($table, $field, $row, &$additionalInformation) {
+               $backendUser = $this->getBackendUserAuthentication();
+
                $config = $additionalInformation['fieldConf']['config'];
 
                // Setting columns number
-               $cols = MathUtility::forceIntegerInRange($config['cols'] ?: $this->formEngine->defaultInputWidth, $this->formEngine->minimumInputWidth, $this->formEngine->maxInputWidth);
+               $cols = MathUtility::forceIntegerInRange($config['cols'] ?: $this->defaultInputWidth, $this->minimumInputWidth, $this->maxInputWidth);
 
                // Setting number of rows
                $rows = MathUtility::forceIntegerInRange($config['rows'] ?: 5, 1, 20);
                $originalRows = $rows;
 
                $itemFormElementValueLength = strlen($additionalInformation['itemFormElValue']);
-               if ($itemFormElementValueLength > $this->formEngine->charsPerRow * 2) {
-                       $cols = $this->formEngine->maxInputWidth;
+               if ($itemFormElementValueLength > $this->charactersPerRow * 2) {
+                       $cols = $this->maxInputWidth;
                        $rows = MathUtility::forceIntegerInRange(
-                               round($itemFormElementValueLength / $this->formEngine->charsPerRow),
+                               round($itemFormElementValueLength / $this->charactersPerRow),
                                count(explode(LF, $additionalInformation['itemFormElValue'])),
                                20
                        );
@@ -58,10 +68,17 @@ class TextElement extends AbstractFormElement {
 
                // must be called after the cols and rows calculation, so the parameters are applied
                // to read-only fields as well.
-               if ($this->isRenderReadonly() || $config['readOnly']) {
+               if ($this->isGlobalReadonly() || $config['readOnly']) {
                        $config['cols'] = $cols;
                        $config['rows'] = $rows;
-                       return $this->formEngine->getSingleField_typeNone_render($config, $additionalInformation['itemFormElValue']);
+                       $noneElement = GeneralUtility::makeInstance(NoneElement::class, $this->formEngine);
+                       $elementConfiguration = array(
+                               'fieldConf' => array(
+                                       'config' => $config,
+                               ),
+                               'itemFormElValue' => $additionalInformation['itemFormElValue'],
+                       );
+                       return $noneElement->render('', '', '', $elementConfiguration);
                }
 
                $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
@@ -79,7 +96,7 @@ class TextElement extends AbstractFormElement {
                $altItem = '<input type="hidden" name="' . htmlspecialchars($additionalInformation['itemFormElName']) . '" value="' . htmlspecialchars($additionalInformation['itemFormElValue']) . '" />';
                $item = '';
                // If RTE is generally enabled (TYPO3_CONF_VARS and user settings)
-               if ($this->formEngine->RTEenabled) {
+               if ($backendUser->isRTE()) {
                        $parameters = BackendUtility::getSpecConfParametersFromArray($specialConfiguration['rte_transform']['parameters']);
                        // If the field is configured for RTE and if any flag-field is not set to disable it.
                        if (isset($specialConfiguration['richtext']) && (!$parameters['flag'] || !$row[$parameters['flag']])) {
@@ -87,56 +104,40 @@ class TextElement extends AbstractFormElement {
                                list($recordPid, $tsConfigPid) = BackendUtility::getTSCpidCached($table, $row['uid'], $row['pid']);
                                // If the pid-value is not negative (that is, a pid could NOT be fetched)
                                if ($tsConfigPid >= 0) {
-                                       $rteSetup = $this->getBackendUserAuthentication()->getTSConfig('RTE', BackendUtility::getPagesTSconfig($recordPid));
+                                       $rteSetup = $backendUser->getTSConfig('RTE', BackendUtility::getPagesTSconfig($recordPid));
                                        $rteTcaTypeValue = BackendUtility::getTCAtypeValue($table, $row);
                                        $rteSetupConfiguration = BackendUtility::RTEsetup($rteSetup['properties'], $table, $field, $rteTcaTypeValue);
                                        if (!$rteSetupConfiguration['disabled']) {
-                                               if (!$this->formEngine->disableRTE) {
-                                                       $this->formEngine->RTEcounter++;
-                                                       // Get RTE object, draw form and set flag:
-                                                       $rteObject = BackendUtility::RTEgetObj();
-                                                       $item = $rteObject->drawRTE(
-                                                               $this->formEngine,
-                                                               $table,
-                                                               $field,
-                                                               $row,
-                                                               $additionalInformation,
-                                                               $specialConfiguration,
-                                                               $rteSetupConfiguration,
-                                                               $rteTcaTypeValue,
-                                                               '',
-                                                               $tsConfigPid
-                                                       );
-
-                                                       // Wizard
-                                                       $item = $this->formEngine->renderWizards(
-                                                               array($item, $altItem),
-                                                               $config['wizards'],
-                                                               $table,
-                                                               $row,
-                                                               $field,
-                                                               $additionalInformation,
-                                                               $additionalInformation['itemFormElName'],
-                                                               $specialConfiguration,
-                                                               TRUE
-                                                       );
-                                                       $rteWasLoaded = TRUE;
-                                               } else {
-                                                       $rteWouldHaveBeenLoaded = TRUE;
-                                                       $this->formEngine->commentMessages[] = $additionalInformation['itemFormElName'] . ': RTE is disabled by the on-page RTE-flag (probably you can enable it by the check-box in the bottom of this page!)';
-                                               }
-                                       } else {
-                                               $this->formEngine->commentMessages[] = $additionalInformation['itemFormElName'] . ': RTE is disabled by the Page TSconfig, "RTE"-key (eg. by RTE.default.disabled=0 or such)';
+                                               $this->formEngine->RTEcounter++;
+                                               // Get RTE object, draw form and set flag:
+                                               $rteObject = BackendUtility::RTEgetObj();
+                                               $item = $rteObject->drawRTE(
+                                                       $this->formEngine,
+                                                       $table,
+                                                       $field,
+                                                       $row,
+                                                       $additionalInformation,
+                                                       $specialConfiguration,
+                                                       $rteSetupConfiguration,
+                                                       $rteTcaTypeValue,
+                                                       '',
+                                                       $tsConfigPid
+                                               );
+
+                                               // Wizard
+                                               $item = $this->renderWizards(
+                                                       array($item, $altItem),
+                                                       $config['wizards'],
+                                                       $table,
+                                                       $row,
+                                                       $field,
+                                                       $additionalInformation,
+                                                       $additionalInformation['itemFormElName'],
+                                                       $specialConfiguration,
+                                                       TRUE
+                                               );
+                                               $rteWasLoaded = TRUE;
                                        }
-                               } else {
-                                       $this->formEngine->commentMessages[] = $additionalInformation['itemFormElName'] . ': PID value could NOT be fetched. Rare error, normally with new records.';
-                               }
-                       } else {
-                               if (!isset($specialConfiguration['richtext'])) {
-                                       $this->formEngine->commentMessages[] = $additionalInformation['itemFormElName'] . ': RTE was not configured for this field in TCA-types';
-                               }
-                               if (!(!$parameters['flag'] || !$row[$parameters['flag']])) {
-                                       $this->formEngine->commentMessages[] = $additionalInformation['itemFormElName'] . ': Field-flag (' . $additionalInformation['flag'] . ') has been set to disable RTE!';
                                }
                        }
                }
@@ -178,7 +179,7 @@ class TextElement extends AbstractFormElement {
                                // calculate inline styles
                                $styles = array();
                                // add the max-height from the users' preference to it
-                               $maximumHeight = (int)$this->getBackendUserAuthentication()->uc['resizeTextareas_MaxHeight'];
+                               $maximumHeight = (int)$backendUser->uc['resizeTextareas_MaxHeight'];
                                if ($maximumHeight > 0) {
                                        $styles[] = 'max-height: ' . $maximumHeight . 'px';
                                }
@@ -212,7 +213,7 @@ class TextElement extends AbstractFormElement {
                                                        . '>' . GeneralUtility::formatForTextarea($additionalInformation['itemFormElValue']) . '</textarea>';
 
                                // Wrap a wizard around the item?
-                               $item = $this->formEngine->renderWizards(
+                               $item = $this->renderWizards(
                                        array($item, $altItem),
                                        $config['wizards'],
                                        $table,
@@ -224,7 +225,7 @@ class TextElement extends AbstractFormElement {
                                        $rteWouldHaveBeenLoaded
                                );
 
-                               $maximumWidth = (int)$this->formEngine->formMaxWidth($cols);
+                               $maximumWidth = (int)$this->formMaxWidth($cols);
                                $item = '<div class="form-control-wrap"' . ($maximumWidth ? ' style="max-width: ' . $maximumWidth . 'px"' : '') . '>' . $item . '</div>';
                        }
                }
index e186133..d6f662f 100644 (file)
@@ -175,7 +175,7 @@ class TreeElement extends AbstractFormElement {
                                tcaExclusiveKeys: "' . ($PA['fieldConf']['config']['exclusiveKeys'] ? $PA['fieldConf']['config']['exclusiveKeys'] : '') . '",
                                ucId: "' . md5(($table . '|' . $field)) . '",
                                selModel: TYPO3.Components.Tree.EmptySelectionModel,
-                               disabled: ' . ($PA['fieldConf']['config']['readOnly'] || $this->isRenderReadonly() ? 'true' : 'false') . '
+                               disabled: ' . ($PA['fieldConf']['config']['readOnly'] || $this->isGlobalReadonly() ? 'true' : 'false') . '
                        });' . LF .
                                ($autoSizeMax
                                        ? 'tree' . $id . '.bodyStyle = "max-height: ' . $autoSizeMax . 'px;min-height: ' . $height . 'px;";'
index c0e0360..536ab80 100644 (file)
@@ -30,7 +30,6 @@ class UnknownElement extends AbstractFormElement {
         */
        public function render($table, $field, $row, &$additionalInformation) {
                return 'Unknown type: ' . $additionalInformation['fieldConf']['config']['form_type'] . '<br />';
-
        }
 
 }
diff --git a/typo3/sysext/backend/Classes/Form/Element/ValueSlider.php b/typo3/sysext/backend/Classes/Form/Element/ValueSlider.php
deleted file mode 100644 (file)
index b17ec01..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-<?php
-namespace TYPO3\CMS\Backend\Form\Element;
-
-/*
- * 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!
- */
-
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-/**
- * TCEforms wizard for rendering an AJAX selector for records
- *
- * @author Steffen Kamper <steffen@typo3.org>
- */
-class ValueSlider {
-
-       /**
-        * Renders the slider value wizard
-        *
-        * @param array $params
-        * @param \TYPO3\CMS\Backend\Form\FormEngine $pObj
-        * @return string
-        */
-       public function renderWizard(&$params, &$pObj) {
-               $pObj->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/ValueSlider.js');
-               $field = $params['field'];
-               $value = $params['row'][$field];
-               // If Slider is used in a flexform
-               if (!empty($params['flexFormPath'])) {
-                       $flexFormTools = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools::class);
-                       $flexFormValue = $flexFormTools->getArrayValueByPath($params['flexFormPath'], GeneralUtility::xml2array($value));
-                       if ($flexFormValue !== NULL) {
-                               $value = $flexFormValue;
-                       }
-               }
-               $itemName = $params['itemName'];
-               // Set default values (which correspond to those of the JS component)
-               $min = 0;
-               $max = 10000;
-               // Use the range property, if defined, to set min and max values
-               if (isset($params['fieldConfig']['range'])) {
-                       $min = isset($params['fieldConfig']['range']['lower']) ? (int)$params['fieldConfig']['range']['lower'] : 0;
-                       $max = isset($params['fieldConfig']['range']['upper']) ? (int)$params['fieldConfig']['range']['upper'] : 10000;
-               }
-               $elementType = $params['fieldConfig']['type'];
-               $step = $params['wConf']['step'] ?: 1;
-               $width = (int)$params['wConf']['width'] ?: 400;
-               $type = 'null';
-               if (isset($params['fieldConfig']['eval'])) {
-                       $eval = GeneralUtility::trimExplode(',', $params['fieldConfig']['eval'], TRUE);
-                       if (in_array('time', $eval)) {
-                               $type = 'time';
-                               $value = (int)$value;
-                       } elseif (in_array('int', $eval)) {
-                               $type = 'int';
-                               $value = (int)$value;
-                       } elseif (in_array('double2', $eval)) {
-                               $type = 'double';
-                               $value = (double) $value;
-                       }
-               }
-               if (isset($params['fieldConfig']['items'])) {
-                       $type = 'array';
-                       $value = (int)$value;
-               }
-               $callback = $params['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
-               $getField = $params['fieldChangeFunc']['typo3form.fieldGet'];
-               $id = 'slider-' . $params['md5ID'];
-               $contents = '<div id="' . $id . '"></div>';
-               $js = '
-               new TYPO3.Components.TcaValueSlider({
-                       minValue: ' . $min . ',
-                       maxValue: ' . $max . ',
-                       value: ' . $value . ',
-                       increment: ' . $step . ',
-                       renderTo: "' . $id . '",
-                       itemName: "' . $itemName . '",
-                       changeCallback: "' . $callback . '",
-                       getField: "' . $getField . '",
-                       width: "' . $width . '",
-                       type: "' . $type . '",
-                       elementType: "' . $elementType . '"
-               });
-               ';
-               /** @var $pageRenderer \TYPO3\CMS\Core\Page\PageRenderer */
-               $pageRenderer = $GLOBALS['SOBE']->doc->getPageRenderer();
-               $pageRenderer->addExtOnReadyCode($js);
-               return $contents;
-       }
-
-}
index 6dc240a..7566396 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Backend\Form;
 
 use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
 
 /**
  * Contains FlexForm manipulation methods as part of the TCEforms
@@ -79,7 +80,7 @@ class FlexFormsHelper extends \TYPO3\CMS\Backend\Form\FormEngine {
                        return $dataStructure;
                }
                // Get field configuration from page TSConfig
-               $TSconfig = $this->setTSconfig($table, $tableRow);
+               $TSconfig = FormEngineUtility::getTSconfigForTableRow($table, $tableRow);
                if (!empty($TSconfig[$tableField][($flexformIdentifier . '.')])) {
                        $sheetConf = GeneralUtility::removeDotsFromTS($TSconfig[$tableField][$flexformIdentifier . '.']);
                }
@@ -187,7 +188,7 @@ class FlexFormsHelper extends \TYPO3\CMS\Backend\Form\FormEngine {
                                continue;
                        }
                        // Getting the selector box items from system
-                       $selItems = $this->addSelectOptionsToItemArray($this->initItemArray($field['TCEforms']), $field['TCEforms'], $this->setTSconfig($table, $tableRow), $tableField);
+                       $selItems = FormEngineUtility::addSelectOptionsToItemArray(FormEngineUtility::initItemArray($field['TCEforms']), $field['TCEforms'], FormEngineUtility::getTSconfigForTableRow($table, $tableRow), $tableField);
 
                        // Possibly filter some items
                        $selItems = ArrayUtility::keepItemsInArray(
@@ -199,10 +200,11 @@ class FlexFormsHelper extends \TYPO3\CMS\Backend\Form\FormEngine {
                        );
 
                        // Possibly add some items
-                       $selItems = $this->addItems($selItems, $addItems);
+                       $selItems = FormEngineUtility::addItems($selItems, $addItems);
                        // Process items by a user function
                        if (!empty($field['TCEforms']['config']['itemsProcFunc'])) {
-                               $selItems = $this->procItems($selItems, $fieldConf['config'], $field['TCEforms']['config'], $table, $tableRow, $tableField);
+                               $dataPreprocessor = GeneralUtility::makeInstance(DataPreprocessor::class);
+                               $selItems = $dataPreprocessor->procItems($selItems, $fieldConf['config'], $field['TCEforms']['config'], $table, $tableRow, $tableField);
                        }
                        // Remove special configuration options after creating items to prevent double parsing
                        foreach ($this->removeSelectConfig as $option) {
index 7250506..a165550 100644 (file)
@@ -14,24 +14,28 @@ namespace TYPO3\CMS\Backend\Form;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider;
 use TYPO3\CMS\Backend\Form\Element\AbstractFormElement;
 use TYPO3\CMS\Backend\Form\Element\InlineElement;
+use TYPO3\CMS\Backend\Form\Element\NoneElement;
+use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\DatabaseConnection;
+use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
 use TYPO3\CMS\Core\Html\HtmlParser;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
 use TYPO3\CMS\Core\Messaging\FlashMessageService;
-use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Core\Utility\DiffUtility;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
-use TYPO3\CMS\Core\Utility\PathUtility;
 use TYPO3\CMS\Lang\LanguageService;
 
+
 /**
  * 'TCEforms' - Class for creating the backend editing forms.
  *
@@ -41,57 +45,16 @@ use TYPO3\CMS\Lang\LanguageService;
 class FormEngine {
 
        /**
-        * @var array
-        */
-       public $palFieldArr = array();
-
-       /**
         * @var bool
         */
        public $disableWizards = FALSE;
 
        /**
-        * @var bool
-        */
-       public $isPalettedoc = FALSE;
-
-       /**
-        * @var int
-        */
-       public $paletteMargin = 1;
-
-       /**
-        * @var string
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
-        */
-       public $defStyle = '';
-
-       /**
-        * @var array
-        */
-       public $cachedTSconfig = array();
-
-       /**
-        * @var array
-        */
-       public $cachedTSconfig_fieldLevel = array();
-
-       /**
-        * @var array
-        */
-       public $cachedLanguageFlag = array();
-
-       /**
         * @var array|NULL
         */
        public $cachedAdditionalPreviewLanguages = NULL;
 
        /**
-        * @var array
-        */
-       public $transformedRow = array();
-
-       /**
         * @var string
         */
        public $extJSCODE = '';
@@ -99,11 +62,6 @@ class FormEngine {
        /**
         * @var array
         */
-       public $printNeededJS = array();
-
-       /**
-        * @var array
-        */
        public $hiddenFieldAccum = array();
 
        /**
@@ -136,14 +94,6 @@ class FormEngine {
        public $additionalPreviewLanguageData = array();
 
        /**
-        * Set this to the 'backPath' pointing back to the typo3 admin directory
-        * from the script where this form is displayed.
-        *
-        * @var string
-        */
-       public $backPath = '';
-
-       /**
         * Alternative return URL path (default is \TYPO3\CMS\Core\Utility\GeneralUtility::linkThisScript())
         *
         * @var string
@@ -168,20 +118,6 @@ class FormEngine {
        public $palettesCollapsed = FALSE;
 
        /**
-        * If set, the RTE is disabled (from form display, eg. by checkbox in the bottom of the page!)
-        *
-        * @var bool
-        */
-       public $disableRTE = FALSE;
-
-       /**
-        * If FALSE, then all CSH will be disabled, regardless of settings in $this->edit_showFieldHelp
-        *
-        * @var bool
-        */
-       public $globalShowHelp = TRUE;
-
-       /**
         * If this evaluates to TRUE, the forms are rendering only localization relevant fields of the records.
         *
         * @var string
@@ -198,429 +134,230 @@ class FormEngine {
        public $fieldOrder = '';
 
        /**
-        * If set to FALSE, palettes will NEVER be rendered.
+        * When enabled all elements are rendered non-editable
         *
         * @var bool
         */
-       public $doPrintPalette = TRUE;
+       protected $renderReadonly = FALSE;
 
+       // INTERNAL, static
        /**
-        * Set to initialized clipboard object;
-        * Then the element browser will offer a link to paste in records from clipboard.
+        * The string to prepend formfield names with.
         *
-        * @var \TYPO3\CMS\Backend\Clipboard\Clipboard|NULL
+        * @var string
         */
-       public $clipObj = NULL;
+       public $prependFormFieldNames = 'data';
 
        /**
-        * Enable click menu on reference icons.
+        * The string to prepend commands for tcemain::process_cmdmap with
         *
-        * @var bool
-        */
-       public $enableClickMenu = FALSE;
-
-       /**
-        * @var bool
+        * @var string
         */
-       public $enableTabMenu = FALSE;
+       public $prependCmdFieldNames = 'cmd';
 
        /**
-        * When enabled all fields are rendered non-editable
+        * The string to prepend FILE form field names with
         *
-        * @var bool
+        * @var string
         */
-       protected $renderReadonly = FALSE;
+       public $prependFormFieldNames_file = 'data_files';
 
        /**
-        * Form field width compensation: Factor of "size=12" to "style="width: 12*12px"
-        * for form field widths of style-aware browsers
+        * The string to prepend form field names that are active (not NULL)
         *
-        * @var float
+        * @var string
         */
-       public $form_rowsToStylewidth = 12;
+       protected $prependFormFieldNamesActive = 'control[active]';
 
        /**
-        * Value that gets added for style="width: ...px" for textareas compared to input fields.
+        * Set by readPerms()  (caching)
         *
-        * @var int
+        * @var string
         */
-       protected $form_additionalTextareaStyleWidth = 23;
+       public $perms_clause = '';
 
        /**
-        * Form field width compensation: Compensation for large documents, doc-tab (editing)
+        * Set by readPerms()  (caching-flag)
         *
-        * @var float
+        * @var bool
         */
-       public $form_largeComp = 1.33;
+       public $perms_clause_set = FALSE;
 
        /**
-        * The number of chars expected per row when the height of a text area field is
-        * automatically calculated based on the number of characters found in the field content.
+        * Counter that is incremented before an RTE is created. Can be used for unique ids etc.
         *
         * @var int
         */
-       public $charsPerRow = 40;
+       public $RTEcounter = 0;
 
        /**
-        * The maximum abstract value for textareas
+        * Total wrapping for the table rows
         *
-        * @var int
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
+        * @var string
         */
-       public $maxTextareaWidth = 48;
+       public $totalWrap = '<hr />|<hr />';
 
        /**
-        * The default abstract value for input and textarea elements
+        * Field template
         *
-        * @var int
-        * @internal
+        * @var string
         */
-       public $defaultInputWidth = 30;
+       public $fieldTemplate = '<strong>###FIELD_NAME###</strong><br />###FIELD_ITEM###<hr />';
 
        /**
-        * The minimum abstract value for input and textarea elements
+        * Template subpart for palette fields
         *
-        * @var int
-        * @internal
+        * @var string
         */
-       public $minimumInputWidth = 10;
+       protected $paletteFieldTemplate = '';
 
        /**
-        * The maximum abstract value for input and textarea elements
+        * Wrapping template code for a section
         *
-        * @var int
-        * @internal
+        * @var string
+        * @deprecatd since TYPO3 CMS 7, will be removed in CMS 8
         */
-       public $maxInputWidth = 50;
+       public $sectionWrap = '';
 
        /**
-        * Default style for the selector boxes used for multiple items in "select" and "group" types.
+        * Template for palette headers
         *
         * @var string
         */
-       public $defaultMultipleSelectorStyle = '';
+       public $palFieldTemplateHeader = '';
 
-       // INTERNAL, static
        /**
-        * The string to prepend formfield names with.
+        * Template for palettes
         *
         * @var string
         */
-       public $prependFormFieldNames = 'data';
+       public $palFieldTemplate = '';
 
        /**
-        * The string to prepend commands for tcemain::process_cmdmap with
+        * Set to the fields NOT to display, if any
         *
-        * @var string
+        * @var array|NULL
         */
-       public $prependCmdFieldNames = 'cmd';
+       public $excludeElements = NULL;
 
        /**
-        * The string to prepend FILE form field names with
+        * During rendering of forms this will keep track of which palettes
+        * has already been rendered (so they are not rendered twice by mistake)
         *
-        * @var string
+        * @var array
         */
-       public $prependFormFieldNames_file = 'data_files';
+       public $palettesRendered = array();
 
        /**
-        * The string to prepend form field names that are active (not NULL)
+        * This array of fields will be set as hidden-fields instead of rendered normally!
+        * For instance palette fields edited in the top frame are set as hidden fields
+        * since the main form has to submit the values.
+        * The top frame actually just sets the value in the main form!
         *
-        * @var string
+        * @var array
         */
-       protected $prependFormFieldNamesActive = 'control[active]';
+       public $hiddenFieldListArr = array();
 
        /**
-        * The name attribute of the form
+        * Used to register input-field names, which are required. (Done during rendering of the fields).
+        * This information is then used later when the JavaScript is made.
         *
-        * @var string
+        * @var array
         */
-       public $formName = 'editform';
+       public $requiredFields = array();
 
        /**
-        * Whitelist that allows TCA field configuration to be overridden by TSconfig
+        * Used to register input-field names, which are required an have additional requirements.
+        * (e.g. like a date/time must be positive integer)
+        * The information of this array is merged with $this->requiredFields later.
         *
-        * @see overrideFieldConf()
         * @var array
         */
-       public $allowOverrideMatrix = array();
+       public $requiredAdditional = array();
 
        /**
-        * Set by readPerms()  (caching)
+        * Used to register the min and max number of elements
+        * for selector boxes where that apply (in the "group" type for instance)
         *
-        * @var string
+        * @var array
         */
-       public $perms_clause = '';
+       public $requiredElements = array();
 
        /**
-        * Set by readPerms()  (caching-flag)
+        * Used to determine where $requiredFields or $requiredElements are nested (in Tabs or IRRE)
         *
-        * @var bool
+        * @var array
         */
-       public $perms_clause_set = FALSE;
+       public $requiredNested = array();
 
        /**
-        * Used to indicate the mode of CSH (Context Sensitive Help),
-        * whether it should be icons-only ('icon') or not at all (blank).
+        * Keeps track of the rendering depth of nested records
         *
-        * @var bool
+        * @var int
         */
-       public $edit_showFieldHelp = FALSE;
+       public $renderDepth = 0;
 
        /**
-        * @var bool
+        * Color scheme buffer
+        *
+        * @var array
+        * @deprecatd since TYPO3 CMS 7, will be removed in CMS 8
         */
-       public $edit_docModuleUpload = FALSE;
+       public $savedSchemes = array();
 
        /**
-        * Loaded with info about the browser when class is instantiated
+        * holds the path an element is nested in (e.g. required for RTEhtmlarea)
         *
         * @var array
         */
-       public $clientInfo = array();
+       public $dynNestedStack = array();
 
+       // Internal, registers for user defined functions etc.
        /**
-        * TRUE, if RTE is possible for the current user (based on result from BE_USER->isRTE())
+        * Additional HTML code, printed before the form
         *
-        * @var bool
+        * @var array
         */
-       public $RTEenabled = FALSE;
+       public $additionalCode_pre = array();
 
        /**
-        * If $this->RTEenabled was FALSE, you can find the reasons listed in this array
-        * which is filled with reasons why the RTE could not be loaded)
+        * Additional JavaScript, printed before the form
         *
-        * @var string
+        * @var array
+        * @deprecatd since TYPO3 CMS 7, will be removed in CMS 8
         */
-       public $RTEenabled_notReasons = '';
+       public $additionalJS_pre = array();
 
        /**
-        * Counter that is incremented before an RTE is created. Can be used for unique ids etc.
+        * Additional JavaScript printed after the form
         *
-        * @var int
+        * @var array
         */
-       public $RTEcounter = 0;
+       public $additionalJS_post = array();
 
        /**
-        * Contains current color scheme
+        * Additional JavaScript executed on submit; If you set "OK" variable it will raise an error
+        * about RTEs not being loaded and offer to block further submission.
         *
         * @var array
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
         */
-       public $colorScheme = array();
+       public $additionalJS_submit = array();
 
        /**
-        * Contains current class scheme
+        * Additional JavaScript executed when section element is deleted.
+        * This is necessary, for example, to correctly clean up HTMLArea RTE (bug #8232)
         *
         * @var array
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
         */
-       public $classScheme = array();
+       public $additionalJS_delete = array();
 
        /**
-        * Contains the default color scheme
-        *
-        * @var array
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
+        * @var \TYPO3\CMS\Backend\Form\Element\InlineElement
         */
-       public $defColorScheme = array();
+       public $inline;
 
        /**
-        * Contains the default class scheme
-        *
-        * @var array
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
-        */
-       public $defClassScheme = array();
-
-       /**
-        * Contains field style values
-        *
-        * @var array|NULL
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
-        */
-       public $fieldStyle = NULL;
-
-       /**
-        * Contains border style values
-        *
-        * @var array|NULL
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
-        */
-       public $borderStyle = NULL;
-
-       /**
-        * An accumulation of messages from the class
-        *
-        * @var array
-        */
-       public $commentMessages = array();
-
-       /**
-        * Total wrapping for the table rows
-        *
-        * @var string
-        */
-       public $totalWrap = '<hr />|<hr />';
-
-       /**
-        * Field template
-        *
-        * @var string
-        */
-       public $fieldTemplate = '<strong>###FIELD_NAME###</strong><br />###FIELD_ITEM###<hr />';
-
-       /**
-        * Template subpart for palette fields
-        *
-        * @var string
-        */
-       protected $paletteFieldTemplate = '';
-
-       /**
-        * Wrapping template code for a section
-        *
-        * @var string
-        * @deprecatd since TYPO3 CMS 7, will be removed in CMS 8
-        */
-       public $sectionWrap = '';
-
-       /**
-        * Template for palette headers
-        *
-        * @var string
-        */
-       public $palFieldTemplateHeader = '';
-
-       /**
-        * Template for palettes
-        *
-        * @var string
-        */
-       public $palFieldTemplate = '';
-
-       /**
-        * Set to the fields NOT to display, if any
-        *
-        * @var array|NULL
-        */
-       public $excludeElements = NULL;
-
-       /**
-        * During rendering of forms this will keep track of which palettes
-        * has already been rendered (so they are not rendered twice by mistake)
-        *
-        * @var array
-        */
-       public $palettesRendered = array();
-
-       /**
-        * This array of fields will be set as hidden-fields instead of rendered normally!
-        * For instance palette fields edited in the top frame are set as hidden fields
-        * since the main form has to submit the values.
-        * The top frame actually just sets the value in the main form!
-        *
-        * @var array
-        */
-       public $hiddenFieldListArr = array();
-
-       /**
-        * Used to register input-field names, which are required. (Done during rendering of the fields).
-        * This information is then used later when the JavaScript is made.
-        *
-        * @var array
-        */
-       public $requiredFields = array();
-
-       /**
-        * Used to register input-field names, which are required an have additional requirements.
-        * (e.g. like a date/time must be positive integer)
-        * The information of this array is merged with $this->requiredFields later.
-        *
-        * @var array
-        */
-       public $requiredAdditional = array();
-
-       /**
-        * Used to register the min and max number of elements
-        * for selector boxes where that apply (in the "group" type for instance)
-        *
-        * @var array
-        */
-       public $requiredElements = array();
-
-       /**
-        * Used to determine where $requiredFields or $requiredElements are nested (in Tabs or IRRE)
-        *
-        * @var array
-        */
-       public $requiredNested = array();
-
-       /**
-        * Keeps track of the rendering depth of nested records
-        *
-        * @var int
-        */
-       public $renderDepth = 0;
-
-       /**
-        * Color scheme buffer
-        *
-        * @var array
-        */
-       public $savedSchemes = array();
-
-       /**
-        * holds the path an element is nested in (e.g. required for RTEhtmlarea)
-        *
-        * @var array
-        */
-       public $dynNestedStack = array();
-
-       // Internal, registers for user defined functions etc.
-       /**
-        * Additional HTML code, printed before the form
-        *
-        * @var array
-        */
-       public $additionalCode_pre = array();
-
-       /**
-        * Additional JavaScript, printed before the form
-        *
-        * @var array
-        */
-       public $additionalJS_pre = array();
-
-       /**
-        * Additional JavaScript printed after the form
-        *
-        * @var array
-        */
-       public $additionalJS_post = array();
-
-       /**
-        * Additional JavaScript executed on submit; If you set "OK" variable it will raise an error
-        * about RTEs not being loaded and offer to block further submission.
-        *
-        * @var array
-        */
-       public $additionalJS_submit = array();
-
-       /**
-        * Additional JavaScript executed when section element is deleted.
-        * This is necessary, for example, to correctly clean up HTMLArea RTE (bug #8232)
-        *
-        * @var array
-        */
-       public $additionalJS_delete = array();
-
-       /**
-        * @var \TYPO3\CMS\Backend\Form\Element\InlineElement
-        */
-       public $inline;
-
-       /**
-        * Array containing hook class instances called once for a form
+        * Array containing hook class instances called once for a form
         *
         * @var array
         */
@@ -648,11 +385,6 @@ class FormEngine {
        public $templateFile = '';
 
        /**
-        * @var \TYPO3\CMS\Backend\Form\Element\SuggestElement
-        */
-       protected $suggest;
-
-       /**
         * protected properties which were public
         * use old property name as key and new property name as value
         * e.g. 'foo_BarName' => 'fooBarName'
@@ -670,28 +402,9 @@ class FormEngine {
         *
         */
        public function __construct() {
-               $this->clientInfo = GeneralUtility::clientInfo();
-               $this->RTEenabled = $this->getBackendUserAuthentication()->isRTE();
-               if (!$this->RTEenabled) {
-                       $this->RTEenabled_notReasons = implode(LF, $this->getBackendUserAuthentication()->RTE_errors);
-                       $this->commentMessages[] = 'RTE NOT ENABLED IN SYSTEM due to:' . LF . $this->RTEenabled_notReasons;
-               }
-               // Define whitelist that allows TCA field configuration to be overridden by TSconfig, @see overrideFieldConf():
-               $this->allowOverrideMatrix = array(
-                       'input' => array('size', 'max', 'readOnly'),
-                       'text' => array('cols', 'rows', 'wrap', 'readOnly'),
-                       'check' => array('cols', 'showIfRTE', 'readOnly'),
-                       'select' => array('size', 'autoSizeMax', 'maxitems', 'minitems', 'readOnly', 'treeConfig'),
-                       'group' => array('size', 'autoSizeMax', 'max_size', 'show_thumbs', 'maxitems', 'minitems', 'disable_controls', 'readOnly'),
-                       'inline' => array('appearance', 'behaviour', 'foreign_label', 'foreign_selector', 'foreign_unique', 'maxitems', 'minitems', 'size', 'autoSizeMax', 'symmetric_label', 'readOnly')
-               );
                // Create instance of InlineElement only if this a non-IRRE-AJAX call:
-               if (!isset($GLOBALS['ajaxID']) || strpos($GLOBALS['ajaxID'], \TYPO3\CMS\Backend\Form\Element\InlineElement::class . '::') !== 0) {
-                       $this->inline = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\InlineElement::class);
-               }
-               // Create instance of \TYPO3\CMS\Backend\Form\Element\SuggestElement only if this a non-Suggest-AJAX call:
-               if (!isset($GLOBALS['ajaxID']) || strpos($GLOBALS['ajaxID'], \TYPO3\CMS\Backend\Form\Element\SuggestElement::class . '::') !== 0) {
-                       $this->suggest = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\SuggestElement::class);
+               if (!isset($GLOBALS['ajaxID']) || strpos($GLOBALS['ajaxID'], InlineElement::class . '::') !== 0) {
+                       $this->inline = GeneralUtility::makeInstance(InlineElement::class);
                }
                // Prepare user defined objects (if any) for hooks which extend this function:
                $this->hookObjectsMainFields = array();
@@ -769,12 +482,8 @@ class FormEngine {
         */
        public function initDefaultBEmode() {
                $this->prependFormFieldNames = 'data';
-               $this->formName = 'editform';
                $this->setNewBEDesign();
-               $this->edit_showFieldHelp = (bool)$this->getBackendUserAuthentication()->uc['edit_showFieldHelp'];
-               $this->edit_docModuleUpload = (bool)$this->getBackendUserAuthentication()->uc['edit_docModuleUpload'];
                $this->inline->init($this);
-               $this->suggest->init($this);
        }
 
        /*******************************************************
@@ -855,7 +564,7 @@ class FormEngine {
                $tabIdentStringMD5 = '';
                if ($GLOBALS['TCA'][$table]) {
                        // Load the description content for the table.
-                       if ($this->edit_showFieldHelp || $this->doLoadTableDescr($table)) {
+                       if ($this->doLoadTableDescr($table)) {
                                $languageService->loadSingleTableDescription($table);
                        }
                        // Get the current "type" value for the record.
@@ -877,7 +586,7 @@ class FormEngine {
                                        $excludeElements = ($this->excludeElements = $this->getExcludeElements($table, $row, $typeNum));
                                        $fields = $this->mergeFieldsWithAddedFields($fields, $this->getFieldsToAdd($table, $row, $typeNum), $table);
                                        // If TCEforms will render a tab menu in the next step, push the name to the tab stack:
-                                       if (strstr($itemList, '--div--') !== FALSE && $this->enableTabMenu) {
+                                       if (strstr($itemList, '--div--') !== FALSE) {
                                                $tabIdentString = 'TCEforms:' . $table . ':' . $row['uid'];
                                                $tabIdentStringMD5 = $this->getDocumentTemplate()->getDynTabMenuId($tabIdentString);
                                                // Remember that were currently working on the general tab:
@@ -911,18 +620,16 @@ class FormEngine {
                                                                $out_array[$out_sheet][$out_pointer] .= $sField;
                                                        } elseif ($theField == '--div--') {
                                                                if ($cc > 0) {
-                                                                       if ($this->enableTabMenu) {
-                                                                               // Remove last tab entry from the dynNestedStack:
-                                                                               $out_sheet++;
-                                                                               // Remove the previous sheet from stack (if any):
-                                                                               $this->popFromDynNestedStack('tab', $tabIdentStringMD5 . '-' . $out_sheet);
-                                                                               // Remember on which sheet we're currently working:
-                                                                               $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-' . ($out_sheet + 1));
-                                                                               $out_array[$out_sheet] = array();
-                                                                               $out_array_meta[$out_sheet]['title'] = $languageService->sL($fieldLabel);
-                                                                               // Register newline for Tab
-                                                                               $out_array_meta[$out_sheet]['newline'] = $additionalPalette == 'newline';
-                                                                       }
+                                                                       // Remove last tab entry from the dynNestedStack:
+                                                                       $out_sheet++;
+                                                                       // Remove the previous sheet from stack (if any):
+                                                                       $this->popFromDynNestedStack('tab', $tabIdentStringMD5 . '-' . $out_sheet);
+                                                                       // Remember on which sheet we're currently working:
+                                                                       $this->pushToDynNestedStack('tab', $tabIdentStringMD5 . '-' . ($out_sheet + 1));
+                                                                       $out_array[$out_sheet] = array();
+                                                                       $out_array_meta[$out_sheet]['title'] = $languageService->sL($fieldLabel);
+                                                                       // Register newline for Tab
+                                                                       $out_array_meta[$out_sheet]['newline'] = $additionalPalette == 'newline';
                                                                } else {
                                                                        // Setting alternative title for "General" tab if "--div--" is the very first element.
                                                                        $out_array_meta[$out_sheet]['title'] = $languageService->sL($fieldLabel);
@@ -998,7 +705,6 @@ class FormEngine {
                if ($out_sheet === 0) {
                        $output = '<div class="tab-content">' . $output . '</div>';
                }
-               $output = $output;
 
                return $output;
        }
@@ -1014,7 +720,7 @@ class FormEngine {
         * @return string TCEform elements in a string.
         */
        public function getListedFields($table, $row, $list) {
-               if ($this->edit_showFieldHelp || $this->doLoadTableDescr($table)) {
+               if ($this->doLoadTableDescr($table)) {
                        $this->getLanguageService()->loadSingleTableDescription($table);
                }
                $out = '';
@@ -1049,9 +755,6 @@ class FormEngine {
         * @return string HTML code.
         */
        public function getPaletteFields($table, $row, $palette, $header = '', $itemList = '', $collapsedHeader = NULL) {
-               if (!$this->doPrintPalette) {
-                       return '';
-               }
                $out = '';
                $parts = $this->loadPaletteElements($table, $row, $palette, $itemList);
                // Put palette together if there are fields in it:
@@ -1101,6 +804,8 @@ class FormEngine {
         * @return mixed String (normal) or array (palettes)
         */
        public function getSingleField($table, $field, $row, $altName = '', $palette = FALSE, $extra = '', $pal = 0) {
+               $backendUser = $this->getBackendUserAuthentication();
+
                // Hook: getSingleField_preProcess
                foreach ($this->hookObjectsSingleField as $hookObj) {
                        if (method_exists($hookObj, 'getSingleField_preProcess')) {
@@ -1123,27 +828,27 @@ class FormEngine {
                // Evaluate display condition
                $displayConditionResult = TRUE;
                if (is_array($PA['fieldConf']) && $PA['fieldConf']['displayCond'] && is_array($row)) {
-                       /** @var $elementConditionMatcher \TYPO3\CMS\Backend\Form\ElementConditionMatcher */
-                       $elementConditionMatcher = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\ElementConditionMatcher::class);
+                       /** @var $elementConditionMatcher ElementConditionMatcher */
+                       $elementConditionMatcher = GeneralUtility::makeInstance(ElementConditionMatcher::class);
                        $displayConditionResult = $elementConditionMatcher->match($PA['fieldConf']['displayCond'], $row);
                }
                // Check if this field is configured and editable (according to excludefields + other configuration)
                if (
                        is_array($PA['fieldConf'])
                        && !$skipThisField
-                       && (!$PA['fieldConf']['exclude'] || $this->getBackendUserAuthentication()->check('non_exclude_fields', $table . ':' . $field))
+                       && (!$PA['fieldConf']['exclude'] || $backendUser->check('non_exclude_fields', $table . ':' . $field))
                        && $PA['fieldConf']['config']['form_type'] != 'passthrough'
-                       && ($this->RTEenabled || !$PA['fieldConf']['config']['showIfRTE'])
+                       && ($backendUser->isRTE() || !$PA['fieldConf']['config']['showIfRTE'])
                        && $displayConditionResult
                        && (!$GLOBALS['TCA'][$table]['ctrl']['languageField'] || $PA['fieldConf']['l10n_display'] || ($PA['fieldConf']['l10n_mode'] !== 'exclude') || $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] <= 0)
                        && (!$GLOBALS['TCA'][$table]['ctrl']['languageField'] || !$this->localizationMode || $this->localizationMode === $PA['fieldConf']['l10n_cat'])
                ) {
                        // Fetching the TSconfig for the current table/field. This includes the $row which means that
-                       $PA['fieldTSConfig'] = $this->setTSconfig($table, $row, $field);
+                       $PA['fieldTSConfig'] = FormEngineUtility::getTSconfigForTableRow($table, $row, $field);
                        // If the field is NOT disabled from TSconfig (which it could have been) then render it
                        if (!$PA['fieldTSConfig']['disabled']) {
                                // Override fieldConf by fieldTSconfig:
-                               $PA['fieldConf']['config'] = $this->overrideFieldConf($PA['fieldConf']['config'], $PA['fieldTSConfig']);
+                               $PA['fieldConf']['config'] = FormEngineUtility::overrideFieldConf($PA['fieldConf']['config'], $PA['fieldTSConfig']);
                                // Init variables:
                                $PA['itemFormElName'] = $this->prependFormFieldNames . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
                                // Form field name, in case of file uploads
@@ -1171,7 +876,7 @@ class FormEngine {
                                        || !empty($GLOBALS['TCA'][$table]['ctrl']['requestUpdate'])
                                        && GeneralUtility::inList(str_replace(' ', '', $GLOBALS['TCA'][$table]['ctrl']['requestUpdate']), $field)
                                ) {
-                                       if ($this->getBackendUserAuthentication()->jsConfirmation(1)) {
+                                       if ($backendUser->jsConfirmation(1)) {
                                                $alertMsgOnChange = 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
                                        } else {
                                                $alertMsgOnChange = 'if (TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
@@ -1185,8 +890,6 @@ class FormEngine {
                                } else {
                                        $languageService = $this->getLanguageService();
                                        // Render as a normal field:
-                                       // onFocus attribute to add to the field:
-                                       $PA['onFocus'] = $palJSfunc && !$this->getBackendUserAuthentication()->uc['dontShowPalettesOnFocusInAB'] ? ' onfocus="' . htmlspecialchars($palJSfunc) . '"' : '';
                                        $PA['label'] = $PA['altName'] ?: $PA['fieldConf']['label'];
                                        $PA['label'] = $PA['fieldTSConfig']['label'] ?: $PA['label'];
                                        $PA['label'] = $PA['fieldTSConfig']['label.'][$languageService->lang] ?: $PA['label'];
@@ -1219,7 +922,7 @@ class FormEngine {
                                        // If the record has been saved and the "linkTitleToSelf" is set, we make the field name into a link, which will load ONLY this field in alt_doc.php
                                        $label = htmlspecialchars($PA['label'], ENT_COMPAT, 'UTF-8', FALSE);
                                        if (MathUtility::canBeInterpretedAsInteger($row['uid']) && $PA['fieldTSConfig']['linkTitleToSelf'] && !GeneralUtility::_GP('columnsOnly')) {
-                                               $lTTS_url = $this->backPath . 'alt_doc.php?edit[' . $table . '][' . $row['uid'] . ']=edit&columnsOnly=' . $field . '&returnUrl=' . rawurlencode($this->thisReturnUrl());
+                                               $lTTS_url = 'alt_doc.php?edit[' . $table . '][' . $row['uid'] . ']=edit&columnsOnly=' . $field . '&returnUrl=' . rawurlencode($this->thisReturnUrl());
                                                $label = '<a href="' . htmlspecialchars($lTTS_url) . '">' . $label . '</a>';
                                        }
 
@@ -1231,6 +934,11 @@ class FormEngine {
                                                $this->additionalJS_post[] = 'typo3form.fieldTogglePlaceholder('
                                                        . GeneralUtility::quoteJSvalue($PA['itemFormElName']) . ', ' . ($checked ? 'false' : 'true') . ');';
 
+                                               $noneElement = GeneralUtility::makeInstance(NoneElement::class, $this);
+                                               $noneElementConfiguration = $PA;
+                                               $noneElementConfiguration['itemFormElValue'] = GeneralUtility::fixed_lgd_cs($placeholder, 30);
+                                               $noneElementHtml = $noneElement->render('', '', '', $noneElementConfiguration);
+
                                                $item = '
                                                        <input type="hidden" name="' . htmlspecialchars($PA['itemFormElNameActive']) . '" value="0" />
                                                        <div class="checkbox">
@@ -1240,7 +948,7 @@ class FormEngine {
                                                                </label>
                                                        </div>
                                                        <div class="t3js-formengine-placeholder-placeholder">
-                                                               ' . $this->getSingleField_typeNone_render($PA['fieldConf']['config'], GeneralUtility::fixed_lgd_cs($placeholder, 30)) . '
+                                                               ' . $noneElementHtml . '
                                                        </div>
                                                        <div class="t3js-formengine-placeholder-formfield">' . $item . '</div>';
                                        }
@@ -1280,8 +988,6 @@ class FormEngine {
                                                ';
                                        }
                                }
-                       } else {
-                               $this->commentMessages[] = $this->prependFormFieldNames . '[' . $table . '][' . $row['uid'] . '][' . $field . ']: Disabled by TSconfig';
                        }
                }
                // Hook: getSingleField_postProcess
@@ -1335,34 +1041,33 @@ class FormEngine {
                        }
                        $formElement = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\Element\\' . $typeClassNameMapping[$type], $this);
                        if ($formElement instanceof AbstractFormElement) {
-                               $formElement->setRenderReadonly($this->getRenderReadonly());
+                               $formElement->setGlobalOptions($this->getConfigurationOptionsForChildElements());
                        }
                        $item = $formElement->render($table, $field, $row, $PA);
                }
                return $item;
        }
 
+       /**
+        * Returns an array of global form settings to be given to child elements.
+        *
+        * @return array
+        */
+       protected function getConfigurationOptionsForChildElements() {
+               return array(
+                       'renderReadonly' => $this->getRenderReadonly(),
+                       'disabledWizards' => $this->disableWizards,
+                       'returnUrl' => $this->thisReturnUrl(),
+                       // Inline is handed over temporarily until FormEngine uses a real object tree
+                       'inline' => $this->inline,
+               );
+       }
+
        /**********************************************************
         *
         * Rendering of each TCEform field type
         *
         ************************************************************/
-       /**
-        * Generation of TCEform elements of the type "input"
-        * This will render a single-line input form field, possibly with various control/validation features
-        *
-        * @param string $table The table name of the record
-        * @param string $field The field name which this element is supposed to edit
-        * @param array $row The record data array where the value(s) for the field can be found
-        * @param array $PA An array with additional configuration options.
-        * @return string The HTML code for the TCEform field
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\InputElement
-        */
-       public function getSingleField_typeInput($table, $field, $row, &$PA) {
-               GeneralUtility::logDeprecatedFunction();
-               return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\InputElement::class, $this)
-                       ->render($table, $field, $row, $PA);
-       }
 
        /**
         * Renders a view widget to handle and activate NULL values.
@@ -1423,3468 +1128,2850 @@ class FormEngine {
                return $result;
        }
 
-       /**
-        * Generation of TCEform elements of the type "text"
-        * This will render a <textarea> OR RTE area form field, possibly with various control/validation features
-        *
-        * @param string $table The table name of the record
-        * @param string $field The field name which this element is supposed to edit
-        * @param array $row The record data array where the value(s) for the field can be found
-        * @param array $PA An array with additional configuration options.
-        * @return string The HTML code for the TCEform field
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\TextElement
-        */
-       public function getSingleField_typeText($table, $field, $row, &$PA) {
-               GeneralUtility::logDeprecatedFunction();
-               return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\TextElement::class, $this)
-                       ->setRenderReadonly($this->getRenderReadonly())
-                       ->render($table, $field, $row, $PA);
-       }
 
+       /************************************************************
+        *
+        * "Configuration" fetching/processing functions
+        *
+        ************************************************************/
        /**
-        * Generation of TCEform elements of the type "check"
-        * This will render a check-box OR an array of checkboxes
+        * Calculate and return the current "types" pointer value for a record
         *
-        * @param string $table The table name of the record
-        * @param string $field The field name which this element is supposed to edit
-        * @param array $row The record data array where the value(s) for the field can be found
-        * @param array $PA An array with additional configuration options.
-        * @return string The HTML code for the TCEform field
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\CheckboxElement
+        * @param string $table The table name. MUST be in $GLOBALS['TCA']
+        * @param array $row The row from the table, should contain at least the "type" field, if applicable.
+        * @return string Return the "type" value for this record, ready to pick a "types" configuration from the $GLOBALS['TCA'] array.
+        * @throws \RuntimeException
         */
-       public function getSingleField_typeCheck($table, $field, $row, &$PA) {
-               GeneralUtility::logDeprecatedFunction();
-               return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\CheckboxElement::class, $this)
-                       ->setRenderReadonly($this->getRenderReadonly())
-                       ->render($table, $field, $row, $PA);
+       public function getRTypeNum($table, $row) {
+               $typeNum = 0;
+               $field = $GLOBALS['TCA'][$table]['ctrl']['type'];
+               if ($field) {
+                       if (strpos($field, ':') !== FALSE) {
+                               list($pointerField, $foreignTypeField) = explode(':', $field);
+                               $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$pointerField]['config'];
+                               $relationType = $fieldConfig['type'];
+                               if ($relationType === 'select') {
+                                       $foreignUid = $row[$pointerField];
+                                       $foreignTable = $fieldConfig['foreign_table'];
+                               } elseif ($relationType === 'group') {
+                                       $values = FormEngineUtility::extractValuesOnlyFromValueLabelList($row[$pointerField]);
+                                       list(, $foreignUid) = GeneralUtility::revExplode('_', $values[0], 2);
+                                       $allowedTables = explode(',', $fieldConfig['allowed']);
+                                       // Always take the first configured table.
+                                       $foreignTable = $allowedTables[0];
+                               } else {
+                                       throw new \RuntimeException('TCA Foreign field pointer fields are only allowed to be used with group or select field types.', 1325861239);
+                               }
+                               if ($foreignUid) {
+                                       $foreignRow = BackendUtility::getRecord($foreignTable, $foreignUid, $foreignTypeField);
+                                       $this->registerDefaultLanguageData($foreignTable, $foreignRow);
+                                       if ($foreignRow[$foreignTypeField]) {
+                                               $foreignTypeFieldConfig = $GLOBALS['TCA'][$table]['columns'][$field];
+                                               $typeNum = $this->getLanguageOverlayRawValue($foreignTable, $foreignRow, $foreignTypeField, $foreignTypeFieldConfig);
+                                       }
+                               }
+                       } else {
+                               $typeFieldConfig = $GLOBALS['TCA'][$table]['columns'][$field];
+                               $typeNum = $this->getLanguageOverlayRawValue($table, $row, $field, $typeFieldConfig);
+                       }
+               }
+               if (empty($typeNum)) {
+                       // If that value is an empty string, set it to "0" (zero)
+                       $typeNum = 0;
+               }
+               // If current typeNum doesn't exist, set it to 0 (or to 1 for historical reasons, if 0 doesn't exist)
+               if (!$GLOBALS['TCA'][$table]['types'][$typeNum]) {
+                       $typeNum = $GLOBALS['TCA'][$table]['types']['0'] ? 0 : 1;
+               }
+               // Force to string. Necessary for eg '-1' to be recognized as a type value.
+               $typeNum = (string)$typeNum;
+               return $typeNum;
        }
 
        /**
-        * Generation of TCEform elements of the type "radio"
-        * This will render a series of radio buttons.
+        * Used to adhoc-rearrange the field order normally set in the [types][showitem] list
         *
-        * @param string $table The table name of the record
-        * @param string $field The field name which this element is supposed to edit
-        * @param array $row The record data array where the value(s) for the field can be found
-        * @param array $PA An array with additional configuration options.
-        * @return string The HTML code for the TCEform field
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\RadioElement
+        * @param array $fields A [types][showitem] list of fields, exploded by ",
+        * @return array Returns rearranged version (keys are changed around as well.)
+        * @see getMainFields()
         */
-       public function getSingleField_typeRadio($table, $field, $row, &$PA) {
-               GeneralUtility::logDeprecatedFunction();
-               return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\RadioElement::class, $this)
-                       ->setRenderReadonly($this->getRenderReadonly())
-                       ->render($table, $field, $row, $PA);
+       public function rearrange($fields) {
+               $fO = array_flip(GeneralUtility::trimExplode(',', $this->fieldOrder, TRUE));
+               $newFields = array();
+               foreach ($fields as $cc => $content) {
+                       $cP = GeneralUtility::trimExplode(';', $content);
+                       if (isset($fO[$cP[0]])) {
+                               $newFields[$fO[$cP[0]]] = $content;
+                               unset($fields[$cc]);
+                       }
+               }
+               ksort($newFields);
+               $fields = array_merge($newFields, $fields);
+               return $fields;
        }
 
        /**
-        * Generation of TCEform elements of the type "select"
-        * This will render a selector box element, or possibly a special construction with two selector boxes.
-        * That depends on configuration.
+        * Producing an array of field names NOT to display in the form,
+        * based on settings from subtype_value_field, bitmask_excludelist_bits etc.
+        * Notice, this list is in NO way related to the "excludeField" flag
         *
-        * @param string $table The table name of the record
-        * @param string $field The field name which this element is supposed to edit
-        * @param array $row The record data array where the value(s) for the field can be found
-        * @param array $PA An array with additional configuration options.
-        * @return string The HTML code for the TCEform field
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\SelectElement
+        * @param string $table Table name, MUST be in $GLOBALS['TCA']
+        * @param array $row A record from table.
+        * @param string $typeNum A "type" pointer value, probably the one calculated based on the record array.
+        * @return array Array with fieldnames as values. The fieldnames are those which should NOT be displayed "anyways
+        * @see getMainFields()
         */
-       public function getSingleField_typeSelect($table, $field, $row, &$PA) {
-               GeneralUtility::logDeprecatedFunction();
-               return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\SelectElement::class, $this)
-                       ->setRenderReadonly($this->getRenderReadonly())
-                       ->render($table, $field, $row, $PA);
+       public function getExcludeElements($table, $row, $typeNum) {
+               // Init:
+               $excludeElements = array();
+               // If a subtype field is defined for the type
+               if ($GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field']) {
+                       $sTfield = $GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field'];
+                       if (trim($GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_excludelist'][$row[$sTfield]])) {
+                               $excludeElements = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_excludelist'][$row[$sTfield]], TRUE);
+                       }
+               }
+               // If a bitmask-value field has been configured, then find possible fields to exclude based on that:
+               if ($GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_value_field']) {
+                       $sTfield = $GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_value_field'];
+                       $sTValue = MathUtility::forceIntegerInRange($row[$sTfield], 0);
+                       if (is_array($GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_excludelist_bits'])) {
+                               foreach ($GLOBALS['TCA'][$table]['types'][$typeNum]['bitmask_excludelist_bits'] as $bitKey => $eList) {
+                                       $bit = substr($bitKey, 1);
+                                       if (MathUtility::canBeInterpretedAsInteger($bit)) {
+                                               $bit = MathUtility::forceIntegerInRange($bit, 0, 30);
+                                               if ($bitKey[0] === '-' && !($sTValue & pow(2, $bit)) || $bitKey[0] === '+' && $sTValue & pow(2, $bit)) {
+                                                       $excludeElements = array_merge($excludeElements, GeneralUtility::trimExplode(',', $eList, TRUE));
+                                               }
+                                       }
+                               }
+                       }
+               }
+               // Return the array of elements:
+               return $excludeElements;
        }
 
        /**
-        * Generation of TCEform elements of the type "group"
-        * This will render a selectorbox into which elements from either the file system or database can be inserted. Relations.
+        * Finds possible field to add to the form, based on subtype fields.
         *
-        * @param string $table The table name of the record
-        * @param string $field The field name which this element is supposed to edit
-        * @param array $row The record data array where the value(s) for the field can be found
-        * @param array $PA An array with additional configuration options.
-        * @return string The HTML code for the TCEform field
-        * @deprecated since 7.0 - will be removed two versions later; Use \TYPO3\CMS\Backend\Form\Element\GroupElement
+        * @param string $table Table name, MUST be in $GLOBALS['TCA']
+        * @param array $row A record from table.
+        * @param string $typeNum A "type" pointer value, probably the one calculated based on the record array.
+        * @return array An array containing two values: 1) Another array containing field names to add and 2) the subtype value field.
+        * @see getMainFields()
         */
-       public function getSingleField_typeGroup($table, $field, $row, &$PA) {
-               GeneralUtility::logDeprecatedFunction();
-               return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\GroupElement::class, $this)
-                       ->setRenderReadonly($this->getRenderReadonly())
-                       ->render($table, $field, $row, $PA);
+       public function getFieldsToAdd($table, $row, $typeNum) {
+               // Init:
+               $addElements = array();
+               // If a subtype field is defined for the type
+               $sTfield = '';
+               if ($GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field']) {
+                       $sTfield = $GLOBALS['TCA'][$table]['types'][$typeNum]['subtype_value_field'];
+                       if (trim($GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_addlist'][$row[$sTfield]])) {
+                               $addElements = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['types'][$typeNum]['subtypes_addlist'][$row[$sTfield]], TRUE);
+                       }
+               }
+               // Return the return
+               return array($addElements, $sTfield);
        }
 
        /**
-        * Generation of TCEform elements of the type "none"
-        * This will render a non-editable display of the content of the field.
+        * Merges the current [types][showitem] array with the array of fields to add for the current subtype field of the "type" value.
         *
-        * @param string $table The table name of the record
-        * @param string $field The field name which this element is supposed to edit
-        * @param array $row The record data array where the value(s) for the field can be found
-        * @param array $PA An array with additional configuration options.
-        * @return string The HTML code for the TCEform field
-        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use \TYPO3\CMS\Backend\Form\Element\NoneElement
+        * @param array $fields A [types][showitem] list of fields, exploded by ",
+        * @param array $fieldsToAdd The output from getFieldsToAdd()
+        * @param string $table The table name, if we want to consider it's palettes when positioning the new elements
+        * @return array Return the modified $fields array.
+        * @see getMainFields(),getFieldsToAdd()
         */
-       public function getSingleField_typeNone($table, $field, $row, &$PA) {
-               GeneralUtility::logDeprecatedFunction();
-               return $item = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\Element\NoneElement::class, $this)
-                       ->setRenderReadonly($this->getRenderReadonly())
-                       ->render($table, $field, $row, $PA);
+       public function mergeFieldsWithAddedFields($fields, $fieldsToAdd, $table = '') {
+               if (count($fieldsToAdd[0])) {
+                       $c = 0;
+                       $found = FALSE;
+                       foreach ($fields as $fieldInfo) {
+                               list($fieldName, $label, $paletteName) = GeneralUtility::trimExplode(';', $fieldInfo);
+                               if ($fieldName === $fieldsToAdd[1]) {
+                                       $found = TRUE;
+                               } elseif ($fieldName === '--palette--' && $paletteName && $table !== '') {
+                                       // Look inside the palette
+                                       if (is_array($GLOBALS['TCA'][$table]['palettes'][$paletteName])) {
+                                               $itemList = $GLOBALS['TCA'][$table]['palettes'][$paletteName]['showitem'];
+                                               if ($itemList) {
+                                                       $paletteFields = GeneralUtility::trimExplode(',', $itemList, TRUE);
+                                                       foreach ($paletteFields as $info) {
+                                                               $fieldParts = GeneralUtility::trimExplode(';', $info);
+                                                               $theField = $fieldParts[0];
+                                                               if ($theField === $fieldsToAdd[1]) {
+                                                                       $found = TRUE;
+                                                                       break 1;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               if ($found) {
+                                       array_splice($fields, $c + 1, 0, $fieldsToAdd[0]);
+                                       break;
+                       &