[BUGFIX] Correct record title escaping
[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\MathUtility;
20 use TYPO3\CMS\Core\Utility\StringUtility;
21
22 /**
23 * Render a widget with two boxes side by side.
24 *
25 * This is rendered for config type=select, maxitems > 1, renderType=selectMultipleSideBySide set
26 */
27 class SelectMultipleSideBySideElement extends AbstractFormElement
28 {
29 /**
30 * Render side by side element.
31 *
32 * @return array As defined in initializeResultArray() of AbstractNode
33 */
34 public function render()
35 {
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(trim($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 the array with selected items:
63 $itemsArray = $parameterArray['itemFormElValue'] ?: [];
64
65 // Perform modification of the selected items array:
66 foreach ($itemsArray as $itemNumber => $itemValue) {
67 $itemArray = array(
68 0 => $itemValue,
69 1 => '',
70 );
71
72 if (isset($parameterArray['fieldTSConfig']['altIcons.'][$itemValue])) {
73 $itemArray[2] = $parameterArray['fieldTSConfig']['altIcons.'][$itemValue];
74 }
75
76 foreach ($selItems as $selItem) {
77 if ($selItem[1] == $itemValue) {
78 $itemArray[1] = $selItem[0];
79 break;
80 }
81 }
82 $itemsArray[$itemNumber] = implode('|', $itemArray);
83 }
84
85 // size must be at least two, as there are always maxitems > 1 (see parent function)
86 if (isset($config['size'])) {
87 $size = (int)$config['size'];
88 } else {
89 $size = 2;
90 }
91 $size = $config['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($itemsArray) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size;
92 $allowMultiple = !empty($config['multiple']);
93
94 $itemsToSelect = [];
95 $filterTextfield = [];
96 $filterSelectbox = '';
97 if (!$disabled) {
98 // Create option tags:
99 $opt = array();
100 foreach ($selItems as $p) {
101 $disabledAttr = '';
102 $classAttr = '';
103 if (!$allowMultiple && in_array((string)$p[1], $parameterArray['itemFormElValue'], true)) {
104 $disabledAttr = ' disabled="disabled"';
105 $classAttr = ' class="hidden"';
106 }
107 $opt[] = '<option value="' . htmlspecialchars($p[1]) . '" title="' . htmlspecialchars($p[0]) . '"' . $classAttr . $disabledAttr . '>' . htmlspecialchars($p[0]) . '</option>';
108 }
109 // Put together the selector box:
110 $selector_itemListStyle = isset($config['itemListStyle'])
111 ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"'
112 : '';
113 $sOnChange = implode('', $parameterArray['fieldChangeFunc']);
114
115 $multiSelectId = StringUtility::getUniqueId('tceforms-multiselect-');
116 $itemsToSelect[] = '<select data-relatedfieldname="' . htmlspecialchars($parameterArray['itemFormElName']) . '" '
117 . 'data-exclusivevalues="' . htmlspecialchars($config['exclusiveKeys']) . '" '
118 . 'id="' . $multiSelectId . '" '
119 . 'data-formengine-input-name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" '
120 . 'class="form-control t3js-formengine-select-itemstoselect" '
121 . ($size ? ' size="' . $size . '" ' : '')
122 . 'onchange="' . htmlspecialchars($sOnChange) . '" '
123 . $this->getValidationDataAsDataAttribute($config)
124 . $selector_itemListStyle
125 . '>';
126 $itemsToSelect[] = implode(LF, $opt);
127 $itemsToSelect[] = '</select>';
128
129 // enable filter functionality via a text field
130 if ($config['enableMultiSelectFilterTextfield']) {
131 $filterTextfield[] = '<span class="input-group input-group-sm">';
132 $filterTextfield[] = '<span class="input-group-addon">';
133 $filterTextfield[] = '<span class="fa fa-filter"></span>';
134 $filterTextfield[] = '</span>';
135 $filterTextfield[] = '<input class="t3js-formengine-multiselect-filter-textfield form-control" value="">';
136 $filterTextfield[] = '</span>';
137 }
138
139 // enable filter functionality via a select
140 if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) {
141 $filterDropDownOptions = array();
142 foreach ($config['multiSelectFilterItems'] as $optionElement) {
143 $optionValue = $this->getLanguageService()->sL(isset($optionElement[1]) && trim($optionElement[1]) !== '' ? trim($optionElement[1])
144 : trim($optionElement[0]));
145 $filterDropDownOptions[] = '<option value="' . htmlspecialchars($this->getLanguageService()->sL(trim($optionElement[0]))) . '">'
146 . htmlspecialchars($optionValue) . '</option>';
147 }
148 $filterSelectbox = '<select class="form-control input-sm t3js-formengine-multiselect-filter-dropdown">'
149 . implode(LF, $filterDropDownOptions) . '</select>';
150 }
151 }
152
153 if (!empty(trim($filterSelectbox)) && !empty($filterTextfield)) {
154 $filterSelectbox = '<div class="form-multigroup-item form-multigroup-element">' . $filterSelectbox . '</div>';
155 $filterTextfield = '<div class="form-multigroup-item form-multigroup-element">' . implode(LF, $filterTextfield) . '</div>';
156 $selectBoxFilterContents = '<div class="t3js-formengine-multiselect-filter-container form-multigroup-wrap">' . $filterSelectbox . $filterTextfield . '</div>';
157 } else {
158 $selectBoxFilterContents = trim($filterSelectbox . ' ' . implode(LF, $filterTextfield));
159 }
160
161 // Pass to "dbFileIcons" function:
162 $params = array(
163 'size' => $size,
164 'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
165 'style' => isset($config['selectedListStyle'])
166 ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
167 : '',
168 'dontShowMoveIcons' => $maxitems <= 1,
169 'maxitems' => $maxitems,
170 'info' => '',
171 'headers' => array(
172 'selector' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.selected'),
173 'items' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.items'),
174 'selectorbox' => $selectBoxFilterContents,
175 ),
176 'noBrowser' => 1,
177 'rightbox' => implode(LF, $itemsToSelect),
178 'readOnly' => $disabled
179 );
180 $html .= $this->dbFileIcons($parameterArray['itemFormElName'], '', '', $itemsArray, '', $params);
181
182 // Wizards:
183 if (!$disabled) {
184 $html = $this->renderWizards(
185 array($html),
186 $config['wizards'],
187 $table,
188 $this->data['databaseRow'],
189 $field,
190 $parameterArray,
191 $parameterArray['itemFormElName'],
192 BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras'])
193 );
194 }
195
196 $resultArray = $this->initializeResultArray();
197 $resultArray['html'] = $html;
198 return $resultArray;
199 }
200
201 /**
202 * @return BackendUserAuthentication
203 */
204 protected function getBackendUserAuthentication()
205 {
206 return $GLOBALS['BE_USER'];
207 }
208 }