Commit 0ee65b8f authored by Christian Kuhn's avatar Christian Kuhn Committed by Anja Leichsenring
Browse files

[!!!][FEATURE] FormEngine: The extendables

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's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: default avatarFrank Nägler <typo3@naegler.net>
Tested-by: default avatarFrank Nägler <typo3@naegler.net>
Reviewed-by: Markus Klein's avatarMarkus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein's avatarMarkus Klein <markus.klein@typo3.org>
Reviewed-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
parent 7231ac0f
...@@ -41,7 +41,7 @@ class InputElement extends AbstractFormElement { ...@@ -41,7 +41,7 @@ class InputElement extends AbstractFormElement {
$isDateField = FALSE; $isDateField = FALSE;
$config = $parameterArray['fieldConf']['config']; $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); $size = MathUtility::forceIntegerInRange($config['size'] ?: $this->defaultInputWidth, $this->minimumInputWidth, $this->maxInputWidth);
$evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE); $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
$classes = array(); $classes = array();
...@@ -87,7 +87,7 @@ class InputElement extends AbstractFormElement { ...@@ -87,7 +87,7 @@ class InputElement extends AbstractFormElement {
), ),
'itemFormElValue' => $itemFormElValue, 'itemFormElValue' => $itemFormElValue,
); );
$options['type'] = 'none'; $options['renderType'] = 'none';
/** @var NodeFactory $nodeFactory */ /** @var NodeFactory $nodeFactory */
$nodeFactory = $this->globalOptions['nodeFactory']; $nodeFactory = $this->globalOptions['nodeFactory'];
return $nodeFactory->create($options)->render(); return $nodeFactory->create($options)->render();
......
...@@ -49,7 +49,7 @@ class SelectCheckBoxElement extends AbstractFormElement { ...@@ -49,7 +49,7 @@ class SelectCheckBoxElement extends AbstractFormElement {
} }
$this->resultArray = $this->initializeResultArray(); $this->resultArray = $this->initializeResultArray();
// "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. // "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); $selItems = FormEngineUtility::getSelectItems($table, $field, $row, $parameterArray);
// Creating the label for the "No Matching Value" entry. // Creating the label for the "No Matching Value" entry.
......
...@@ -51,7 +51,7 @@ class SelectMultipleSideBySideElement extends AbstractFormElement { ...@@ -51,7 +51,7 @@ class SelectMultipleSideBySideElement extends AbstractFormElement {
} }
$this->resultArray = $this->initializeResultArray(); $this->resultArray = $this->initializeResultArray();
// "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. // "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); $selItems = FormEngineUtility::getSelectItems($table, $field, $row, $parameterArray);
// Creating the label for the "No Matching Value" entry. // Creating the label for the "No Matching Value" entry.
......
...@@ -50,7 +50,7 @@ class SelectSingleBoxElement extends AbstractFormElement { ...@@ -50,7 +50,7 @@ class SelectSingleBoxElement extends AbstractFormElement {
} }
$this->resultArray = $this->initializeResultArray(); $this->resultArray = $this->initializeResultArray();
// "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. // "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); $selItems = FormEngineUtility::getSelectItems($table, $field, $row, $parameterArray);
// Creating the label for the "No Matching Value" entry. // Creating the label for the "No Matching Value" entry.
......
...@@ -53,7 +53,7 @@ class SelectSingleElement extends AbstractFormElement { ...@@ -53,7 +53,7 @@ class SelectSingleElement extends AbstractFormElement {
$this->resultArray = $this->initializeResultArray(); $this->resultArray = $this->initializeResultArray();
// "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. // "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); $selItems = FormEngineUtility::getSelectItems($table, $field, $row, $parameterArray);
// Creating the label for the "No Matching Value" entry. // Creating the label for the "No Matching Value" entry.
......
...@@ -55,7 +55,7 @@ class SelectTreeElement extends AbstractFormElement { ...@@ -55,7 +55,7 @@ class SelectTreeElement extends AbstractFormElement {
$resultArray = $this->initializeResultArray(); $resultArray = $this->initializeResultArray();
// "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. // "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); $selItems = FormEngineUtility::getSelectItems($table, $field, $row, $parameterArray);
$maxitems = (int)$config['maxitems']; $maxitems = (int)$config['maxitems'];
......
...@@ -17,7 +17,6 @@ namespace TYPO3\CMS\Backend\Form\Element; ...@@ -17,7 +17,6 @@ namespace TYPO3\CMS\Backend\Form\Element;
use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\MathUtility; use TYPO3\CMS\Core\Utility\MathUtility;
use TYPO3\CMS\Backend\Form\FormEngine;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Backend\Form\NodeFactory; use TYPO3\CMS\Backend\Form\NodeFactory;
...@@ -35,8 +34,7 @@ class TextElement extends AbstractFormElement { ...@@ -35,8 +34,7 @@ class TextElement extends AbstractFormElement {
protected $charactersPerRow = 40; protected $charactersPerRow = 40;
/** /**
* This will render a <textarea> OR RTE area form field, * This will render a <textarea>
* possibly with various control/validation features
* *
* @return array As defined in initializeResultArray() of AbstractNode * @return array As defined in initializeResultArray() of AbstractNode
*/ */
...@@ -85,7 +83,7 @@ class TextElement extends AbstractFormElement { ...@@ -85,7 +83,7 @@ class TextElement extends AbstractFormElement {
), ),
'itemFormElValue' => $parameterArray['itemFormElValue'], 'itemFormElValue' => $parameterArray['itemFormElValue'],
); );
$options['type'] = 'none'; $options['renderType'] = 'none';
/** @var NodeFactory $nodeFactory */ /** @var NodeFactory $nodeFactory */
$nodeFactory = $this->globalOptions['nodeFactory']; $nodeFactory = $this->globalOptions['nodeFactory'];
return $nodeFactory->create($options)->render(); return $nodeFactory->create($options)->render();
...@@ -103,168 +101,102 @@ class TextElement extends AbstractFormElement { ...@@ -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. // "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 // 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']) . '" />'; $altItem = '<input type="hidden" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" />';
$html = ''; $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 // Show message, if no RTE (field can only be edited with RTE!)
$html = $this->renderWizards( if ($specialConfiguration['rte_only']) {
array($html, $altItem), $html = '<p><em>' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.noRTEfound')) . '</em></p>';
$config['wizards'], } else {
$table, // validation
$row, foreach ($evalList as $func) {
$fieldName, if ($func === 'required') {
$parameterArray, $resultArray['requiredFields'][$table . '_' . $row['uid'] . '_' . $fieldName] = $parameterArray['itemFormElName'];
$parameterArray['itemFormElName'], } else {
$specialConfiguration, // Hint: There is a similar hook for "evaluateFieldValue" in DataHandler
TRUE $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 // calculate classes
$styles = array(); $classes = array();
// add the max-height from the users' preference to it $classes[] = 'form-control';
$maximumHeight = (int)$backendUser->uc['resizeTextareas_MaxHeight']; $classes[] = 't3js-formengine-textarea';
if ($maximumHeight > 0) { if ($specialConfiguration['fixed-font']) {
$styles[] = 'max-height: ' . $maximumHeight . 'px'; $classes[] = 'text-monospace';
} }
if ($specialConfiguration['enable-tab']) {
$classes[] = 't3js-enable-tab';
}
// calculate attributes // calculate styles
$attributes = array(); $styles = array();
$attributes['id'] = str_replace('.', '', uniqid('formengine-textarea-', TRUE)); // add the max-height from the users' preference to it
$attributes['name'] = $parameterArray['itemFormElName']; $maximumHeight = (int)$backendUser->uc['resizeTextareas_MaxHeight'];
if (!empty($styles)) { if ($maximumHeight > 0) {
$attributes['style'] = implode(' ', $styles); $styles[] = 'max-height: ' . $maximumHeight . 'px';
} }
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) . '"';
}
// Build the textarea // calculate attributes
$placeholderValue = $this->getPlaceholderValue($table, $config, $row); $attributes = array();
$placeholderAttribute = ''; $attributes['id'] = str_replace('.', '', uniqid('formengine-textarea-', TRUE));
if (!empty($placeholderValue)) { $attributes['name'] = $parameterArray['itemFormElName'];
$placeholderAttribute = ' placeholder="' . htmlspecialchars(trim($languageService->sL($placeholderValue))) . '" '; 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' // Build the textarea
. $attributeString $placeholderValue = $this->getPlaceholderValue($table, $config, $row);
. $placeholderAttribute $placeholderAttribute = '';
. $parameterArray['onFocus'] if (!empty($placeholderValue)) {
. '>' . GeneralUtility::formatForTextarea($parameterArray['itemFormElValue']) . '</textarea>'; $placeholderAttribute = ' placeholder="' . htmlspecialchars(trim($languageService->sL($placeholderValue))) . '" ';
}
// Wrap a wizard around the item? $html .= '<textarea'
$html = $this->renderWizards( . $attributeString
array($html, $altItem), . $placeholderAttribute
$config['wizards'], . $parameterArray['onFocus']
$table, . '>' . GeneralUtility::formatForTextarea($parameterArray['itemFormElValue']) . '</textarea>';
$row,
$fieldName, // Wrap a wizard around the item?
$parameterArray, $html = $this->renderWizards(
$parameterArray['itemFormElName'], array($html, $altItem),
$specialConfiguration, $config['wizards'],
$rteWouldHaveBeenLoaded $table,
); $row,
$fieldName,
$parameterArray,
$parameterArray['itemFormElName'],
$specialConfiguration,
FALSE
);
$maximumWidth = (int)$this->formMaxWidth($cols); $maximumWidth = (int)$this->formMaxWidth($cols);
$html = '<div class="form-control-wrap"' . ($maximumWidth ? ' style="max-width: ' . $maximumWidth . 'px"' : '') . '>' . $html . '</div>'; $html = '<div class="form-control-wrap"' . ($maximumWidth ? ' style="max-width: ' . $maximumWidth . 'px"' : '') . '>' . $html . '</div>';
}
} }
$resultArray['html'] = $html; $resultArray['html'] = $html;
return $resultArray; return $resultArray;
} }
......
...@@ -303,7 +303,7 @@ class FormEngine { ...@@ -303,7 +303,7 @@ class FormEngine {
} }
$options = $this->getConfigurationOptionsForChildElements(); $options = $this->getConfigurationOptionsForChildElements();
$options['type'] = 'fullRecordContainer'; $options['renderType'] = 'fullRecordContainer';
$resultArray = $this->nodeFactory->create($options)->render(); $resultArray = $this->nodeFactory->create($options)->render();
$content = $resultArray['html']; $content = $resultArray['html'];
...@@ -345,7 +345,7 @@ class FormEngine { ...@@ -345,7 +345,7 @@ class FormEngine {
$options = $this->getConfigurationOptionsForChildElements(); $options = $this->getConfigurationOptionsForChildElements();
$options['singleFieldToRender'] = $theFieldToReturn; $options['singleFieldToRender'] = $theFieldToReturn;
$options['type'] = 'soloFieldContainer'; $options['renderType'] = 'soloFieldContainer';
$resultArray = $this->nodeFactory->create($options)->render(); $resultArray = $this->nodeFactory->create($options)->render();
$html = $resultArray['html']; $html = $resultArray['html'];
...@@ -383,7 +383,7 @@ class FormEngine { ...@@ -383,7 +383,7 @@ class FormEngine {
$options = $this->getConfigurationOptionsForChildElements(); $options = $this->getConfigurationOptionsForChildElements();
$options['fieldListToRender'] = $list; $options['fieldListToRender'] = $list;
$options['type'] = 'listOfFieldsContainer'; $options['renderType'] = 'listOfFieldsContainer';
$resultArray = $this->nodeFactory->create($options)->render(); $resultArray = $this->nodeFactory->create($options)->render();
$html = $resultArray['html']; $html = $resultArray['html'];
...@@ -430,6 +430,7 @@ class FormEngine { ...@@ -430,6 +430,7 @@ class FormEngine {
'palettesCollapsed' => $this->palettesCollapsed, 'palettesCollapsed' => $this->palettesCollapsed,
'table' => $this->table, 'table' => $this->table,
'databaseRow' => $this->databaseRow, 'databaseRow' => $this->databaseRow,
'recordTypeValue' => '',
'additionalPreviewLanguages' => $this->additionalPreviewLanguages, 'additionalPreviewLanguages' => $this->additionalPreviewLanguages,
'localizationMode' => $this->localizationMode, // @todo: find out the details, Warning, this overlaps with inline behaviour localizationMode 'localizationMode' => $this->localizationMode, // @todo: find out the details, Warning, this overlaps with inline behaviour localizationMode
'elementBaseName' => '', 'elementBaseName' => '',
...@@ -545,7 +546,7 @@ class FormEngine { ...@@ -545,7 +546,7 @@ class FormEngine {
$options['inlineStructure'] = $this->inlineStackProcessor->getStructure(); $options['inlineStructure'] = $this->inlineStackProcessor->getStructure();
$options['isAjaxContext'] = TRUE; $options['isAjaxContext'] = TRUE;
$options['type'] = 'inlineRecordContainer'; $options['renderType'] = 'inlineRecordContainer';
$childArray = $this->nodeFactory->create($options)->render(); $childArray = $this->nodeFactory->create($options)->render();
if ($childArray === FALSE) { if ($childArray === FALSE) {
...@@ -677,7 +678,7 @@ class FormEngine { ...@@ -677,7 +678,7 @@ class FormEngine {
$options['inlineStructure'] = $this->inlineStackProcessor->getStructure(); $options['inlineStructure'] = $this->inlineStackProcessor->getStructure();
$options['isAjaxContext'] = TRUE; $options['isAjaxContext'] = TRUE;
$options['type'] = 'inlineRecordContainer'; $options['renderType'] = 'inlineRecordContainer';
$childArray = $this->nodeFactory->create($options)->render(); $childArray = $this->nodeFactory->create($options)->render();
if ($childArray === FALSE) { if ($childArray === FALSE) {
...@@ -786,7 +787,7 @@ class FormEngine { ...@@ -786,7 +787,7 @@ class FormEngine {
$options['inlineStructure'] = $this->inlineStackProcessor->getStructure(); $options['inlineStructure'] = $this->inlineStackProcessor->getStructure();
$options['isAjaxContext'] = TRUE; $options['isAjaxContext'] = TRUE;
$options['type'] = 'inlineRecordContainer'; $options['renderType'] = 'inlineRecordContainer';
$childArray = $this->nodeFactory->create($options)->render(); $childArray = $this->nodeFactory->create($options)->render();
$html .= $childArray['html']; $html .= $childArray['html'];
$childArray['html'] = ''; $childArray['html'] = '';
......
...@@ -20,16 +20,11 @@ use TYPO3\CMS\Backend\Form\Element; ...@@ -20,16 +20,11 @@ use TYPO3\CMS\Backend\Form\Element;
/** /**
* Create an element object depending on type. * 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 { class NodeFactory {
/** /**
* Default registry of node-type to handling class * Default registry of node name to handling class
* *
* @var array * @var array
*/ */
...@@ -62,48 +57,86 @@ class NodeFactory { ...@@ -62,48 +57,86 @@ class NodeFactory {
'selectTree' => Element\SelectTreeElement::class, 'selectTree' => Element\SelectTreeElement::class,
'selectSingle' => Element\SelectSingleElement::class, 'selectSingle' => Element\SelectSingleElement::class,
'selectSingleBox' => Element\SelectSingleBoxElement::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, 'text' => Element\TextElement::class,
'unknown' => Element\UnknownElement::class, 'unknown' => Element\UnknownElement::class,
'user' => Element\UserElement::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() { 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 * @param array $globalOptions All information to decide which class should be instantiated and given down to sub nodes
* @return AbstractNode * @return AbstractNode
* @throws Exception * @throws Exception
*/ */
public function create(array $globalOptions) { public function