[!!!][TASK] TCA: Remove wizard _HIDDENFIELD and hideParent
[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\Core\Utility\ArrayUtility;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Core\Utility\MathUtility;
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
21 use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
22 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
23
24 /**
25 * Render a widget with two boxes side by side.
26 *
27 * This is rendered for config type=select, maxitems > 1, no other renderMode set
28 */
29 class SelectMultipleSideBySideElement extends AbstractFormElement {
30
31 /**
32 * @var array Result array given returned by render() - This property is a helper until class is properly refactored
33 */
34 protected $resultArray = array();
35
36 /**
37 * Render side by side element.
38 *
39 * @return array As defined in initializeResultArray() of AbstractNode
40 */
41 public function render() {
42 $table = $this->globalOptions['table'];
43 $field = $this->globalOptions['fieldName'];
44 $row = $this->globalOptions['databaseRow'];
45 $parameterArray = $this->globalOptions['parameterArray'];
46 // Field configuration from TCA:
47 $config = $parameterArray['fieldConf']['config'];
48 $disabled = '';
49 if ($this->isGlobalReadonly() || $config['readOnly']) {
50 $disabled = ' disabled="disabled"';
51 }
52 $this->resultArray = $this->initializeResultArray();
53 // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
54 $specConf = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
55 $selItems = FormEngineUtility::getSelectItems($table, $field, $row, $parameterArray);
56
57 // Creating the label for the "No Matching Value" entry.
58 $noMatchingLabel = isset($parameterArray['fieldTSConfig']['noMatchingValue_label'])
59 ? $this->getLanguageService()->sL($parameterArray['fieldTSConfig']['noMatchingValue_label'])
60 : '[ ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue') . ' ]';
61
62 $html = $this->getSingleField_typeSelect_multiple($table, $field, $row, $parameterArray, $config, $selItems, $noMatchingLabel);
63
64 // Wizards:
65 if (!$disabled) {
66 $html = $this->renderWizards(array($html), $config['wizards'], $table, $row, $field, $parameterArray, $parameterArray['itemFormElName'], $specConf);
67 }
68 $this->resultArray['html'] = $html;
69 return $this->resultArray;
70 }
71
72 /**
73 * Creates a multiple-selector box (two boxes, side-by-side)
74 *
75 * @param string $table See getSingleField_typeSelect()
76 * @param string $field See getSingleField_typeSelect()
77 * @param array $row See getSingleField_typeSelect()
78 * @param array $parameterArray See getSingleField_typeSelect()
79 * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
80 * @param array $selItems Items available for selection
81 * @param string $noMatchingLabel Label for no-matching-value
82 * @return string The HTML code for the item
83 */
84 protected function getSingleField_typeSelect_multiple($table, $field, $row, $parameterArray, $config, $selItems, $noMatchingLabel) {
85 $languageService = $this->getLanguageService();
86 $item = '';
87 $disabled = '';
88 if ($this->isGlobalReadonly() || $config['readOnly']) {
89 $disabled = ' disabled="disabled"';
90 }
91 // Setting this hidden field (as a flag that JavaScript can read out)
92 if (!$disabled) {
93 $item .= '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '_mul" value="' . ($config['multiple'] ? 1 : 0) . '" />';
94 }
95 // Set max and min items:
96 $maxitems = MathUtility::forceIntegerInRange($config['maxitems'], 0);
97 if (!$maxitems) {
98 $maxitems = 100000;
99 }
100 // Get "removeItems":
101 $removeItems = GeneralUtility::trimExplode(',', $parameterArray['fieldTSConfig']['removeItems'], TRUE);
102 // Get the array with selected items:
103 $itemArray = GeneralUtility::trimExplode(',', $parameterArray['itemFormElValue'], TRUE);
104
105 // Possibly filter some items:
106 $itemArray = ArrayUtility::keepItemsInArray(
107 $itemArray,
108 $parameterArray['fieldTSConfig']['keepItems'],
109 function ($value) {
110 $parts = explode('|', $value, 2);
111 return rawurldecode($parts[0]);
112 }
113 );
114
115 // Perform modification of the selected items array:
116 foreach ($itemArray as $tk => $tv) {
117 $tvP = explode('|', $tv, 2);
118 $evalValue = $tvP[0];
119 $isRemoved = in_array($evalValue, $removeItems)
120 || $config['type'] == 'select' && $config['authMode']
121 && !$this->getBackendUserAuthentication()->checkAuthMode($table, $field, $evalValue, $config['authMode']);
122 if ($isRemoved && !$parameterArray['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
123 $tvP[1] = rawurlencode(@sprintf($noMatchingLabel, $evalValue));
124 } else {
125 if (isset($parameterArray['fieldTSConfig']['altLabels.'][$evalValue])) {
126 $tvP[1] = rawurlencode($languageService->sL($parameterArray['fieldTSConfig']['altLabels.'][$evalValue]));
127 }
128 if (isset($parameterArray['fieldTSConfig']['altIcons.'][$evalValue])) {
129 $tvP[2] = $parameterArray['fieldTSConfig']['altIcons.'][$evalValue];
130 }
131 }
132 if ($tvP[1] == '') {
133 // Case: flexform, default values supplied, no label provided (bug #9795)
134 foreach ($selItems as $selItem) {
135 if ($selItem[1] == $tvP[0]) {
136 $tvP[1] = html_entity_decode($selItem[0]);
137 break;
138 }
139 }
140 }
141 $itemArray[$tk] = implode('|', $tvP);
142 }
143
144 // size must be at least two, as there are always maxitems > 1 (see parent function)
145 if (isset($config['size'])) {
146 $size = (int)$config['size'];
147 } else {
148 $size = 2;
149 }
150 $size = $config['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($itemArray) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size;
151
152 $itemsToSelect = '';
153 $filterTextfield = '';
154 $filterSelectbox = '';
155 if (!$disabled) {
156 // Create option tags:
157 $opt = array();
158 $styleAttrValue = '';
159 foreach ($selItems as $p) {
160 if ($config['iconsInOptionTags']) {
161 $styleAttrValue = FormEngineUtility::optionTagStyle($p[2]);
162 }
163 $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"'
164 . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '')
165 . ' title="' . $p[0] . '">' . $p[0] . '</option>';
166 }
167 // Put together the selector box:
168 $selector_itemListStyle = isset($config['itemListStyle'])
169 ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"'
170 : '';
171 $sOnChange = implode('', $parameterArray['fieldChangeFunc']);
172
173 $multiSelectId = str_replace('.', '', uniqid('tceforms-multiselect-', TRUE));
174 $itemsToSelect = '
175 <select data-relatedfieldname="' . htmlspecialchars($parameterArray['itemFormElName']) . '" data-exclusivevalues="'
176 . htmlspecialchars($config['exclusiveKeys']) . '" id="' . $multiSelectId . '" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '_sel" '
177 . ' class="form-control t3js-formengine-select-itemstoselect" '
178 . ($size ? ' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars($sOnChange) . '"'
179 . $parameterArray['onFocus'] . $this->getValidationDataAsDataAttribute($config) . $selector_itemListStyle . '>
180 ' . implode('
181 ', $opt) . '
182 </select>';
183
184 // enable filter functionality via a text field
185 if ($config['enableMultiSelectFilterTextfield']) {
186 $filterTextfield = '
187 <span class="input-group input-group-sm">
188 <span class="input-group-addon">
189 <span class="fa fa-filter"></span>
190 </span>
191 <input class="t3js-formengine-multiselect-filter-textfield form-control" value="" />
192 </span>';
193 }
194
195 // enable filter functionality via a select
196 if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) {
197 $filterDropDownOptions = array();
198 foreach ($config['multiSelectFilterItems'] as $optionElement) {
199 $optionValue = $languageService->sL(isset($optionElement[1]) && $optionElement[1] != '' ? $optionElement[1]
200 : $optionElement[0]);
201 $filterDropDownOptions[] = '<option value="' . htmlspecialchars($languageService->sL($optionElement[0])) . '">'
202 . htmlspecialchars($optionValue) . '</option>';
203 }
204 $filterSelectbox = '<select class="form-control input-sm t3js-formengine-multiselect-filter-dropdown">
205 ' . implode('
206 ', $filterDropDownOptions) . '
207 </select>';
208 }
209 }
210
211 if (!empty(trim($filterSelectbox)) && !empty(trim($filterTextfield))) {
212 $filterSelectbox = '<div class="form-multigroup-item form-multigroup-element">' . $filterSelectbox . '</div>';
213 $filterTextfield = '<div class="form-multigroup-item form-multigroup-element">' . $filterTextfield . '</div>';
214 $selectBoxFilterContents = '<div class="t3js-formengine-multiselect-filter-container form-multigroup-wrap">' . $filterSelectbox . $filterTextfield . '</div>';
215 } else {
216 $selectBoxFilterContents = trim($filterSelectbox . ' ' . $filterTextfield);
217 }
218
219 // Pass to "dbFileIcons" function:
220 $params = array(
221 'size' => $size,
222 'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
223 'style' => isset($config['selectedListStyle'])
224 ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
225 : '',
226 'dontShowMoveIcons' => $maxitems <= 1,
227 'maxitems' => $maxitems,
228 'info' => '',
229 'headers' => array(
230 'selector' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.selected'),
231 'items' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.items'),
232 'selectorbox' => $selectBoxFilterContents,
233 ),
234 'noBrowser' => 1,
235 'rightbox' => $itemsToSelect,
236 'readOnly' => $disabled
237 );
238 $item .= $this->dbFileIcons($parameterArray['itemFormElName'], '', '', $itemArray, '', $params, $parameterArray['onFocus']);
239 return $item;
240 }
241
242 /**
243 * @return BackendUserAuthentication
244 */
245 protected function getBackendUserAuthentication() {
246 return $GLOBALS['BE_USER'];
247 }
248
249 }