TYPO3 CMS  TYPO3_8-7
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 $defaultFieldControl = [
37  'editPopup' => [
38  'renderType' => 'editPopup',
39  'disabled' => true,
40  ],
41  'addRecord' => [
42  'renderType' => 'addRecord',
43  'disabled' => true,
44  'after' => [ 'editPopup' ],
45  ],
46  'listModule' => [
47  'renderType' => 'listModule',
48  'disabled' => true,
49  'after' => [ 'addRecord' ],
50  ],
51  ];
52 
58  protected $defaultFieldWizard = [
59  'localizationStateSelector' => [
60  'renderType' => 'localizationStateSelector',
61  ],
62  'otherLanguageContent' => [
63  'renderType' => 'otherLanguageContent',
64  'after' => [
65  'localizationStateSelector'
66  ],
67  ],
68  'defaultLanguageDifferences' => [
69  'renderType' => 'defaultLanguageDifferences',
70  'after' => [
71  'otherLanguageContent',
72  ],
73  ],
74  ];
75 
81  public function render()
82  {
83  $languageService = $this->getLanguageService();
84  $resultArray = $this->initializeResultArray();
85 
86  $parameterArray = $this->data['parameterArray'];
87  $config = $parameterArray['fieldConf']['config'];
88  $elementName = $parameterArray['itemFormElName'];
89 
90  if ($config['readOnly']) {
91  // Early return for the relatively simple read only case
92  return $this->renderReadOnly();
93  }
94 
95  $possibleItems = $config['items'];
96  $selectedItems = $parameterArray['itemFormElValue'] ?: [];
97  $selectedItemsCount = count($selectedItems);
98 
99  $maxItems = $config['maxitems'];
100  $autoSizeMax = MathUtility::forceIntegerInRange($config['autoSizeMax'], 0);
101  $size = 2;
102  if (isset($config['size'])) {
103  $size = (int)$config['size'];
104  }
105  if ($autoSizeMax >= 1) {
106  $size = MathUtility::forceIntegerInRange($selectedItemsCount + 1, MathUtility::forceIntegerInRange($size, 1), $autoSizeMax);
107  }
108  $itemCanBeSelectedMoreThanOnce = !empty($config['multiple']);
109 
110  $listOfSelectedValues = [];
111  $selectedItemsHtml = [];
112  foreach ($selectedItems as $itemValue) {
113  foreach ($possibleItems as $possibleItem) {
114  if ($possibleItem[1] == $itemValue) {
115  $title = $possibleItem[0];
116  $listOfSelectedValues[] = $itemValue;
117  $selectedItemsHtml[] = '<option value="' . htmlspecialchars($itemValue) . '" title="' . htmlspecialchars($title) . '">' . htmlspecialchars($title) . '</option>';
118  break;
119  }
120  }
121  }
122 
123  $selectableItemsHtml = [];
124  foreach ($possibleItems as $possibleItem) {
125  $disabledAttr = '';
126  $classAttr = '';
127  if (!$itemCanBeSelectedMoreThanOnce && in_array((string)$possibleItem[1], $selectedItems, true)) {
128  $disabledAttr = ' disabled="disabled"';
129  $classAttr = ' class="hidden"';
130  }
131  $selectableItemsHtml[] =
132  '<option value="'
133  . htmlspecialchars($possibleItem[1])
134  . '" title="' . htmlspecialchars($possibleItem[0]) . '"'
135  . $classAttr . $disabledAttr
136  . '>'
137  . htmlspecialchars($possibleItem[0]) .
138  '</option>';
139  }
140 
141  // Html stuff for filter and select filter on top of right side of multi select boxes
142  $filterTextfield = [];
143  if ($config['enableMultiSelectFilterTextfield']) {
144  $filterTextfield[] = '<span class="input-group input-group-sm">';
145  $filterTextfield[] = '<span class="input-group-addon">';
146  $filterTextfield[] = '<span class="fa fa-filter"></span>';
147  $filterTextfield[] = '</span>';
148  $filterTextfield[] = '<input class="t3js-formengine-multiselect-filter-textfield form-control" value="">';
149  $filterTextfield[] = '</span>';
150  }
151  $filterDropDownOptions = [];
152  if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) {
153  foreach ($config['multiSelectFilterItems'] as $optionElement) {
154  $value = $languageService->sL($optionElement[0]);
155  $label = $value;
156  if (isset($optionElement[1]) && trim($optionElement[1]) !== '') {
157  $label = $languageService->sL($optionElement[1]);
158  }
159  $filterDropDownOptions[] = '<option value="' . htmlspecialchars($value) . '">' . htmlspecialchars($label) . '</option>';
160  }
161  }
162  $filterHtml = [];
163  if (!empty($filterTextfield) || !empty($filterDropDownOptions)) {
164  $filterHtml[] = '<div class="form-multigroup-item-wizard">';
165  if (!empty($filterTextfield) && !empty($filterDropDownOptions)) {
166  $filterHtml[] = '<div class="t3js-formengine-multiselect-filter-container form-multigroup-wrap">';
167  $filterHtml[] = '<div class="form-multigroup-item form-multigroup-element">';
168  $filterHtml[] = '<select class="form-control input-sm t3js-formengine-multiselect-filter-dropdown">';
169  $filterHtml[] = implode(LF, $filterDropDownOptions);
170  $filterHtml[] = '</select>';
171  $filterHtml[] = '</div>';
172  $filterHtml[] = '<div class="form-multigroup-item form-multigroup-element">';
173  $filterHtml[] = implode(LF, $filterTextfield);
174  $filterHtml[] = '</div>';
175  $filterHtml[] = '</div>';
176  } elseif (!empty($filterTextfield)) {
177  $filterHtml[] = implode(LF, $filterTextfield);
178  } else {
179  $filterHtml[] = '<select class="form-control input-sm t3js-formengine-multiselect-filter-dropdown">';
180  $filterHtml[] = implode(LF, $filterDropDownOptions);
181  $filterHtml[] = '</select>';
182  }
183  $filterHtml[] = '</div>';
184  }
185 
186  $classes = [];
187  $classes[] = 'form-control';
188  $classes[] = 'tceforms-multiselect';
189  if ($maxItems === 1) {
190  $classes[] = 'form-select-no-siblings';
191  }
192  $multipleAttribute = '';
193  if ($maxItems !== 1 && $size !== 1) {
194  $multipleAttribute = ' multiple="multiple"';
195  }
196  $selectedListStyle = '';
197  if (isset($config['selectedListStyle'])) {
198  GeneralUtility::deprecationLog('TCA property selectedListStyle is deprecated since TYPO3 v8 and will be removed in v9');
199  $selectedListStyle = ' style="' . htmlspecialchars($config['selectedListStyle']) . '"';
200  }
201  $selectableListStyle = '';
202  if (isset($config['itemListStyle'])) {
203  GeneralUtility::deprecationLog('TCA property itemListStyle is deprecated since TYPO3 v8 and will be removed in v9');
204  $selectableListStyle = ' style="' . htmlspecialchars($config['itemListStyle']) . '"';
205  }
206 
207  $legacyWizards = $this->renderWizards();
208  $legacyFieldControlHtml = implode(LF, $legacyWizards['fieldControl']);
209  $legacyFieldWizardHtml = implode(LF, $legacyWizards['fieldWizard']);
210 
211  $fieldInformationResult = $this->renderFieldInformation();
212  $fieldInformationHtml = $fieldInformationResult['html'];
213  $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
214 
215  $fieldControlResult = $this->renderFieldControl();
216  $fieldControlHtml = $legacyFieldControlHtml . $fieldControlResult['html'];
217  $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
218 
219  $fieldWizardResult = $this->renderFieldWizard();
220  $fieldWizardHtml = $legacyFieldWizardHtml . $fieldWizardResult['html'];
221  $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
222 
223  $html = [];
224  $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
225  $html[] = $fieldInformationHtml;
226  $html[] = '<div class="form-wizards-wrap">';
227  $html[] = '<div class="form-wizards-element">';
228  $html[] = '<input type="hidden" data-formengine-input-name="' . htmlspecialchars($elementName) . '" value="' . (int)$itemCanBeSelectedMoreThanOnce . '" />';
229  $html[] = '<div class="form-multigroup-wrap t3js-formengine-field-group">';
230  $html[] = '<div class="form-multigroup-item form-multigroup-element">';
231  $html[] = '<label>';
232  $html[] = htmlspecialchars($languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.selected'));
233  $html[] = '</label>';
234  $html[] = '<div class="form-wizards-wrap form-wizards-aside">';
235  $html[] = '<div class="form-wizards-element">';
236  $html[] = '<select';
237  $html[] = ' id="' . StringUtility::getUniqueId('tceforms-multiselect-') . '"';
238  $html[] = ' size="' . $size . '"';
239  $html[] = ' class="' . implode(' ', $classes) . '"';
240  $html[] = $multipleAttribute;
241  $html[] = ' data-formengine-input-name="' . htmlspecialchars($elementName) . '"';
242  $html[] = $selectedListStyle;
243  $html[] = '>';
244  $html[] = implode(LF, $selectedItemsHtml);
245  $html[] = '</select>';
246  $html[] = '</div>';
247  $html[] = '<div class="form-wizards-items-aside">';
248  $html[] = '<div class="btn-group-vertical">';
249  if ($maxItems > 1 && $size >= 5) {
250  $html[] = '<a href="#"';
251  $html[] = ' class="btn btn-default t3js-btn-moveoption-top"';
252  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
253  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.move_to_top')) . '"';
254  $html[] = '>';
255  $html[] = $this->iconFactory->getIcon('actions-move-to-top', Icon::SIZE_SMALL)->render();
256  $html[] = '</a>';
257  }
258  if ($maxItems > 1) {
259  $html[] = '<a href="#"';
260  $html[] = ' class="btn btn-default t3js-btn-moveoption-up"';
261  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
262  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.move_up')) . '"';
263  $html[] = '>';
264  $html[] = $this->iconFactory->getIcon('actions-move-up', Icon::SIZE_SMALL)->render();
265  $html[] = '</a>';
266  $html[] = '<a href="#"';
267  $html[] = ' class="btn btn-default t3js-btn-moveoption-down"';
268  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
269  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.move_down')) . '"';
270  $html[] = '>';
271  $html[] = $this->iconFactory->getIcon('actions-move-down', Icon::SIZE_SMALL)->render();
272  $html[] = '</a>';
273  }
274  if ($maxItems > 1 && $size >= 5) {
275  $html[] = '<a href="#"';
276  $html[] = ' class="btn btn-default t3js-btn-moveoption-bottom"';
277  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
278  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.move_to_bottom')) . '"';
279  $html[] = '>';
280  $html[] = $this->iconFactory->getIcon('actions-move-to-bottom', Icon::SIZE_SMALL)->render();
281  $html[] = '</a>';
282  }
283  $html[] = '<a href="#"';
284  $html[] = ' class="btn btn-default t3js-btn-removeoption"';
285  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
286  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.remove_selected')) . '"';
287  $html[] = '>';
288  $html[] = $this->iconFactory->getIcon('actions-selection-delete', Icon::SIZE_SMALL)->render();
289  $html[] = '</a>';
290  $html[] = '</div>';
291  $html[] = '</div>';
292  $html[] = '</div>';
293  $html[] = '</div>';
294  $html[] = '<div class="form-multigroup-item form-multigroup-element">';
295  $html[] = '<label>';
296  $html[] = htmlspecialchars($languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.items'));
297  $html[] = '</label>';
298  $html[] = '<div class="form-wizards-wrap form-wizards-aside">';
299  $html[] = '<div class="form-wizards-element">';
300  $html[] = implode(LF, $filterHtml);
301  $html[] = '<select';
302  $html[] = ' data-relatedfieldname="' . htmlspecialchars($elementName) . '"';
303  $html[] = ' data-exclusivevalues="' . htmlspecialchars($config['exclusiveKeys']) . '"';
304  $html[] = ' id="' . StringUtility::getUniqueId('tceforms-multiselect-') . '"';
305  $html[] = ' data-formengine-input-name="' . htmlspecialchars($elementName) . '"';
306  $html[] = ' class="form-control t3js-formengine-select-itemstoselect"';
307  $html[] = ' size="' . $size . '"';
308  $html[] = ' onchange="' . htmlspecialchars(implode('', $parameterArray['fieldChangeFunc'])) . '"';
309  $html[] = ' data-formengine-validation-rules="' . htmlspecialchars($this->getValidationDataAsJsonString($config)) . '"';
310  $html[] = $selectableListStyle;
311  $html[] = '>';
312  $html[] = implode(LF, $selectableItemsHtml);
313  $html[] = '</select>';
314  $html[] = '</div>';
315  $html[] = '<div class="form-wizards-items-aside">';
316  $html[] = '<div class="btn-group-vertical">';
317  $html[] = $fieldControlHtml;
318  $html[] = '</div>';
319  $html[] = '</div>';
320  $html[] = '</div>';
321  $html[] = '</div>';
322  $html[] = '</div>';
323  $html[] = '<input type="hidden" name="' . htmlspecialchars($elementName) . '" value="' . htmlspecialchars(implode(',', $listOfSelectedValues)) . '" />';
324  $html[] = '</div>';
325  $html[] = '<div class="form-wizards-items-bottom">';
326  $html[] = $fieldWizardHtml;
327  $html[] = '</div>';
328  $html[] = '</div>';
329  $html[] = '</div>';
330 
331  $resultArray['html'] = implode(LF, $html);
332  return $resultArray;
333  }
334 
341  protected function renderReadOnly()
342  {
343  $languageService = $this->getLanguageService();
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  $html = [];
383  $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
384  $html[] = '<div class="form-wizards-wrap">';
385  $html[] = '<div class="form-wizards-element">';
386  $html[] = '<label>';
387  $html[] = htmlspecialchars($languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.selected'));
388  $html[] = '</label>';
389  $html[] = '<div class="form-wizards-wrap form-wizards-aside">';
390  $html[] = '<div class="form-wizards-element">';
391  $html[] = '<select';
392  $html[] = ' id="' . StringUtility::getUniqueId('tceforms-multiselect-') . '"';
393  $html[] = ' size="' . $size . '"';
394  $html[] = ' class="form-control tceforms-multiselect"';
395  $html[] = $multiple;
396  $html[] = ' data-formengine-input-name="' . htmlspecialchars($fieldName) . '"';
397  $html[] = ' disabled="disabled">';
398  $html[] = '/>';
399  $html[] = implode(LF, $optionsHtml);
400  $html[] = '</select>';
401  $html[] = '</div>';
402  $html[] = '</div>';
403  $html[] = '<input type="hidden" name="' . htmlspecialchars($fieldName) . '" value="' . htmlspecialchars(implode(',', $listOfSelectedValues)) . '" />';
404  $html[] = '</div>';
405  $html[] = '</div>';
406  $html[] = '</div>';
407 
408  $resultArray = $this->initializeResultArray();
409  $resultArray['html'] = implode(LF, $html);
410  return $resultArray;
411  }
412 
416  protected function getLanguageService()
417  {
418  return $GLOBALS['LANG'];
419  }
420 
424  protected function getBackendUserAuthentication()
425  {
426  return $GLOBALS['BE_USER'];
427  }
428 }
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
renderWizards( $itemKinds=null, $wizConf=null, $table=null, $row=null, $fieldName=null, $PA=null, $itemName=null, $specConf=null, $RTE=null)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
mergeChildReturnIntoExistingResult(array $existing, array $childReturn, bool $mergeHtml=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']