[BUGFIX] Fixed broken filters on SelectMultipleSideBySideElement
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Element / SelectMultipleSideBySideElement.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form\Element;
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
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Core\Utility\MathUtility;
21 use TYPO3\CMS\Core\Utility\StringUtility;
22
23 /**
24 * Render a widget with two boxes side by side.
25 *
26 * This is rendered for config type=select, maxitems > 1, no other renderMode set
27 */
28 class SelectMultipleSideBySideElement extends AbstractFormElement {
29
30 /**
31 * Render side by side element.
32 *
33 * @return array As defined in initializeResultArray() of AbstractNode
34 */
35 public function render() {
36 $table = $this->data['tableName'];
37 $field = $this->data['fieldName'];
38 $parameterArray = $this->data['parameterArray'];
39 // Field configuration from TCA:
40 $config = $parameterArray['fieldConf']['config'];
41
42 // Creating the label for the "No Matching Value" entry.
43 $noMatchingLabel = isset($parameterArray['fieldTSConfig']['noMatchingValue_label'])
44 ? $this->getLanguageService()->sL($parameterArray['fieldTSConfig']['noMatchingValue_label'])
45 : '[ ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue') . ' ]';
46
47 $selItems = $config['items'];
48 $html = '';
49 $disabled = '';
50 if ($config['readOnly']) {
51 $disabled = ' disabled="disabled"';
52 }
53 // Setting this hidden field (as a flag that JavaScript can read out)
54 if (!$disabled) {
55 $html .= '<input type="hidden" data-formengine-input-name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" value="' . ($config['multiple'] ? 1 : 0) . '" />';
56 }
57 // Set max and min items:
58 $maxitems = MathUtility::forceIntegerInRange($config['maxitems'], 0);
59 if (!$maxitems) {
60 $maxitems = 100000;
61 }
62 // Get "removeItems":
63 $removeItems = GeneralUtility::trimExplode(',', $parameterArray['fieldTSConfig']['removeItems'], TRUE);
64 // Get the array with selected items:
65 $itemsArray = $parameterArray['itemFormElValue'];
66
67 // Perform modification of the selected items array:
68 // @todo: this part should probably be moved to TcaSelectItems provider?!
69 foreach ($itemsArray as $itemNumber => $itemValue) {
70 $itemArray = array(
71 0 => $itemValue,
72 1 => '',
73 );
74 $itemIcon = NULL;
75 $isRemoved = in_array($itemValue, $removeItems)
76 || $config['type'] == 'select' && $config['authMode']
77 && !$this->getBackendUserAuthentication()->checkAuthMode($table, $field, $itemValue, $config['authMode']);
78 if ($isRemoved && !$parameterArray['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
79 $itemArray[1] = rawurlencode(@sprintf($noMatchingLabel, $itemValue));
80 } else {
81 if (isset($parameterArray['fieldTSConfig']['altLabels.'][$itemValue])) {
82 $itemArray[1] = rawurlencode($this->getLanguageService()->sL($parameterArray['fieldTSConfig']['altLabels.'][$itemValue]));
83 }
84 if (isset($parameterArray['fieldTSConfig']['altIcons.'][$itemValue])) {
85 $itemArray[2] = $parameterArray['fieldTSConfig']['altIcons.'][$itemValue];
86 }
87 }
88 if ($itemArray[1] === '') {
89 foreach ($selItems as $selItem) {
90 if ($selItem[1] == $itemValue) {
91 $itemArray[1] = $selItem[0];
92 break;
93 }
94 }
95 }
96 $itemsArray[$itemNumber] = implode('|', $itemArray);
97 }
98
99 // size must be at least two, as there are always maxitems > 1 (see parent function)
100 if (isset($config['size'])) {
101 $size = (int)$config['size'];
102 } else {
103 $size = 2;
104 }
105 $size = $config['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($itemsArray) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size;
106
107 $itemsToSelect = [];
108 $filterTextfield = '';
109 $filterSelectbox = '';
110 if (!$disabled) {
111 // Create option tags:
112 $opt = array();
113 foreach ($selItems as $p) {
114 $opt[] = '<option value="' . htmlspecialchars($p[1]) . '" title="' . $p[0] . '">' . $p[0] . '</option>';
115 }
116 // Put together the selector box:
117 $selector_itemListStyle = isset($config['itemListStyle'])
118 ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"'
119 : '';
120 $sOnChange = implode('', $parameterArray['fieldChangeFunc']);
121
122 $multiSelectId = StringUtility::getUniqueId('tceforms-multiselect-');
123 $itemsToSelect[] = '<select data-relatedfieldname="' . htmlspecialchars($parameterArray['itemFormElName']) . '" '
124 . 'data-exclusivevalues="' . htmlspecialchars($config['exclusiveKeys']) . '" '
125 . 'id="' . $multiSelectId . '" '
126 . 'data-formengine-input-name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" '
127 . 'class="form-control t3js-formengine-select-itemstoselect" '
128 . ($size ? ' size="' . $size . '" ' : '')
129 . 'onchange="' . htmlspecialchars($sOnChange) . '" '
130 . $parameterArray['onFocus']
131 . $this->getValidationDataAsDataAttribute($config)
132 . $selector_itemListStyle
133 . '>';
134 $itemsToSelect[] = implode(LF, $opt);
135 $itemsToSelect[] = '</select>';
136
137 // enable filter functionality via a text field
138 $filterTextfield = [];
139 if ($config['enableMultiSelectFilterTextfield']) {
140 $filterTextfield[] = '<span class="input-group input-group-sm">';
141 $filterTextfield[] = '<span class="input-group-addon">';
142 $filterTextfield[] = '<span class="fa fa-filter"></span>';
143 $filterTextfield[] = '</span>';
144 $filterTextfield[] = '<input class="t3js-formengine-multiselect-filter-textfield form-control" value="">';
145 $filterTextfield[] = '</span>';
146 }
147
148 // enable filter functionality via a select
149 if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) {
150 $filterDropDownOptions = array();
151 foreach ($config['multiSelectFilterItems'] as $optionElement) {
152 $optionValue = $this->getLanguageService()->sL(isset($optionElement[1]) && $optionElement[1] != '' ? $optionElement[1]
153 : $optionElement[0]);
154 $filterDropDownOptions[] = '<option value="' . htmlspecialchars($this->getLanguageService()->sL($optionElement[0])) . '">'
155 . htmlspecialchars($optionValue) . '</option>';
156 }
157 $filterSelectbox = '<select class="form-control input-sm t3js-formengine-multiselect-filter-dropdown">'
158 . implode(LF, $filterDropDownOptions) . '</select>';
159 }
160 }
161
162 if (!empty(trim($filterSelectbox)) && !empty($filterTextfield)) {
163 $filterSelectbox = '<div class="form-multigroup-item form-multigroup-element">' . $filterSelectbox . '</div>';
164 $filterTextfield = '<div class="form-multigroup-item form-multigroup-element">' . implode(LF, $filterTextfield) . '</div>';
165 $selectBoxFilterContents = '<div class="t3js-formengine-multiselect-filter-container form-multigroup-wrap">' . $filterSelectbox . $filterTextfield . '</div>';
166 } else {
167 $selectBoxFilterContents = trim($filterSelectbox . ' ' . implode(LF, $filterTextfield));
168 }
169
170 // Pass to "dbFileIcons" function:
171 $params = array(
172 'size' => $size,
173 'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
174 'style' => isset($config['selectedListStyle'])
175 ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
176 : '',
177 'dontShowMoveIcons' => $maxitems <= 1,
178 'maxitems' => $maxitems,
179 'info' => '',
180 'headers' => array(
181 'selector' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.selected'),
182 'items' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.items'),
183 'selectorbox' => $selectBoxFilterContents,
184 ),
185 'noBrowser' => 1,
186 'rightbox' => implode(LF, $itemsToSelect),
187 'readOnly' => $disabled
188 );
189 $html .= $this->dbFileIcons($parameterArray['itemFormElName'], '', '', $itemsArray, '', $params, $parameterArray['onFocus']);
190
191 // Wizards:
192 if (!$disabled) {
193 $html = $this->renderWizards(
194 array($html),
195 $config['wizards'],
196 $table,
197 $this->data['databaseRow'],
198 $field,
199 $parameterArray,
200 $parameterArray['itemFormElName'],
201 BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras'])
202 );
203 }
204
205 $resultArray = $this->initializeResultArray();
206 $resultArray['html'] = $html;
207 return $resultArray;
208 }
209
210 /**
211 * @return BackendUserAuthentication
212 */
213 protected function getBackendUserAuthentication() {
214 return $GLOBALS['BE_USER'];
215 }
216 }