‪TYPO3CMS  9.5
SelectMultipleSideBySideElement.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
23 
30 {
36  protected ‪$defaultFieldInformation = [
37  'tcaDescription' => [
38  'renderType' => 'tcaDescription',
39  ],
40  ];
41 
47  protected ‪$defaultFieldControl = [
48  'editPopup' => [
49  'renderType' => 'editPopup',
50  'disabled' => true,
51  ],
52  'addRecord' => [
53  'renderType' => 'addRecord',
54  'disabled' => true,
55  'after' => [ 'editPopup' ],
56  ],
57  'listModule' => [
58  'renderType' => 'listModule',
59  'disabled' => true,
60  'after' => [ 'addRecord' ],
61  ],
62  ];
63 
69  protected ‪$defaultFieldWizard = [
70  'localizationStateSelector' => [
71  'renderType' => 'localizationStateSelector',
72  ],
73  'otherLanguageContent' => [
74  'renderType' => 'otherLanguageContent',
75  'after' => [
76  'localizationStateSelector'
77  ],
78  ],
79  'defaultLanguageDifferences' => [
80  'renderType' => 'defaultLanguageDifferences',
81  'after' => [
82  'otherLanguageContent',
83  ],
84  ],
85  ];
86 
92  public function ‪render()
93  {
94  $languageService = $this->‪getLanguageService();
95  $resultArray = $this->‪initializeResultArray();
96 
97  $parameterArray = $this->data['parameterArray'];
98  $config = $parameterArray['fieldConf']['config'];
99  $elementName = $parameterArray['itemFormElName'];
100 
101  if ($config['readOnly']) {
102  // Early return for the relatively simple read only case
103  return $this->‪renderReadOnly();
104  }
105 
106  $possibleItems = $config['items'];
107  $selectedItems = $parameterArray['itemFormElValue'] ?: [];
108  $selectedItemsCount = count($selectedItems);
109 
110  $maxItems = $config['maxitems'];
111  $autoSizeMax = ‪MathUtility::forceIntegerInRange($config['autoSizeMax'], 0);
112  $size = 2;
113  if (isset($config['size'])) {
114  $size = (int)$config['size'];
115  }
116  if ($autoSizeMax >= 1) {
117  $size = ‪MathUtility::forceIntegerInRange($selectedItemsCount + 1, ‪MathUtility::forceIntegerInRange($size, 1), $autoSizeMax);
118  }
119  $itemCanBeSelectedMoreThanOnce = !empty($config['multiple']);
120 
121  $listOfSelectedValues = [];
122  $selectedItemsHtml = [];
123  foreach ($selectedItems as $itemValue) {
124  foreach ($possibleItems as $possibleItem) {
125  if ($possibleItem[1] == $itemValue) {
126  $title = $possibleItem[0];
127  $listOfSelectedValues[] = $itemValue;
128  $selectedItemsHtml[] = '<option value="' . htmlspecialchars($itemValue) . '" title="' . htmlspecialchars($title) . '">' . htmlspecialchars($this->‪appendValueToLabelInDebugMode($title, $itemValue)) . '</option>';
129  break;
130  }
131  }
132  }
133 
134  $selectableItemsHtml = [];
135  foreach ($possibleItems as $possibleItem) {
136  $disabledAttr = '';
137  $classAttr = '';
138  if (!$itemCanBeSelectedMoreThanOnce && in_array((string)$possibleItem[1], $selectedItems, true)) {
139  $disabledAttr = ' disabled="disabled"';
140  $classAttr = ' class="hidden"';
141  }
142  $selectableItemsHtml[] =
143  '<option value="'
144  . htmlspecialchars($possibleItem[1])
145  . '" title="' . htmlspecialchars($possibleItem[0]) . '"'
146  . $classAttr . $disabledAttr
147  . '>'
148  . htmlspecialchars($this->‪appendValueToLabelInDebugMode($possibleItem[0], $possibleItem[1])) .
149  '</option>';
150  }
151 
152  // Html stuff for filter and select filter on top of right side of multi select boxes
153  $filterTextfield = [];
154  if ($config['enableMultiSelectFilterTextfield']) {
155  $filterTextfield[] = '<span class="input-group input-group-sm">';
156  $filterTextfield[] = '<span class="input-group-addon">';
157  $filterTextfield[] = '<span class="fa fa-filter"></span>';
158  $filterTextfield[] = '</span>';
159  $filterTextfield[] = '<input class="t3js-formengine-multiselect-filter-textfield form-control" value="">';
160  $filterTextfield[] = '</span>';
161  }
162  $filterDropDownOptions = [];
163  if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) {
164  foreach ($config['multiSelectFilterItems'] as $optionElement) {
165  $value = $languageService->sL($optionElement[0]);
166  $label = $value;
167  if (isset($optionElement[1]) && trim($optionElement[1]) !== '') {
168  $label = $languageService->sL($optionElement[1]);
169  }
170  $filterDropDownOptions[] = '<option value="' . htmlspecialchars($value) . '">' . htmlspecialchars($label) . '</option>';
171  }
172  }
173  $filterHtml = [];
174  if (!empty($filterTextfield) || !empty($filterDropDownOptions)) {
175  $filterHtml[] = '<div class="form-multigroup-item-wizard">';
176  if (!empty($filterTextfield) && !empty($filterDropDownOptions)) {
177  $filterHtml[] = '<div class="t3js-formengine-multiselect-filter-container form-multigroup-wrap">';
178  $filterHtml[] = '<div class="form-multigroup-item form-multigroup-element">';
179  $filterHtml[] = '<select class="form-control input-sm t3js-formengine-multiselect-filter-dropdown">';
180  $filterHtml[] = implode(LF, $filterDropDownOptions);
181  $filterHtml[] = '</select>';
182  $filterHtml[] = '</div>';
183  $filterHtml[] = '<div class="form-multigroup-item form-multigroup-element">';
184  $filterHtml[] = implode(LF, $filterTextfield);
185  $filterHtml[] = '</div>';
186  $filterHtml[] = '</div>';
187  } elseif (!empty($filterTextfield)) {
188  $filterHtml[] = implode(LF, $filterTextfield);
189  } else {
190  $filterHtml[] = '<select class="form-control input-sm t3js-formengine-multiselect-filter-dropdown">';
191  $filterHtml[] = implode(LF, $filterDropDownOptions);
192  $filterHtml[] = '</select>';
193  }
194  $filterHtml[] = '</div>';
195  }
196 
197  $classes = [];
198  $classes[] = 'form-control';
199  $classes[] = 'tceforms-multiselect';
200  if ($maxItems === 1) {
201  $classes[] = 'form-select-no-siblings';
202  }
203  $multipleAttribute = '';
204  if ($maxItems !== 1 && $size !== 1) {
205  $multipleAttribute = ' multiple="multiple"';
206  }
207 
208  $fieldInformationResult = $this->‪renderFieldInformation();
209  $fieldInformationHtml = $fieldInformationResult['html'];
210  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
211 
212  $fieldControlResult = $this->‪renderFieldControl();
213  $fieldControlHtml = $fieldControlResult['html'];
214  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
215 
216  $fieldWizardResult = $this->‪renderFieldWizard();
217  $fieldWizardHtml = $fieldWizardResult['html'];
218  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
219 
220  $html = [];
221  $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
222  $html[] = $fieldInformationHtml;
223  $html[] = '<div class="form-wizards-wrap">';
224  $html[] = '<div class="form-wizards-element">';
225  $html[] = '<input type="hidden" data-formengine-input-name="' . htmlspecialchars($elementName) . '" value="' . (int)$itemCanBeSelectedMoreThanOnce . '" />';
226  $html[] = '<div class="form-multigroup-wrap t3js-formengine-field-group">';
227  $html[] = '<div class="form-multigroup-item form-multigroup-element">';
228  $html[] = '<label>';
229  $html[] = htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.selected'));
230  $html[] = '</label>';
231  $html[] = '<div class="form-wizards-wrap form-wizards-aside">';
232  $html[] = '<div class="form-wizards-element">';
233  $html[] = '<select';
234  $html[] = ' id="' . ‪StringUtility::getUniqueId('tceforms-multiselect-') . '"';
235  $html[] = ' size="' . $size . '"';
236  $html[] = ' class="' . implode(' ', $classes) . '"';
237  $html[] = $multipleAttribute;
238  $html[] = ' data-formengine-input-name="' . htmlspecialchars($elementName) . '"';
239  $html[] = '>';
240  $html[] = implode(LF, $selectedItemsHtml);
241  $html[] = '</select>';
242  $html[] = '</div>';
243  $html[] = '<div class="form-wizards-items-aside">';
244  $html[] = '<div class="btn-group-vertical">';
245  if ($maxItems > 1 && $size >= 5) {
246  $html[] = '<a href="#"';
247  $html[] = ' class="btn btn-default t3js-btn-moveoption-top"';
248  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
249  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_to_top')) . '"';
250  $html[] = '>';
251  $html[] = $this->iconFactory->getIcon('actions-move-to-top', ‪Icon::SIZE_SMALL)->render();
252  $html[] = '</a>';
253  }
254  if ($maxItems > 1) {
255  $html[] = '<a href="#"';
256  $html[] = ' class="btn btn-default t3js-btn-moveoption-up"';
257  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
258  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_up')) . '"';
259  $html[] = '>';
260  $html[] = $this->iconFactory->getIcon('actions-move-up', ‪Icon::SIZE_SMALL)->render();
261  $html[] = '</a>';
262  $html[] = '<a href="#"';
263  $html[] = ' class="btn btn-default t3js-btn-moveoption-down"';
264  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
265  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_down')) . '"';
266  $html[] = '>';
267  $html[] = $this->iconFactory->getIcon('actions-move-down', ‪Icon::SIZE_SMALL)->render();
268  $html[] = '</a>';
269  }
270  if ($maxItems > 1 && $size >= 5) {
271  $html[] = '<a href="#"';
272  $html[] = ' class="btn btn-default t3js-btn-moveoption-bottom"';
273  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
274  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_to_bottom')) . '"';
275  $html[] = '>';
276  $html[] = $this->iconFactory->getIcon('actions-move-to-bottom', ‪Icon::SIZE_SMALL)->render();
277  $html[] = '</a>';
278  }
279  $html[] = '<a href="#"';
280  $html[] = ' class="btn btn-default t3js-btn-removeoption"';
281  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
282  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.remove_selected')) . '"';
283  $html[] = '>';
284  $html[] = $this->iconFactory->getIcon('actions-selection-delete', ‪Icon::SIZE_SMALL)->render();
285  $html[] = '</a>';
286  $html[] = '</div>';
287  $html[] = '</div>';
288  $html[] = '</div>';
289  $html[] = '</div>';
290  $html[] = '<div class="form-multigroup-item form-multigroup-element">';
291  $html[] = '<label>';
292  $html[] = htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.items'));
293  $html[] = '</label>';
294  $html[] = '<div class="form-wizards-wrap form-wizards-aside">';
295  $html[] = '<div class="form-wizards-element">';
296  $html[] = implode(LF, $filterHtml);
297  $html[] = '<select';
298  $html[] = ' data-relatedfieldname="' . htmlspecialchars($elementName) . '"';
299  $html[] = ' data-exclusivevalues="' . htmlspecialchars($config['exclusiveKeys']) . '"';
300  $html[] = ' id="' . ‪StringUtility::getUniqueId('tceforms-multiselect-') . '"';
301  $html[] = ' data-formengine-input-name="' . htmlspecialchars($elementName) . '"';
302  $html[] = ' class="form-control t3js-formengine-select-itemstoselect"';
303  $html[] = ' size="' . $size . '"';
304  $html[] = ' onchange="' . htmlspecialchars(implode('', $parameterArray['fieldChangeFunc'])) . '"';
305  $html[] = ' data-formengine-validation-rules="' . htmlspecialchars($this->‪getValidationDataAsJsonString($config)) . '"';
306  $html[] = '>';
307  $html[] = implode(LF, $selectableItemsHtml);
308  $html[] = '</select>';
309  $html[] = '</div>';
310  if (!empty($fieldControlHtml)) {
311  $html[] = '<div class="form-wizards-items-aside">';
312  $html[] = '<div class="btn-group-vertical">';
313  $html[] = $fieldControlHtml;
314  $html[] = '</div>';
315  $html[] = '</div>';
316  }
317  $html[] = '</div>';
318  $html[] = '</div>';
319  $html[] = '</div>';
320  $html[] = '<input type="hidden" name="' . htmlspecialchars($elementName) . '" value="' . htmlspecialchars(implode(',', $listOfSelectedValues)) . '" />';
321  $html[] = '</div>';
322  if (!empty($fieldWizardHtml)) {
323  $html[] = '<div class="form-wizards-items-bottom">';
324  $html[] = $fieldWizardHtml;
325  $html[] = '</div>';
326  }
327  $html[] = '</div>';
328  $html[] = '</div>';
329 
330  $resultArray['html'] = implode(LF, $html);
331  return $resultArray;
332  }
333 
340  protected function ‪renderReadOnly()
341  {
342  $languageService = $this->‪getLanguageService();
343  $resultArray = $this->‪initializeResultArray();
344 
345  $parameterArray = $this->data['parameterArray'];
346  $config = $parameterArray['fieldConf']['config'];
347  $fieldName = $parameterArray['itemFormElName'];
348 
349  $possibleItems = $config['items'];
350  $selectedItems = $parameterArray['itemFormElValue'] ?: [];
351  if (!is_array($selectedItems)) {
352  $selectedItems = GeneralUtility::trimExplode(',', $selectedItems, true);
353  }
354  $selectedItemsCount = count($selectedItems);
355 
356  $autoSizeMax = ‪MathUtility::forceIntegerInRange($config['autoSizeMax'], 0);
357  $size = 2;
358  if (isset($config['size'])) {
359  $size = (int)$config['size'];
360  }
361  if ($autoSizeMax >= 1) {
362  $size = ‪MathUtility::forceIntegerInRange($selectedItemsCount + 1, ‪MathUtility::forceIntegerInRange($size, 1), $autoSizeMax);
363  }
364  $multiple = '';
365  if ($size !== 1) {
366  $multiple = ' multiple="multiple"';
367  }
368 
369  $listOfSelectedValues = [];
370  $optionsHtml = [];
371  foreach ($selectedItems as $itemValue) {
372  foreach ($possibleItems as $possibleItem) {
373  if ($possibleItem[1] == $itemValue) {
374  $title = $possibleItem[0];
375  $listOfSelectedValues[] = $itemValue;
376  $optionsHtml[] = '<option value="' . htmlspecialchars($itemValue) . '" title="' . htmlspecialchars($title) . '">' . htmlspecialchars($title) . '</option>';
377  break;
378  }
379  }
380  }
381 
382  $fieldInformationResult = $this->‪renderFieldInformation();
383  $fieldInformationHtml = $fieldInformationResult['html'];
384  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
385 
386  $html = [];
387  $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
388  $html[] = $fieldInformationHtml;
389  $html[] = '<div class="form-wizards-wrap">';
390  $html[] = '<div class="form-wizards-element">';
391  $html[] = '<label>';
392  $html[] = htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.selected'));
393  $html[] = '</label>';
394  $html[] = '<div class="form-wizards-wrap form-wizards-aside">';
395  $html[] = '<div class="form-wizards-element">';
396  $html[] = '<select';
397  $html[] = ' id="' . ‪StringUtility::getUniqueId('tceforms-multiselect-') . '"';
398  $html[] = ' size="' . $size . '"';
399  $html[] = ' class="form-control tceforms-multiselect"';
400  $html[] = $multiple;
401  $html[] = ' data-formengine-input-name="' . htmlspecialchars($fieldName) . '"';
402  $html[] = ' disabled="disabled">';
403  $html[] = '/>';
404  $html[] = implode(LF, $optionsHtml);
405  $html[] = '</select>';
406  $html[] = '</div>';
407  $html[] = '</div>';
408  $html[] = '<input type="hidden" name="' . htmlspecialchars($fieldName) . '" value="' . htmlspecialchars(implode(',', $listOfSelectedValues)) . '" />';
409  $html[] = '</div>';
410  $html[] = '</div>';
411  $html[] = '</div>';
412 
413  $resultArray['html'] = implode(LF, $html);
414  return $resultArray;
415  }
416 
420  protected function ‪getLanguageService()
421  {
422  return ‪$GLOBALS['LANG'];
423  }
424 
428  protected function ‪getBackendUserAuthentication()
429  {
430  return ‪$GLOBALS['BE_USER'];
431  }
432 }
‪TYPO3\CMS\Core\Imaging\Icon\SIZE_SMALL
‪const SIZE_SMALL
Definition: Icon.php:29
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldInformation
‪array renderFieldInformation()
Definition: AbstractFormElement.php:71
‪TYPO3\CMS\Backend\Form\AbstractNode\mergeChildReturnIntoExistingResult
‪array mergeChildReturnIntoExistingResult(array $existing, array $childReturn, bool $mergeHtml=true)
Definition: AbstractNode.php:115
‪TYPO3\CMS\Backend\Form\AbstractNode\initializeResultArray
‪array initializeResultArray()
Definition: AbstractNode.php:88
‪TYPO3\CMS\Backend\Form\Element\SelectMultipleSideBySideElement
Definition: SelectMultipleSideBySideElement.php:30
‪TYPO3\CMS\Core\Imaging\Icon
Definition: Icon.php:25
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\appendValueToLabelInDebugMode
‪string int appendValueToLabelInDebugMode($label, $value)
Definition: AbstractFormElement.php:377
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement
Definition: AbstractFormElement.php:31
‪TYPO3\CMS\Backend\Form\Element\SelectMultipleSideBySideElement\$defaultFieldWizard
‪array $defaultFieldWizard
Definition: SelectMultipleSideBySideElement.php:66
‪TYPO3\CMS\Backend\Form\Element
Definition: AbstractFormElement.php:2
‪TYPO3\CMS\Backend\Form\Element\SelectMultipleSideBySideElement\renderReadOnly
‪array renderReadOnly()
Definition: SelectMultipleSideBySideElement.php:337
‪TYPO3\CMS\Backend\Form\AbstractNode\getValidationDataAsJsonString
‪string getValidationDataAsJsonString(array $config)
Definition: AbstractNode.php:153
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldControl
‪array renderFieldControl()
Definition: AbstractFormElement.php:87
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:45
‪TYPO3\CMS\Backend\Form\Element\SelectMultipleSideBySideElement\$defaultFieldInformation
‪array $defaultFieldInformation
Definition: SelectMultipleSideBySideElement.php:35
‪TYPO3\CMS\Backend\Form\Element\SelectMultipleSideBySideElement\getBackendUserAuthentication
‪BackendUserAuthentication getBackendUserAuthentication()
Definition: SelectMultipleSideBySideElement.php:425
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static string getUniqueId($prefix='')
Definition: StringUtility.php:91
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:21
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:29
‪TYPO3\CMS\Backend\Form\Element\SelectMultipleSideBySideElement\$defaultFieldControl
‪array $defaultFieldControl
Definition: SelectMultipleSideBySideElement.php:45
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:21
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldWizard
‪array renderFieldWizard()
Definition: AbstractFormElement.php:103
‪TYPO3\CMS\Backend\Form\Element\SelectMultipleSideBySideElement\render
‪array render()
Definition: SelectMultipleSideBySideElement.php:89
‪TYPO3\CMS\Backend\Form\Element\SelectMultipleSideBySideElement\getLanguageService
‪LanguageService getLanguageService()
Definition: SelectMultipleSideBySideElement.php:417