‪TYPO3CMS  ‪main
TextElement.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
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 
19 
24 
31 {
37  protected ‪$defaultFieldInformation = [
38  'tcaDescription' => [
39  'renderType' => 'tcaDescription',
40  ],
41  ];
42 
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 
72  protected ‪$charactersPerRow = 40;
73 
79  public function ‪render(): array
80  {
81  $table = $this->data['tableName'];
82  $fieldName = $this->data['fieldName'];
83  $parameterArray = $this->data['parameterArray'];
84  $resultArray = $this->‪initializeResultArray();
85 
86  $itemValue = $parameterArray['itemFormElValue'];
87  $config = $parameterArray['fieldConf']['config'];
88  $width = null;
89  if ($config['cols'] ?? false) {
90  $width = $this->‪formMaxWidth(‪MathUtility::forceIntegerInRange($config['cols'], $this->minimumInputWidth, $this->maxInputWidth));
91  }
92  $fieldId = ‪StringUtility::getUniqueId('formengine-textarea-');
93  $renderedLabel = $this->‪renderLabel($fieldId);
94 
95  // Setting number of rows
96  $rows = ‪MathUtility::forceIntegerInRange(($config['rows'] ?? 5) ?: 5, 1, 20);
97  $originalRows = $rows;
98  $itemFormElementValueLength = strlen((string)$itemValue);
99  if ($itemFormElementValueLength > ($this->charactersPerRow * 2)) {
101  (int)round($itemFormElementValueLength / $this->charactersPerRow),
102  count(explode(LF, (string)$itemValue)),
103  20
104  );
105  if ($rows < $originalRows) {
106  $rows = $originalRows;
107  }
108  }
109 
110  $fieldInformationResult = $this->‪renderFieldInformation();
111  $fieldInformationHtml = $fieldInformationResult['html'];
112  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
113 
114  if ($config['readOnly'] ?? false) {
115  $html = [];
116  $html[] = $renderedLabel;
117  $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
118  $html[] = $fieldInformationHtml;
119  $html[] = '<div class="form-wizards-wrap">';
120  $html[] = '<div class="form-wizards-element">';
121  $html[] = '<div class="form-control-wrap"' . ($width ? ' style="max-width: ' . $width . 'px">' : '>');
122  $html[] = '<textarea class="form-control" id="' . htmlspecialchars($fieldId) . '" rows="' . $rows . '" disabled>';
123  $html[] = htmlspecialchars((string)$itemValue);
124  $html[] = '</textarea>';
125  $html[] = '</div>';
126  $html[] = '</div>';
127  $html[] = '</div>';
128  $html[] = '</div>';
129  $resultArray['html'] = implode(LF, $html);
130  return $resultArray;
131  }
132 
133  $languageService = $this->‪getLanguageService();
134  $itemName = (string)$parameterArray['itemFormElName'];
135 
136  // @todo: The whole eval handling is a mess and needs refactoring - Especially for this element,
137  // since the resolved $evalList is currently not used at all, because FormEngineValidation
138  // does not support eval for <textarea> elements.
139  $evalList = ‪GeneralUtility::trimExplode(',', $config['eval'] ?? '', true);
140  foreach ($evalList as $func) {
141  // @todo: This is ugly: The code should find out on it's own whether an eval definition is a
142  // @todo: keyword like "date", or a class reference. The global registration could be dropped then
143  // Pair hook to the one in \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_input_Eval()
144  // There is a similar hook for "evaluateFieldValue" in DataHandler and InputTextElement
145  if (isset(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func])) {
146  if (class_exists($func)) {
147  $evalObj = GeneralUtility::makeInstance($func);
148  if (method_exists($evalObj, 'deevaluateFieldValue')) {
149  $_params = [
150  'value' => $itemValue,
151  ];
152  $itemValue = $evalObj->deevaluateFieldValue($_params);
153  }
154  }
155  }
156  }
157 
158  $attributes = array_merge(
159  [
160  'id' => $fieldId,
161  'name' => $itemName,
162  'data-formengine-validation-rules' => $this->‪getValidationDataAsJsonString($config),
163  'data-formengine-input-name' => $itemName,
164  'rows' => (string)$rows,
165  'wrap' => (string)(($config['wrap'] ?? 'virtual') ?: 'virtual'),
166  ],
167  $this->getOnFieldChangeAttrs('change', $parameterArray['fieldChangeFunc'] ?? [])
168  );
169  $classes = [
170  'form-control',
171  't3js-formengine-textarea',
172  'formengine-textarea',
173  ];
174  if ($config['fixedFont'] ?? false) {
175  $classes[] = 'font-monospace';
176  }
177  if ($config['enableTabulator'] ?? false) {
178  $classes[] = 't3js-enable-tab';
179  }
180  $attributes['class'] = implode(' ', $classes);
181 
182  $maxLength = (int)($config['max'] ?? 0);
183  if ($maxLength > 0) {
184  $attributes['maxlength'] = (string)$maxLength;
185  }
186  $minlength = (int)($config['min'] ?? 0);
187  if ($minlength > 0 && ($maxLength === 0 || $minlength <= $maxLength)) {
188  $attributes['minlength'] = (string)$minlength;
189  }
190  if (!empty($config['placeholder'])) {
191  $attributes['placeholder'] = trim($config['placeholder']);
192  }
193 
194  $valuePickerHtml = [];
195  if (is_array($config['valuePicker']['items'] ?? false)) {
196  $valuePickerConfiguration = [
197  'mode' => $config['valuePicker']['mode'] ?? 'replace',
198  'linked-field' => '[data-formengine-input-name="' . $itemName . '"]',
199  ];
200  $valuePickerAttributes = array_merge(
201  [
202  'class' => 'form-select form-control-adapt',
203  ],
204  $this->getOnFieldChangeAttrs('change', $parameterArray['fieldChangeFunc'] ?? [])
205  );
206 
207  $valuePickerHtml[] = '<typo3-formengine-valuepicker ' . GeneralUtility::implodeAttributes($valuePickerConfiguration, true) . '>';
208  $valuePickerHtml[] = '<select ' . GeneralUtility::implodeAttributes($valuePickerAttributes, true) . '>';
209  $valuePickerHtml[] = '<option></option>';
210  foreach ($config['valuePicker']['items'] as $item) {
211  $valuePickerHtml[] = '<option value="' . htmlspecialchars($item[1]) . '">' . htmlspecialchars($languageService->sL($item[0])) . '</option>';
212  }
213  $valuePickerHtml[] = '</select>';
214  $valuePickerHtml[] = '</typo3-formengine-valuepicker>';
215 
216  $resultArray['javaScriptModules'][] = ‪JavaScriptModuleInstruction::create('@typo3/backend/form-engine/field-wizard/value-picker.js');
217  }
218 
219  $fieldControlResult = $this->‪renderFieldControl();
220  $fieldControlHtml = $fieldControlResult['html'];
221  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
222 
223  $fieldWizardResult = $this->‪renderFieldWizard();
224  $fieldWizardHtml = $fieldWizardResult['html'];
225  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
226 
227  $mainFieldHtml = [];
228  $mainFieldHtml[] = '<div class="form-control-wrap"' . ($width ? ' style="max-width: ' . $width . 'px">' : '>');
229  $mainFieldHtml[] = '<div class="form-wizards-wrap">';
230  $mainFieldHtml[] = '<div class="form-wizards-element">';
231  $mainFieldHtml[] = '<textarea ' . GeneralUtility::implodeAttributes($attributes, true) . '>' . htmlspecialchars((string)$itemValue) . '</textarea>';
232  $mainFieldHtml[] = '</div>';
233  if (!empty($valuePickerHtml) || !empty($fieldControlHtml)) {
234  $mainFieldHtml[] = '<div class="form-wizards-items-aside form-wizards-items-aside--field-control">';
235  $mainFieldHtml[] = '<div class="btn-group">';
236  $mainFieldHtml[] = implode(LF, $valuePickerHtml);
237  $mainFieldHtml[] = $fieldControlHtml;
238  $mainFieldHtml[] = '</div>';
239  $mainFieldHtml[] = '</div>';
240  }
241  if (!empty($fieldWizardHtml)) {
242  $mainFieldHtml[] = '<div class="form-wizards-items-bottom">';
243  $mainFieldHtml[] = $fieldWizardHtml;
244  $mainFieldHtml[] = '</div>';
245  }
246  $mainFieldHtml[] = '</div>';
247  $mainFieldHtml[] = '</div>';
248  $mainFieldHtml = implode(LF, $mainFieldHtml);
249 
250  $nullControlNameEscaped = htmlspecialchars('control[active][' . $table . '][' . $this->data['databaseRow']['uid'] . '][' . $fieldName . ']');
251 
252  $fullElement = $mainFieldHtml;
253  if ($this->‪hasNullCheckboxButNoPlaceholder()) {
254  $checked = $itemValue !== null ? ' checked="checked"' : '';
255  $fullElement = [];
256  $fullElement[] = '<div class="t3-form-field-disable"></div>';
257  $fullElement[] = '<div class="form-check t3-form-field-eval-null-checkbox">';
258  $fullElement[] = '<input type="hidden" name="' . $nullControlNameEscaped . '" value="0" />';
259  $fullElement[] = '<input type="checkbox" class="form-check-input" name="' . $nullControlNameEscaped . '" id="' . $nullControlNameEscaped . '" value="1"' . $checked . ' />';
260  $fullElement[] = '<label class="form-check-label" for="' . $nullControlNameEscaped . '">';
261  $fullElement[] = $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.nullCheckbox');
262  $fullElement[] = '</label>';
263  $fullElement[] = '</div>';
264  $fullElement[] = $mainFieldHtml;
265  $fullElement = implode(LF, $fullElement);
266  } elseif ($this->‪hasNullCheckboxWithPlaceholder()) {
267  $checked = $itemValue !== null ? ' checked="checked"' : '';
268  $placeholder = $shortenedPlaceholder = (string)($config['placeholder'] ?? '');
269  if ($placeholder !== '') {
270  $shortenedPlaceholder = ‪GeneralUtility::fixed_lgd_cs($placeholder, 20);
271  if ($placeholder !== $shortenedPlaceholder) {
272  $overrideLabel = sprintf(
273  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.placeholder.override'),
274  '<span title="' . htmlspecialchars($placeholder) . '">' . htmlspecialchars($shortenedPlaceholder) . '</span>'
275  );
276  } else {
277  $overrideLabel = sprintf(
278  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.placeholder.override'),
279  htmlspecialchars($placeholder)
280  );
281  }
282  } else {
283  $overrideLabel = $languageService->sL(
284  'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.placeholder.override_not_available'
285  );
286  }
287  $fullElement = [];
288  $fullElement[] = '<div class="form-check t3js-form-field-eval-null-placeholder-checkbox">';
289  $fullElement[] = '<input type="hidden" name="' . $nullControlNameEscaped . '" value="0" />';
290  $fullElement[] = '<input type="checkbox" class="form-check-input" name="' . $nullControlNameEscaped . '" id="' . $nullControlNameEscaped . '" value="1"' . $checked . ' />';
291  $fullElement[] = '<label class="form-check-label" for="' . $nullControlNameEscaped . '">';
292  $fullElement[] = $overrideLabel;
293  $fullElement[] = '</label>';
294  $fullElement[] = '</div>';
295  $fullElement[] = '<div class="t3js-formengine-placeholder-placeholder">';
296  $fullElement[] = '<div class="form-control-wrap"' . ($width ? ' style="max-width: ' . $width . 'px">' : '>');
297  $fullElement[] = '<textarea';
298  $fullElement[] = ' class="form-control formengine-textarea' . (isset($config['fixedFont']) ? ' font-monospace' : '') . '"';
299  $fullElement[] = ' disabled="disabled"';
300  $fullElement[] = ' rows="' . htmlspecialchars($attributes['rows']) . '"';
301  $fullElement[] = ' wrap="' . htmlspecialchars($attributes['wrap']) . '"';
302  $fullElement[] = isset($attributes['style']) ? ' style="' . htmlspecialchars($attributes['style']) . '"' : '';
303  $fullElement[] = isset($attributes['maxlength']) ? ' maxlength="' . htmlspecialchars($attributes['maxlength']) . '"' : '';
304  $fullElement[] = '>';
305  $fullElement[] = htmlspecialchars($shortenedPlaceholder);
306  $fullElement[] = '</textarea>';
307  $fullElement[] = '</div>';
308  $fullElement[] = '</div>';
309  $fullElement[] = '<div class="t3js-formengine-placeholder-formfield">';
310  $fullElement[] = $mainFieldHtml;
311  $fullElement[] = '</div>';
312  $fullElement = implode(LF, $fullElement);
313  }
314 
315  $resultArray['html'] = $renderedLabel . '
316  <typo3-formengine-element-text class="formengine-field-item t3js-formengine-field-item" recordFieldId="' . htmlspecialchars($fieldId) . '">
317  ' . $fieldInformationHtml . '
318  ' . $fullElement . '
319  </typo3-formengine-element-text>';
320 
321  $resultArray['javaScriptModules'][] = ‪JavaScriptModuleInstruction::create('@typo3/backend/form-engine/element/text-element.js');
322 
323  return $resultArray;
324  }
325 }
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldInformation
‪array renderFieldInformation()
Definition: AbstractFormElement.php:73
‪TYPO3\CMS\Core\Utility\GeneralUtility\fixed_lgd_cs
‪static string fixed_lgd_cs(string $string, int $chars, string $appendString='...')
Definition: GeneralUtility.php:92
‪TYPO3\CMS\Backend\Form\AbstractNode\mergeChildReturnIntoExistingResult
‪array mergeChildReturnIntoExistingResult(array $existing, array $childReturn, bool $mergeHtml=true)
Definition: AbstractNode.php:104
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction\create
‪static create(string $name, string $exportName=null)
Definition: JavaScriptModuleInstruction.php:47
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement
Definition: AbstractFormElement.php:37
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction
Definition: JavaScriptModuleInstruction.php:23
‪TYPO3\CMS\Backend\Form\Element\TextElement\$defaultFieldInformation
‪array $defaultFieldInformation
Definition: TextElement.php:36
‪TYPO3\CMS\Backend\Form\Element
Definition: AbstractFormElement.php:16
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldControl
‪array renderFieldControl()
Definition: AbstractFormElement.php:89
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\getLanguageService
‪getLanguageService()
Definition: AbstractFormElement.php:456
‪TYPO3\CMS\Backend\Form\Element\TextElement\$defaultFieldWizard
‪array $defaultFieldWizard
Definition: TextElement.php:46
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\formMaxWidth
‪int formMaxWidth($size=48)
Definition: AbstractFormElement.php:332
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\Form\AbstractNode\getValidationDataAsJsonString
‪getValidationDataAsJsonString(array $config)
Definition: AbstractNode.php:133
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderLabel
‪renderLabel(string $for)
Definition: AbstractFormElement.php:119
‪TYPO3\CMS\Backend\Form\Element\TextElement
Definition: TextElement.php:31
‪TYPO3\CMS\Backend\Form\Element\TextElement\render
‪array render()
Definition: TextElement.php:76
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange(mixed $theInt, int $min, int $max=2000000000, int $defaultValue=0)
Definition: MathUtility.php:34
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:24
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldWizard
‪array renderFieldWizard()
Definition: AbstractFormElement.php:105
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\hasNullCheckboxWithPlaceholder
‪hasNullCheckboxWithPlaceholder()
Definition: AbstractFormElement.php:195
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:822
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\hasNullCheckboxButNoPlaceholder
‪hasNullCheckboxButNoPlaceholder()
Definition: AbstractFormElement.php:163
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static getUniqueId(string $prefix='')
Definition: StringUtility.php:57
‪TYPO3\CMS\Backend\Form\AbstractNode\initializeResultArray
‪initializeResultArray()
Definition: AbstractNode.php:77
‪TYPO3\CMS\Backend\Form\Element\TextElement\$charactersPerRow
‪int $charactersPerRow
Definition: TextElement.php:69