Commit 40f4bc2b authored by Simon Gilli's avatar Simon Gilli Committed by Christian Kuhn
Browse files

[FEATURE] Introduce palette descriptions

A new TCA property "description" is available to be added to
palette configurations. It allows to provide additional text,
which will be rendered by FormEngine between the palette label
and the corresponding fields. It is similar to the TCA field
description, introduced in #85410.

This will support editors as specific field usages can be
clarified directly in the UI.

In contrast to the palette label, the new description property
can not be overwritten on a record type basis.

Resolves: #89507
Releases: master
Change-Id: I4390e13830d359d54c37a347b91960de5639da4c
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/62109

Tested-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
parent 405affd3
......@@ -294,6 +294,11 @@ select {
.form-section-headline {
margin-top: 0;
margin-bottom: 10px;
& + .form-section-description {
margin-top: -5px;
margin-bottom: 10px;
}
}
//
......
......@@ -75,6 +75,7 @@ class PaletteAndSingleContainer extends AbstractContainer
'fieldHtml' => 'element2',
),
),
'paletteDescription' => 'palette1Description',
),
1 => array(
'type' => 'single',
......@@ -85,7 +86,7 @@ class PaletteAndSingleContainer extends AbstractContainer
2 => array(
'type' => 'palette2',
'fieldName' => 'palette2',
'fieldLabel' => '', // Palettes may not have a label
'fieldLabel' => '', // Palette label is optional
'elements' => array(
0 => array(
'type' => 'single',
......@@ -103,6 +104,7 @@ class PaletteAndSingleContainer extends AbstractContainer
'fieldHtml' => 'element5',
),
),
'paletteDescription' => '', // Palette description is optional
),
);
*/
......@@ -119,19 +121,23 @@ class PaletteAndSingleContainer extends AbstractContainer
$paletteElementArray = $this->createPaletteContentArray($fieldConfiguration['paletteName']);
if (!empty($paletteElementArray)) {
$mainStructureCounter++;
// If there is no label in ['types']['aType']['showitem'] for this palette: "--palette--;;aPalette",
// then use ['palettes']['aPalette']['label'] if given.
$paletteLabel = $fieldConfiguration['fieldLabel'];
if ($paletteLabel === null
&& !empty($this->data['processedTca']['palettes'][$fieldConfiguration['paletteName']]['label'])
) {
// If there is no label in ['types']['aType']['showitem'] for this palette: "--palette--;;aPalette" but
// not "--palette--;LLL:aLabelReference;aPalette", then use ['palettes']['aPalette']['label'] if given.
if ($paletteLabel === null && !empty($this->data['processedTca']['palettes'][$fieldConfiguration['paletteName']]['label'])) {
$paletteLabel = $this->data['processedTca']['palettes'][$fieldConfiguration['paletteName']]['label'];
}
// Get description of palette.
$paletteDescription = $this->data['processedTca']['palettes'][$fieldConfiguration['paletteName']]['description'] ?? '';
$targetStructure[$mainStructureCounter] = [
'type' => 'palette',
'fieldName' => $fieldConfiguration['paletteName'],
'fieldLabel' => $languageService->sL($paletteLabel),
'elements' => $paletteElementArray,
'paletteDescription' => $languageService->sL($paletteDescription),
];
}
} else {
......@@ -174,7 +180,12 @@ class PaletteAndSingleContainer extends AbstractContainer
$paletteElementsHtml = '<div class="row">' . $paletteElementsHtml . '</div>';
$content[] = $this->fieldSetWrap($paletteElementsHtml, $isHiddenPalette, $element['fieldLabel']);
$content[] = $this->fieldSetWrap(
$paletteElementsHtml,
$isHiddenPalette,
$element['fieldLabel'],
$element['paletteDescription']
);
} else {
// Return raw HTML only in case of user element with no wrapping requested
if ($this->isUserNoTableWrappingField($element)) {
......@@ -336,9 +347,10 @@ class PaletteAndSingleContainer extends AbstractContainer
* @param string $content Incoming content
* @param bool $paletteHidden TRUE if the palette is hidden
* @param string $label Given label
* @param string $description Given decription
* @return string Wrapped content
*/
protected function fieldSetWrap($content, $paletteHidden = false, $label = '')
protected function fieldSetWrap($content, $paletteHidden = false, $label = '', $description = '')
{
$fieldSetClass = 'form-section';
if ($paletteHidden) {
......@@ -352,6 +364,10 @@ class PaletteAndSingleContainer extends AbstractContainer
$result[] = '<h4 class="form-section-headline">' . htmlspecialchars($label) . '</h4>';
}
if (!empty($description)) {
$result[] = '<p class="form-section-description text-muted">' . htmlspecialchars($description) . '</p>';
}
$result[] = $content;
$result[] = '</fieldset>';
return implode(LF, $result);
......
......@@ -73,8 +73,9 @@ class PaletteAndSingleContainerTest extends UnitTestCase
$GLOBALS['BE_USER'] = $backendUserAuthentication->reveal();
$languageService->loadSingleTableDescription(Argument::cetera())->willReturn('');
// Expect translation call to the label reference
// Expect translation call to the label reference and empty description
$languageService->sL($labelReference)->willReturnArgument(0);
$languageService->sL('')->willReturnArgument(0);
$expectedChildDataArray = $input;
$expectedChildDataArray['renderType'] = 'singleFieldContainer';
......@@ -89,7 +90,7 @@ class PaletteAndSingleContainerTest extends UnitTestCase
/**
* @test
*/
public function renderUsesPaletteLabelFromPaletteArray()
public function renderUsesPaletteValuesFromPaletteArray()
{
$nodeFactoryProphecy = $this->prophesize(NodeFactory::class);
$singleFieldContainerProphecy = $this->prophesize(SingleFieldContainer::class);
......@@ -105,6 +106,7 @@ class PaletteAndSingleContainerTest extends UnitTestCase
$singleFieldContainerProphecy->render(Argument::cetera())->shouldBeCalled()->willReturn($singleFieldContainerReturn);
$labelReference = 'LLL:EXT:Resources/Private/Language/locallang.xlf:aLabel';
$descriptionReference = 'LLL:EXT:Resources/Private/Language/locallang.xlf:aDescription';
$input = [
'tableName' => 'aTable',
'recordTypeValue' => 'aType',
......@@ -115,6 +117,7 @@ class PaletteAndSingleContainerTest extends UnitTestCase
'palettes' => [
'aPalette' => [
'label' => $labelReference,
'description' => $descriptionReference,
'showitem' => 'aField',
],
],
......@@ -130,8 +133,9 @@ class PaletteAndSingleContainerTest extends UnitTestCase
$GLOBALS['BE_USER'] = $backendUserAuthentication->reveal();
$languageService->loadSingleTableDescription(Argument::cetera())->willReturn('');
// Expect translation call to the label reference
// Expect translation call to the label and description references
$languageService->sL($labelReference)->willReturnArgument(0);
$languageService->sL($descriptionReference)->willReturnArgument(0);
$expectedChildDataArray = $input;
$expectedChildDataArray['renderType'] = 'singleFieldContainer';
......@@ -139,14 +143,15 @@ class PaletteAndSingleContainerTest extends UnitTestCase
$nodeFactoryProphecy->create($expectedChildDataArray)->willReturn($singleFieldContainerProphecy->reveal());
$containerResult = (new PaletteAndSingleContainer($nodeFactoryProphecy->reveal(), $input))->render();
// Expect label is in answer HTML
// Expect label and description are in answer HTML
self::assertStringContainsString($labelReference, $containerResult['html']);
self::assertStringContainsString($descriptionReference, $containerResult['html']);
}
/**
* @test
*/
public function renderPrefersFieldArrayPaletteLabelOverPaletteLabel()
public function renderPrefersFieldArrayPaletteValuesOverPaletteValues()
{
$nodeFactoryProphecy = $this->prophesize(NodeFactory::class);
$singleFieldContainerProphecy = $this->prophesize(SingleFieldContainer::class);
......@@ -162,7 +167,8 @@ class PaletteAndSingleContainerTest extends UnitTestCase
$singleFieldContainerProphecy->render(Argument::cetera())->shouldBeCalled()->willReturn($singleFieldContainerReturn);
$labelReferenceFieldArray = 'LLL:EXT:Resources/Private/Language/locallang.xlf:aLabel';
$labelReferencePaletteArray = 'LLL:EXT:Resources/Private/Language/locallang.xlf:aLabel';
$labelReferencePaletteArray = 'LLL:EXT:Resources/Private/Language/locallang.xlf:aLabelPalette';
$descriptionReferencePaletteArray = 'LLL:EXT:Resources/Private/Language/locallang.xlf:aDescriptionPalette';
$input = [
'tableName' => 'aTable',
'recordTypeValue' => 'aType',
......@@ -173,6 +179,7 @@ class PaletteAndSingleContainerTest extends UnitTestCase
'palettes' => [
'aPalette' => [
'label' => $labelReferencePaletteArray,
'description' => $descriptionReferencePaletteArray,
'showitem' => 'aField',
],
],
......@@ -188,8 +195,9 @@ class PaletteAndSingleContainerTest extends UnitTestCase
$GLOBALS['BE_USER'] = $backendUserAuthentication->reveal();
$languageService->loadSingleTableDescription(Argument::cetera())->willReturn('');
// Expect translation call to the label reference
// Expect translation call to the label and description references
$languageService->sL($labelReferenceFieldArray)->willReturnArgument(0);
$languageService->sL($descriptionReferencePaletteArray)->willReturnArgument(0);
$expectedChildDataArray = $input;
$expectedChildDataArray['renderType'] = 'singleFieldContainer';
......@@ -197,7 +205,8 @@ class PaletteAndSingleContainerTest extends UnitTestCase
$nodeFactoryProphecy->create($expectedChildDataArray)->willReturn($singleFieldContainerProphecy->reveal());
$containerResult = (new PaletteAndSingleContainer($nodeFactoryProphecy->reveal(), $input))->render();
// Expect label is in answer HTML
// Expect label and description are in answer HTML
self::assertStringContainsString($labelReferenceFieldArray, $containerResult['html']);
self::assertStringContainsString($descriptionReferencePaletteArray, $containerResult['html']);
}
}
.. include:: ../../Includes.txt
==================================================
Feature: #89507 - Add description for TCA palettes
==================================================
See :issue:`89507`
Description
===========
A new `TCA` property `description` on palettes entry level has been
introduced. If provided, FormEngine will render its value below the
palette label, similar to the TCA field description. The value data
type is the same as for the palette label: a localized string. This
additional help text can therefore be used to clarify some field
usages directly in the UI.
.. note::
In contrast to the palette label, the description property can not
be overwritten on a record type basis.
Example usage:
.. code-block:: php
'types' => [
'0' => [
'showitem' => '
--div--;palette,
--palette--;;palette_1,
'
]
],
'palettes' => [
'palette_1' => [
'label' => 'palette_1',
'description' => 'palette_1_description',
'showitem' => 'palette_field_1, palette_field_2, palette_field_3',
],
],
Impact
======
Integrators now have the ability to add additional information
to TCA palettes, supporting editors on their daily work.
.. index:: Backend, TCA, ext:backend
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment