Commit 84be5e61 authored by Christian Kuhn's avatar Christian Kuhn
Browse files

[!!!][FEATURE] FormEngine element level refactoring

The patch introduces a new API on FormEngine element level
that substitutes the old "wizards" / renderWizard() API
with a more powerful system.

Single wizards are now split into one of three categories:
* An informational wizard
* A control button / icon
* A true wizard with additonal functionality

Method renderWizards() is still called in elements for compatibility
reasons if people added own scrip/popup/userFunc wizards, but all
core wizards are migrated.

The patch significantly cleans the HTML of single elements, especially
HTML stuff that was added by the SingleFieldContainer is now put down
to single elements, while main HTML wraps formerly done by renderWizards()
is fetched "up" to single elements. This gives single elements full
control about the main HTML it is producing, which is a must have
preparation in order to further advance in this area and to switch
single elements to fluid rendering in one of the next steps.

The patch brings a pretty huge list of TCA changes and
simplifications, all TCA changes are supported by TCA migration,
so existing extensions should benefit out of the box and just
get deprecations logged.

Change-Id: I45083e14e45bbf40c06267b51c9d0b7c15e2f7ab
Resolves: #79440
Resolves: #70032
Releases: master
Reviewed-on: https://review.typo3.org/51151

Tested-by: default avatarTYPO3com <no-reply@typo3.com>
Reviewed-by: Wouter Wolters's avatarWouter Wolters <typo3@wouterwolters.nl>
Tested-by: Mona Muzaffar's avatarMona Muzaffar <mona.muzaffar@gmx.de>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
parent 6752a362
......@@ -314,36 +314,26 @@ select {
// Form Wizards
//
.form-wizards-wrap {
&.form-wizards-top {
> .form-wizards-items {
margin-bottom: 9px;
}
display: table;
width: 100%;
> .form-wizards-element {
display: table-cell;
width: 100%;
}
&.form-wizards-bottom {
> .form-wizards-element {
margin-bottom: 9px;
}
> .form-wizards-items-top {
display: table-row;
}
&.form-wizards-aside {
display: table;
width: 100%;
> .form-wizards-element {
width: 100%;
}
> .form-wizards-element,
> .form-wizards-items {
display: table-cell;
vertical-align: top;
}
> .form-wizards-items {
white-space: nowrap;
padding-left: 5px;
}
> .form-wizards-items-aside {
display: table-cell;
vertical-align: top;
padding-left: 5px;
white-space: nowrap;
}
}
.form-wizards-element {
> .table-fit {
margin-bottom: 9px;
> .form-wizards-items-bottom {
display: table-row;
}
> .form-wizards-items-bottom:first-child {
margin-top: 4px;
}
}
......
......@@ -75,6 +75,7 @@
"always-add-alias-loader": true,
"class-alias-maps": [
"typo3/sysext/fluid/Migrations/Code/ClassAliasMap.php",
"typo3/sysext/rtehtmlarea/Migrations/Code/ClassAliasMap.php",
"typo3/sysext/version/Migrations/Code/ClassAliasMap.php"
]
},
......
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "2acb42e35d36e35f70942355d0b8e669",
"content-hash": "1fe12bb655c3cb1c01ee8d0e5b945e1e",
"packages": [
{
"name": "cogpowered/finediff",
......
......@@ -24,6 +24,10 @@ use TYPO3\CMS\Core\Utility\PathUtility;
/**
* Script Class for colorpicker wizard
*
* Unused with new renderType "inputColorPicker" since v8.
*
* @deprecated since TYPO3 v8, will be removed in TYPO3 v9
*/
class ColorpickerController extends AbstractWizardController
{
......@@ -119,9 +123,12 @@ class ColorpickerController extends AbstractWizardController
/**
* Constructor
*
* @deprecated since TYPO3 v8, will be removed in TYPO3 v9
*/
public function __construct()
{
GeneralUtility::logDeprecatedFunction();
parent::__construct();
$this->getLanguageService()->includeLLFile('EXT:lang/Resources/Private/Language/locallang_wizards.xlf');
$GLOBALS['SOBE'] = $this;
......
......@@ -97,7 +97,7 @@ class SuggestWizardController
$pageTsConfig = BackendUtility::getPagesTSconfig($pid);
$wizardConfig = $fieldConfig['wizards']['suggest'];
$wizardConfig = $fieldConfig['suggestOptions'] ?? [];
$queryTables = $this->getTablesToQueryFromFieldConfiguration($fieldConfig);
$whereClause = $this->getWhereClause($fieldConfig);
......
<?php
declare(strict_types=1);
namespace TYPO3\CMS\Backend\Form;
/*
......@@ -22,6 +23,13 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
*/
abstract class AbstractNode implements NodeInterface
{
/**
* Instance of the node factory to create sub elements, container and single element expansions.
*
* @var NodeFactory
*/
protected $nodeFactory;
/**
* Main data array to work on, given from parent to child elements
*
......@@ -30,13 +38,30 @@ abstract class AbstractNode implements NodeInterface
protected $data = [];
/**
* Set data to data array.
* A list of default field information added to the element / container.
*
* @todo: Should NOT set the nodeFactory instance, this is done by AbstractContainer only,
* @todo: but not done for Element classes: Elements are tree leaves, they MUST
* @todo: not create new nodes again.
* @todo: Currently, AbstractFormElement still does that, but do not rely on the fact that
* @todo: Element classes have an instance of NodeFactory at hand.
* @var array
*/
protected $defaultFieldInformation = [];
/**
* A list of default field controls added to the element / container.
* This property is often reset by single elements.
*
* @var array
*/
protected $defaultFieldControl = [];
/**
* A list of default field wizards added to the element / container.
* This property is often reset by single elements.
*
* @var array
*/
protected $defaultFieldWizard = [];
/**
* Set data to data array and register node factory to render sub elements
*
* @param NodeFactory $nodeFactory
* @param array $data
......@@ -44,6 +69,7 @@ abstract class AbstractNode implements NodeInterface
public function __construct(NodeFactory $nodeFactory, array $data)
{
$this->data = $data;
$this->nodeFactory = $nodeFactory;
}
/**
......@@ -60,7 +86,7 @@ abstract class AbstractNode implements NodeInterface
*
* @return array
*/
protected function initializeResultArray()
protected function initializeResultArray(): array
{
return [
'additionalJavaScriptPost' => [],
......@@ -68,7 +94,9 @@ abstract class AbstractNode implements NodeInterface
'additionalHiddenFields' => [],
'additionalInlineLanguageLabelFiles' => [],
'stylesheetFiles' => [],
// can hold strings or arrays, string = requireJS module, array = requireJS module + callback e.g. array('TYPO3/Foo/Bar', 'function() {}')
// can hold strings or arrays,
// string = requireJS module,
// array = requireJS module + callback e.g. array('TYPO3/Foo/Bar', 'function() {}')
'requireJsModules' => [],
'inlineData' => [],
'html' => '',
......@@ -80,14 +108,17 @@ abstract class AbstractNode implements NodeInterface
*
* @param array $existing Currently merged array
* @param array $childReturn Array returned by child
* @param bool $mergeHtml If false, the ['html'] section of $childReturn will NOT be added to $existing
* @return array Result array
*/
protected function mergeChildReturnIntoExistingResult(array $existing, array $childReturn)
protected function mergeChildReturnIntoExistingResult(array $existing, array $childReturn, bool $mergeHtml = true): array
{
if (!empty($childReturn['html'])) {
if ($mergeHtml && !empty($childReturn['html'])) {
$existing['html'] .= LF . $childReturn['html'];
}
if (!empty($childReturn['extJSCODE'])) {
// @deprecated since TYPO3 CMS 8, will be removed in TYPO3 CMS 9.
GeneralUtility::logDeprecatedFunction();
$existing['extJSCODE'] .= LF . $childReturn['extJSCODE'];
}
foreach ($childReturn['additionalJavaScriptPost'] as $value) {
......@@ -127,9 +158,11 @@ abstract class AbstractNode implements NodeInterface
*
* @param array $config
* @return string
* @deprecated since TYPO3 v8, will be removed in TYPO3 v9 - use getValidationDataAsJsonString() instead
*/
protected function getValidationDataAsDataAttribute(array $config)
protected function getValidationDataAsDataAttribute(array $config): string
{
GeneralUtility::logDeprecatedFunction();
return sprintf(' data-formengine-validation-rules="%s" ', htmlspecialchars($this->getValidationDataAsJsonString($config)));
}
......@@ -139,24 +172,28 @@ abstract class AbstractNode implements NodeInterface
* @param array $config
* @return string
*/
protected function getValidationDataAsJsonString(array $config)
protected function getValidationDataAsJsonString(array $config): string
{
$validationRules = [];
if (!empty($config['eval'])) {
$evalList = GeneralUtility::trimExplode(',', $config['eval'], true);
unset($config['eval']);
foreach ($evalList as $evalType) {
$validationRules[] = [
'type' => $evalType,
'config' => $config
];
}
}
if (!empty($config['range'])) {
$validationRules[] = [
$newValidationRule = [
'type' => 'range',
'config' => $config['range']
];
if (!empty($config['range']['lower'])) {
$newValidationRule['lower'] = $config['range']['lower'];
}
if (!empty($config['range']['upper'])) {
$newValidationRule['upper'] = $config['range']['upper'];
}
$validationRules[] = $newValidationRule;
}
if (!empty($config['maxitems']) || !empty($config['minitems'])) {
$minItems = (isset($config['minitems'])) ? (int)$config['minitems'] : 0;
......
......@@ -15,10 +15,7 @@ namespace TYPO3\CMS\Backend\Form\Container;
*/
use TYPO3\CMS\Backend\Form\AbstractNode;
use TYPO3\CMS\Backend\Form\NodeFactory;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
......@@ -29,30 +26,61 @@ use TYPO3\CMS\Fluid\View\StandaloneView;
abstract class AbstractContainer extends AbstractNode
{
/**
* Instance of the node factory to create sub elements and container.
* Merge field information configuration with default and render them.
*
* @var NodeFactory
* @return array Result array
*/
protected $nodeFactory;
protected function renderFieldInformation(): array
{
$options = $this->data;
$fieldInformation = $this->defaultFieldInformation;
$currentRenderType = $this->data['renderType'];
$fieldInformationFromTca = $options['processedTca']['ctrl']['container'][$currentRenderType]['fieldInformation'] ?? [];
ArrayUtility::mergeRecursiveWithOverrule($fieldInformation, $fieldInformationFromTca);
$options['renderType'] = 'fieldInformation';
$options['renderData']['fieldInformation'] = $fieldInformation;
return $this->nodeFactory->create($options)->render();
}
/**
* Merge field control configuration with default controls and render them.
*
* @return array Result array
*/
protected function renderFieldControl(): array
{
$options = $this->data;
$fieldControl = $this->defaultFieldControl;
$currentRenderType = $this->data['renderType'];
$fieldControlFromTca = $options['processedTca']['ctrl']['container'][$currentRenderType]['fieldControl'] ?? [];
ArrayUtility::mergeRecursiveWithOverrule($fieldControl, $fieldControlFromTca);
$options['renderType'] = 'fieldControl';
$options['renderData']['fieldControl'] = $fieldControl;
return $this->nodeFactory->create($options)->render();
}
/**
* Container objects give $nodeFactory down to other containers.
* Merge field wizard configuration with default wizards and render them.
*
* @param NodeFactory $nodeFactory
* @param array $data
* @return array Result array
*/
public function __construct(NodeFactory $nodeFactory, array $data)
protected function renderFieldWizard(): array
{
parent::__construct($nodeFactory, $data);
$this->nodeFactory = $nodeFactory;
$options = $this->data;
$fieldWizard = $this->defaultFieldWizard;
$currentRenderType = $this->data['renderType'];
$fieldWizardFromTca = $options['processedTca']['ctrl']['container'][$currentRenderType]['fieldWizard'] ?? [];
ArrayUtility::mergeRecursiveWithOverrule($fieldWizard, $fieldWizardFromTca);
$options['renderType'] = 'fieldWizard';
$options['renderData']['fieldWizard'] = $fieldWizard;
return $this->nodeFactory->create($options)->render();
}
/**
* A single field of TCA 'types' 'showitem' can have four semicolon separated configuration options:
* A single field of TCA 'types' 'showitem' can have three semicolon separated configuration options:
* fieldName: Name of the field to be found in TCA 'columns' section
* fieldLabel: An alternative field label
* paletteName: Name of a palette to be found in TCA 'palettes' section that is rendered after this field
* extra: Special configuration options of this field
*
* @param string $field Semicolon separated field configuration
* @throws \RuntimeException
......@@ -96,57 +124,4 @@ abstract class AbstractContainer extends AbstractNode
]);
return $view->render();
}
/**
* Rendering preview output of a field value which is not shown as a form field but just outputted.
*
* @param string $value The value to output
* @param array $config Configuration for field.
* @param string $field Name of field.
* @return string HTML formatted output
*/
protected function previewFieldValue($value, $config, $field = '')
{
if ($config['config']['type'] === 'group' && ($config['config']['internal_type'] === 'file' || $config['config']['internal_type'] === 'file_reference')) {
// Ignore upload folder if internal_type is file_reference
if ($config['config']['internal_type'] === 'file_reference') {
$config['config']['uploadfolder'] = '';
}
$table = 'tt_content';
// Making the array of file items:
$itemArray = GeneralUtility::trimExplode(',', $value, true);
// Showing thumbnails:
$imgs = [];
$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
foreach ($itemArray as $imgRead) {
$imgParts = explode('|', $imgRead);
$imgPath = rawurldecode($imgParts[0]);
$rowCopy = [];
$rowCopy[$field] = $imgPath;
// Icon + click menu:
$absFilePath = GeneralUtility::getFileAbsFileName($config['config']['uploadfolder'] ? $config['config']['uploadfolder'] . '/' . $imgPath : $imgPath);
$fileInformation = pathinfo($imgPath);
$title = $fileInformation['basename'] . ($absFilePath && @is_file($absFilePath))
? ' (' . GeneralUtility::formatSize(filesize($absFilePath)) . ')'
: ' - FILE NOT FOUND!';
$fileIcon = '<span title="' . htmlspecialchars($title) . '">' . $iconFactory->getIconForFileExtension($fileInformation['extension'], Icon::SIZE_SMALL)->render() . '</span>';
$imgs[] =
'<span class="text-nowrap">' .
BackendUtility::thumbCode(
$rowCopy,
$table,
$field,
'',
'',
$config['config']['uploadfolder'], 0, ' align="middle"'
) .
($absFilePath ? BackendUtility::wrapClickMenuOnIcon($fileIcon, $absFilePath, 0, 1, '', '+copy,info,edit,view') : $fileIcon) .
$imgPath .
'</span>';
}
return implode('<br />', $imgs);
} else {
return nl2br(htmlspecialchars($value));
}
}
}
......@@ -113,10 +113,9 @@ class FlexFormContainerContainer extends AbstractContainer
$html[] = '</div>';
$html[] = '</div>';
$containerContentResult['html'] = '';
$resultArray = $this->initializeResultArray();
$resultArray['html'] = implode(LF, $html);
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $containerContentResult);
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $containerContentResult, false);
return $resultArray;
}
......
......@@ -75,7 +75,6 @@ class FlexFormElementContainer extends AbstractContainer
'label' => $languageService->sL(trim($flexFormFieldArray['label'])),
'config' => $flexFormFieldArray['config'],
'children' => $flexFormFieldArray['children'],
'defaultExtras' => $flexFormFieldArray['defaultExtras'],
'onChange' => $flexFormFieldArray['onChange'],
],
'fieldChangeFunc' => $parameterArray['fieldChangeFunc'],
......@@ -152,8 +151,7 @@ class FlexFormElementContainer extends AbstractContainer
$html[] = '</div>';
$resultArray['html'] .= implode(LF, $html);
$childResult['html'] = '';
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childResult);
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childResult, false);
}
}
......
......@@ -91,8 +91,7 @@ class FlexFormTabsContainer extends AbstractContainer
'linkTitle' => trim($sheetDataStructure['ROOT']['sheetShortDescr']) ? $languageService->sL(trim($sheetDataStructure['ROOT']['sheetShortDescr'])) : '',
];
$childReturn['html'] = '';
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childReturn);
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childReturn, false);
}
$resultArray['html'] = $this->renderTabMenu($tabElements, $domIdPrefix);
......
......@@ -285,8 +285,7 @@ class InlineControlContainer extends AbstractContainer
$options['renderType'] = 'inlineRecordContainer';
$childResult = $this->nodeFactory->create($options)->render();
$html .= $childResult['html'];
$childArray['html'] = '';
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childResult);
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childResult, false);
if (!$options['isInlineDefaultLanguageRecordInLocalizedParentContext']) {
// Don't add record to list of "valid" uids if it is only the default
// language record of a not yet localized child
......@@ -323,7 +322,7 @@ class InlineControlContainer extends AbstractContainer
// Publish the uids of the child records in the given order to the browser
$html .= '<input type="hidden" name="' . $nameForm . '" value="' . implode(',', $sortableRecordUids) . '" '
. $this->getValidationDataAsDataAttribute(['type' => 'inline', 'minitems' => $config['minitems'], 'maxitems' => $config['maxitems']])
. ' data-formengine-validation-rules="' . htmlspecialchars($this->getValidationDataAsJsonString(['type' => 'inline', 'minitems' => $config['minitems'], 'maxitems' => $config['maxitems']])) . '"'
. ' class="inlineRecord" />';
// Close the wrap for all inline fields (container)
$html .= '</div>';
......
......@@ -138,13 +138,11 @@ class InlineRecordContainer extends AbstractContainer
if (isset($data['combinationChild'])) {
$combinationChild = $this->renderCombinationChild($data, $appendFormFieldNames);
$combinationHtml = $combinationChild['html'];
$combinationChild['html'] = '';
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $combinationChild);
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $combinationChild, false);
}
$childArray = $this->renderChild($data);
$html = $childArray['html'];
$childArray['html'] = '';
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childArray);
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childArray, false);
} else {
// This string is the marker for the JS-function to check if the full content has already been loaded
$html = '<!--notloaded-->';
......
......@@ -129,8 +129,18 @@ class OuterWrapContainer extends AbstractContainer
]);
}
$fieldInformationResult = $this->renderFieldInformation();
$fieldInformationHtml = $fieldInformationResult['html'];
$result = $this->mergeChildReturnIntoExistingResult($result, $fieldInformationResult, false);
$fieldWizardResult = $this->renderfieldWizard();
$fieldWizardHtml = $fieldWizardResult['html'];
$result = $this->mergeChildReturnIntoExistingResult($result, $fieldWizardResult, false);
$view->assignMultiple([
'pageTitle' => $pageTitle,
'fieldInformationHtml' => $fieldInformationHtml,
'fieldWizardHtml' => $fieldWizardHtml,
'childHtml' => $childHtml,
'icon' => $icon,
'tableTitle' => $tableTitle,
......
......@@ -149,8 +149,7 @@ class PaletteAndSingleContainer extends AbstractContainer
];
}
$childResultArray['html'] = '';
$this->resultArray = $this->mergeChildReturnIntoExistingResult($this->resultArray, $childResultArray);
$this->resultArray = $this->mergeChildReturnIntoExistingResult($this->resultArray, $childResultArray, false);
}
}
......@@ -226,9 +225,8 @@ class PaletteAndSingleContainer extends AbstractContainer
'fieldLabel' => $fieldLabel,
'fieldHtml' => $singleFieldContentArray['html'],
];
$singleFieldContentArray['html'] = '';
}
$this->resultArray = $this->mergeChildReturnIntoExistingResult($this->resultArray, $singleFieldContentArray);
$this->resultArray = $this->mergeChildReturnIntoExistingResult($this->resultArray, $singleFieldContentArray, false);
}
}
......
......@@ -16,12 +16,8 @@ namespace TYPO3\CMS\Backend\Form\Container;
use TYPO3\CMS\Backend\Form\InlineStackProcessor;
use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
use TYPO3\CMS\Core\Utility\DiffUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\MathUtility;
use TYPO3\CMS\Lang\LanguageService;
......@@ -32,8 +28,7 @@ use TYPO3\CMS\Lang\LanguageService;
* This container is the last one in the chain before processing is handed over to single element classes.
* If a single field is of type flex or inline, it however creates FlexFormEntryContainer or InlineControlContainer.
*
* The container does various checks and processing for a given single fields, for example it resolves
* display conditions and the HTML to compare different languages.
* The container does various checks and processing for a given single fields.
*/
class SingleFieldContainer extends AbstractContainer
{
......@@ -46,18 +41,12 @@ class SingleFieldContainer extends AbstractContainer
public function render()
{
$backendUser = $this->getBackendUserAuthentication();
$languageService = $this->getLanguageService();
$resultArray = $this->initializeResultArray();
$table = $this->data['tableName'];
$row = $this->data['databaseRow'];
$fieldName = $this->data['fieldName'];
// @todo: it should be safe at this point, this array exists ...
if (!is_array($this->data['processedTca']['columns'][$fieldName])) {
return $resultArray;
}
$parameterArray = [];
$parameterArray['fieldConf'] = $this->data['processedTca']['columns'][$fieldName];
......@@ -152,14 +141,18 @@ class SingleFieldContainer extends AbstractContainer
// JavaScript code for event handlers:
$parameterArray['fieldChangeFunc'] = [];
$parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'TBE_EDITOR.fieldChanged(' . GeneralUtility::quoteJSvalue($table) . ',' . GeneralUtility::quoteJSvalue($row['uid']) . ',' . GeneralUtility::quoteJSvalue($fieldName) . ',' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ');';
$parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'TBE_EDITOR.fieldChanged('
. GeneralUtility::quoteJSvalue($table) . ','
. GeneralUtility::quoteJSvalue($row['uid']) . ','
. GeneralUtility::quoteJSvalue($fieldName) . ','
. GeneralUtility::quoteJSvalue($parameterArray['itemFormElName'])
. ');';
if ($alertMsgOnChange) {
$parameterArray['fieldChangeFunc']['alert'] = $alertMsgOnChange;
}
// If this is the child of an inline type and it is the field creating the label
if ($this->isInlineChildAndLabelField($table, $fieldName)) {
/** @var InlineStackProcessor $inlineStackProcessor */
$inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
$inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']);
$inlineDomObjectId = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']);
......@@ -171,7 +164,10 @@ class SingleFieldContainer extends AbstractContainer
$row['uid']