[!!!][FEATURE] FormEngine: The extendables 62/39662/32
authorChristian Kuhn <lolli@schwarzbu.ch>
Fri, 22 May 2015 12:02:13 +0000 (14:02 +0200)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Wed, 3 Jun 2015 22:25:29 +0000 (00:25 +0200)
For details, see the ReST files with examples for new API
and TCA changes.

* Split TCA config "type" to "type" and "renderType":
  TCA config "type" is a technical debt since it both defines the
  database storage as well as the widget that is used to render
  a certain field in FormEngine. While "type" is kept, the
  render widget is now extracted to a "renderType".

* t3editor uses this "renderType" now. type=text with
  renderType=t3editor will call the new T3editorElement provided
  by ext:t3editor, and falls back to TextElement if t3editor is
  not loaded.

* t3editor is now enabled for "setup" and "constants" of
  sys_template records if opening the whole record.

* t3editor now works when configured in a flex form.

* Introduce an API in FormEngine NodeFactory to register new
  renderType, used by t3editor.

* Introduce a resolver API in FormEngine NodeFactory to change
  the class that renders a widget or container.

* Split TextElement into TextElement that only renders a textarea
  and RichTextElement provided by ext:rtehtmlarea that renders RTE.
  ext:rtehtmlarea uses the new resolver API to route rendering to
  its own class in case RTE is enabled and configured for a field.

* In TCA section "types" a new array "columnsOverrides" is
  introduced that allows overwriting some column configurations
  of fields. Currently, this works for some View/FormEngine related
  settings like renderType and defaultExtras.

* TCA Migration is introduced to dynamically rewrite TCA before
  it is put into cache.

* TCA migration is called a second time in ext:compatibility6 in
  case TCA is still registered via ext_tables.php. This has performance
  penalty since it is done on every frontend and backend call.

* TCA migration is also called dynamically for flex form definitions.

* TCA migration moves configured t3editor wizards to type=text with
  renderType=t3editor.

* TCA migration removes the 5th parameter "style pointer" from
  types showitem

* TCA migration moves the 4th showitem parameter "extra configuration"
  to "defaultExtras" of "columnsOverrides" of given TCA type.

Change-Id: Ia2c2bc16463a01021c7a6be765b4efa872a130fd
Resolves: #67229
Releases: master
Reviewed-on: http://review.typo3.org/39662
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Frank Nägler <typo3@naegler.net>
Tested-by: Frank Nägler <typo3@naegler.net>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
62 files changed:
typo3/sysext/backend/Classes/Form/Container/AbstractContainer.php
typo3/sysext/backend/Classes/Form/Container/FlexFormContainer.php
typo3/sysext/backend/Classes/Form/Container/FlexFormContainerContainer.php
typo3/sysext/backend/Classes/Form/Container/FlexFormElementContainer.php
typo3/sysext/backend/Classes/Form/Container/FlexFormLanguageContainer.php
typo3/sysext/backend/Classes/Form/Container/FlexFormNoTabsContainer.php
typo3/sysext/backend/Classes/Form/Container/FlexFormSectionContainer.php
typo3/sysext/backend/Classes/Form/Container/FlexFormTabsContainer.php
typo3/sysext/backend/Classes/Form/Container/FullRecordContainer.php
typo3/sysext/backend/Classes/Form/Container/InlineControlContainer.php
typo3/sysext/backend/Classes/Form/Container/InlineRecordContainer.php
typo3/sysext/backend/Classes/Form/Container/ListOfFieldsContainer.php
typo3/sysext/backend/Classes/Form/Container/NoTabsContainer.php
typo3/sysext/backend/Classes/Form/Container/PaletteAndSingleContainer.php
typo3/sysext/backend/Classes/Form/Container/SingleFieldContainer.php
typo3/sysext/backend/Classes/Form/Container/SoloFieldContainer.php
typo3/sysext/backend/Classes/Form/Container/TabsContainer.php
typo3/sysext/backend/Classes/Form/Element/AbstractFormElement.php
typo3/sysext/backend/Classes/Form/Element/GroupElement.php
typo3/sysext/backend/Classes/Form/Element/ImageManipulationElement.php
typo3/sysext/backend/Classes/Form/Element/InputElement.php
typo3/sysext/backend/Classes/Form/Element/SelectCheckBoxElement.php
typo3/sysext/backend/Classes/Form/Element/SelectMultipleSideBySideElement.php
typo3/sysext/backend/Classes/Form/Element/SelectSingleBoxElement.php
typo3/sysext/backend/Classes/Form/Element/SelectSingleElement.php
typo3/sysext/backend/Classes/Form/Element/SelectTreeElement.php
typo3/sysext/backend/Classes/Form/Element/TextElement.php
typo3/sysext/backend/Classes/Form/FormEngine.php
typo3/sysext/backend/Classes/Form/NodeFactory.php
typo3/sysext/backend/Classes/Form/NodeResolverInterface.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Utility/BackendUtility.php
typo3/sysext/backend/Tests/Unit/Form/NodeFatoryTest.php
typo3/sysext/backend/Tests/Unit/Utility/BackendUtilityTest.php
typo3/sysext/compatibility6/Classes/Hooks/ExtTablesPostProcessing/TcaMigration.php [new file with mode: 0644]
typo3/sysext/compatibility6/Configuration/TCA/Overrides/tt_content.php
typo3/sysext/compatibility6/Migrations/Code/ClassAliasMap.php
typo3/sysext/compatibility6/Migrations/Code/LegacyClassesForIde.php
typo3/sysext/compatibility6/ext_localconf.php
typo3/sysext/core/Classes/DataHandling/DataHandler.php
typo3/sysext/core/Classes/Migrations/TcaMigration.php [new file with mode: 0644]
typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/core/Configuration/TCA/sys_news.php
typo3/sysext/core/Documentation/Changelog/master/Breaking-67229-FormEngineRelatedClasses.rst [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Deprecation-67229-TcaChanges.rst [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Feature-67229-FormEngineNodeFactoryApi.rst [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php [new file with mode: 0644]
typo3/sysext/css_styled_content/Configuration/TCA/Overrides/tt_content.php
typo3/sysext/filemetadata/Configuration/TCA/Overrides/sys_file_metadata.php
typo3/sysext/form/Configuration/TCA/Overrides/tt_content.php
typo3/sysext/mediace/Configuration/TCA/Overrides/tt_content.php
typo3/sysext/rtehtmlarea/Classes/Controller/FrontendRteController.php [deleted file]
typo3/sysext/rtehtmlarea/Classes/Form/Element/RichTextElement.php [new file with mode: 0644]
typo3/sysext/rtehtmlarea/Classes/Form/Resolver/RichTextNodeResolver.php [new file with mode: 0644]
typo3/sysext/rtehtmlarea/Classes/RteHtmlAreaBase.php
typo3/sysext/rtehtmlarea/ext_localconf.php
typo3/sysext/t3editor/Classes/Form/Element/T3editorElement.php [new file with mode: 0644]
typo3/sysext/t3editor/Classes/FormWizard.php [deleted file]
typo3/sysext/t3editor/Classes/T3editor.php
typo3/sysext/t3editor/Configuration/TCA/Overrides/sys_template.php [new file with mode: 0644]
typo3/sysext/t3editor/Configuration/TCA/Overrides/tt_content.php
typo3/sysext/t3editor/ext_localconf.php

index 40415cf..7b9082f 100644 (file)
@@ -206,20 +206,13 @@ abstract class AbstractContainer extends AbstractNode {
         */
        protected function explodeSingleFieldShowItemConfiguration($field) {
                $fieldArray = GeneralUtility::trimExplode(';', $field);
-               /**
-                * @todo: In general, fieldName must always be given, that is why this exception would be useful.
-                * @todo: But in older versions there was a fifth parameter and settings like ';;;;2-2-2' were used,
-                * @todo; which is obsolete now. Stuff like that could later be parsed-out on a different level of the
-                * @todo: system, the exception could then be commented in again.
                if (empty($fieldArray[0])) {
                        throw new \RuntimeException('Field must not be empty', 1426448465);
                }
-                */
                return array(
-                       'fieldName' => $fieldArray[0] ?: '', // This ternary could be removed if above todo is resolved
+                       'fieldName' => $fieldArray[0],
                        'fieldLabel' => $fieldArray[1] ?: NULL,
                        'paletteName' => $fieldArray[2] ?: NULL,
-                       'fieldExtra' => $fieldArray[3] ?: NULL,
                );
        }
 
index 24efab9..ca12cbe 100644 (file)
@@ -77,7 +77,7 @@ class FlexFormContainer extends AbstractContainer {
                $options = $this->globalOptions;
                $options['flexFormDataStructureArray'] = $flexFormDataStructureArray;
                $options['flexFormRowData'] = $flexFormRowData;
-               $options['type'] = 'flexFormLanguageContainer';
+               $options['renderType'] = 'flexFormLanguageContainer';
                /** @var NodeFactory $nodeFactory */
                $nodeFactory = $this->globalOptions['nodeFactory'];
                return $nodeFactory->create($options)->render();
index a816ebc..379ffd9 100644 (file)
@@ -95,7 +95,7 @@ class FlexFormContainerContainer extends AbstractContainer {
                $options['flexFormFieldIdentifierPrefix'] = $flexFormFieldIdentifierPrefix;
                // Append container specific stuff to field prefix
                $options['flexFormFormPrefix'] =  $flexFormFormPrefix . '[' . $flexFormContainerCounter . '][' .  $this->globalOptions['flexFormContainerName'] . '][el]';
-               $options['type'] = 'flexFormElementContainer';
+               $options['renderType'] = 'flexFormElementContainer';
                /** @var NodeFactory $nodeFactory */
                $nodeFactory = $this->globalOptions['nodeFactory'];
                $containerContentResult = $nodeFactory->create($options)->render();
index c5e6117..eb08f89 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Backend\Form\Container;
  */
 
 use TYPO3\CMS\Backend\Form\ElementConditionMatcher;
+use TYPO3\CMS\Core\Migrations\TcaMigration;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Lang\LanguageService;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
@@ -78,7 +79,7 @@ class FlexFormElementContainer extends AbstractContainer {
                                $options['flexFormRowData'] = is_array($flexFormRowData[$flexFormFieldName]['el']) ? $flexFormRowData[$flexFormFieldName]['el'] : array();
                                $options['flexFormSectionType'] = $flexFormFieldName;
                                $options['flexFormSectionTitle'] = $sectionTitle;
-                               $options['type'] = 'flexFormSectionContainer';
+                               $options['renderType'] = 'flexFormSectionContainer';
                                /** @var NodeFactory $nodeFactory */
                                $nodeFactory = $this->globalOptions['nodeFactory'];
                                $sectionContainerResult = $nodeFactory->create($options)->render();
@@ -99,6 +100,26 @@ class FlexFormElementContainer extends AbstractContainer {
                                        continue;
                                }
 
+                               // On-the-fly migration for flex form "TCA"
+                               // @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. This can be removed *if* no additional TCA migration is added with CMS 8, see class TcaMigration
+                               $dummyTca = array(
+                                       'dummyTable' => array(
+                                               'columns' => array(
+                                                       'dummyField' => $flexFormFieldArray['TCEforms'],
+                                               ),
+                                       ),
+                               );
+                               $tcaMigration = GeneralUtility::makeInstance(TcaMigration::class);
+                               $migratedTca = $tcaMigration->migrate($dummyTca);
+                               $messages = $tcaMigration->getMessages();
+                               if (!empty($messages)) {
+                                       $context = 'FormEngine did an on-the-fly migration of a flex form data structure. This is deprecated and will be removed'
+                                               . ' with TYPO3 CMS 8. Merge the following changes into the flex form definition of table ' . $table . ' in field ' . $fieldName . ':';
+                                       array_unshift($messages, $context);
+                                       GeneralUtility::deprecationLog(implode(LF, $messages));
+                               }
+                               $flexFormFieldArray['TCEforms'] = $migratedTca['dummyTable']['columns']['dummyField'];
+
                                // Set up options for single element
                                $fakeParameterArray = array(
                                        'fieldConf' => array(
@@ -147,7 +168,13 @@ class FlexFormElementContainer extends AbstractContainer {
                                $options = $this->globalOptions;
                                $options['parameterArray'] = $fakeParameterArray;
                                $options['elementBaseName'] = $this->globalOptions['elementBaseName'] . $flexFormFormPrefix . '[' . $flexFormFieldName . '][' . $vDEFkey . ']';
-                               $options['type'] = $flexFormFieldArray['TCEforms']['config']['type'];
+
+                               if (!empty($flexFormFieldArray['TCEforms']['config']['renderType'])) {
+                                       $options['renderType'] = $flexFormFieldArray['TCEforms']['config']['renderType'];
+                               } else {
+                                       // Fallback to type if no renderType is given
+                                       $options['renderType'] = $flexFormFieldArray['TCEforms']['config']['type'];
+                               }
                                /** @var NodeFactory $nodeFactory */
                                $nodeFactory = $this->globalOptions['nodeFactory'];
                                $childResult = $nodeFactory->create($options)->render();
index 115a240..e495f4a 100644 (file)
@@ -99,13 +99,13 @@ class FlexFormLanguageContainer extends AbstractContainer {
                        $options['flexFormCurrentLanguage'] = $flexFormCurrentLanguage;
                        $options['flexFormNoEditDefaultLanguage'] = $flexFormNoEditDefaultLanguage;
                        if (!$hasTabs) {
-                               $options['type'] = 'flexFormNoTabsContainer';
+                               $options['renderType'] = 'flexFormNoTabsContainer';
                                /** @var NodeFactory $nodeFactory */
                                $nodeFactory = $this->globalOptions['nodeFactory'];
                                $flexFormNoTabsResult = $nodeFactory->create($options)->render();
                                $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $flexFormNoTabsResult);
                        } else {
-                               $options['type'] = 'flexFormTabsContainer';
+                               $options['renderType'] = 'flexFormTabsContainer';
                                /** @var NodeFactory $nodeFactory */
                                $nodeFactory = $this->globalOptions['nodeFactory'];
                                $flexFormTabsContainerResult = $nodeFactory->create($options)->render();
index 1246007..50e2962 100644 (file)
@@ -78,7 +78,7 @@ class FlexFormNoTabsContainer extends AbstractContainer {
                $options['flexFormFormPrefix'] = '[data][' . $flexFormSheetNameInRowData . '][' . $flexFormCurrentLanguage . ']';
                $options['parameterArray'] = $parameterArray;
 
-               $options['type'] = 'flexFormElementContainer';
+               $options['renderType'] = 'flexFormElementContainer';
                /** @var NodeFactory $nodeFactory */
                $nodeFactory = $this->globalOptions['nodeFactory'];
                return $nodeFactory->create($options)->render();
index aa2399b..20dc008 100644 (file)
@@ -76,7 +76,7 @@ class FlexFormSectionContainer extends AbstractContainer {
                                        $options['flexFormContainerCounter'] = $flexFormContainerCounter;
                                        $options['flexFormContainerTitle'] = $sectionTitle;
                                        $options['flexFormContainerElementCollapsed'] = (bool)$existingSectionContainerData['el']['_TOGGLE'];
-                                       $options['type'] = 'flexFormContainerContainer';
+                                       $options['renderType'] = 'flexFormContainerContainer';
                                        /** @var NodeFactory $nodeFactory */
                                        $nodeFactory = $this->globalOptions['nodeFactory'];
                                        $flexFormContainerContainerResult = $nodeFactory->create($options)->render();
@@ -105,7 +105,7 @@ class FlexFormSectionContainer extends AbstractContainer {
                        $options['flexFormContainerCounter'] = $flexFormFieldIdentifierPrefix . '-form';
                        $options['flexFormContainerTitle'] = $sectionTitle;
                        $options['flexFormContainerElementCollapsed'] = FALSE;
-                       $options['type'] = 'flexFormContainerContainer';
+                       $options['renderType'] = 'flexFormContainerContainer';
                        /** @var NodeFactory $nodeFactory */
                        $nodeFactory = $this->globalOptions['nodeFactory'];
                        $flexFormContainerContainerTemplateResult = $nodeFactory->create($options)->render();
index d84f485..239c661 100644 (file)
@@ -92,7 +92,7 @@ class FlexFormTabsContainer extends AbstractContainer {
                                'tab',
                                $tabIdString . '-' . $tabCounter,
                        );
-                       $options['type'] = 'flexFormElementContainer';
+                       $options['renderType'] = 'flexFormElementContainer';
                        /** @var NodeFactory $nodeFactory */
                        $nodeFactory = $this->globalOptions['nodeFactory'];
                        $childReturn = $nodeFactory->create($options)->render();
index 37db657..114e24d 100644 (file)
@@ -99,17 +99,18 @@ class FullRecordContainer extends AbstractContainer {
                $options['fieldsArray'] = $fieldsArray;
                // Palettes may contain elements that should be excluded, resolved in PaletteContainer
                $options['excludeElements'] = $excludeElements;
+               $options['recordTypeValue'] = $recordTypeValue;
                $options['defaultLanguageData'] = $this->defaultLanguageData;
                $options['defaultLanguageDataDiff'] = $this->defaultLanguageDataDiff;
                $options['additionalPreviewLanguageData'] = $this->additionalPreviewLanguageData;
 
                if ($hasTabs) {
-                       $options['type'] = 'tabsContainer';
+                       $options['renderType'] = 'tabsContainer';
                        /** @var NodeFactory $nodeFactory */
                        $nodeFactory = $this->globalOptions['nodeFactory'];
                        $resultArray = $nodeFactory->create($options)->render();
                } else {
-                       $options['type'] = 'noTabsContainer';
+                       $options['renderType'] = 'noTabsContainer';
                        /** @var NodeFactory $nodeFactory */
                        $nodeFactory = $this->globalOptions['nodeFactory'];
                        $resultArray = $nodeFactory->create($options)->render();
index 4327e38..75e4265 100644 (file)
@@ -223,7 +223,7 @@ class InlineControlContainer extends AbstractContainer {
                                $options['inlineRelatedRecordConfig'] = $config;
                                $options['inlineData'] = $this->inlineData;
                                $options['inlineStructure'] = $inlineStackProcessor->getStructure();
-                               $options['type'] = 'inlineRecordContainer';
+                               $options['renderType'] = 'inlineRecordContainer';
                                /** @var NodeFactory $nodeFactory */
                                $nodeFactory = $this->globalOptions['nodeFactory'];
                                $childArray = $nodeFactory->create($options)->render();
index 48f2425..f8cc598 100644 (file)
@@ -217,7 +217,7 @@ class InlineRecordContainer extends AbstractContainer {
                        $domObjectId . '-' . $table . '-' . $row['uid'],
                );
                $options['overruleTypesArray'] = $overruleTypesArray;
-               $options['type'] = 'fullRecordContainer';
+               $options['renderType'] = 'fullRecordContainer';
                /** @var NodeFactory $nodeFactory */
                $nodeFactory = $this->globalOptions['nodeFactory'];
                return $nodeFactory->create($options)->render();
index 5ec2b22..7bdfbef 100644 (file)
@@ -72,7 +72,7 @@ class ListOfFieldsContainer extends AbstractContainer {
 
                $options = $this->globalOptions;
                $options['fieldsArray'] = $finalFieldsConfiguration;
-               $options['type'] = 'paletteAndSingleContainer';
+               $options['renderType'] = 'paletteAndSingleContainer';
                /** @var NodeFactory $nodeFactory */
                $nodeFactory = $this->globalOptions['nodeFactory'];
                return $nodeFactory->create($options)->render();
index e97ca56..4606e21 100644 (file)
@@ -32,7 +32,7 @@ class NoTabsContainer extends AbstractContainer {
         */
        public function render() {
                $options = $this->globalOptions;
-               $options['type'] = 'paletteAndSingleContainer';
+               $options['renderType'] = 'paletteAndSingleContainer';
                /** @var NodeFactory $nodeFactory */
                $nodeFactory = $this->globalOptions['nodeFactory'];
                $resultArray = $nodeFactory->create($options)->render();
index 157c779..46f580a 100644 (file)
@@ -135,9 +135,8 @@ class PaletteAndSingleContainer extends AbstractContainer {
 
                                $options = $this->globalOptions;
                                $options['fieldName'] = $fieldName;
-                               $options['fieldExtra'] = $fieldConfiguration['fieldExtra'];
 
-                               $options['type'] = 'singleFieldContainer';
+                               $options['renderType'] = 'singleFieldContainer';
                                /** @var NodeFactory $nodeFactory */
                                $nodeFactory = $this->globalOptions['nodeFactory'];
                                $childResultArray = $nodeFactory->create($options)->render();
@@ -259,9 +258,8 @@ class PaletteAndSingleContainer extends AbstractContainer {
                                }
                                $options = $this->globalOptions;
                                $options['fieldName'] = $fieldName;
-                               $options['fieldExtra'] = $fieldArray['fieldExtra'];
 
-                               $options['type'] = 'singleFieldContainer';
+                               $options['renderType'] = 'singleFieldContainer';
                                /** @var NodeFactory $nodeFactory */
                                $nodeFactory = $this->globalOptions['nodeFactory'];
                                $singleFieldContentArray = $nodeFactory->create($options)->render();
index 14a8a2d..75da98f 100644 (file)
@@ -19,6 +19,7 @@ use TYPO3\CMS\Backend\Form\NodeFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
+use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Lang\LanguageService;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
@@ -56,9 +57,19 @@ class SingleFieldContainer extends AbstractContainer {
                }
 
                $parameterArray = array();
-               $parameterArray['extra'] = $this->globalOptions['fieldExtra'];
                $parameterArray['fieldConf'] = $GLOBALS['TCA'][$table]['columns'][$fieldName];
 
+               // Overlay fieldConf with possible defined columnsOverrides of given record type
+               $recordTypeValue = $this->globalOptions['recordTypeValue'];
+               // Hint: 0 is a valid $recordTypeValue, !empty() does not work here
+               if (trim($recordTypeValue) !== '' && is_array($GLOBALS['TCA'][$table]['types'][$recordTypeValue]['columnsOverrides'][$fieldName])) {
+                       // Merge columnsOverrides of this field over existing field configuration
+                       ArrayUtility::mergeRecursiveWithOverrule(
+                               $parameterArray['fieldConf'],
+                               $GLOBALS['TCA'][$table]['types'][$recordTypeValue]['columnsOverrides'][$fieldName]
+                       );
+               }
+
                // A couple of early returns in case the field should not be rendered
                // Check if this field is configured and editable according to exclude fields and other configuration
                if (
@@ -159,7 +170,12 @@ class SingleFieldContainer extends AbstractContainer {
                        $options = $this->globalOptions;
                        $options['parameterArray'] = $parameterArray;
                        $options['elementBaseName'] = $newElementBaseName;
-                       $options['type'] = $parameterArray['fieldConf']['config']['type'];
+                       if (!empty($parameterArray['fieldConf']['config']['renderType'])) {
+                               $options['renderType'] = $parameterArray['fieldConf']['config']['renderType'];
+                       } else {
+                               // Fallback to type if no renderType is given
+                               $options['renderType'] = $parameterArray['fieldConf']['config']['type'];
+                       }
                        /** @var NodeFactory $nodeFactory */
                        $nodeFactory = $this->globalOptions['nodeFactory'];
                        $resultArray = $nodeFactory->create($options)->render();
@@ -252,7 +268,7 @@ class SingleFieldContainer extends AbstractContainer {
                                $options['table'] = '';
                                $options['parameterArray'] = $parameterArray;
                                $options['parameterArray']['itemFormElValue'] = GeneralUtility::fixed_lgd_cs($placeholder, 30);
-                               $options['type'] = 'none';
+                               $options['renderType'] = 'none';
                                /** @var NodeFactory $nodeFactory */
                                $nodeFactory = $this->globalOptions['nodeFactory'];
                                $noneElementResult = $nodeFactory->create($options)->render();
index 685c18b..0db6623 100644 (file)
@@ -68,9 +68,9 @@ class SoloFieldContainer extends AbstractContainer {
                                                if ($GLOBALS['TCA'][$table]['columns'][$fieldName]) {
                                                        $options = $this->globalOptions;
                                                        $options['fieldName'] = $fieldName;
-                                                       $options['fieldExtra'] = $fieldConfiguration['fieldExtra'];
+                                                       $options['recordTypeValue'] = $recordTypeValue;
 
-                                                       $options['type'] = 'singleFieldContainer';
+                                                       $options['renderType'] = 'singleFieldContainer';
                                                        /** @var NodeFactory $nodeFactory */
                                                        $nodeFactory = $this->globalOptions['nodeFactory'];
                                                        $resultArray = $nodeFactory->create($options)->render();
index a903abc..af5ae1a 100644 (file)
@@ -86,7 +86,7 @@ class TabsContainer extends AbstractContainer {
                        foreach ($elements as $element) {
                                $options['fieldsArray'][] = implode(';', $element);
                        }
-                       $options['type'] = 'paletteAndSingleContainer';
+                       $options['renderType'] = 'paletteAndSingleContainer';
                        /** @var NodeFactory $nodeFactory */
                        $nodeFactory = $this->globalOptions['nodeFactory'];
                        $childArray = $nodeFactory->create($options)->render();
index 447b421..a698e47 100644 (file)
@@ -435,7 +435,7 @@ abstract class AbstractFormElement extends AbstractNode {
                                                ),
                                                'itemFormElValue' => $PA['itemFormElValue'],
                                        );
-                                       $options['type'] = 'none';
+                                       $options['renderType'] = 'none';
                                        /** @var NodeFactory $nodeFactory */
                                        $nodeFactory = $this->globalOptions['nodeFactory'];
                                        $noneElementResult = $nodeFactory->create($options)->render();
index 51d5151..6cf2c87 100644 (file)
@@ -62,7 +62,7 @@ class GroupElement extends AbstractFormElement {
                $noDelete = isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'delete');
 
                // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
-               $specConf = BackendUtility::getSpecConfParts($parameterArray['extra'], $parameterArray['fieldConf']['defaultExtras']);
+               $specConf = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
 
                // Register properties in requiredElements
                $resultArray['requiredElements'][$parameterArray['itemFormElName']] = array(
index b66d7d7..3b6511e 100644 (file)
@@ -76,7 +76,7 @@ class ImageManipulationElement extends AbstractFormElement {
                                ),
                                'itemFormElValue' => $parameterArray['itemFormElValue'],
                        );
-                       $options['type'] = 'none';
+                       $options['renderType'] = 'none';
                        /** @var NodeFactory $nodeFactory */
                        $nodeFactory = $this->globalOptions['nodeFactory'];
                        return $nodeFactory->create($options)->render();
index 6e2cf3f..fe08548 100644 (file)
@@ -41,7 +41,7 @@ class InputElement extends AbstractFormElement {
                $isDateField = FALSE;
 
                $config = $parameterArray['fieldConf']['config'];
-               $specConf = BackendUtility::getSpecConfParts($parameterArray['extra'], $parameterArray['fieldConf']['defaultExtras']);
+               $specConf = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
                $size = MathUtility::forceIntegerInRange($config['size'] ?: $this->defaultInputWidth, $this->minimumInputWidth, $this->maxInputWidth);
                $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
                $classes = array();
@@ -87,7 +87,7 @@ class InputElement extends AbstractFormElement {
                                ),
                                'itemFormElValue' => $itemFormElValue,
                        );
-                       $options['type'] = 'none';
+                       $options['renderType'] = 'none';
                        /** @var NodeFactory $nodeFactory */
                        $nodeFactory = $this->globalOptions['nodeFactory'];
                        return $nodeFactory->create($options)->render();
index 898cc2e..8739d0f 100644 (file)
@@ -49,7 +49,7 @@ class SelectCheckBoxElement extends AbstractFormElement {
                }
                $this->resultArray = $this->initializeResultArray();
                // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
-               $specConf = BackendUtility::getSpecConfParts($parameterArray['extra'], $parameterArray['fieldConf']['defaultExtras']);
+               $specConf = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
                $selItems = FormEngineUtility::getSelectItems($table, $field, $row, $parameterArray);
 
                // Creating the label for the "No Matching Value" entry.
index 01c6186..e7f3fa2 100644 (file)
@@ -51,7 +51,7 @@ class SelectMultipleSideBySideElement extends AbstractFormElement {
                }
                $this->resultArray = $this->initializeResultArray();
                // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
-               $specConf = BackendUtility::getSpecConfParts($parameterArray['extra'], $parameterArray['fieldConf']['defaultExtras']);
+               $specConf = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
                $selItems = FormEngineUtility::getSelectItems($table, $field, $row, $parameterArray);
 
                // Creating the label for the "No Matching Value" entry.
index 87fc6f1..7edbc9f 100644 (file)
@@ -50,7 +50,7 @@ class SelectSingleBoxElement extends AbstractFormElement {
                }
                $this->resultArray = $this->initializeResultArray();
                // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
-               $specConf = BackendUtility::getSpecConfParts($parameterArray['extra'], $parameterArray['fieldConf']['defaultExtras']);
+               $specConf = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
                $selItems = FormEngineUtility::getSelectItems($table, $field, $row, $parameterArray);
 
                // Creating the label for the "No Matching Value" entry.
index 7c42acd..5cd79d2 100644 (file)
@@ -53,7 +53,7 @@ class SelectSingleElement extends AbstractFormElement {
                $this->resultArray = $this->initializeResultArray();
 
                // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
-               $specConf = BackendUtility::getSpecConfParts($parameterArray['extra'], $parameterArray['fieldConf']['defaultExtras']);
+               $specConf = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
                $selItems = FormEngineUtility::getSelectItems($table, $field, $row, $parameterArray);
 
                // Creating the label for the "No Matching Value" entry.
index 8f7b6c0..b872f6d 100644 (file)
@@ -55,7 +55,7 @@ class SelectTreeElement extends AbstractFormElement {
                $resultArray = $this->initializeResultArray();
 
                // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
-               $specConf = BackendUtility::getSpecConfParts($parameterArray['extra'], $parameterArray['fieldConf']['defaultExtras']);
+               $specConf = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
                $selItems = FormEngineUtility::getSelectItems($table, $field, $row, $parameterArray);
 
                $maxitems = (int)$config['maxitems'];
index c944b4b..9ab6a95 100644 (file)
@@ -17,7 +17,6 @@ namespace TYPO3\CMS\Backend\Form\Element;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
-use TYPO3\CMS\Backend\Form\FormEngine;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Backend\Form\NodeFactory;
 
@@ -35,8 +34,7 @@ class TextElement extends AbstractFormElement {
        protected $charactersPerRow = 40;
 
        /**
-        * This will render a <textarea> OR RTE area form field,
-        * possibly with various control/validation features
+        * This will render a <textarea>
         *
         * @return array As defined in initializeResultArray() of AbstractNode
         */
@@ -85,7 +83,7 @@ class TextElement extends AbstractFormElement {
                                ),
                                'itemFormElValue' => $parameterArray['itemFormElValue'],
                        );
-                       $options['type'] = 'none';
+                       $options['renderType'] = 'none';
                        /** @var NodeFactory $nodeFactory */
                        $nodeFactory = $this->globalOptions['nodeFactory'];
                        return $nodeFactory->create($options)->render();
@@ -103,168 +101,102 @@ class TextElement extends AbstractFormElement {
                                );
                        }
                }
-               // Init RTE vars
-               // Set TRUE, if the RTE is loaded; If not a normal textarea is shown.
-               $rteWasLoaded = FALSE;
-               // Set TRUE, if the RTE would have been loaded if it wasn't for the disable-RTE flag in the bottom of the page...
-               $rteWouldHaveBeenLoaded = FALSE;
                // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. Traditionally, this is where RTE configuration has been found.
-               $specialConfiguration = BackendUtility::getSpecConfParts($parameterArray['extra'], $parameterArray['fieldConf']['defaultExtras']);
+               $specialConfiguration = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
                // Setting up the altItem form field, which is a hidden field containing the value
                $altItem = '<input type="hidden" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" />';
                $html = '';
-               // If RTE is generally enabled (TYPO3_CONF_VARS and user settings)
-               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']])) {
-                               BackendUtility::fixVersioningPid($table, $row);
-                               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 = $backendUser->getTSConfig('RTE', BackendUtility::getPagesTSconfig($recordPid));
-                                       $rteTcaTypeValue = BackendUtility::getTCAtypeValue($table, $row);
-                                       $rteSetupConfiguration = BackendUtility::RTEsetup($rteSetup['properties'], $table, $fieldName, $rteTcaTypeValue);
-                                       if (!$rteSetupConfiguration['disabled']) {
-                                               // Get RTE object, draw form and set flag:
-                                               $rteObject = BackendUtility::RTEgetObj();
-                                               $dummyFormEngine = new FormEngine();
-                                               $rteResult = $rteObject->drawRTE(
-                                                       $dummyFormEngine,
-                                                       $table,
-                                                       $fieldName,
-                                                       $row,
-                                                       $parameterArray,
-                                                       $specialConfiguration,
-                                                       $rteSetupConfiguration,
-                                                       $rteTcaTypeValue,
-                                                       '',
-                                                       $tsConfigPid,
-                                                       $this->globalOptions,
-                                                       $this->initializeResultArray()
-                                               );
-                                               // This is a compat layer for "other" RTE's: If the result is not an array, it is the html string,
-                                               // otherwise it is a structure similar to our casual return array
-                                               // @todo: This interface needs a full re-definition, RTE should probably be its own type in the
-                                               // @todo: end, and other RTE implementations could then just override this.
-                                               if (is_array($rteResult)) {
-                                                       $html = $rteResult['html'];
-                                                       $rteResult['html'] = '';
-                                                       $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $rteResult);
-                                               } else {
-                                                       $html = $rteResult;
-                                               }
 
-                                               // Wizard
-                                               $html = $this->renderWizards(
-                                                       array($html, $altItem),
-                                                       $config['wizards'],
-                                                       $table,
-                                                       $row,
-                                                       $fieldName,
-                                                       $parameterArray,
-                                                       $parameterArray['itemFormElName'],
-                                                       $specialConfiguration,
-                                                       TRUE
+               // Show message, if no RTE (field can only be edited with RTE!)
+               if ($specialConfiguration['rte_only']) {
+                       $html = '<p><em>' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.noRTEfound')) . '</em></p>';
+               } else {
+                       // validation
+                       foreach ($evalList as $func) {
+                               if ($func === 'required') {
+                                       $resultArray['requiredFields'][$table . '_' . $row['uid'] . '_' . $fieldName] = $parameterArray['itemFormElName'];
+                               } else {
+                                       // Hint: There is a similar hook for "evaluateFieldValue" in DataHandler
+                                       $evalObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func] . ':&' . $func);
+                                       if (is_object($evalObj) && method_exists($evalObj, 'deevaluateFieldValue')) {
+                                               $_params = array(
+                                                       'value' => $parameterArray['itemFormElValue']
                                                );
-                                               $rteWasLoaded = TRUE;
+                                               $parameterArray['itemFormElValue'] = $evalObj->deevaluateFieldValue($_params);
                                        }
                                }
                        }
-               }
-               // Display ordinary field if RTE was not loaded.
-               if (!$rteWasLoaded) {
-                       // Show message, if no RTE (field can only be edited with RTE!)
-                       if ($specialConfiguration['rte_only']) {
-                               $html = '<p><em>' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.noRTEfound')) . '</em></p>';
-                       } else {
-                               // validation
-                               foreach ($evalList as $func) {
-                                       if ($func === 'required') {
-                                               $resultArray['requiredFields'][$table . '_' . $row['uid'] . '_' . $fieldName] = $parameterArray['itemFormElName'];
-                                       } else {
-                                               // Pair hook to the one in \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_input_Eval()
-                                               // and \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_text_Eval()
-                                               $evalObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func] . ':&' . $func);
-                                               if (is_object($evalObj) && method_exists($evalObj, 'deevaluateFieldValue')) {
-                                                       $_params = array(
-                                                               'value' => $parameterArray['itemFormElValue']
-                                                       );
-                                                       $parameterArray['itemFormElValue'] = $evalObj->deevaluateFieldValue($_params);
-                                               }
-                                       }
-                               }
-
-                               // calculate classes
-                               $classes = array();
-                               $classes[] = 'form-control';
-                               $classes[] = 't3js-formengine-textarea';
-                               if ($specialConfiguration['fixed-font']) {
-                                       $classes[] = 'text-monospace';
-                               }
-                               if ($specialConfiguration['enable-tab']) {
-                                       $classes[] = 't3js-enable-tab';
-                               }
 
-                               // calculate styles
-                               $styles = array();
-                               // add the max-height from the users' preference to it
-                               $maximumHeight = (int)$backendUser->uc['resizeTextareas_MaxHeight'];
-                               if ($maximumHeight > 0) {
-                                       $styles[] = 'max-height: ' . $maximumHeight . 'px';
-                               }
+                       // calculate classes
+                       $classes = array();
+                       $classes[] = 'form-control';
+                       $classes[] = 't3js-formengine-textarea';
+                       if ($specialConfiguration['fixed-font']) {
+                               $classes[] = 'text-monospace';
+                       }
+                       if ($specialConfiguration['enable-tab']) {
+                               $classes[] = 't3js-enable-tab';
+                       }
 
-                               // calculate attributes
-                               $attributes = array();
-                               $attributes['id'] = str_replace('.', '', uniqid('formengine-textarea-', TRUE));
-                               $attributes['name'] = $parameterArray['itemFormElName'];
-                               if (!empty($styles)) {
-                                       $attributes['style'] = implode(' ', $styles);
-                               }
-                               if (!empty($classes)) {
-                                       $attributes['class'] = implode(' ', $classes);
-                               }
-                               $attributes['rows'] = $rows;
-                               $attributes['wrap'] = $specialConfiguration['nowrap'] ? 'off' : ($config['wrap'] ?: 'virtual');
-                               $attributes['onChange'] = implode('', $parameterArray['fieldChangeFunc']);
-                               if (isset($config['max']) && (int)$config['max'] > 0) {
-                                       $attributes['maxlength'] = (int)$config['max'];
-                               }
-                               $attributeString = '';
-                               foreach ($attributes as $attributeName => $attributeValue) {
-                                       $attributeString .= ' '. $attributeName . '="' . htmlspecialchars($attributeValue) . '"';
-                               }
+                       // calculate styles
+                       $styles = array();
+                       // add the max-height from the users' preference to it
+                       $maximumHeight = (int)$backendUser->uc['resizeTextareas_MaxHeight'];
+                       if ($maximumHeight > 0) {
+                               $styles[] = 'max-height: ' . $maximumHeight . 'px';
+                       }
 
-                               // Build the textarea
-                               $placeholderValue = $this->getPlaceholderValue($table, $config, $row);
-                               $placeholderAttribute = '';
-                               if (!empty($placeholderValue)) {
-                                       $placeholderAttribute = ' placeholder="' . htmlspecialchars(trim($languageService->sL($placeholderValue))) . '" ';
-                               }
+                       // calculate attributes
+                       $attributes = array();
+                       $attributes['id'] = str_replace('.', '', uniqid('formengine-textarea-', TRUE));
+                       $attributes['name'] = $parameterArray['itemFormElName'];
+                       if (!empty($styles)) {
+                               $attributes['style'] = implode(' ', $styles);
+                       }
+                       if (!empty($classes)) {
+                               $attributes['class'] = implode(' ', $classes);
+                       }
+                       $attributes['rows'] = $rows;
+                       $attributes['wrap'] = $specialConfiguration['nowrap'] ? 'off' : ($config['wrap'] ?: 'virtual');
+                       $attributes['onChange'] = implode('', $parameterArray['fieldChangeFunc']);
+                       if (isset($config['max']) && (int)$config['max'] > 0) {
+                               $attributes['maxlength'] = (int)$config['max'];
+                       }
+                       $attributeString = '';
+                       foreach ($attributes as $attributeName => $attributeValue) {
+                               $attributeString .= ' '. $attributeName . '="' . htmlspecialchars($attributeValue) . '"';
+                       }
 
-                               $html .= '<textarea'
-                                       . $attributeString
-                                       . $placeholderAttribute
-                                       . $parameterArray['onFocus']
-                                       . '>' . GeneralUtility::formatForTextarea($parameterArray['itemFormElValue']) . '</textarea>';
+                       // Build the textarea
+                       $placeholderValue = $this->getPlaceholderValue($table, $config, $row);
+                       $placeholderAttribute = '';
+                       if (!empty($placeholderValue)) {
+                               $placeholderAttribute = ' placeholder="' . htmlspecialchars(trim($languageService->sL($placeholderValue))) . '" ';
+                       }
 
-                               // Wrap a wizard around the item?
-                               $html = $this->renderWizards(
-                                       array($html, $altItem),
-                                       $config['wizards'],
-                                       $table,
-                                       $row,
-                                       $fieldName,
-                                       $parameterArray,
-                                       $parameterArray['itemFormElName'],
-                                       $specialConfiguration,
-                                       $rteWouldHaveBeenLoaded
-                               );
+                       $html .= '<textarea'
+                               . $attributeString
+                               . $placeholderAttribute
+                               . $parameterArray['onFocus']
+                               . '>' . GeneralUtility::formatForTextarea($parameterArray['itemFormElValue']) . '</textarea>';
+
+                       // Wrap a wizard around the item?
+                       $html = $this->renderWizards(
+                               array($html, $altItem),
+                               $config['wizards'],
+                               $table,
+                               $row,
+                               $fieldName,
+                               $parameterArray,
+                               $parameterArray['itemFormElName'],
+                               $specialConfiguration,
+                               FALSE
+                       );
 
-                               $maximumWidth = (int)$this->formMaxWidth($cols);
-                               $html = '<div class="form-control-wrap"' . ($maximumWidth ? ' style="max-width: ' . $maximumWidth . 'px"' : '') . '>' . $html . '</div>';
-                       }
+                       $maximumWidth = (int)$this->formMaxWidth($cols);
+                       $html = '<div class="form-control-wrap"' . ($maximumWidth ? ' style="max-width: ' . $maximumWidth . 'px"' : '') . '>' . $html . '</div>';
                }
+
                $resultArray['html'] = $html;
                return $resultArray;
        }
index 3da57ae..4164f17 100644 (file)
@@ -303,7 +303,7 @@ class FormEngine {
                }
 
                $options = $this->getConfigurationOptionsForChildElements();
-               $options['type'] = 'fullRecordContainer';
+               $options['renderType'] = 'fullRecordContainer';
                $resultArray = $this->nodeFactory->create($options)->render();
 
                $content = $resultArray['html'];
@@ -345,7 +345,7 @@ class FormEngine {
 
                $options = $this->getConfigurationOptionsForChildElements();
                $options['singleFieldToRender'] = $theFieldToReturn;
-               $options['type'] = 'soloFieldContainer';
+               $options['renderType'] = 'soloFieldContainer';
                $resultArray = $this->nodeFactory->create($options)->render();
                $html = $resultArray['html'];
 
@@ -383,7 +383,7 @@ class FormEngine {
 
                $options = $this->getConfigurationOptionsForChildElements();
                $options['fieldListToRender'] = $list;
-               $options['type'] = 'listOfFieldsContainer';
+               $options['renderType'] = 'listOfFieldsContainer';
                $resultArray = $this->nodeFactory->create($options)->render();
                $html = $resultArray['html'];
 
@@ -430,6 +430,7 @@ class FormEngine {
                        'palettesCollapsed' => $this->palettesCollapsed,
                        'table' => $this->table,
                        'databaseRow' => $this->databaseRow,
+                       'recordTypeValue' => '',
                        'additionalPreviewLanguages' => $this->additionalPreviewLanguages,
                        'localizationMode' => $this->localizationMode, // @todo: find out the details, Warning, this overlaps with inline behaviour localizationMode
                        'elementBaseName' => '',
@@ -545,7 +546,7 @@ class FormEngine {
                $options['inlineStructure'] = $this->inlineStackProcessor->getStructure();
                $options['isAjaxContext'] = TRUE;
 
-               $options['type'] = 'inlineRecordContainer';
+               $options['renderType'] = 'inlineRecordContainer';
                $childArray = $this->nodeFactory->create($options)->render();
 
                if ($childArray === FALSE) {
@@ -677,7 +678,7 @@ class FormEngine {
                $options['inlineStructure'] = $this->inlineStackProcessor->getStructure();
                $options['isAjaxContext'] = TRUE;
 
-               $options['type'] = 'inlineRecordContainer';
+               $options['renderType'] = 'inlineRecordContainer';
                $childArray = $this->nodeFactory->create($options)->render();
 
                if ($childArray === FALSE) {
@@ -786,7 +787,7 @@ class FormEngine {
                                $options['inlineStructure'] = $this->inlineStackProcessor->getStructure();
                                $options['isAjaxContext'] = TRUE;
 
-                               $options['type'] = 'inlineRecordContainer';
+                               $options['renderType'] = 'inlineRecordContainer';
                                $childArray = $this->nodeFactory->create($options)->render();
                                $html .= $childArray['html'];
                                $childArray['html'] = '';
index bbb5e49..71ee647 100644 (file)
@@ -20,16 +20,11 @@ use TYPO3\CMS\Backend\Form\Element;
 
 /**
  * Create an element object depending on type.
- *
- * @todo: This is currently just a straight ahead approach. A registry should be added allowing
- * @todo: extensions to overwrite existing implementations and all Element and Container classes
- * @todo: should be created through this factory. The factory itself could be added in the constructor
- * @todo: of AbstractNode to have it always available.
  */
 class NodeFactory {
 
        /**
-        * Default registry of node-type to handling class
+        * Default registry of node name to handling class
         *
         * @var array
         */
@@ -62,48 +57,86 @@ class NodeFactory {
                'selectTree' => Element\SelectTreeElement::class,
                'selectSingle' => Element\SelectSingleElement::class,
                'selectSingleBox' => Element\SelectSingleBoxElement::class,
+               // t3editor is defined with a fallback so extensions can use it even if ext:t3editor is not loaded
+               't3editor' => Element\TextElement::class,
                'text' => Element\TextElement::class,
                'unknown' => Element\UnknownElement::class,
                'user' => Element\UserElement::class,
        );
 
        /**
-        * Set up factory
+        * Node resolver classes
+        * Nested array with nodeName as key, (sorted) priority as sub key and class as value
+        *
+        * @var array
+        */
+       protected $nodeResolver = array();
+
+       /**
+        * Set up factory. Initialize additionally registered nodes.
         */
        public function __construct() {
-               // @todo: Add additional base types and override existing types
+               $this->registerAdditionalNodeTypesFromConfiguration();
+               $this->initializeNodeResolver();
        }
 
        /**
-        * Create an element depending on type
+        * Create a node depending on type
         *
         * @param array $globalOptions All information to decide which class should be instantiated and given down to sub nodes
         * @return AbstractNode
         * @throws Exception
         */
        public function create(array $globalOptions) {
-               if (!is_string($globalOptions['type'])) {
-                       throw new Exception('No type definition found', 1431452406);
+               if (empty($globalOptions['renderType'])) {
+                       throw new Exception('No renderType definition found', 1431452406);
                }
-               $type = $globalOptions['type'];
+               $type = $globalOptions['renderType'];
 
                if ($type === 'select') {
                        $config = $globalOptions['parameterArray']['fieldConf']['config'];
-                       $maxitems = (int)$config['maxitems'];
+                       $maxItems = (int)$config['maxitems'];
                        if (isset($config['renderMode']) && $config['renderMode'] === 'tree') {
                                $type = 'selectTree';
-                       } elseif ($maxitems <= 1) {
+                       } elseif ($maxItems <= 1) {
                                $type = 'selectSingle';
                        } elseif (isset($config['renderMode']) && $config['renderMode'] === 'singlebox') {
                                $type = 'selectSingleBox';
                        } elseif (isset($config['renderMode']) && $config['renderMode'] === 'checkbox') {
                                $type = 'selectCheckBox';
                        } else {
+                               // @todo: This "catch all" else should be removed to allow registration of own renderTypes for type=select
                                $type = 'selectMultipleSideBySide';
                        }
                }
 
                $className = isset($this->nodeTypes[$type]) ? $this->nodeTypes[$type] : $this->nodeTypes['unknown'];
+
+               if (!empty($this->nodeResolver[$type])) {
+                       // Resolver with highest priority is called first. If it returns with a new class name,
+                       // it will be taken and loop is aborted, otherwise resolver with next lower priority is called.
+                       foreach ($this->nodeResolver[$type] as $priority => $resolverClassName) {
+                               /** @var NodeResolverInterface $resolver */
+                               $resolver = $this->instantiate($resolverClassName);
+                               if (!$resolver instanceof NodeResolverInterface) {
+                                       throw new Exception(
+                                               'Node resolver for type ' . $type . ' at priority ' . $priority . ' must implement NodeResolverInterface',
+                                               1433157422
+                                       );
+                               }
+                               // Resolver classes do NOT receive the name of the already resolved class. Single
+                               // resolvers should not have dependencies to each other or the default implementation,
+                               // so they also shouldn't know the output of a different resolving class.
+                               // Additionally, the globalOptions array is NOT given by reference here, changing config is a
+                               // task of container classes alone and must not be abused here.
+                               $newClassName = $resolver->setGlobalOptions($globalOptions)->resolve();
+                               if ($newClassName !== NULL) {
+                                       $className = $newClassName;
+                                       break;
+                               }
+                       }
+               }
+
                /** @var AbstractNode $nodeInstance */
                $nodeInstance = $this->instantiate($className);
                if (!$nodeInstance instanceof NodeInterface) {
@@ -113,6 +146,88 @@ class NodeFactory {
        }
 
        /**
+        * Add node types from nodeRegistry to $this->nodeTypes.
+        * This can be used to add new render types or to overwrite existing node types. The registered class must
+        * implement the NodeInterface and will be called if a node with this renderType is rendered.
+        *
+        * @throws Exception if configuration is incomplete or two nodes with identical priorities are registered
+        */
+       protected function registerAdditionalNodeTypesFromConfiguration() {
+               // List of additional or override nodes
+               $registeredTypeOverrides = $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'];
+               // Sanitize input array
+               $registeredPrioritiesForNodeNames = array();
+               foreach ($registeredTypeOverrides as $override) {
+                       if (!isset($override['nodeName']) || !isset($override['class']) || !isset($override['priority'])) {
+                               throw new Exception(
+                                       'Key class, nodeName or priority missing for an entry in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'formEngine\'][\'nodeRegistry\']',
+                                       1432207533
+                               );
+                       }
+                       if ($override['priority'] < 0 || $override['priority'] > 100) {
+                               throw new Exception(
+                                       'Priority of element ' . $override['nodeName'] . ' with class ' . $override['class'] . ' is ' . $override['priority'] . ', but must between 0 and 100',
+                                       1432223531
+                               );
+                       }
+                       if (isset($registeredPrioritiesForNodeNames[$override['nodeName']][$override['priority']])) {
+                               throw new Exception(
+                                       'Element ' . $override['nodeName'] . ' already has an override registered with priority ' . $override['priority'],
+                                       1432223893
+                               );
+                       }
+                       $registeredPrioritiesForNodeNames[$override['nodeName']][$override['priority']] = '';
+               }
+               // Add element with highest priority to registry
+               $highestPriority = array();
+               foreach ($registeredTypeOverrides as $override) {
+                       if (!isset($highestPriority[$override['nodeName']]) || $override['priority'] > $highestPriority[$override['nodeName']]) {
+                               $highestPriority[$override['nodeName']] = $override['priority'];
+                               $this->nodeTypes[$override['nodeName']] = $override['class'];
+                       }
+               }
+       }
+
+       /**
+        * Add resolver and add them sorted to a local property.
+        * This can be used to manipulate the nodeName to class resolution with own code.
+        *
+        * @throws Exception if configuration is incomplete or two resolver with identical priorities are registered
+        */
+       protected function initializeNodeResolver() {
+               // List of node resolver
+               $registeredNodeResolvers = $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'];
+               $resolversByType = array();
+               foreach ($registeredNodeResolvers as $nodeResolver) {
+                       if (!isset($nodeResolver['nodeName']) || !isset($nodeResolver['class']) || !isset($nodeResolver['priority'])) {
+                               throw new Exception(
+                                       'Key class, nodeName or priority missing for an entry in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'formEngine\'][\'nodeResolver\']',
+                                       1433155522
+                               );
+                       }
+                       if ($nodeResolver['priority'] < 0 || $nodeResolver['priority'] > 100) {
+                               throw new Exception(
+                                       'Priority of element ' . $nodeResolver['nodeName'] . ' with class ' . $nodeResolver['class'] . ' is ' . $nodeResolver['priority'] . ', but must between 0 and 100',
+                                       1433155563
+                               );
+                       }
+                       if (isset($resolversByType[$nodeResolver['nodeName']][$nodeResolver['priority']])) {
+                               throw new Exception(
+                                       'Element ' . $nodeResolver['nodeName'] . ' already has a resolver registered with priority ' . $nodeResolver['priority'],
+                                       1433155705
+                               );
+                       }
+                       $resolversByType[$nodeResolver['nodeName']][$nodeResolver['priority']] = $nodeResolver['class'];
+               }
+               $sortedResolversByType = array();
+               foreach ($resolversByType as $nodeName => $prioritiesAndClasses) {
+                       krsort($prioritiesAndClasses);
+                       $sortedResolversByType[$nodeName] = $prioritiesAndClasses;
+               }
+               $this->nodeResolver = $sortedResolversByType;
+       }
+
+       /**
         * Instantiate given class name
         *
         * @param string $className Given class name
diff --git a/typo3/sysext/backend/Classes/Form/NodeResolverInterface.php b/typo3/sysext/backend/Classes/Form/NodeResolverInterface.php
new file mode 100644 (file)
index 0000000..06f6772
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+namespace TYPO3\CMS\Backend\Form;
+
+/*
+ * 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!
+ */
+
+/**
+ * Interface must be implemented by node resolver classes
+ */
+interface NodeResolverInterface {
+
+       /**
+        * Set global options from parent instance
+        *
+        * @param array $globalOptions Global options like 'readonly' for all elements
+        * @return $this
+        */
+       public function setGlobalOptions(array $globalOptions);
+
+       /**
+        * Main resolver method
+        *
+        * @return string|void New class name or void if this resolver does not change current class name.
+        */
+       public function resolve();
+
+}
index f698a07..c2a141e 100644 (file)
@@ -768,9 +768,16 @@ class BackendUtility {
                        $altFieldList = array();
                        // Traverse fields in types config and parse the configuration into a nice array:
                        foreach ($fieldList as $k => $v) {
-                               list($pFieldName, $pAltTitle, $pPalette, $pSpec) = GeneralUtility::trimExplode(';', $v);
-                               $defaultExtras = is_array($GLOBALS['TCA'][$table]['columns'][$pFieldName]) ? $GLOBALS['TCA'][$table]['columns'][$pFieldName]['defaultExtras'] : '';
-                               $specConfParts = self::getSpecConfParts($pSpec, $defaultExtras);
+                               list($pFieldName, $pAltTitle, $pPalette) = GeneralUtility::trimExplode(';', $v);
+                               $defaultExtras = '';
+                               if (!empty($typesConf['columnsOverrides'][$pFieldName]['config']['defaultExtras'])) {
+                                       // Use defaultExtras from columnsOverrides if given
+                                       $defaultExtras = $typesConf['columnsOverrides'][$pFieldName]['config']['defaultExtras'];
+                               } elseif (!empty($GLOBALS['TCA'][$table]['columns'][$pFieldName]['defaultExtras'])) {
+                                       // Use defaultExtras from columns if given
+                                       $defaultExtras = $GLOBALS['TCA'][$table]['columns'][$pFieldName]['defaultExtras'];
+                               }
+                               $specConfParts = self::getSpecConfParts($defaultExtras);
                                $fieldList[$k] = array(
                                        'field' => $pFieldName,
                                        'title' => $pAltTitle,
@@ -859,19 +866,24 @@ class BackendUtility {
        }
 
        /**
-        * Parses a part of the field lists in the "types"-section of $GLOBALS['TCA'] arrays, namely the "special configuration" at index 3 (position 4)
+        * Parses "defaultExtras" of $GLOBALS['TCA'] columns config section to an array.
         * Elements are splitted by ":" and within those parts, parameters are splitted by "|".
-        * Everything is returned in an array and you should rather see it visually than listen to me anymore now...  Check out example in Inside TYPO3
         *
-        * @param string $str Content from the "types" configuration of TCA (the special configuration) - see description of function
-        * @param string $defaultExtras The ['defaultExtras'] value from field configuration
+        * See unit tests for details.
+        *
+        * @param string $defaultExtrasString "defaultExtras" string from columns config
+        * @param string $_ @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8
         * @return array
         */
-       static public function getSpecConfParts($str, $defaultExtras) {
-               // Add defaultExtras:
-               $specConfParts = GeneralUtility::trimExplode(':', $defaultExtras . ':' . $str, TRUE);
+       static public function getSpecConfParts($defaultExtrasString, $_ = '') {
+               if (!empty($_)) {
+                       GeneralUtility::deprecationLog('Second parameter of BackendUtility::getSpecConfParts() is deprecated. Will be removed with TYPO3 CMS 8');
+                       // Prepend old parameter, can be overwritten by casual defaultExtras string, then.
+                       $defaultExtrasString = $_ . ':' . $defaultExtrasString;
+               }
+               $specConfParts = GeneralUtility::trimExplode(':', $defaultExtrasString, TRUE);
                $reg = array();
-               if (count($specConfParts)) {
+               if (!empty($specConfParts)) {
                        foreach ($specConfParts as $k2 => $v2) {
                                unset($specConfParts[$k2]);
                                if (preg_match('/(.*)\\[(.*)\\]/', $v2, $reg)) {
index 83f1096..e5262c6 100644 (file)
@@ -18,6 +18,7 @@ use TYPO3\CMS\Backend\Form\Element;
 use TYPO3\CMS\Core\Tests\UnitTestCase;
 use TYPO3\CMS\Backend\Form\NodeFactory;
 use TYPO3\CMS\Backend\Form\NodeInterface;
+use TYPO3\CMS\Backend\Form\NodeResolverInterface;
 
 /**
  * Test case
@@ -27,8 +28,224 @@ class NodeFactoryTest extends UnitTestCase {
        /**
         * @test
         * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1432207533
         */
-       public function createThrowsExceptionIfTypeIsNotGiven() {
+       public function constructThrowsExceptionIfOverrideMissesNodeNameKey() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       1433089391 => array(
+                               'class' => 'foo',
+                               'priority' => 23,
+                       ),
+               );
+               new NodeFactory();
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1432207533
+        */
+       public function constructThrowsExceptionIfOverrideMissesPriorityKey() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       1433089393 => array(
+                               'nodeName' => 'foo',
+                               'class' => 'bar',
+                       ),
+               );
+               new NodeFactory();
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1432207533
+        */
+       public function constructThrowsExceptionIfOverrideMissesClassKey() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       1433089392 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 23,
+                       ),
+               );
+               new NodeFactory();
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1432223531
+        */
+       public function constructThrowsExceptionIfOverridePriorityIsLowerThanZero() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       1433089394 => array(
+                               'nodeName' => 'foo',
+                               'class' => 'bar',
+                               'priority' => -23,
+                       ),
+               );
+               new NodeFactory();
+
+       }
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1432223531
+        */
+       public function constructThrowsExceptionIfOverridePriorityIsHigherThanHundred() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       1433089395 => array(
+                               'nodeName' => 'foo',
+                               'class' => 'bar',
+                               'priority' => 142,
+                       ),
+               );
+               new NodeFactory();
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1432223893
+        */
+       public function constructorThrowsExceptionIfOverrideTwoNodesWithSamePriorityAndSameNodeNameAreRegistered() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       1433089396 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 20,
+                               'class' => 'fooClass',
+                       ),
+                       1433089397 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 20,
+                               'class' => 'barClass',
+                       ),
+               );
+               new NodeFactory();
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1433155522
+        */
+       public function constructThrowsExceptionIfResolverMissesNodeNameKey() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'] = array(
+                       1433154905 => array(
+                               'class' => 'foo',
+                               'priority' => 23,
+                       ),
+               );
+               new NodeFactory();
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1433155522
+        */
+       public function constructThrowsExceptionIfResolverMissesPriorityKey() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'] = array(
+                       1433154905 => array(
+                               'nodeName' => 'foo',
+                               'class' => 'bar',
+                       ),
+               );
+               new NodeFactory();
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1433155522
+        */
+       public function constructThrowsExceptionIfResolverMissesClassKey() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'] = array(
+                       1433154906 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 23,
+                       ),
+               );
+               new NodeFactory();
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1433155563
+        */
+       public function constructThrowsExceptionIfResolverPriorityIsLowerThanZero() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'] = array(
+                       1433154907 => array(
+                               'nodeName' => 'foo',
+                               'class' => 'bar',
+                               'priority' => -23,
+                       ),
+               );
+               new NodeFactory();
+
+       }
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1433155563
+        */
+       public function constructThrowsExceptionIfResolverPriorityIsHigherThanHundred() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'] = array(
+                       1433154908 => array(
+                               'nodeName' => 'foo',
+                               'class' => 'bar',
+                               'priority' => 142,
+                       ),
+               );
+               new NodeFactory();
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1433155705
+        */
+       public function constructorThrowsExceptionIfResolverTwoNodesWithSamePriorityAndSameNodeNameAreRegistered() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'] = array(
+                       1433154909 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 20,
+                               'class' => 'fooClass',
+                       ),
+                       1433154910 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 20,
+                               'class' => 'barClass',
+                       ),
+               );
+               new NodeFactory();
+       }
+
+       /**
+        * @test
+        */
+       public function constructorThrowsNoExceptionIfResolverWithSamePriorityButDifferentNodeNameAreRegistered() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'] = array(
+                       1433154909 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 20,
+                               'class' => 'fooClass',
+                       ),
+                       1433154910 => array(
+                               'nodeName' => 'bar',
+                               'priority' => 20,
+                               'class' => 'barClass',
+                       ),
+               );
+               new NodeFactory();
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1431452406
+        */
+       public function createThrowsExceptionIfRenderTypeIsNotGiven() {
                $subject = new NodeFactory();
                $subject->create(array());
        }
@@ -36,23 +253,24 @@ class NodeFactoryTest extends UnitTestCase {
        /**
         * @test
         * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1431872546
         */
        public function createThrowsExceptionIfNodeDoesNotImplementNodeInterface() {
                $mockNode = new \stdClass();
-               /** @var NodeInterface|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
+               /** @var NodeFactory|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
                $mockSubject = $this->getMock(NodeFactory::class, array('instantiate'), array(), '', FALSE);
                $mockSubject->expects($this->once())->method('instantiate')->will($this->returnValue($mockNode));
-               $mockSubject->create(array('type' => 'foo'));
+               $mockSubject->create(array('renderType' => 'foo'));
        }
 
        /**
         * @test
         */
        public function createSetsGlobalOptionsInInstantiatedObject() {
-               $globalOptions = array('type' => 'foo');
+               $globalOptions = array('renderType' => 'foo');
                $mockNode = $this->getMock(NodeInterface::class, array(), array(), '', FALSE);
                $mockNode->expects($this->once())->method('setGlobalOptions')->with($globalOptions);
-               /** @var NodeInterface|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
+               /** @var NodeFactory|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
                $mockSubject = $this->getMock(NodeFactory::class, array('instantiate'), array(), '', FALSE);
                $mockSubject->expects($this->once())->method('instantiate')->will($this->returnValue($mockNode));
                $mockSubject->create($globalOptions);
@@ -63,7 +281,7 @@ class NodeFactoryTest extends UnitTestCase {
         */
        public function createReturnsInstanceOfUnknownElementIfTypeIsNotRegistered() {
                $subject = new NodeFactory();
-               $this->assertInstanceOf(Element\UnknownElement::class, $subject->create(array('type' => 'foo')));
+               $this->assertInstanceOf(Element\UnknownElement::class, $subject->create(array('renderType' => 'foo')));
        }
 
        /**
@@ -71,7 +289,7 @@ class NodeFactoryTest extends UnitTestCase {
         */
        public function createReturnsInstanceOfSelectTreeElementIfNeeded() {
                $globalOptions = array(
-                       'type' => 'select',
+                       'renderType' => 'select',
                        'parameterArray' => array(
                                'fieldConf' => array(
                                        'config' => array(
@@ -89,7 +307,7 @@ class NodeFactoryTest extends UnitTestCase {
         */
        public function createReturnsInstanceOfSelectSingleElementIfNeeded() {
                $globalOptions = array(
-                       'type' => 'select',
+                       'renderType' => 'select',
                        'parameterArray' => array(
                                'fieldConf' => array(
                                        'config' => array(
@@ -107,7 +325,7 @@ class NodeFactoryTest extends UnitTestCase {
         */
        public function createReturnsInstanceOfSelectSingleElementIfSelectboxIsConfiguredButMaxitemsIsOne() {
                $globalOptions = array(
-                       'type' => 'select',
+                       'renderType' => 'select',
                        'parameterArray' => array(
                                'fieldConf' => array(
                                        'config' => array(
@@ -126,7 +344,7 @@ class NodeFactoryTest extends UnitTestCase {
         */
        public function createReturnsInstanceOfSelectSingleElementIfCheckboxIsConfiguredButMaxitemsIsOne() {
                $globalOptions = array(
-                       'type' => 'select',
+                       'renderType' => 'select',
                        'parameterArray' => array(
                                'fieldConf' => array(
                                        'config' => array(
@@ -145,7 +363,7 @@ class NodeFactoryTest extends UnitTestCase {
         */
        public function createReturnsInstanceOfSelectSingleBoxElementIfNeeded() {
                $globalOptions = array(
-                       'type' => 'select',
+                       'renderType' => 'select',
                        'parameterArray' => array(
                                'fieldConf' => array(
                                        'config' => array(
@@ -164,7 +382,7 @@ class NodeFactoryTest extends UnitTestCase {
         */
        public function createReturnsInstanceOfSelectCheckBoxElementIfNeeded() {
                $globalOptions = array(
-                       'type' => 'select',
+                       'renderType' => 'select',
                        'parameterArray' => array(
                                'fieldConf' => array(
                                        'config' => array(
@@ -183,7 +401,7 @@ class NodeFactoryTest extends UnitTestCase {
         */
        public function createReturnsInstanceOfSelectMultipleSideBySideElementIfNeeded() {
                $globalOptions = array(
-                       'type' => 'select',
+                       'renderType' => 'select',
                        'parameterArray' => array(
                                'fieldConf' => array(
                                        'config' => array(
@@ -196,4 +414,240 @@ class NodeFactoryTest extends UnitTestCase {
                $this->assertInstanceOf(Element\SelectMultipleSideBySideElement::class, $subject->create($globalOptions));
        }
 
+       /**
+        * @test
+        */
+       public function createInstantiatesNewRegisteredElement() {
+               $globalOptions = array('renderType' => 'foo');
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       array(
+                               'nodeName' => 'foo',
+                               'priority' => 20,
+                               'class' => \stdClass::class,
+                       ),
+               );
+               $mockNode = $this->getMock(NodeInterface::class, array(), array(), '', FALSE);
+               /** @var NodeFactory|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
+               $mockSubject = $this->getMock(NodeFactory::class, array('instantiate'));
+               $mockSubject->expects($this->once())->method('instantiate')->with('stdClass')->will($this->returnValue($mockNode));
+               $mockSubject->create($globalOptions);
+       }
+
+       /**
+        * @test
+        */
+       public function createInstantiatesElementRegisteredWithHigherPriorityWithOneGivenOrder() {
+               $globalOptions = array('renderType' => 'foo');
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       1433089467 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 20,
+                               'class' => 'foo1Class',
+                       ),
+                       1433089468 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 30,
+                               'class' => 'foo2Class',
+                       ),
+               );
+               $mockNode = $this->getMock(NodeInterface::class, array(), array(), '', FALSE);
+               /** @var NodeFactory|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
+               $mockSubject = $this->getMock(NodeFactory::class, array('instantiate'));
+               $mockSubject->expects($this->once())->method('instantiate')->with('foo2Class')->will($this->returnValue($mockNode));
+               $mockSubject->create($globalOptions);
+       }
+
+       /**
+        * @test
+        */
+       public function createInstantiatesElementRegisteredWithHigherPriorityWithOtherGivenOrder() {
+               $globalOptions = array('renderType' => 'foo');
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       1433089469 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 30,
+                               'class' => 'foo2Class',
+                       ),
+                       1433089470 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 20,
+                               'class' => 'foo1Class',
+                       ),
+               );
+               $mockNode = $this->getMock(NodeInterface::class, array(), array(), '', FALSE);
+               /** @var NodeFactory|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
+               $mockSubject = $this->getMock(NodeFactory::class, array('instantiate'));
+               $mockSubject->expects($this->once())->method('instantiate')->with('foo2Class')->will($this->returnValue($mockNode));
+               $mockSubject->create($globalOptions);
+       }
+
+       /**
+        * @test
+        * @expectedException \TYPO3\CMS\Backend\Form\Exception
+        * @expectedExceptionCode 1433157422
+        */
+       public function createThrowsExceptionIfResolverDoesNotImplementNodeResolverInterface() {
+               $globalOptions = array('renderType' => 'foo');
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'] = array(
+                       1433156887 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 10,
+                               'class' => 'fooClass',
+                       ),
+               );
+               $mockResolver = $this->getMock(\stdClass::class);
+
+               /** @var NodeFactory|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
+               $mockSubject = $this->getMock(NodeFactory::class, array('instantiate'));
+               $mockSubject->expects($this->at(0))->method('instantiate')->will($this->returnValue($mockResolver));
+               $mockSubject->create($globalOptions);
+       }
+
+       /**
+        * @test
+        */
+       public function createInstantiatesResolverWithHighestPriorityFirstWithOneGivenOrder() {
+               $globalOptions = array('renderType' => 'foo');
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       array(
+                               'nodeName' => 'foo',
+                               'priority' => 20,
+                               'class' => \stdClass::class,
+                       ),
+               );
+               $mockNode = $this->getMock(NodeInterface::class, array(), array(), '', FALSE);
+
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'] = array(
+                       1433156887 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 10,
+                               'class' => 'foo1Class',
+                       ),
+                       1433156888 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 30,
+                               'class' => 'foo2Class',
+                       ),
+               );
+               $mockResolver1 = $this->getMock(NodeResolverInterface::class);
+               $mockResolver1->expects($this->once())->method('setGlobalOptions')->will($this->returnValue($mockResolver1));
+               $mockResolver2 = $this->getMock(NodeResolverInterface::class);
+               $mockResolver2->expects($this->once())->method('setGlobalOptions')->will($this->returnValue($mockResolver2));
+
+               /** @var NodeFactory|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
+               $mockSubject = $this->getMock(NodeFactory::class, array('instantiate'));
+               $mockSubject->expects($this->at(0))->method('instantiate')->with('foo2Class')->will($this->returnValue($mockResolver2));
+               $mockSubject->expects($this->at(1))->method('instantiate')->with('foo1Class')->will($this->returnValue($mockResolver1));
+               $mockSubject->expects($this->at(2))->method('instantiate')->will($this->returnValue($mockNode));
+               $mockSubject->create($globalOptions);
+       }
+
+       /**
+        * @test
+        */
+       public function createInstantiatesResolverWithHighestPriorityFirstWithOtherGivenOrder() {
+               $globalOptions = array('renderType' => 'foo');
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       array(
+                               'nodeName' => 'foo',
+                               'priority' => 20,
+                               'class' => \stdClass::class,
+                       ),
+               );
+               $mockNode = $this->getMock(NodeInterface::class, array(), array(), '', FALSE);
+
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'] = array(
+                       1433156887 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 30,
+                               'class' => 'foo1Class',
+                       ),
+                       1433156888 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 10,
+                               'class' => 'foo2Class',
+                       ),
+               );
+               $mockResolver1 = $this->getMock(NodeResolverInterface::class);
+               $mockResolver1->expects($this->once())->method('setGlobalOptions')->will($this->returnValue($mockResolver1));
+               $mockResolver2 = $this->getMock(NodeResolverInterface::class);
+               $mockResolver2->expects($this->once())->method('setGlobalOptions')->will($this->returnValue($mockResolver2));
+
+               /** @var NodeFactory|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
+               $mockSubject = $this->getMock(NodeFactory::class, array('instantiate'));
+               $mockSubject->expects($this->at(0))->method('instantiate')->with('foo1Class')->will($this->returnValue($mockResolver1));
+               $mockSubject->expects($this->at(1))->method('instantiate')->with('foo2Class')->will($this->returnValue($mockResolver2));
+               $mockSubject->expects($this->at(2))->method('instantiate')->will($this->returnValue($mockNode));
+               $mockSubject->create($globalOptions);
+       }
+
+       /**
+        * @test
+        */
+       public function createInstantiatesNodeClassReturnedByResolver() {
+               $globalOptions = array('renderType' => 'foo');
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       array(
+                               'nodeName' => 'foo',
+                               'priority' => 20,
+                               'class' => \stdClass::class,
+                       ),
+               );
+               $mockNode = $this->getMock(NodeInterface::class, array(), array(), '', FALSE);
+
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'] = array(
+                       1433156887 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 30,
+                               'class' => 'foo1Class',
+                       ),
+               );
+               $mockResolver1 = $this->getMock(NodeResolverInterface::class);
+               $mockResolver1->expects($this->once())->method('setGlobalOptions')->will($this->returnValue($mockResolver1));
+               $mockResolver1->expects($this->once())->method('resolve')->will($this->returnValue('fooNodeClass'));
+
+               /** @var NodeFactory|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
+               $mockSubject = $this->getMock(NodeFactory::class, array('instantiate'));
+               $mockSubject->expects($this->at(0))->method('instantiate')->will($this->returnValue($mockResolver1));
+               $mockSubject->expects($this->at(1))->method('instantiate')->with('fooNodeClass')->will($this->returnValue($mockNode));
+               $mockSubject->create($globalOptions);
+       }
+
+       /**
+        * @test
+        */
+       public function createDoesNotCallSecondResolverWithLowerPriorityIfFirstResolverReturnedClassName() {
+               $globalOptions = array('renderType' => 'foo');
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'] = array(
+                       array(
+                               'nodeName' => 'foo',
+                               'priority' => 20,
+                               'class' => \stdClass::class,
+                       ),
+               );
+               $mockNode = $this->getMock(NodeInterface::class, array(), array(), '', FALSE);
+
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'] = array(
+                       1433156887 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 30,
+                               'class' => 'foo1Class',
+                       ),
+                       1433156888 => array(
+                               'nodeName' => 'foo',
+                               'priority' => 10,
+                               'class' => 'foo2Class',
+                       ),
+               );
+               $mockResolver1 = $this->getMock(NodeResolverInterface::class);
+               $mockResolver1->expects($this->once())->method('setGlobalOptions')->will($this->returnValue($mockResolver1));
+               $mockResolver1->expects($this->once())->method('resolve')->will($this->returnValue('fooNodeClass'));
+
+               /** @var NodeFactory|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
+               $mockSubject = $this->getMock(NodeFactory::class, array('instantiate'));
+               $mockSubject->expects($this->at(0))->method('instantiate')->with('foo1Class')->will($this->returnValue($mockResolver1));
+               $mockSubject->expects($this->at(1))->method('instantiate')->with('fooNodeClass')->will($this->returnValue($mockNode));
+               $mockSubject->create($globalOptions);
+       }
+
 }
index f7d961d..9271496 100644 (file)
@@ -1458,4 +1458,30 @@ class BackendUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                $this->assertSame($expected, $subject->_call('replaceL10nModeFields', $table, $row));
        }
 
+       /**
+        * @test
+        */
+       public function getSpecConfPartsSplitsDefaultExtras() {
+               $defaultExtras = 'nowrap:wizards[foo|bar]:anotherDefaultExtras:some[other|setting|with|parameters]';
+               $expected = array(
+                       'nowrap' => 1,
+                       'wizards' => array(
+                               'parameters' => array(
+                                       0 => 'foo',
+                                       1 => 'bar',
+                               ),
+                       ),
+                       'anotherDefaultExtras' => 1,
+                       'some' => array(
+                               'parameters' => array(
+                                       0 => 'other',
+                                       1 => 'setting',
+                                       2 => 'with',
+                                       3 => 'parameters',
+                               ),
+                       ),
+               );
+               $this->assertEquals($expected, BackendUtility::getSpecConfParts($defaultExtras));
+       }
+
 }
diff --git a/typo3/sysext/compatibility6/Classes/Hooks/ExtTablesPostProcessing/TcaMigration.php b/typo3/sysext/compatibility6/Classes/Hooks/ExtTablesPostProcessing/TcaMigration.php
new file mode 100644 (file)
index 0000000..7e9ed29
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+namespace TYPO3\CMS\Compatibility6\Hooks\ExtTablesPostProcessing;
+
+/*
+ * 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\Database\TableConfigurationPostProcessingHookInterface;
+use TYPO3\Cms\Core\Utility\GeneralUtility;
+
+/**
+ * Migrate TCA that was added by extensions in ext_tables.php
+ *
+ * This is deprecated, all extensions should register / manipulate TCA in Configuration/TCA nowadays.
+ */
+class TcaMigration implements TableConfigurationPostProcessingHookInterface {
+
+       /**
+        * Run migration dynamically a second time on *every* request.
+        * This can not be cached and is slow.
+        *
+        * @return void
+        */
+       public function processData() {
+               /** @var \TYPO3\CMS\Core\Migrations\TcaMigration $tcaMigration */
+               $tcaMigration = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Migrations\TcaMigration::class);
+               $GLOBALS['TCA'] = $tcaMigration->migrate($GLOBALS['TCA']);
+               $messages = $tcaMigration->getMessages();
+               if (!empty($messages)) {
+                       $context = 'ext:compatibility6 did an automatic migration of TCA during boostrap. This costs performance on every'
+                               . ' call. It also means some old extensions register TCA in ext_tables.php and not in Configuration/TCA.'
+                               . ' Please adapt TCA accordingly until this message is not thrown anymore and unload extension compatibility6'
+                               . ' as soon as possible';
+                       array_unshift($messages, $context);
+                       GeneralUtility::deprecationLog(implode(LF, $messages));
+               }
+
+       }
+}
index e354a50..620823e 100644 (file)
@@ -338,7 +338,7 @@ $GLOBALS['TCA']['tt_content']['types']['mailform'] = array(
        'showitem' => '
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.header;header,
-               bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext.ALT.mailform_formlabel;;nowrap:wizards[forms],
+               bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext.ALT.mailform_formlabel,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.appearance,
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.frames;frames,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access,
@@ -348,6 +348,18 @@ $GLOBALS['TCA']['tt_content']['types']['mailform'] = array(
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.mailform;mailform,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.extended'
 );
+$baseDefaultExtrasOfBodytext = '';
+if (!empty($GLOBALS['TCA']['tt_content']['columns']['bodytext']['defaultExtras'])) {
+       $baseDefaultExtrasOfBodytext = $GLOBALS['TCA']['tt_content']['columns']['bodytext']['defaultExtras'] . ':';
+}
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides'])) {
+       $GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides'] = array();
+}
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides']['bodytext'])) {
+       $GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides']['bodytext'] = array();
+}
+$GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides']['bodytext']['defaultExtras'] = $baseDefaultExtrasOfBodytext . 'nowrap:wizards[forms]';
+
 $GLOBALS['TCA']['tt_content']['palettes']['mailform'] = array(
        'showitem' => 'pages;LLL:EXT:cms/locallang_ttc.xlf:pages.ALT.mailform, --linebreak--, subheader;LLL:EXT:cms/locallang_ttc.xlf:subheader.ALT.mailform_formlabel',
        'canNotCollapse' => 1
index de45aeb..3ecee91 100644 (file)
@@ -1124,7 +1124,6 @@ return array(
        'tx_rtehtmlarea_parse_html' => \TYPO3\CMS\Rtehtmlarea\Controller\ParseHtmlController::class,
        'tx_rtehtmlarea_SC_browse_links' => \TYPO3\CMS\Rtehtmlarea\Controller\BrowseLinksController::class,
        'tx_rtehtmlarea_pi3' => \TYPO3\CMS\Rtehtmlarea\Controller\CustomAttributeController::class,
-       'tx_rtehtmlarea_pi2' => \TYPO3\CMS\Rtehtmlarea\Controller\FrontendRteController::class,
        'tx_rtehtmlarea_SC_select_image' => \TYPO3\CMS\Rtehtmlarea\Controller\SelectImageController::class,
        'tx_rtehtmlarea_pi1' => \TYPO3\CMS\Rtehtmlarea\Controller\SpellCheckingController::class,
        'tx_rtehtmlarea_abouteditor' => \TYPO3\CMS\Rtehtmlarea\Extension\AboutEditor::class,
@@ -1210,7 +1209,6 @@ return array(
        'tx_sysaction_list' => \TYPO3\CMS\SysAction\ActionList::class,
        'tx_sysaction_task' => \TYPO3\CMS\SysAction\ActionTask::class,
        'tx_t3editor_codecompletion' => \TYPO3\CMS\T3editor\CodeCompletion::class,
-       'tx_t3editor_tceforms_wizard' => \TYPO3\CMS\T3editor\FormWizard::class,
        'tx_t3editor_hooks_fileedit' => \TYPO3\CMS\T3editor\Hook\FileEditHook::class,
        'tx_t3editor_hooks_tstemplateinfo' => \TYPO3\CMS\T3editor\Hook\TypoScriptTemplateInfoHook::class,
        'tx_t3editor' => \TYPO3\CMS\T3editor\T3editor::class,
index 7f26d4d..8981d63 100644 (file)
@@ -5589,11 +5589,6 @@ class tx_rtehtmlarea_pi3 extends \TYPO3\CMS\Rtehtmlarea\Controller\CustomAttribu
 /**
  * @deprecated since 6.0, removed since 7.0
  */
-class tx_rtehtmlarea_pi2 extends \TYPO3\CMS\Rtehtmlarea\Controller\FrontendRteController {}
-
-/**
- * @deprecated since 6.0, removed since 7.0
- */
 class tx_rtehtmlarea_SC_select_image extends \TYPO3\CMS\Rtehtmlarea\Controller\SelectImageController {}
 
 /**
@@ -6014,11 +6009,6 @@ class tx_t3editor_codecompletion extends \TYPO3\CMS\T3editor\CodeCompletion {}
 /**
  * @deprecated since 6.0, removed since 7.0
  */
-class tx_t3editor_tceforms_wizard extends \TYPO3\CMS\T3editor\FormWizard {}
-
-/**
- * @deprecated since 6.0, removed since 7.0
- */
 class tx_t3editor_hooks_fileedit extends \TYPO3\CMS\T3editor\Hook\FileEditHook {}
 
 /**
index 0b9021c..e73f434 100644 (file)
@@ -1,6 +1,12 @@
 <?php
 defined('TYPO3_MODE') or die();
 
+// TCA migration if TCA registration still happened in ext_tables.php
+if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'])) {
+       $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'] = array();
+}
+$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'][] = \TYPO3\CMS\Compatibility6\Hooks\ExtTablesPostProcessing\TcaMigration::class;
+
 if (TYPO3_MODE === 'FE') {
 
        // Register legacy content objects
index b94ee4e..8da1464 100644 (file)
@@ -2959,7 +2959,7 @@ class DataHandler {
                                                                                // Calculating/Retrieving some values here:
                                                                                list(, , $recFieldName) = explode(':', $CVrecFID);
                                                                                $theTypeString = BackendUtility::getTCAtypeValue($CVtable, $this->checkValue_currentRecord);
-                                                                               $specConf = BackendUtility::getSpecConfParts('', $dsConf['TCEforms']['defaultExtras']);
+                                                                               $specConf = BackendUtility::getSpecConfParts($dsConf['TCEforms']['defaultExtras']);
                                                                                // Find, thisConfig:
                                                                                $RTEsetup = $this->BE_USER->getTSConfig('RTE', BackendUtility::getPagesTSconfig($CVtscPID));
                                                                                $thisConfig = BackendUtility::RTEsetup($RTEsetup['properties'], $CVtable, $recFieldName, $theTypeString);
diff --git a/typo3/sysext/core/Classes/Migrations/TcaMigration.php b/typo3/sysext/core/Classes/Migrations/TcaMigration.php
new file mode 100644 (file)
index 0000000..9f15eb0
--- /dev/null
@@ -0,0 +1,272 @@
+<?php
+namespace TYPO3\CMS\Core\Migrations;
+
+/*
+ * 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;
+
+/**
+ * Migrate TCA from old to new syntax. Used in bootstrap and Flex Form Data Structures.
+ *
+ * @internal Class and API may change any time.
+ */
+class TcaMigration {
+
+       /**
+        * Accumulate migration messages
+        *
+        * @var array
+        */
+       protected $messages = array();
+
+       /**
+        * Migrate old TCA to new TCA.
+        *
+        * See unit tests for details.
+        *
+        * @param array $tca
+        * @return array
+        */
+       public function migrate(array $tca) {
+               $tca = $this->migrateT3editorWizardToRenderTypeT3editorIfNotEnabledByTypeConfig($tca);
+               $tca = $this->migrateSpecialConfigurationAndRemoveShowItemStylePointerConfig($tca);
+               $tca = $this->migrateT3editorWizardWithEnabledByTypeConfigToColumnsOverrides($tca);
+               // @todo: if showitem/defaultExtras wizards[xy] is migrated to columnsOverrides here, enableByTypeConfig could be dropped
+               return $tca;
+       }
+
+       /**
+        * Get messages of migrated fields. Can be used for deprecation messages after migrate() was called.
+        *
+        * @return array Migration messages
+        */
+       public function getMessages() {
+               return $this->messages;
+       }
+
+       /**
+        * Migrate type=text field with t3editor wizard to renderType=t3editor without this wizard
+        *
+        * @param array $tca Incoming TCA
+        * @return array Migrated TCA
+        */
+       protected function migrateT3editorWizardToRenderTypeT3editorIfNotEnabledByTypeConfig(array $tca) {
+               $newTca = $tca;
+               foreach ($tca as $table => $tableDefinition) {
+                       if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
+                               continue;
+                       }
+                       foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
+                               if (
+                                       !empty($fieldConfig['config']['type']) // type is set
+                                       && trim($fieldConfig['config']['type']) === 'text' // to "text"
+                                       && isset($fieldConfig['config']['wizards'])
+                                       && is_array($fieldConfig['config']['wizards']) // and there are wizards
+                               ) {
+                                       foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
+                                               if (
+                                                       !empty($wizardConfig['userFunc']) // a userFunc is defined
+                                                       && trim($wizardConfig['userFunc']) === 'TYPO3\\CMS\\T3editor\\FormWizard->main' // and set to FormWizard
+                                                       && (
+                                                               !isset($wizardConfig['enableByTypeConfig']) // and enableByTypeConfig is not set
+                                                               || (isset($wizardConfig['enableByTypeConfig']) && !$wizardConfig['enableByTypeConfig'])  // or set, but not enabled
+                                                       )
+                                               ) {
+                                                       // Set renderType from text to t3editor
+                                                       $newTca[$table]['columns'][$fieldName]['config']['renderType'] = 't3editor';
+                                                       // Unset this wizard definition
+                                                       unset($newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]);
+                                                       // Move format parameter
+                                                       if (!empty($wizardConfig['params']['format'])) {
+                                                               $newTca[$table]['columns'][$fieldName]['config']['format'] = $wizardConfig['params']['format'];
+                                                       }
+                                                       $this->messages[] = 'Migrated t3editor wizard in TCA of table ' . $table . ' field ' . $fieldName . ' to a renderType definition.';
+                                               }
+                                       }
+                                       // If no wizard is left after migration, unset the whole sub array
+                                       if (empty($newTca[$table]['columns'][$fieldName]['config']['wizards'])) {
+                                               unset($newTca[$table]['columns'][$fieldName]['config']['wizards']);
+                                       }
+                               }
+                       }
+               }
+               return $newTca;
+       }
+
+       /**
+        * Remove "style pointer", the 5th parameter from "types" "showitem" configuration.
+        * Move "specConf", 4th parameter from "tyes" "showitem" to "types" "columnsOverrides.
+        *
+        * @param array $tca Incoming TCA
+        * @return array Modified TCA
+        */
+       protected function migrateSpecialConfigurationAndRemoveShowItemStylePointerConfig(array $tca) {
+               $newTca = $tca;
+               foreach ($tca as $table => $tableDefinition) {
+                       if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
+                               continue;
+                       }
+                       foreach ($tableDefinition['types'] as $typeName => $typeArray) {
+                               if (!is_string($typeArray['showitem']) || strpos($typeArray['showitem'], ';') === FALSE) {
+                                       // Continue directly if no semicolon is found
+                                       continue;
+                               }
+                               $itemList = GeneralUtility::trimExplode(',', $typeArray['showitem'], TRUE);
+                               $newFieldStrings = array();
+                               foreach ($itemList as $fieldString) {
+                                       // Unpack the field definition, migrate and remove as much as possible
+                                       // Keep empty parameters in trimExplode here (third parameter FALSE), so position is not changed
+                                       $fieldArray = GeneralUtility::trimExplode(';', $fieldString);
+                                       $fieldArray = array(
+                                               'fieldName' => isset($fieldArray[0]) ? $fieldArray[0] : '',
+                                               'fieldLabel' => isset($fieldArray[1]) ? $fieldArray[1] : NULL,
+                                               'paletteName' => isset($fieldArray[2]) ? $fieldArray[2] : NULL,
+                                               'fieldExtra' => isset($fieldArray[3]) ? $fieldArray[3] : NULL,
+                                       );
+                                       if (!empty($fieldArray['fieldExtra'])) {
+                                               // Move fieldExtra "specConf" to columnsOverrides "defaultExtras"
+                                               if (!isset($newTca[$table]['types'][$typeName]['columnsOverrides'])) {
+                                                       $newTca[$table]['types'][$typeName]['columnsOverrides'] = array();
+                                               }
+                                               if (!isset($newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']])) {
+                                                       $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']] = array();
+                                               }
+                                               // Merge with given defaultExtras from columns.
+                                               // They will be the first part of the string, so if "specConf" from types changes the same settings,
+                                               // those will override settings from defaultExtras of columns
+                                               $newDefaultExtras = array();
+                                               if (!empty($tca[$table]['columns'][$fieldArray['fieldName']]['defaultExtras'])) {
+                                                       $newDefaultExtras[] = $tca[$table]['columns'][$fieldArray['fieldName']]['defaultExtras'];
+                                               }
+                                               $newDefaultExtras[] = $fieldArray['fieldExtra'];
+                                               $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldArray['fieldName']]['defaultExtras'] = implode(':', $newDefaultExtras);
+                                       }
+                                       unset($fieldArray['fieldExtra']);
+                                       if (count($fieldArray) === 3 && empty($fieldArray['paletteName'])) {
+                                               unset($fieldArray['paletteName']);
+                                       }
+                                       if (count($fieldArray) === 2 && empty($fieldArray['fieldLabel'])) {
+                                               unset($fieldArray['fieldLabel']);
+                                       }
+                                       if (count($fieldArray) === 1 && empty($fieldArray['fieldName'])) {
+                                               // The field may vanish if nothing is left
+                                               unset($fieldArray['fieldName']);
+                                       }
+                                       $newFieldString = implode(';', $fieldArray);
+                                       if ($newFieldString !== $fieldString) {
+                                               $this->messages[] = 'Changed showitem string of TCA table ' . $table . ' type ' . $typeName . '.';
+                                       }
+                                       if (!empty($newFieldString)) {
+                                               $newFieldStrings[] = $newFieldString;
+                                       }
+                               }
+                               $newTca[$table]['types'][$typeName]['showitem'] = implode(',', $newFieldStrings);
+                       }
+               }
+               return $newTca;
+       }
+
+       /**
+        * Migrate type=text field with t3editor wizard that is "enableByTypeConfig" to columnsOverrides
+        * with renderType=t3editor
+        *
+        * @param array $tca Incoming TCA
+        * @return array Migrated TCA
+        */
+       protected function migrateT3editorWizardWithEnabledByTypeConfigToColumnsOverrides(array $tca) {
+               $newTca = $tca;
+               foreach ($tca as $table => $tableDefinition) {
+                       if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
+                               continue;
+                       }
+                       foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) {
+                               if (
+                                       !empty($fieldConfig['config']['type']) // type is set
+                                       && trim($fieldConfig['config']['type']) === 'text' // to "text"
+                                       && isset($fieldConfig['config']['wizards'])
+                                       && is_array($fieldConfig['config']['wizards']) // and there are wizards
+                               ) {
+                                       foreach ($fieldConfig['config']['wizards'] as $wizardName => $wizardConfig) {
+                                               if (
+                                                       !empty($wizardConfig['userFunc']) // a userFunc is defined
+                                                       && trim($wizardConfig['userFunc']) === 'TYPO3\CMS\T3editor\FormWizard->main' // and set to FormWizard
+                                                       && !empty($wizardConfig['enableByTypeConfig']) // and enableByTypeConfig is enabled
+                                               ) {
+                                                       // Remove this wizard
+                                                       unset($newTca[$table]['columns'][$fieldName]['config']['wizards'][$wizardName]);
+                                                       // Find configured types that use this wizard
+                                                       if (!isset($tableDefinition['types']) || !is_array($tableDefinition['types'])) {
+                                                               // No type definition at all ... continue directly
+                                                               continue;
+                                                       }
+                                                       foreach ($tableDefinition['types'] as $typeName => $typeArray) {
+                                                               if (
+                                                                       empty($typeArray['columnsOverrides'][$fieldName]['defaultExtras'])
+                                                                       || strpos($typeArray['columnsOverrides'][$fieldName]['defaultExtras'], $wizardName) === FALSE
+                                                               ) {
+                                                                       // Continue directly if this wizard is not enabled for given type
+                                                                       continue;
+                                                               }
+                                                               $defaultExtras = $typeArray['columnsOverrides'][$fieldName]['defaultExtras'];
+                                                               $defaultExtrasArray = GeneralUtility::trimExplode(':', $defaultExtras, TRUE);
+                                                               $newDefaultExtrasArray = array();
+                                                               foreach ($defaultExtrasArray as $fieldExtraField) {
+                                                                       // There might be multiple enabled wizards separated by | ... split them
+                                                                       if (substr($fieldExtraField, 0, 8) === 'wizards[') {
+                                                                               $enabledWizards = substr($fieldExtraField, 8, strlen($fieldExtraField) - 8); // Cut off "wizards[
+                                                                               $enabledWizards = substr($enabledWizards, 0, strlen($enabledWizards) - 1);
+                                                                               $enabledWizardsArray = GeneralUtility::trimExplode('|', $enabledWizards, TRUE);
+                                                                               $newEnabledWizardsArray = array();
+                                                                               foreach ($enabledWizardsArray as $enabledWizardName) {
+                                                                                       if ($enabledWizardName === $wizardName) {
+                                                                                               // Found a columnsOverrides configuration that has this wizard enabled
+                                                                                               // Force renderType = t3editor
+                                                                                               $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['config']['renderType'] = 't3editor';
+                                                                                               // Transfer format option if given
+                                                                                               if (!empty($wizardConfig['params']['format'])) {
+                                                                                                       $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['config']['format'] = $wizardConfig['params']['format'];
+                                                                                               }
+                                                                                               $this->messages[] = 'Migrated t3editor wizard in TCA of table ' . $table . ' field ' . $fieldName
+                                                                                                       . ' to a renderType definition with columnsOverrides in type ' . $typeName . '.';
+                                                                                       } else {
+                                                                                               // Some other enabled wizard
+                                                                                               $newEnabledWizardsArray[] = $enabledWizardName;
+                                                                                       }
+                                                                               }
+                                                                               if (!empty($newEnabledWizardsArray)) {
+                                                                                       $newDefaultExtrasArray[] = 'wizards[' . implode('|', $newEnabledWizardsArray) . ']';
+                                                                               }
+                                                                       } else {
+                                                                               $newDefaultExtrasArray[] = $fieldExtraField;
+                                                                       }
+                                                               }
+                                                               if (!empty($newDefaultExtrasArray)) {
+                                                                       $newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['defaultExtras'] = implode(':', $newDefaultExtrasArray);
+                                                               } else {
+                                                                       unset($newTca[$table]['types'][$typeName]['columnsOverrides'][$fieldName]['defaultExtras']);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       // If no wizard is left after migration, unset the whole sub array
+                                       if (empty($newTca[$table]['columns'][$fieldName]['config']['wizards'])) {
+                                               unset($newTca[$table]['columns'][$fieldName]['config']['wizards']);
+                                       }
+                               }
+                       }
+               }
+               return $newTca;
+       }
+
+}
index 22aa8b4..81225a7 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Core\Utility;
 
 use TYPO3\CMS\Core\Category\CategoryRegistry;
 use TYPO3\CMS\Core\Package\PackageManager;
+use TYPO3\CMS\Core\Migrations\TcaMigration;
 
 /**
  * Extension Management functions
@@ -302,7 +303,7 @@ class ExtensionManagementUtility {
                                $paletteCount = preg_match_all('/(?:^|,)                    # Line start or a comma
                                        (?:
                                            \\s*\\-\\-palette\\-\\-;[^;]*;([^,$]*)|              # --palette--;label;paletteName
-                                           \\s*\\b[^;,]+\\b(?:;[^;]*;([^;,]+);?[^;,]*;?)?[^,]*  # field;label;paletteName[;options[;colors]]
+                                           \\s*\\b[^;,]+\\b(?:;[^;]*;([^;,]+);?[^;,]*;?)?[^,]*  # @deprecated since TYPO3 CMS 7: field;label;paletteName[;options[;colors]]
                                        )/x', $typeDetails['showitem'], $paletteMatches);
                                if ($paletteCount > 0) {
                                        $paletteNames = array_filter(array_merge($paletteMatches[1], $paletteMatches[2]));
@@ -1652,6 +1653,19 @@ tt_content.' . $key . $suffix . ' {
                        }
                }
 
+               // TCA migration
+               // @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. This can be removed *if* no additional TCA migration is added with CMS 8, see class TcaMigration
+               $tcaMigration = GeneralUtility::makeInstance(TcaMigration::class);
+               $GLOBALS['TCA'] = $tcaMigration->migrate($GLOBALS['TCA']);
+               $messages = $tcaMigration->getMessages();
+               if (!empty($messages)) {
+                       $context = 'Automatic TCA migration done during boostrap. Please adapt TCA accordingly, these migrations'
+                               . ' will be removed with TYPO3 CMS 8. The backend module "Configuration -> TCA" shows the modified values.'
+                               . ' Please adapt these areas:';
+                       array_unshift($messages, $context);
+                       GeneralUtility::deprecationLog(implode(LF, $messages));
+               }
+
                static::emitTcaIsBeingBuiltSignal($GLOBALS['TCA']);
        }
 
index cc852a8..61992b6 100644 (file)
@@ -277,6 +277,10 @@ return array(
                ),
                'isInitialInstallationInProgress' => FALSE,             // Boolean: If TRUE, the installation is 'in progress'. This value is handled within the install tool step installer internally.
                'clearCacheSystem' => FALSE,            // Boolean: If set, the toolbar menu entry for clearing system caches (core cache, class cache, etc.) is visible for admin users.
+               'formEngine' => array(
+                       'nodeRegistry' => array(), // Array: Registry to add or overwrite FormEngine nodes. Main key is a timestamp of the date when an entry is added, sub keys type, priority and class are required. Class must implement TYPO3\CMS\Backend\Form\NodeInterface.
+                       'nodeResolver' => array(), // Array: Additional node resolver. Main key is a timestamp of the date when an entry is added, sub keys type, priority and class are required. Class must implement TYPO3\CMS\Backend\Form\NodeResolverInterface.
+               ),
        ),
        'EXT' => array( // Options related to the Extension Management
                'allowGlobalInstall' => FALSE,          // Boolean: If set, global extensions in typo3/ext/ are allowed to be installed, updated and deleted etc.
index 9d920f7..105ffdd 100644 (file)
@@ -78,12 +78,13 @@ return array(
                                                )
                                        )
                                )
-                       )
+                       ),
+                       'defaultExtras' => 'richtext:rte_transform[flag=rte_enabled|mode=ts_css]',
                )
        ),
        'types' => array(
-               '1' => array('showitem' => '
-                       hidden, title, content;;9;richtext:rte_transform[flag=rte_enabled|mode=ts_css],
-                       --div--;LLL:EXT:lang/locallang_tca.xlf:sys_news.tabs.access, starttime, endtime')
-       )
+               '1' => array(
+                       'showitem' => 'hidden, title, content, --div--;LLL:EXT:lang/locallang_tca.xlf:sys_news.tabs.access, starttime, endtime',
+               ),
+       ),
 );
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-67229-FormEngineRelatedClasses.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-67229-FormEngineRelatedClasses.rst
new file mode 100644 (file)
index 0000000..89ed6fc
--- /dev/null
@@ -0,0 +1,34 @@
+==============================================
+Breaking: #67229 - FormEngine related classses
+==============================================
+
+
+Description
+===========
+
+With the further development of FormEngine, some minor changes on ``PHP`` level were applied:
+
+* Class ``TYPO3\CMS\T3editor\FormWizard`` is removed
+
+* Class ``TYPO3\CMS\Rtehtmlarea\Controller\FrontendRteController`` is removed
+
+* Method signature of class ``TYPO3\CMS\Utility\BackendUtility`` method ``getSpecConfParts`` changed
+
+
+Impact
+======
+
+Using code will fatal or not be called any longer.
+
+
+Affected Installations
+======================
+
+If extensions use above classes or methods. Since these classes are mostly core internal
+it is quite unlikely any project in the wild is affected.
+
+
+Migration
+=========
+
+Use the newly introduced API.
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-67229-TcaChanges.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-67229-TcaChanges.rst
new file mode 100644 (file)
index 0000000..2f83cfb
--- /dev/null
@@ -0,0 +1,235 @@
+=================================
+Deprecation: #65290 - TCA changes
+=================================
+
+
+Description
+===========
+
+Some details in the main ``Table Configuration Array, TCA``, known on PHP side as ``$GLOBALS['TCA']`` changed.
+
+
+Simplified ``types`` ``showitem`` configuration using ``columnsOverrides``
+--------------------------------------------------------------------------
+
+If a field is configured as ``type`` in ``TCA`` ``ctrl`` section, the value of this database field determines
+which fields are shown if opening a record in the backend. The shown fields are configured in ``TCA`` section
+``types`` ``showitem`` and is a comma separated list of field names. Each field name can have 4 additional
+semicolon separated options, from which the last two are dropped and moved:
+
+Before:
+
+.. code-block:: php
+
+       'types' => array(
+               'aType' => array(
+                       'showitem' => 'aField,anotherField;otherLabel;aPalette;special:configuration;a-style-indicator,thirdField',
+               ),
+       ),
+
+
+If a record is opened that has the type field set to ``aType``, it would show the three fields ``aField``, ``anotherField``
+and ``thirdField``. The second field ``anotherField`` has further configuration and shows a different label, adds an additional
+palette below the field referenced as ``aPalette``, adds ``special:configuration`` as special configuration and changes
+the style with its last field. The last two parameters were changed: The style configuration is obsolete since 7.1 and has been removed therefore.
+The special configuration is identical to ``defaultExtras`` field of a ``columns`` field section and can be added with this
+name in a new introduced array ``columnsOverrides`` that is parallel to ``showitem`` of this type:
+
+.. code-block:: php
+
+       'types' => array(
+               'aType' => array(
+                       'showitem' => 'aField,anotherField;otherLabel;aPalette,thirdField',
+                       'columnsOverrides` => array(
+                               'anotherField' => array(
+                                       'defaultExtras' => 'special:configuration',
+                               ),
+                       ),
+               ),
+       ),
+
+
+So, the 4th parameter is transferred to ``columnsOverrides`` while the 5th parameter is removed.
+
+This change enables more flexible overrides of column configuration based on given type. This is currently used in
+``FormEngine`` only, so only view related parameters must be overwritten here. It is not supported to change data handling
+related parameters like ``type=text`` to ``type=select`` or similar, but it is possible to change for example the number
+of rows shown in a ``type=text`` column field:
+
+.. code-block:: php
+
+       'types' => array(
+               'aType' => array(
+                       'showitem' => 'aField,anotherField;otherLabel;aPalette,thirdField',
+                       'columnsOverrides` => array(
+                               'anotherField' => array(
+                                       'config' => array(
+                                               'rows' => 42,
+                                       ),
+                               ),
+                       ),
+               ),
+       ),
+
+
+It is also possible to remove a given configuration from the default configuration using the ``__UNSET`` keyword. Again,
+this is only supported for view related configuration options. Changing for instance an ``eval`` option may cripple the
+PHP side validation done by the DataHandler that checks and stores values.
+
+.. code-block:: php
+
+       'types' => array(
+               'aType' => array(
+                       'columnsOverrides` => array(
+                               'bodytext' => array(
+                                       'config' => array(
+                                               'rows' => '__UNSET',
+                                       ),
+                               ),
+                       ),
+               ),
+       ),
+
+
+The above example would remove the ``rows`` parameter of the ``bodytext`` field columns configuration, so a default
+value would be used instead.
+
+
+Simplified t3editor configuration
+---------------------------------
+
+t3editor is no longer configured and enabled as wizard.
+
+Configuration for a column field looked like this before:
+
+.. code-block:: php
+
+       'bodytext' => array(
+               'config' => array(
+                       'type' => 'text',
+                       'rows' => 42,
+                       'wizards' => array(
+                               't3editor' => array(
+                                       'type' => 'userFunc',
+                                       'userFunc' => 'TYPO3\CMS\T3editor\FormWizard->main',
+                                       'title' => 't3editor',
+                                       'icon' => 'wizard_table.gif',
+                                       'module' => array(
+                                               'name' => 'wizard_table'
+                                       ),
+                                       'params' => array(
+                                               'format' => 'html',
+                                               'style' => 'width:98%; height: 60%;'
+                                       ),
+                               ),
+                       ),
+               ),
+       ),
+
+
+The new configuration is simplified to:
+
+.. code-block:: php
+
+       'bodytext' => array(
+               'exclude' => 1,
+               'label' => 'aLabel',
+               'config' => array(
+                       'type' => 'text',
+                       'renderType' => 't3editor',
+                       'format' => 'html',
+                       'rows' => 42,
+               ),
+       ),
+
+
+In case t3editor was only enabled for a specific type, this was previously done with
+``enableByTypeConfig`` within the wizard configuration and ``wizards[theWizardName]`` as
+the 4th semicolon separated parameter of the accorting field in section ``showitem`` of the
+``type`` where t3editor should be enabled. Old configuration was:
+
+.. code-block:: php
+
+       'columns' => array(
+               'bodytext' => array(
+                       'exclude' => 1,
+                       'label' => 'aLabel',
+                       'config' => array(
+                               'type' => 'text',
+                               'rows' => 42,
+                               'wizards' => array(
+                                       't3editorHtml' => array(
+                                               'type' => 'userFunc',
+                                               'userFunc' => 'TYPO3\CMS\T3editor\FormWizard->main',
+                                               'enableByTypeConfig' => 1,
+                                               'title' => 't3editor',
+                                               'icon' => 'wizard_table.gif',
+                                               'module' => array(
+                                                       'name' => 'wizard_table'
+                                               ),
+                                               'params' => array(
+                                                       'format' => 'html',
+                                                       'style' => 'width:98%; height: 60%;'
+                                               ),
+                                       ),
+                               ),
+                       ),
+               ),
+       ),
+       'types' => array(
+               'firstType' => array(
+                       'showitem' => 'bodytext;;;wizards[t3editorHtml]',
+               ),
+       ),
+
+
+This now uses the new ``columnsOverrides`` feature parallel to ``showitem``:
+
+.. code-block:: php
+
+       'columns' => array(
+               'bodytext' => array(
+                       'config' => array(
+                               'type' => 'text',
+                               'rows' => 42,
+                       ),
+               ),
+       ),
+       'types' => array(
+               'firstType' => array(
+                       'showitem' => 'bodytext',
+                       'columnsOverrides' => array(
+                               'bodytext' => array(
+                                       'config' => array(
+                                               'format' => 'typoscript',
+                                               'renderType' => 't3editor',
+                                       ),
+                               ),
+                       ),
+               ),
+
+
+Impact
+======
+
+TCA is automatically migrated during bootstrap of the TYPO3 core and the result is cached.
+In case TCA is still registered or changed in extensions with entries in ``ext_tables.php``, and automatic
+migration of this part of ``TCA`` is only triggered if extension ``compatibility6`` is loaded. This has a
+performance penalty since the migration in ``compatibility6`` is then done on every frontend and backend
+script call and is not cached.
+It is strongly advised to move remaining ``TCA`` changes from ``ext_tables`` to ``Configuration/TCA`` or
+``Configuration/TCA/Overrides`` of the according extension and to unload ``compatibility6``.
+
+
+Migration
+=========
+
+An automatic migration is in place. It throws deprecation log entries in case ``TCA`` was changed on the fly.
+The migration logs give hints on what exactly is changed and the final ``TCA`` can be inspected in the backend
+configuration module. If outdated flex form is used, the migration is done within the FormEngine class
+construct on the fly and will throw deprecation warnings as soon as a record with outdated ``TCA`` flex form
+is opened in the backend.
+
+Typical migration of the 4th ``showitem`` parameter involves moving a RTE configuration like
+``richtext:rte_transform[flag=rte_enabled|mode=ts_css]`` or the ``type=text`` flags ``nowrap``, ``fixed-font``
+and ``enabled-tab`` to ``columnsOverrides``.
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-67229-FormEngineNodeFactoryApi.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-67229-FormEngineNodeFactoryApi.rst
new file mode 100644 (file)
index 0000000..3d16519
--- /dev/null
@@ -0,0 +1,101 @@
+============================================
+Feature: #67229 - FormEngine NodeFactory API
+============================================
+
+Description
+===========
+
+The FormEngine class construct was moved to a tree approach with container classes as inner nodes and
+element classes (the rendering widgets) as leaves. Finding, instantiation and preparation of those
+classes is done via ``TYPO3\CMS\Backend\Form\NodeFactory``.
+
+This class was extended with an API to allow flexible overriding and adding of containers and elements:
+
+
+Registration of new nodes and overwriting existing nodes
+--------------------------------------------------------
+
+.. code-black:: php
+
+       $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1433196792] = array(
+               'nodeName' => 'input',
+               'priority' => 40,
+               'class' => \MyVendor\MyExtension\Form\Element\T3editorElement::class,
+       );
+
+
+This registers the class ``MyVendor\MyExtension\Form\Element\T3editorElement`` as render class for
+the type ``input``. It will be called to render elements of this type and must implement the interface
+``TYPO3\CMS\Backend\Form\NodeInterface``. The array key is the unix timestamp of the date when an registry
+element is added and is just used to have a unique key that is very unlikely to collide with others - this
+is the same logic that is used for exception codes. If more than one registry element for the same type
+is registered, the element with highest priority wins. Priority must be set between 0 and 100. Two elements
+with same priority for the same type will throw an exception.
+
+The core extension t3editor uses this API to substitute a ``type=text`` field with ``renderType=t3editor``
+from the default ``TextElement`` to its own ``T3editorElement``.
+
+This registry both allows completely overriding existing implementations of any existing given type, as well as
+registration of a new ``renderType`` for own fancy elements. A TCA configuration for a new renderType
+and its nodeRegistry could look like:
+
+.. code-block:: php
+
+       'columns' => array(
+               'bodytext' => array(
+                       'config' => array(
+                               'type' => 'text',
+                               'renderType' => '3dCloud',
+                       ),
+               ),
+       ),
+
+       $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1433197759] = array(
+               'nodeName' => '3dCloud',
+               'priority' => 40,
+               'class' => \MyVendor\MyExtension\Form\Element\ShowTextAs3dCloudElement::class,
+       );
+
+
+Resolve class resolution to different render classes
+----------------------------------------------------
+
+In case the above API is not flexible enough, another class can be registered to resolve the final
+class that renders a certain element or container differently:
+
+.. code-block:: php
+
+       // Register FormEngine node type resolver hook to render RTE in FormEngine if enabled
+       $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'][1433198160] = array(
+               'nodeName' => 'text',
+               'priority' => 50,
+               'class' => \MyVendor\MyExtension\Form\Resolver\MyTextNodeResolver::class,
+       );
+
+
+This registers a resolver class at priority 50 if the type ``text`` should be rendered. This class must
+implement ``TYPO3\CMS\Backend\Form\NodeResolverInterface`` and can return a different class name that is
+called as render class. The render class in turn must implement ``TYPO3\CMS\Backend\Form\NodeInterface``.
+
+The array key is again a unix timestamp of the date when this resolver code is registered. Multiple resolvers
+are a chain, the resolver with highest priority is asked first, and the chain is called until one resolver
+returns a new class name. If no resolver returns anything, the default class name will be instantiated and rendered.
+
+Priority is again between 0 and 100 and two resolver for the same type and same priority will throw an exception.
+
+The resolver will receive the full ``globalOptions`` array with all settings to take a resolve decision
+on all incoming values.
+
+This API is used by core extension rtehtmlarea to route the rendering of ``type=text`` to its own
+``RichTextElement`` class in case the editor is enabled for this field and for the user.
+
+This API allows fine grained resolution of render-nodes based on any need, for instance it would be
+easily possible to call another different richtext implementation (eg. TinyMCE) for specific fields
+of own extensions based on moon phases, by adding a resolver class with a higher priority.
+
+
+Warning
+-------
+
+The internal data given to the resolver class still may change. Both the ``globalOptions`` and the current
+``renderType`` values are subject to change without further notice until TYPO3 CMS 7 LTS.
diff --git a/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php b/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php
new file mode 100644 (file)
index 0000000..1794dcc
--- /dev/null
@@ -0,0 +1,363 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Migrations;
+
+/*
+ * 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\Tests\UnitTestCase;
+use TYPO3\CMS\Core\Migrations\TcaMigration;
+
+/**
+ * Test case
+ */
+class TcaMigrationTest extends UnitTestCase {
+
+       /**
+        * @test
+        */
+       public function migrateReturnsGivenArrayUnchangedIfNoMigrationNeeded() {
+               $input = $expected = array(
+                       'aTable' => array(
+                               'ctrl' => array(
+                                       'aKey' => 'aValue',
+                               ),
+                               'columns' => array(
+                                       'aField' => array(
+                                               'label' => 'foo',
+                                               'config' => array(
+                                                       'type' => 'aType',
+                                                       'lolli' => 'did this',
+                                               )
+                                       ),
+                               ),
+                               'types' => array(
+                                       0 => array(
+                                               'showitem' => 'this,should;stay;this,too',
+                                       ),
+                               ),
+                       ),
+               );
+               $subject = new TcaMigration();
+               $this->assertEquals($expected, $subject->migrate($input));
+       }
+
+       /**
+        * @test
+        */
+       public function migrateChangesT3editorWizardToT3editorRenderTypeIfNotEnabledByTypeConfig() {
+               $input = array(
+                       'aTable' => array(
+                               'columns' => array(
+                                       'bodytext' => array(
+                                               'exclude' => 1,
+                                               'label' => 'aLabel',
+                                               'config' => array(
+                                                       'type' => 'text',
+                                                       'rows' => 42,
+                                                       'wizards' => array(
+                                                               't3editor' => array(
+                                                                       'type' => 'userFunc',
+                                                                       'userFunc' => 'TYPO3\CMS\T3editor\FormWizard->main',
+                                                                       'title' => 't3editor',
+                                                                       'icon' => 'wizard_table.gif',
+                                                                       'module' => array(
+                                                                               'name' => 'wizard_table'
+                                                                       ),
+                                                                       'params' => array(
+                                                                               'format' => 'html',
+                                                                               'style' => 'width:98%; height: 60%;'
+                                                                       ),
+                                                               ),
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                       ),
+               );
+               $expected = array(
+                       'aTable' => array(
+                               'columns' => array(
+                                       'bodytext' => array(
+                                               'exclude' => 1,
+                                               'label' => 'aLabel',
+                                               'config' => array(
+                                                       'type' => 'text',
+                                                       'renderType' => 't3editor',
+                                                       'format' => 'html',
+                                                       'rows' => 42,
+                                               ),
+                                       ),
+                               ),
+                       ),
+               );
+               $subject = new TcaMigration();
+               $this->assertEquals($expected, $subject->migrate($input));
+       }
+
+       /**
+        * @test
+        */
+       public function migrateDropsStylePointerFromShowItem() {
+               $input = array(
+                       'aTable' => array(
+                               'types' => array(
+                                       0 => array(
+                                               'showitem' => 'aField,anotherField;with;palette;;and-style-pointer,thirdField',
+                                       ),
+                                       1 => array(
+                                               'showitem' => 'aField,;;;;only-a-style-pointer,anotherField',
+                                       ),
+                               ),
+                       ),
+               );
+               $expected = array(
+                       'aTable' => array(
+                               'types' => array(
+                                       0 => array(
+                                               'showitem' => 'aField,anotherField;with;palette,thirdField',
+                                       ),
+                                       1 => array(
+                                               'showitem' => 'aField,anotherField',
+                                       ),
+                               ),
+                       ),
+               );
+               $subject = new TcaMigration();
+               $this->assertEquals($expected, $subject->migrate($input));
+       }
+
+       /**
+        * @test
+        */
+       public function migrateMovesSpecialConfigurationToColumnsOverridesDefaultExtras() {
+               $input = array(
+                       'aTable' => array(
+                               'types' => array(
+                                       0 => array(
+                                               'showitem' => 'aField,anotherField;with;palette;special:configuration,thirdField',
+                                       ),
+                               ),
+                       ),
+               );
+               $expected = array(
+                       'aTable' => array(
+                               'types' => array(
+                                       0 => array(
+                                               'showitem' => 'aField,anotherField;with;palette,thirdField',
+                                               'columnsOverrides' => array(
+                                                       'anotherField' => array(
+                                                               'defaultExtras' => 'special:configuration',
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                       ),
+               );
+               $subject = new TcaMigration();
+               $this->assertEquals($expected, $subject->migrate($input));
+       }
+
+       /**
+        * @test
+        */
+       public function migrateMovesSpecialConfigurationToColumnsOverridesDefaultExtrasAndMergesExistingDefaultExtras() {
+               $input = array(
+                       'aTable' => array(
+                               'columns' => array(
+                                       'anotherField' => array(
+                                               'defaultExtras' => 'some:values',
+                                       ),
+                               ),
+                               'types' => array(
+                                       0 => array(
+                                               'showitem' => 'aField,anotherField;with;palette;special:configuration,thirdField',
+                                       ),
+                               ),
+                       ),
+               );
+               $expected = array(
+                       'aTable' => array(
+                               'columns' => array(
+                                       'anotherField' => array(
+                                               'defaultExtras' => 'some:values',
+                                       ),
+                               ),
+                               'types' => array(
+                                       0 => array(
+                                               'showitem' => 'aField,anotherField;with;palette,thirdField',
+                                               'columnsOverrides' => array(
+                                                       'anotherField' => array(
+                                                               'defaultExtras' => 'some:values:special:configuration',
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                       ),
+               );
+               $subject = new TcaMigration();
+               $this->assertEquals($expected, $subject->migrate($input));
+       }
+
+       /**
+        * @test
+        */
+       public function migrateChangesT3editorWizardThatIsEnabledByTypeConfigToRenderTypeInColmnnsOverrides() {
+               $input = array(
+                       'aTable' => array(
+                               'columns' => array(
+                                       'bodytext' => array(
+                                               'exclude' => 1,
+                                               'label' => 'aLabel',
+                                               'config' => array(
+                                                       'type' => 'text',
+                                                       'rows' => 42,
+                                                       'wizards' => array(
+                                                               't3editorHtml' => array(
+                                                                       'type' => 'userFunc',
+                                                                       'userFunc' => 'TYPO3\CMS\T3editor\FormWizard->main',
+                                                                       'enableByTypeConfig' => 1,
+                                                                       'title' => 't3editor',
+                                                                       'icon' => 'wizard_table.gif',
+                                                                       'module' => array(
+                                                                               'name' => 'wizard_table'
+                                                                       ),
+                                                                       'params' => array(
+                                                                               'format' => 'html',
+                                                                               'style' => 'width:98%; height: 60%;'
+                                                                       ),
+                                                               ),
+                                                               't3editorTypoScript' => array(
+                                                                       'type' => 'userFunc',
+                                                                       'userFunc' => 'TYPO3\CMS\T3editor\FormWizard->main',
+                                                                       'enableByTypeConfig' => 1,
+                                                                       'title' => 't3editor',
+                                                                       'icon' => 'wizard_table.gif',
+                                                                       'module' => array(
+                                                                               'name' => 'wizard_table'
+                                                                       ),
+                                                                       'params' => array(
+                                                                               'format' => 'typoscript',
+                                                                               'style' => 'width:98%; height: 60%;'
+                                                                       ),
+                                                               ),
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                               'types' => array(
+                                       'firstType' => array(
+                                               'showitem' => 'foo,bodytext;;;wizards[t3editorTypoScript|someOtherWizard],bar',
+                                       ),
+                                       'secondType' => array(
+                                               'showitem' => 'foo,bodytext;;;nowrap:wizards[t3editorHtml], bar',
+                                       ),
+                               ),
+                       ),
+               );
+               $expected = array(
+                       'aTable' => array(
+                               'columns' => array(
+                                       'bodytext' => array(
+                                               'exclude' => 1,
+                                               'label' => 'aLabel',
+                                               'config' => array(
+                                                       'type' => 'text',
+                                                       'rows' => 42,
+                                               ),
+                                       ),
+                               ),
+                               'types' => array(
+                                       'firstType' => array(
+                                               'showitem' => 'foo,bodytext,bar',
+                                               'columnsOverrides' => array(
+                                                       'bodytext' => array(
+                                                               'config' => array(
+                                                                       'format' => 'typoscript',
+                                                                       'renderType' => 't3editor',
+                                                               ),
+                                                               'defaultExtras' => 'wizards[someOtherWizard]',
+                                                       ),
+                                               ),
+                                       ),
+                                       'secondType' => array(
+                                               'showitem' => 'foo,bodytext,bar',
+                                               'columnsOverrides' => array(
+                                                       'bodytext' => array(
+                                                               'config' => array(
+                                                                       'format' => 'html',
+                                                                       'renderType' => 't3editor',
+                                                               ),
+                                                               'defaultExtras' => 'nowrap',
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                       ),
+               );
+               $subject = new TcaMigration();
+               $this->assertEquals($expected, $subject->migrate($input));
+       }
+
+       /**
+        * @test
+        */
+       public function migrateRemovesAnUnusedT3edtiorDefinitionIfEnabledByTypeConfig() {
+               $input = array(
+                       'aTable' => array(
+                               'columns' => array(
+                                       'bodytext' => array(
+                                               'exclude' => 1,
+                                               'label' => 'aLabel',
+                                               'config' => array(
+                                                       'type' => 'text',
+                                                       'rows' => 42,
+                                                       'wizards' => array(
+                                                               't3editorHtml' => array(
+                                                                       'type' => 'userFunc',
+                                                                       'userFunc' => 'TYPO3\CMS\T3editor\FormWizard->main',
+                                                                       'enableByTypeConfig' => 1,
+                                                                       'title' => 't3editor',
+                                                                       'icon' => 'wizard_table.gif',
+                                                                       'module' => array(
+                                                                               'name' => 'wizard_table'
+                                                                       ),
+                                                                       'params' => array(
+                                                                               'format' => 'html',
+                                                                               'style' => 'width:98%; height: 60%;'
+                                                                       ),
+                                                               ),
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                       ),
+               );
+               $expected = array(
+                       'aTable' => array(
+                               'columns' => array(
+                                       'bodytext' => array(
+                                               'exclude' => 1,
+                                               'label' => 'aLabel',
+                                               'config' => array(
+                                                       'type' => 'text',
+                                                       'rows' => 42,
+                                               ),
+                                       ),
+                               ),
+                       ),
+               );
+               $subject = new TcaMigration();
+               $this->assertEquals($expected, $subject->migrate($input));
+       }
+
+}
index fd11b16..da1d52d 100644 (file)
@@ -546,7 +546,7 @@ $GLOBALS['TCA']['tt_content']['types']['header']['showitem'] = '
 $GLOBALS['TCA']['tt_content']['types']['text']['showitem'] = '
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.header;header,
-               bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext_formlabel;;richtext:rte_transform[flag=rte_enabled|mode=ts_css],
+               bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext_formlabel,
                rte_enabled;LLL:EXT:cms/locallang_ttc.xlf:rte_enabled_formlabel,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.appearance,
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.frames;frames,
@@ -555,12 +555,23 @@ $GLOBALS['TCA']['tt_content']['types']['text']['showitem'] = '
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.access;access,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.extended
 ';
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['text']['columnsOverrides'])) {
+       $GLOBALS['TCA']['tt_content']['types']['text']['columnsOverrides'] = array();
+}
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['text']['columnsOverrides']['bodytext'])) {
+       $GLOBALS['TCA']['tt_content']['types']['text']['columnsOverrides']['bodytext'] = array();
+}
+$baseDefaultExtrasOfBodytext = '';
+if (!empty($GLOBALS['TCA']['tt_content']['columns']['bodytext']['defaultExtras'])) {
+       $baseDefaultExtrasOfBodytext = $GLOBALS['TCA']['tt_content']['columns']['bodytext']['defaultExtras'] . ':';
+}
+$GLOBALS['TCA']['tt_content']['types']['text']['columnsOverrides']['bodytext']['defaultExtras'] = $baseDefaultExtrasOfBodytext . 'richtext:rte_transform[flag=rte_enabled|mode=ts_css]';
 
 // Field arrangement for CE "textpic"
 $GLOBALS['TCA']['tt_content']['types']['textpic']['showitem'] = '
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.header;header,
-               bodytext;Text;;richtext:rte_transform[flag=rte_enabled|mode=ts_css],
+               bodytext;Text,
                rte_enabled;LLL:EXT:cms/locallang_ttc.xlf:rte_enabled_formlabel,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.images,
                image,
@@ -574,6 +585,13 @@ $GLOBALS['TCA']['tt_content']['types']['textpic']['showitem'] = '
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.access;access,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.extended
 ';
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['textpic']['columnsOverrides'])) {
+       $GLOBALS['TCA']['tt_content']['types']['textpic']['columnsOverrides'] = array();
+}
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['textpic']['columnsOverrides']['bodytext'])) {
+       $GLOBALS['TCA']['tt_content']['types']['textpic']['columnsOverrides']['bodytext'] = array();
+}
+$GLOBALS['TCA']['tt_content']['types']['textpic']['columnsOverrides']['bodytext']['defaultExtras'] = $baseDefaultExtrasOfBodytext . 'richtext:rte_transform[flag=rte_enabled|mode=ts_css]';
 
 // Field arrangement for CE "image"
 $GLOBALS['TCA']['tt_content']['types']['image']['showitem'] = '
@@ -596,7 +614,7 @@ $GLOBALS['TCA']['tt_content']['types']['image']['showitem'] = '
 $GLOBALS['TCA']['tt_content']['types']['bullets']['showitem'] = '
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.header;header,
-               bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext.ALT.bulletlist_formlabel;;nowrap,
+               bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext.ALT.bulletlist_formlabel,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.appearance,
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.frames;frames,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access,
@@ -604,6 +622,13 @@ $GLOBALS['TCA']['tt_content']['types']['bullets']['showitem'] = '
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.access;access,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.extended
 ';
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['bullets']['columnsOverrides'])) {
+       $GLOBALS['TCA']['tt_content']['types']['bullets']['columnsOverrides'] = array();
+}
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['bullets']['columnsOverrides']['bodytext'])) {
+       $GLOBALS['TCA']['tt_content']['types']['bullets']['columnsOverrides']['bodytext'] = array();
+}
+$GLOBALS['TCA']['tt_content']['types']['bullets']['columnsOverrides']['bodytext']['defaultExtras'] = $baseDefaultExtrasOfBodytext . 'nowrap';
 
 // Field arrangement for CE "table"
 $GLOBALS['TCA']['tt_content']['types']['table']['showitem'] = '
@@ -612,7 +637,7 @@ $GLOBALS['TCA']['tt_content']['types']['table']['showitem'] = '
        --div--;LLL:EXT:cms/locallang_ttc.xlf:CType.I.5,
                layout;;10,
                cols,
-               bodytext;;9;nowrap:wizards[table],
+               bodytext,
                pi_flexform,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.appearance,
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.frames;frames,
@@ -622,6 +647,13 @@ $GLOBALS['TCA']['tt_content']['types']['table']['showitem'] = '
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.access;access,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.extended
 ';
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['table']['columnsOverrides'])) {
+       $GLOBALS['TCA']['tt_content']['types']['table']['columnsOverrides'] = array();
+}
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['table']['columnsOverrides']['bodytext'])) {
+       $GLOBALS['TCA']['tt_content']['types']['table']['columnsOverrides']['bodytext'] = array();
+}
+$GLOBALS['TCA']['tt_content']['types']['table']['columnsOverrides']['bodytext']['defaultExtras'] = $baseDefaultExtrasOfBodytext . 'nowrap:wizards[table]';
 
 // Field arrangement for CE "uploads"
 $GLOBALS['TCA']['tt_content']['types']['uploads']['showitem'] = '
@@ -697,7 +729,7 @@ $GLOBALS['TCA']['tt_content']['types']['div']['showitem'] = '
 $GLOBALS['TCA']['tt_content']['types']['html']['showitem'] = '
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
                header;LLL:EXT:cms/locallang_ttc.xlf:header.ALT.html_formlabel,
-               bodytext,
+               bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext.ALT.html_formlabel,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.appearance,
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.frames;frames,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access,
index 1c42d76..d65a2b7 100644 (file)
@@ -6,76 +6,76 @@ $tca = array(
                'type' => 'file:type',
        ),
        'types' => array(
-               TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => array('showitem' => '
-                                                               fileinfo, title, description, alternative, keywords, caption, download_name,
-
-                                                               --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,
-                                                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.visibility;10;; ,
-                                                                       fe_groups,
-
-                                                               --div--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:tabs.metadata,
-                                                                       creator, --palette--;;20;;,
-                                                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.geo_location;40;;'),
-
-               TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => array('showitem' => '
-                                                               fileinfo, title, description, alternative, keywords, caption, download_name,
-
-                                                               --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,
-                                                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.visibility;10;; ,
-                                                                       fe_groups,
-
-                                                               --div--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:tabs.metadata,
-                                                                       creator, --palette--;;20;;,
-                                                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.geo_location;40;;,
-                                                                       language'),
-
-               TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => array('showitem' => '
-                                                               fileinfo, title, description, alternative, keywords, caption, download_name,
-
-                                                               --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,
-                                                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.visibility;10;; ,
-                                                                       fe_groups,
-
-                                                               --div--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:tabs.metadata,
-                                                                       creator, --palette--;;20;;,
-                                                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.geo_location;40;; ,
-                                                                       --palette--;;30;;,
-                                                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.metrics;50;;'),
-
-               TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => array('showitem' => '
-
-                                                               fileinfo, title, description, alternative, keywords, caption, download_name,
-
-                                                               --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,
-                                                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.visibility;10;; ,
-                                                                       fe_groups,
-
-                                                               --div--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:tabs.metadata,
-                                                                       duration,
-                                                                       creator, --palette--;;20;;, language'),
-
-               TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => array('showitem' => '
-                                                               fileinfo, title, description, alternative, keywords, caption, download_name,
-
-                                                               --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,
-                                                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.visibility;10;; ,
-                                                                       fe_groups,
-
-                                                               --div--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:tabs.metadata,
-                                                                       duration,
-                                                                       creator, --palette--;;20;;, language'),
-
-               TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => array('showitem' => '
-                                                               fileinfo, title, description, alternative, keywords, caption, download_name,
-
-                                                               --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,
-                                                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.visibility;10;; ,
-                                                                       fe_groups,
-
-                                                               --div--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:tabs.metadata,
-                                                                       creator, --palette--;;20;;,
-                                                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.geo_location;40;; ,
-                                                                       language, --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.content_date;60;;, pages'),
+               TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => array(
+                       'showitem' => '
+                               fileinfo, title, description, alternative, keywords, caption, download_name,
+                               --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,
+                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.visibility;10 ,
+                                       fe_groups,
+                               --div--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:tabs.metadata,
+                                       creator, --palette--;;20,
+                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.geo_location;40
+                       ',
+               ),
+               TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => array(
+                       'showitem' => '
+                               fileinfo, title, description, alternative, keywords, caption, download_name,
+                               --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,
+                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.visibility;10 ,
+                                       fe_groups,
+                               --div--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:tabs.metadata,
+                                       creator, --palette--;;20,
+                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.geo_location;40,
+                                       language
+                       ',
+               ),
+               TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => array(
+                       'showitem' => '
+                               fileinfo, title, description, alternative, keywords, caption, download_name,
+                               --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,
+                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.visibility;10 ,
+                                       fe_groups,
+                               --div--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:tabs.metadata,
+                                       creator, --palette--;;20,
+                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.geo_location;40,
+                                       --palette--;;30,
+                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.metrics;50
+                       ',
+               ),
+               TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => array(
+                       'showitem' => '
+                               fileinfo, title, description, alternative, keywords, caption, download_name,
+                               --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,
+                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.visibility;10,
+                                       fe_groups,
+                               --div--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:tabs.metadata,
+                                       duration,
+                                       creator, --palette--;;20, language
+                       ',
+               ),
+               TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => array(
+                       'showitem' => '
+                               fileinfo, title, description, alternative, keywords, caption, download_name,
+                               --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,
+                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.visibility;10,
+                                       fe_groups,
+                               --div--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:tabs.metadata,
+                                       duration,
+                                       creator, --palette--;;20, language
+                       ',
+               ),
+               TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => array(
+                       'showitem' => '
+                               fileinfo, title, description, alternative, keywords, caption, download_name,
+                               --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,
+                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.visibility;10,
+                                       fe_groups,
+                               --div--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:tabs.metadata,
+                                       creator, --palette--;;20,
+                                       --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.geo_location;40,
+                                       language, --palette--;LLL:EXT:filemetadata/Resources/Private/Language/locallang_tca.xlf:palette.content_date;60, pages
+                       ',
+               ),
        ),
        'palettes' => array(
                '10' => array('showitem' => 'visible, status, ranking', 'canNotCollapse' => '1'),
index 933d3a3..9c34508 100644 (file)
@@ -53,13 +53,25 @@ $GLOBALS['TCA']['tt_content']['types']['mailform']['showitem'] = '
        --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general,
        --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.header;header,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:CType.I.8,
-               bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext.ALT.mailform;;nowrap:wizards[forms],
+               bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext.ALT.mailform,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.appearance,
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.frames;frames,
        --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access,
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.visibility;visibility,
                --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.access;access,
 ';
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides'])) {
+       $GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides'] = array();
+}
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides']['bodytext'])) {
+       $GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides']['bodytext'] = array();
+}
+$baseDefaultExtrasOfBodytext = '';
+if (!empty($GLOBALS['TCA']['tt_content']['columns']['bodytext']['defaultExtras'])) {
+       $baseDefaultExtrasOfBodytext = $GLOBALS['TCA']['tt_content']['columns']['bodytext']['defaultExtras'] . ':';
+}
+$GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides']['bodytext']['defaultExtras'] = $baseDefaultExtrasOfBodytext . 'nowrap:wizards[forms]';
+
 
 // Add Default TS to Include static (from extensions)
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('form', 'Configuration/TypoScript/', 'Default TS');
index 4d8ab9c..72a43ea 100644 (file)
@@ -69,14 +69,32 @@ $GLOBALS['TCA']['tt_content']['types']['media'] = array(
                        --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.visibility;visibility,
                        --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.access;access,
                --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.behaviour,
-                       bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext.ALT.media_formlabel;;richtext:rte_transform[flag=rte_enabled|mode=ts_css],
+                       bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext.ALT.media_formlabel,
                --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.extended'
 );
+$baseDefaultExtrasOfBodytext = '';
+if (!empty($GLOBALS['TCA']['tt_content']['columns']['bodytext']['defaultExtras'])) {
+       $baseDefaultExtrasOfBodytext = $GLOBALS['TCA']['tt_content']['columns']['bodytext']['defaultExtras'] . ':';
+}
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['media']['columnsOverrides'])) {
+       $GLOBALS['TCA']['tt_content']['types']['media']['columnsOverrides'] = array();
+}
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['media']['columnsOverrides']['bodytext'])) {
+       $GLOBALS['TCA']['tt_content']['types']['media']['columnsOverrides']['bodytext'] = array();
+}
+$GLOBALS['TCA']['tt_content']['types']['media']['columnsOverrides']['bodytext']['defaultExtras'] = $baseDefaultExtrasOfBodytext . 'richtext:rte_transform[flag=rte_enabled|mode=ts_css]';
 
 $GLOBALS['TCA']['tt_content']['palettes']['multimediafiles'] = array(
-       'showitem' => 'multimedia;LLL:EXT:cms/locallang_ttc.xlf:multimedia_formlabel, bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext.ALT.multimedia_formlabel;;nowrap',
+       'showitem' => 'multimedia;LLL:EXT:cms/locallang_ttc.xlf:multimedia_formlabel, bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext.ALT.multimedia_formlabel',
        'canNotCollapse' => 1
 );
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['multimedia']['columnsOverrides'])) {
+       $GLOBALS['TCA']['tt_content']['types']['multimedia']['columnsOverrides'] = array();
+}
+if (!is_array($GLOBALS['TCA']['tt_content']['types']['multimedia']['columnsOverrides']['bodytext'])) {
+       $GLOBALS['TCA']['tt_content']['types']['multimedia']['columnsOverrides']['bodytext'] = array();
+}
+$GLOBALS['TCA']['tt_content']['types']['multimedia']['columnsOverrides']['bodytext']['defaultExtras'] = $baseDefaultExtrasOfBodytext . 'nowrap';
 
 
 // Add flexform
diff --git a/typo3/sysext/rtehtmlarea/Classes/Controller/FrontendRteController.php b/typo3/sysext/rtehtmlarea/Classes/Controller/FrontendRteController.php
deleted file mode 100644 (file)
index cb73acb..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-<?php
-namespace TYPO3\CMS\Rtehtmlarea\Controller;
-
-/*
- * 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!
- */
-
-/**
- * Front end RTE based on htmlArea
- *
- * @author Stanislas Rolland <typo3(arobas)sjbr.ca>
- */
-class FrontendRteController extends \TYPO3\CMS\Rtehtmlarea\RteHtmlAreaBase {
-
-       // External:
-       public $RTEWrapStyle = '';
-
-       // Alternative style for RTE wrapper <div> tag.
-       public $RTEdivStyle = '';
-
-       // Alternative style for RTE <div> tag.
-       // For the editor
-       /**
-        * @var string
-        */
-       public $elementId;
-
-       /**
-        * @var array
-        */
-       public $elementParts;
-
-       /**
-        * @var int
-        */
-       public $tscPID;
-
-       /**
-        * @var string
-        */
-       public $typeVal;
-
-       /**
-        * @var int
-        */
-       public $thePid;
-
-       /**
-        * @var array
-        */
-       public $RTEsetup = array();
-
-       /**
-        * @var array
-        */
-       public $thisConfig = array();
-
-       public $language;
-
-       public $OutputCharset;
-
-       /**
-        * @var array
-        */
-       public $specConf;
-
-       /**
-        * @var array
-        */
-       public $LOCAL_LANG;
-
-       /**
-        * @var \TYPO3\CMS\Core\Page\PageRenderer
-        */
-       protected $pageRenderer;
-
-       /**
-        * Draws the RTE as an iframe
-        *
-        * @param object $parentObject parent object
-        * @param string $table The table name
-        * @param string $field The field name
-        * @param array $row The current row from which field is being rendered
-        * @param array $PA standard content for rendering form fields from TCEforms. See TCEforms for details on this. Includes for instance the value and the form field name, java script actions and more.
-        * @param array $specConf "special" configuration - what is found at position 4 in the types configuration of a field from record, parsed into an array.
-        * @param array $thisConfig Configuration for RTEs; A mix between TSconfig and otherwise. Contains configuration for display, which buttons are enabled, additional transformation information etc.
-        * @param string $RTEtypeVal Record "type" field value.
-        * @param string $RTErelPath Relative path for images/links in RTE; this is used when the RTE edits content from static files where the path of such media has to be transformed forth and back!
-        * @param int $thePidValue PID value of record (true parent page id)
-        * @return string HTML code for RTE!
-        */
-       public function drawRTE($parentObject, $table, $field, $row, $PA, $specConf, $thisConfig, $RTEtypeVal, $RTErelPath, $thePidValue) {
-               $this->TCEform = $parentObject;
-               $this->client = $this->clientInfo();
-               $this->typoVersion = \TYPO3\CMS\Core\Utility\VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version);
-               /* =======================================
-                * INIT THE EDITOR-SETTINGS
-                * =======================================
-                */
-               // Get the path to this extension:
-               $this->extHttpPath = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::siteRelPath($this->ID);
-               // Get the site URL
-               $this->siteURL = $GLOBALS['TSFE']->absRefPrefix ?: '';
-               // Get the host URL
-               $this->hostURL = '';
-               // Element ID + pid
-               $this->elementId = $PA['itemFormElName'];
-               $this->elementParts[0] = $table;
-               $this->elementParts[1] = $row['uid'];
-               $this->tscPID = $thePidValue;
-               $this->thePid = $thePidValue;
-               // Record "type" field value:
-               $this->typeVal = $RTEtypeVal;
-               // TCA "type" value for record
-               // RTE configuration
-               $pageTSConfig = $GLOBALS['TSFE']->getPagesTSconfig();
-               if (is_array($pageTSConfig) && is_array($pageTSConfig['RTE.'])) {
-                       $this->RTEsetup = $pageTSConfig['RTE.'];
-               }
-               if (is_array($thisConfig) && !empty($thisConfig)) {
-                       $this->thisConfig = $thisConfig;
-               } elseif (is_array($this->RTEsetup['default.']) && is_array($this->RTEsetup['default.']['FE.'])) {
-                       $this->thisConfig = $this->RTEsetup['default.']['FE.'];
-               }
-               // Special configuration (line) and default extras:
-               $this->specConf = $specConf;
-               if ($this->thisConfig['forceHTTPS']) {
-                       $this->extHttpPath = preg_replace('/^(http|https)/', 'https', $this->extHttpPath);
-                       $this->siteURL = preg_replace('/^(http|https)/', 'https', $this->siteURL);
-                       $this->hostURL = preg_replace('/^(http|https)/', 'https', $this->hostURL);
-               }
-               // Register RTE windows:
-               $this->TCEform->RTEwindows[] = $PA['itemFormElName'];
-               $textAreaId = preg_replace('/[^a-zA-Z0-9_:.-]/', '_', $PA['itemFormElName']);
-               $textAreaId = htmlspecialchars(preg_replace('/^[^a-zA-Z]/', 'x', $textAreaId));
-               /* =======================================
-                * LANGUAGES & CHARACTER SETS
-                * =======================================
-                */
-               // Language
-               $GLOBALS['TSFE']->initLLvars();
-               $this->language = $GLOBALS['TSFE']->lang;
-               $this->LOCAL_LANG = \TYPO3\CMS\Core\Utility\GeneralUtility::readLLfile('EXT:' . $this->ID . '/locallang.xlf', $this->language);
-               if ($this->language === 'default' || !$this->language) {
-                       $this->language = 'en';
-               }
-               $this->contentISOLanguage = $GLOBALS['TSFE']->sys_language_isocode ?: 'en';
-               $this->contentLanguageUid = max($row['sys_language_uid'], 0);
-               if ($this->contentLanguageUid && \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('static_info_tables')) {
-                       $tableA = 'sys_language';
-                       $tableB = 'static_languages';
-                       $selectFields = $tableA . '.uid,' . $tableB . '.lg_iso_2,' . $tableB . '.lg_country_iso_2';
-                       $tableAB = $tableA . ' LEFT JOIN ' . $tableB . ' ON ' . $tableA . '.static_lang_isocode=' . $tableB . '.uid';
-                       $whereClause = $tableA . '.uid = ' . intval($this->contentLanguageUid);
-                       $whereClause .= \TYPO3\CMS\Backend\Utility\BackendUtility::BEenableFields($tableA);
-                       $whereClause .= \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause($tableA);
-                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($selectFields, $tableAB, $whereClause);
-                       while ($languageRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                               $this->contentISOLanguage = strtolower(trim($languageRow['lg_iso_2']) . (trim($languageRow['lg_country_iso_2']) ? '_' . trim($languageRow['lg_country_iso_2']) : ''));
-                       }
-               }
-               $this->contentTypo3Language = $this->contentISOLanguage;
-               // Character set
-               $this->charset = $GLOBALS['TSFE']->renderCharset;
-               $this->OutputCharset = $GLOBALS['TSFE']->metaCharset ?: $GLOBALS['TSFE']->renderCharset;
-               // Set the charset of the content
-               $this->contentCharset = $GLOBALS['TSFE']->csConvObj->charSetArray[$this->contentTypo3Language];
-               $this->contentCharset = $this->contentCharset ?: 'utf-8';
-               $this->contentCharset = trim($GLOBALS['TSFE']->config['config']['metaCharset']) ?: $this->contentCharset;
-               /* =======================================
-                * TOOLBAR CONFIGURATION
-                * =======================================
-                */
-               $this->initializeToolbarConfiguration();
-               /* =======================================
-                * SET STYLES
-                * =======================================
-                */
-               $width = 610;
-               if (isset($this->thisConfig['RTEWidthOverride'])) {
-                       if (strstr($this->thisConfig['RTEWidthOverride'], '%')) {
-                               if ($this->client['browser'] != 'msie') {
-                                       $width = (int)$this->thisConfig['RTEWidthOverride'] > 0 ? $this->thisConfig['RTEWidthOverride'] : '100%';
-                               }
-                       } else {
-                               $width = (int)$this->thisConfig['RTEWidthOverride'] > 0 ? (int)$this->thisConfig['RTEWidthOverride'] : $width;
-                       }
-               }
-               $RTEWidth = strstr($width, '%') ? $width : $width . 'px';
-               $height = 380;
-               $RTEHeightOverride = (int)$this->thisConfig['RTEHeightOverride'];
-               $height = $RTEHeightOverride > 0 ? $RTEHeightOverride : $height;
-               $RTEHeight = $height . 'px';
-               $editorWrapWidth = '99%';
-               $editorWrapHeight = '100%';
-               $this->RTEWrapStyle = $this->RTEWrapStyle ?: ($this->RTEdivStyle ?: 'height:' . $editorWrapHeight . '; width:' . $editorWrapWidth . ';');
-               $this->RTEdivStyle = $this->RTEdivStyle ?: 'position:relative; left:0px; top:0px; height:' . $RTEHeight . '; width:' . $RTEWidth . '; border: 1px solid black;';
-               /* =======================================
-                * LOAD JS, CSS and more
-                * =======================================
-                */
-               $this->getPageRenderer();
-               // Register RTE in JS
-               $this->TCEform->additionalJS_post[] = $this->wrapCDATA($this->registerRTEinJS('', '', '', $textAreaId));
-               // Set the save option for the RTE:
-               $this->TCEform->additionalJS_submit[] = $this->setSaveRTE('editform', $textAreaId);
-               $this->pageRenderer->loadRequireJs();
-               // Loading ExtJs JavaScript files and inline code, if not configured in TS setup
-               if (!is_array($GLOBALS['TSFE']->pSetup['javascriptLibs.']['ExtJs.'])) {
-                       $this->pageRenderer->loadExtJs();
-                       $this->pageRenderer->enableExtJSQuickTips();
-               }
-               $this->pageRenderer->addJsFile('sysext/backend/Resources/Public/JavaScript/notifications.js');
-               // Preloading the pageStyle and including RTE skin stylesheets
-               $this->addPageStyle();
-               $this->pageRenderer->addCssFile($this->siteURL . 'typo3/contrib/extjs/resources/css/ext-all-notheme.css');
-               $this->pageRenderer->addCssFile($this->siteURL . 'typo3/sysext/t3skin/extjs/xtheme-t3skin.css');
-               $this->addSkin();
-               // Add RTE JavaScript
-               $this->pageRenderer->loadJquery();
-               $this->addRteJsFiles();
-               $this->pageRenderer->addJsFile($this->buildJSMainLangFile());
-               $this->pageRenderer->addJsInlineCode('HTMLArea-init', $this->getRteInitJsCode(), TRUE);
-               /* =======================================
-                * DRAW THE EDITOR
-                * =======================================
-                */
-               // Transform value:
-               $value = $this->transformContent('rte', $PA['itemFormElValue'], $table, $field, $row, $specConf, $thisConfig, $RTErelPath, $thePidValue);
-               // Further content transformation by registered plugins
-               foreach ($this->registeredPlugins as $pluginId => $plugin) {
-                       if ($this->isPluginEnabled($pluginId) && method_exists($plugin, 'transformContent')) {
-                               $value = $plugin->transformContent($value);
-                       }
-               }
-               // draw the textarea
-               $item = $this->triggerField($PA['itemFormElName']) . '
-                       <div id="pleasewait' . $textAreaId . '" class="pleasewait" style="display: block;" >' . $GLOBALS['TSFE']->csConvObj->conv($GLOBALS['TSFE']->getLLL('Please wait', $this->LOCAL_LANG), $this->charset, $GLOBALS['TSFE']->renderCharset) . '</div>
-                       <div id="editorWrap' . $textAreaId . '" class="editorWrap" style="visibility: hidden; ' . htmlspecialchars($this->RTEWrapStyle) . '">
-                       <textarea id="RTEarea' . $textAreaId . '" name="' . htmlspecialchars($PA['itemFormElName']) . '" rows="0" cols="0" style="' . htmlspecialchars($this->RTEdivStyle) . '">' . \TYPO3\CMS\Core\Utility\GeneralUtility::formatForTextarea($value) . '</textarea>
-                       </div>' . LF;
-               return $item;
-       }
-
-       /**
-        * Add style sheet file to document header
-        *
-        * @param string $key: some key identifying the style sheet
-        * @param string $href: uri to the style sheet file
-        * @param string $title: value for the title attribute of the link element
-        * @param string $relation: value for the rel attribute of the link element
-        * @return void
-        */
-       protected function addStyleSheet($key, $href, $title = '', $relation = 'stylesheet') {
-               $this->pageRenderer->addCssFile($href, $relation, 'screen', $title);
-       }
-
-       /**
-        * Return the JS-Code for copy the HTML-Code from the editor in the hidden input field.
-        * This is for submit function from the form.
-        *
-        * @param string $form: the name of the form
-        * @param string $textareaId: the id of the textarea
-        * @return string the JS-Code
-        */
-       public function setSaveRTE($form, $textareaId) {
-               return '
-               if (RTEarea[\'' . $textareaId . '\'] && !RTEarea[\'' . $textareaId . '\'].deleted) {
-                       var field = document.getElementById(\'RTEarea' . $textareaId . '\');
-                       if (field && field.nodeName.toLowerCase() == \'textarea\') {
-                               field.value = RTEarea[\'' . $textareaId . '\'][\'editor\'].getHTML();
-                       }
-               } else {
-                       OK = 0;
-               }';
-       }
-
-       /**
-        * Gets instance of PageRenderer
-        *
-        * @return      PageRenderer
-        */
-       public function getPageRenderer() {
-               if (!isset($this->pageRenderer)) {
-                       $this->pageRenderer = $GLOBALS['TSFE']->getPageRenderer();
-                       $this->pageRenderer->setBackPath(TYPO3_mainDir);
-               }
-               return $this->pageRenderer;
-       }
-
-       /**
-        * Wrap input string in CDATA enclosure
-        *
-        * @param string $string: input to be wrapped
-        * @return string wrapped string
-        */
-       public function wrapCDATA($string) {
-               return implode(LF, array(
-                       '',
-                       '/*<![CDATA[*/',
-                       $string,
-                       '/*]]>*/'
-               ));
-       }
-
-}
diff --git a/typo3/sysext/rtehtmlarea/Classes/Form/Element/RichTextElement.php b/typo3/sysext/rtehtmlarea/Classes/Form/Element/RichTextElement.php
new file mode 100644 (file)
index 0000000..bcd7fc6
--- /dev/null
@@ -0,0 +1,123 @@
+<?php
+namespace TYPO3\CMS\RteHtmlarea\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\Form\Element\AbstractFormElement;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Backend\Form\FormEngine;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Backend\Form\NodeFactory;
+
+/**
+ * Render rich text editor in FormEngine
+ */
+class RichTextElement extends AbstractFormElement {
+
+       /**
+        * This will render a <textarea> OR RTE area form field,
+        * possibly with various control/validation features
+        *
+        * @return array As defined in initializeResultArray() of AbstractNode
+        */
+       public function render() {
+               $table = $this->globalOptions['table'];
+               $fieldName = $this->globalOptions['fieldName'];
+               $row = $this->globalOptions['databaseRow'];
+               $parameterArray = $this->globalOptions['parameterArray'];
+               $resultArray = $this->initializeResultArray();
+               $backendUser = $this->getBackendUserAuthentication();
+
+               $evalList = GeneralUtility::trimExplode(',', $parameterArray['fieldConf']['config']['eval'], TRUE);
+               if (in_array('required', $evalList, TRUE)) {
+                       $resultArray['requiredFields'][$table . '_' . $row['uid'] . '_' . $fieldName] = $parameterArray['itemFormElName'];
+                       $tabAndInlineStack = $this->globalOptions['tabAndInlineStack'];
+                       if (!empty($tabAndInlineStack) && preg_match('/^(.+\\])\\[(\\w+)\\]$/', $parameterArray['itemFormElName'], $match)) {
+                               array_shift($match);
+                               $resultArray['requiredNested'][$parameterArray['itemFormElName']] = array(
+                                       'parts' => $match,
+                                       'level' => $tabAndInlineStack,
+                               );
+                       }
+               }
+
+               // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. Traditionally, this is where RTE configuration has been found.
+               $specialConfiguration = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
+               // Setting up the altItem form field, which is a hidden field containing the value
+               $altItem = '<input type="hidden" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" />';
+
+               BackendUtility::fixVersioningPid($table, $row);
+               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)
+               $rteSetup = $backendUser->getTSConfig('RTE', BackendUtility::getPagesTSconfig($recordPid));
+               $rteTcaTypeValue = BackendUtility::getTCAtypeValue($table, $row);
+               $rteSetupConfiguration = BackendUtility::RTEsetup($rteSetup['properties'], $table, $fieldName, $rteTcaTypeValue);
+
+               // Get RTE object, draw form and set flag:
+               $rteObject = BackendUtility::RTEgetObj();
+               $dummyFormEngine = new FormEngine();
+               $rteResult = $rteObject->drawRTE(
+                       $dummyFormEngine,
+                       $table,
+                       $fieldName,
+                       $row,
+                       $parameterArray,
+                       $specialConfiguration,
+                       $rteSetupConfiguration,
+                       $rteTcaTypeValue,
+                       '',
+                       $tsConfigPid,
+                       $this->globalOptions,
+                       $this->initializeResultArray()
+               );
+               // This is a compat layer for "other" RTE's: If the result is not an array, it is the html string,
+               // otherwise it is a structure similar to our casual return array
+               // @todo: This interface needs a full re-definition, RTE should probably be its own type in the
+               // @todo: end, and other RTE implementations could then just override this.
+               if (is_array($rteResult)) {
+                       $html = $rteResult['html'];
+                       $rteResult['html'] = '';
+                       $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $rteResult);
+               } else {
+                       $html = $rteResult;
+               }
+
+               // Wizard
+               $html = $this->renderWizards(
+                       array($html, $altItem),
+                       $parameterArray['fieldConf']['config']['wizards'],
+                       $table,
+                       $row,
+                       $fieldName,
+                       $parameterArray,
+                       $parameterArray['itemFormElName'],
+                       $specialConfiguration,
+                       TRUE
+               );
+
+               $resultArray['html'] = $html;
+               return $resultArray;
+       }
+
+       /**
+        * @return BackendUserAuthentication
+        */
+       protected function getBackendUserAuthentication() {
+               return $GLOBALS['BE_USER'];
+       }
+
+}
diff --git a/typo3/sysext/rtehtmlarea/Classes/Form/Resolver/RichTextNodeResolver.php b/typo3/sysext/rtehtmlarea/Classes/Form/Resolver/RichTextNodeResolver.php
new file mode 100644 (file)
index 0000000..9efbdfa
--- /dev/null
@@ -0,0 +1,101 @@
+<?php
+namespace TYPO3\CMS\Rtehtmlarea\Form\Resolver;
+
+/*
+ * 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\Form\NodeResolverInterface;
+use TYPO3\CMS\Rtehtmlarea\Form\Element\RichTextElement;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+
+/**
+ * This resolver will return the RichTextElement render class of ext:rtehtmlarea if RTE is enabled for this field.
+ */
+class RichTextNodeResolver implements NodeResolverInterface {
+
+       /**
+        * Global options from NodeFactory
+        *
+        * @var array
+        */
+       protected $globalOptions;
+
+       /**
+        * Set global options from parent instance
+        *
+        * @param array $globalOptions Global options like 'readonly' for all elements
+        * @return $this
+        */
+       public function setGlobalOptions(array $globalOptions) {
+               $this->globalOptions = $globalOptions;
+               return $this;
+       }
+
+       /**
+        * Returns RichTextElement as class name if RTE widget should be rendered.
+        *
+        * @return string|void New class name or void if this resolver does not change current class name.
+        */
+       public function resolve() {
+               $table = $this->globalOptions['table'];
+               $fieldName = $this->globalOptions['fieldName'];
+               $row = $this->globalOptions['databaseRow'];
+               $parameterArray = $this->globalOptions['parameterArray'];
+               $backendUser = $this->getBackendUserAuthentication();
+
+               if (
+                       // Whole thing is not read only
+                       empty($this->globalOptions['renderReadonly'])
+                       // This field is not read only
+                       && !$parameterArray['fieldConf']['config']['readOnly']
+                       // If RTE is generally enabled by user settings and RTE object registry can return something valid
+                       && $backendUser->isRTE()
+               ) {
+                       $specialConfiguration = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
+                       // $parameters is a key=>value array from "defaultExtras" pipe separated rte_transform string
+                       $parameters = BackendUtility::getSpecConfParametersFromArray($specialConfiguration['rte_transform']['parameters']);
+
+                       if (
+                               // If "richtext" is within defaultExtras
+                               isset($specialConfiguration['richtext'])
+                               // rte_transform[flag=foo] means RTE should only be rendered if the value of db row field "foo" can be interpreted as TRUE
+                               && (!$parameters['flag'] || !$row[$parameters['flag']])
+                       ) {
+                               // Operates by reference on $row! 'pid' is changed ...
+                               BackendUtility::fixVersioningPid($table, $row);
+                               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) {
+                                       // Fetch page ts config and do some magic with it to find out if RTE is disabled on TS level.
+                                       $rteSetup = $backendUser->getTSConfig('RTE', BackendUtility::getPagesTSconfig($recordPid));
+                                       $rteTcaTypeValue = BackendUtility::getTCAtypeValue($table, $row);
+                                       $rteSetupConfiguration = BackendUtility::RTEsetup($rteSetup['properties'], $table, $fieldName, $rteTcaTypeValue);
+                                       if (!$rteSetupConfiguration['disabled']) {
+                                               // Finally, we're sure the editor should really be rendered ...
+                                               return RichtextElement::class;
+                                       }
+                               }
+                       }
+               }
+               return NULL;
+       }
+
+       /**
+        * @return BackendUserAuthentication
+        */
+       protected function getBackendUserAuthentication() {
+               return $GLOBALS['BE_USER'];
+       }
+
+}
index 0290f91..f6652ab 100644 (file)
@@ -306,10 +306,7 @@ class RteHtmlAreaBase extends \TYPO3\CMS\Backend\Rte\AbstractRte {
                if (!$rteIsAvailable) {
                        $this->errorLog[] = 'RTE: Browser not supported.';
                }
-               if (\TYPO3\CMS\Core\Utility\VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version) < 4000000) {
-                       $rteIsAvailable = FALSE;
-                       $this->errorLog[] = 'rte: This version of htmlArea RTE cannot run under this version of TYPO3.';
-               }
+
                return $rteIsAvailable;
        }
 
index 978e901..57a18b3 100644 (file)
@@ -4,6 +4,13 @@ defined('TYPO3_MODE') or die();
 // Registering the RTE object
 $GLOBALS['TYPO3_CONF_VARS']['BE']['RTE_reg']['rtehtmlarea'] = array('objRef' => '&TYPO3\\CMS\\Rtehtmlarea\\RteHtmlAreaBase');
 
+// Register FormEngine node type resolver hook to render RTE in FormEngine if enabled
+$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'][1433167475] = array(
+       'nodeName' => 'text',
+       'priority' => 40,
+       'class' => \TYPO3\CMS\Rtehtmlarea\Form\Resolver\RichTextNodeResolver::class,
+);
+
 // Make the extension version number available to the extension scripts
 require_once \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('rtehtmlarea') . 'ext_emconf.php';
 
diff --git a/typo3/sysext/t3editor/Classes/Form/Element/T3editorElement.php b/typo3/sysext/t3editor/Classes/Form/Element/T3editorElement.php
new file mode 100644 (file)
index 0000000..645c304
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+namespace TYPO3\CMS\T3editor\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\Form\Element\AbstractFormElement;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\T3editor\T3editor;
+use TYPO3\CMS\Core\Utility\MathUtility;
+
+/**
+ * t3editor FormEngine widget
+ */
+class T3editorElement extends AbstractFormElement {
+
+       /**
+        * Render t3editor element
+        *
+        * @return array As defined in initializeResultArray() of AbstractNode
+        */
+       public function render() {
+               $resultArray = $this->initializeResultArray();
+
+               $parameterArray = $this->globalOptions['parameterArray'];
+
+               $rows = MathUtility::forceIntegerInRange($parameterArray['fieldConf']['config']['rows'] ?: 10, 1, 40);
+
+               $t3editor = GeneralUtility::makeInstance(T3editor::class);
+               $t3editor->setMode(isset($parameterArray['fieldConf']['config']['format']) ? $parameterArray['fieldConf']['config']['format'] : T3editor::MODE_MIXED);
+
+               $doc = $GLOBALS['SOBE']->doc;
+               $attributes = 'rows="' . $rows . '"' .
+                       ' wrap="off"' .
+                       ' style="width:96%; height: 60%;"' .
+                       ' onchange="' . $parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] . '" ';
+
+               $resultArray['html'] = $t3editor->getCodeEditor(
+                       $parameterArray['itemFormElName'],
+                       'text-monospace enable-tab',
+                       $parameterArray['itemFormElValue'],
+                       $attributes,
+                       $this->globalOptions['table'] . ' > ' . $this->globalOptions['fieldName'],
+                       array('target' => 0)
+               );
+               $resultArray['html'] .= $t3editor->getJavascriptCode($doc);
+
+               return $resultArray;
+       }
+
+}
diff --git a/typo3/sysext/t3editor/Classes/FormWizard.php b/typo3/sysext/t3editor/Classes/FormWizard.php
deleted file mode 100644 (file)
index 7fcaca8..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-namespace TYPO3\CMS\T3editor;
-
-/*
- * 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!
- */
-
-/**
- * Wizard for tceforms
- *
- * @author Tobias Liebig <mail_typo3@etobi.de>
- */
-class FormWizard {
-
-       /**
-        * Main function
-        *
-        * @param array $parameters
-        * @param object $pObj
-        * @return string|NULL
-        */
-       public function main($parameters, $pObj) {
-               $t3editor = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\T3editor\T3editor::class);
-               if ($parameters['params']['format'] !== '') {
-                       $t3editor->setModeByType($parameters['params']['format']);
-               } else {
-                       $t3editor->setMode(\TYPO3\CMS\T3editor\T3editor::MODE_MIXED);
-               }
-               $config = $GLOBALS['TCA'][$parameters['table']]['columns'][$parameters['field']]['config'];
-               $doc = $GLOBALS['SOBE']->doc;
-               $attributes = 'rows="' . $config['rows'] . '" ' . 'cols="' . $config['cols'] . '" ' . 'wrap="off" ' . 'style="' . $config['wizards']['t3editor']['params']['style'] . '" ' . 'onchange="' . $parameters['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] . '" ';
-               $parameters['item'] = '';
-               $parameters['item'] .= $t3editor->getCodeEditor(
-                       $parameters['itemName'],
-                       'text-monospace enable-tab',
-                       $parameters['row'][$parameters['field']],
-                       $attributes,
-                       $parameters['table'] . ' > ' . $parameters['field'],
-                       array('target' => 0)
-               );
-               $parameters['item'] .= $t3editor->getJavascriptCode($doc);
-               return '';
-       }
-
-}
index f9e8cbc..cb803c7 100644 (file)
@@ -315,7 +315,7 @@ class T3editor implements \TYPO3\CMS\Core\SingletonInterface {
                }
                $code .= '<div>' . '<textarea id="t3editor_' . $this->editorCounter . '" ' . 'name="' . $name . '" ' . 'class="' . $class . '" ' . $additionalParams . ' ' . $alt . '>' . htmlspecialchars($content) . '</textarea></div>';
                $checked = $GLOBALS['BE_USER']->uc['disableT3Editor'] ? 'checked="checked"' : '';
-               $code .= '<br /><br />' . '<div class="checkbox"><label for="t3editor_disableEditor_' . $this->editorCounter . '_checkbox"><input type="checkbox" class="checkbox t3editor_disableEditor" onclick="T3editor.toggleEditor(this);" name="t3editor_disableEditor" value="true" id="t3editor_disableEditor_' . $this->editorCounter . '_checkbox" ' . $checked . ' />' . $GLOBALS['LANG']->getLL('deactivate') . '</label></div><br /><br />';
+               $code .= '<div class="checkbox"><label for="t3editor_disableEditor_' . $this->editorCounter . '_checkbox"><input type="checkbox" class="checkbox t3editor_disableEditor" onclick="T3editor.toggleEditor(this);" name="t3editor_disableEditor" value="true" id="t3editor_disableEditor_' . $this->editorCounter . '_checkbox" ' . $checked . ' />' . $GLOBALS['LANG']->getLL('deactivate') . '</label></div>';
                if (count($hiddenfields)) {
                        foreach ($hiddenfields as $name => $value) {
                                $code .= '<input type="hidden" ' . 'name="' . $name . '" ' . 'value="' . $value . '" />';
diff --git a/typo3/sysext/t3editor/Configuration/TCA/Overrides/sys_template.php b/typo3/sysext/t3editor/Configuration/TCA/Overrides/sys_template.php
new file mode 100644 (file)
index 0000000..e2eec72
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+defined('TYPO3_MODE') or die();
+
+// Activate t3editor for sys_template constants
+if (is_array($GLOBALS['TCA']['sys_template']['columns']['constants']['config'])) {
+       $GLOBALS['TCA']['sys_template']['columns']['constants']['config']['renderType'] = 't3editor';
+       $GLOBALS['TCA']['sys_template']['columns']['constants']['config']['format'] = 'typoscript';
+}
+
+// Activate t3editor for sys_template config
+if (is_array($GLOBALS['TCA']['sys_template']['columns']['config']['config'])) {
+       $GLOBALS['TCA']['sys_template']['columns']['config']['config']['renderType'] = 't3editor';
+       $GLOBALS['TCA']['sys_template']['columns']['config']['config']['format'] = 'typoscript';
+}
index 12f9311..5d6452b 100644 (file)
@@ -1,21 +1,18 @@
 <?php
 defined('TYPO3_MODE') or die();
 
-// Add the t3editor wizard on the bodytext field of tt_content
-$GLOBALS['TCA']['tt_content']['columns']['bodytext']['config']['wizards']['t3editor'] = array(
-       'enableByTypeConfig' => 1,
-       'type' => 'userFunc',
-       'userFunc' => \TYPO3\CMS\T3editor\FormWizard::class . '->main',
-       'title' => 't3editor',
-       'icon' => 'wizard_table.gif',
-       'module' => array(
-               'name' => 'wizard_table'
-       ),
-       'params' => array(
-               'format' => 'html',
-               'style' => 'width:98%; height: 60%;'
-       )
-);
-
-// Activate the t3editor only for type html
-$GLOBALS['TCA']['tt_content']['types']['html']['showitem'] = str_replace('bodytext,', 'bodytext;LLL:EXT:cms/locallang_ttc.xlf:bodytext.ALT.html_formlabel;;nowrap:wizards[t3editor],', $GLOBALS['TCA']['tt_content']['types']['html']['showitem']);
+// Activate t3editor for tt_content type HTML if this type exists
+if (is_array($GLOBALS['TCA']['tt_content']['types']['html'])) {
+       if (!is_array($GLOBALS['TCA']['tt_content']['types']['html']['columnsOverrides'])) {
+               $GLOBALS['TCA']['tt_content']['types']['html']['columnsOverrides'] = array();
+       }
+       if (!is_array($GLOBALS['TCA']['tt_content']['types']['html']['columnsOverrides']['bodytext'])) {
+               $GLOBALS['TCA']['tt_content']['types']['html']['columnsOverrides']['bodytext'] = array();
+       }
+       $GLOBALS['TCA']['tt_content']['types']['html']['columnsOverrides']['bodytext']['defaultExtras'] = 'nowrap';
+       if (!is_array($GLOBALS['TCA']['tt_content']['types']['html']['columnsOverrides']['bodytext']['config'])) {
+               $GLOBALS['TCA']['tt_content']['types']['html']['columnsOverrides']['bodytext']['config'] = array();
+       }
+       $GLOBALS['TCA']['tt_content']['types']['html']['columnsOverrides']['bodytext']['config']['renderType'] = 't3editor';
+       $GLOBALS['TCA']['tt_content']['types']['html']['columnsOverrides']['bodytext']['config']['format'] = 'html';
+}
index b1f8d14..3ecf6a8 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 defined('TYPO3_MODE') or die();
 
-if (TYPO3_MODE == 'BE') {
+if (TYPO3_MODE === 'BE') {
        // Register hooks for tstemplate module
        $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'][] = \TYPO3\CMS\T3editor\Hook\TypoScriptTemplateInfoHook::class . '->preStartPageHook';
        $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postOutputProcessingHook'][] = \TYPO3\CMS\T3editor\Hook\TypoScriptTemplateInfoHook::class . '->postOutputProcessingHook';
@@ -11,3 +11,9 @@ if (TYPO3_MODE == 'BE') {
        $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['preOutputProcessingHook'][] = \TYPO3\CMS\T3editor\Hook\FileEditHook::class . '->preOutputProcessingHook';
        $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['postOutputProcessingHook'][] = \TYPO3\CMS\T3editor\Hook\FileEditHook::class . '->postOutputProcessingHook';
 }
+
+$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1433089350] = array(
+       'nodeName' => 't3editor',
+       'priority' => 40,
+       'class' => \TYPO3\CMS\T3editor\Form\Element\T3editorElement::class,
+);