[TASK] Render wizards of FormEngine elements only if needed
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Element / CheckboxLabeledToggleElement.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Backend\Form\Element;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use TYPO3\CMS\Backend\Form\NodeFactory;
19 use TYPO3\CMS\Core\Imaging\IconRegistry;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21
22 /**
23 * Generation of TCEform elements of the type "check"
24 */
25 class CheckboxLabeledToggleElement extends AbstractFormElement
26 {
27 /**
28 * @var IconRegistry
29 */
30 private $iconRegistry;
31
32 /**
33 * Default field information enabled for this element.
34 *
35 * @var array
36 */
37 protected $defaultFieldInformation = [
38 'tcaDescription' => [
39 'renderType' => 'tcaDescription',
40 ],
41 ];
42
43 /**
44 * Default field wizards enabled for this element.
45 *
46 * @var array
47 */
48 protected $defaultFieldWizard = [
49 'localizationStateSelector' => [
50 'renderType' => 'localizationStateSelector',
51 ],
52 'otherLanguageContent' => [
53 'renderType' => 'otherLanguageContent',
54 'after' => [
55 'localizationStateSelector'
56 ],
57 ],
58 'defaultLanguageDifferences' => [
59 'renderType' => 'defaultLanguageDifferences',
60 'after' => [
61 'otherLanguageContent',
62 ],
63 ],
64 ];
65
66 /**
67 * @param NodeFactory $nodeFactory
68 * @param array $data
69 */
70 public function __construct(NodeFactory $nodeFactory, array $data)
71 {
72 parent::__construct($nodeFactory, $data);
73 $this->iconRegistry = GeneralUtility::makeInstance(IconRegistry::class);
74 }
75
76 /**
77 * This will render a checkbox or an array of checkboxes
78 *
79 * @return array As defined in initializeResultArray() of AbstractNode
80 */
81 public function render(): array
82 {
83 $resultArray = $this->initializeResultArray();
84
85 $elementHtml = '';
86 $disabled = false;
87 if ($this->data['parameterArray']['fieldConf']['config']['readOnly']) {
88 $disabled = true;
89 }
90 // Traversing the array of items
91 $items = $this->data['parameterArray']['fieldConf']['config']['items'];
92
93 $numberOfItems = \count($items);
94 if ($numberOfItems === 0) {
95 $items[] = ['', ''];
96 $numberOfItems = 1;
97 }
98 $formElementValue = (int)$this->data['parameterArray']['itemFormElValue'];
99 $cols = (int)$this->data['parameterArray']['fieldConf']['config']['cols'];
100 if ($cols > 1) {
101 [$colClass, $colClear] = $this->calculateColumnMarkup($cols);
102 $elementHtml .= '<div class="checkbox-row row">';
103 $counter = 0;
104 // $itemKey is important here, because items could have been removed via TSConfig
105 foreach ($items as $itemKey => $itemDefinition) {
106 $label = $itemDefinition[0];
107 $elementHtml .=
108 '<div class="checkbox-column ' . $colClass . '">'
109 . $this->renderSingleCheckboxElement($label, $itemKey, $formElementValue, $numberOfItems, $this->data['parameterArray'], $disabled) .
110 '</div>';
111 ++$counter;
112 if ($counter < $numberOfItems && !empty($colClear)) {
113 foreach ($colClear as $rowBreakAfter => $clearClass) {
114 if ($counter % $rowBreakAfter === 0) {
115 $elementHtml .= '<div class="clearfix ' . $clearClass . '"></div>';
116 }
117 }
118 }
119 }
120 $elementHtml .= '</div>';
121 } else {
122 $counter = 0;
123 foreach ($items as $itemKey => $itemDefinition) {
124 $label = $itemDefinition[0];
125 $elementHtml .= $this->renderSingleCheckboxElement($label, $counter, $formElementValue, $numberOfItems, $this->data['parameterArray'], $disabled);
126 ++$counter;
127 }
128 }
129 if (!$disabled) {
130 $elementHtml .= '<input type="hidden" name="' . htmlspecialchars($this->data['parameterArray']['itemFormElName']) . '" value="' . htmlspecialchars((string)$formElementValue) . '" />';
131 }
132
133 $fieldInformationResult = $this->renderFieldInformation();
134 $fieldInformationHtml = $fieldInformationResult['html'];
135 $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
136
137 $fieldWizardResult = $this->renderFieldWizard();
138 $fieldWizardHtml = $fieldWizardResult['html'];
139 $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
140
141 $html = [];
142 $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
143 $html[] = $fieldInformationHtml;
144 $html[] = '<div class="form-wizards-wrap">';
145 $html[] = '<div class="form-wizards-element">';
146 $html[] = $elementHtml;
147 $html[] = '</div>';
148 if (!$disabled && !empty($fieldWizardHtml)) {
149 $html[] = '<div class="form-wizards-items-bottom">';
150 $html[] = $fieldWizardHtml;
151 $html[] = '</div>';
152 }
153 $html[] = '</div>';
154 $html[] = '</div>';
155
156 $resultArray['html'] = implode(LF, $html);
157 return $resultArray;
158 }
159
160 /**
161 * This functions builds the HTML output for the checkbox
162 *
163 * @param string $label Label of this item
164 * @param int $itemCounter Number of this element in the list of all elements
165 * @param int $formElementValue Value of this element
166 * @param int $numberOfItems Full number of items
167 * @param array $additionalInformation Information with additional configuration options.
168 * @param bool $disabled TRUE if form element is disabled
169 * @return string Single element HTML
170 */
171 protected function renderSingleCheckboxElement($label, $itemCounter, $formElementValue, $numberOfItems, $additionalInformation, $disabled): string
172 {
173 $config = $additionalInformation['fieldConf']['config'];
174 $inline = !empty($config['cols']) && $config['cols'] === 'inline';
175 $invert = isset($config['items'][$itemCounter]['invertStateDisplay']) && $config['items'][$itemCounter]['invertStateDisplay'] === true;
176 $checkboxParameters = $this->checkBoxParams(
177 $additionalInformation['itemFormElName'],
178 $formElementValue,
179 $itemCounter,
180 $numberOfItems,
181 implode('', $additionalInformation['fieldChangeFunc'])
182 );
183 $checkboxId = $additionalInformation['itemFormElID'] . '_' . $itemCounter;
184 return '
185 <div class="checkbox checkbox-type-labeled-toggle' . ($invert ? ' checkbox-invert' : '') . ($inline ? ' checkbox-inline' : '') . (!$disabled ? '' : ' disabled') . '">
186 <input type="checkbox"
187 class="checkbox-input"
188 value="1"
189 data-formengine-input-name="' . htmlspecialchars($additionalInformation['itemFormElName']) . '"
190 ' . $checkboxParameters . '
191 ' . (!$disabled ?: ' disabled="disabled"') . '
192 id="' . $checkboxId . '" />
193 <label class="checkbox-label" for="' . $checkboxId . '">
194 <span class="checkbox-label-switch">
195 <span class="checkbox-label-switch-checked">
196 ' . $config['items'][$itemCounter]['labelChecked'] . '
197 </span>
198 <span class="checkbox-label-switch-unchecked">
199 ' . $config['items'][$itemCounter]['labelUnchecked'] . '
200 </span>
201 </span>
202 <span class="checkbox-label-text">' . $this->appendValueToLabelInDebugMode(($label ? htmlspecialchars($label) : '&nbsp;'), $formElementValue) . '</span>
203 </label>
204 </div>';
205 }
206 }