2 namespace TYPO3\CMS\Backend\Form\Element
;
5 * This file is part of the TYPO3 CMS project.
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.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
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
;
25 * Render a widget with two boxes side by side.
27 * This is rendered for config type=select, maxitems > 1, no other renderMode set
29 class SelectMultipleSideBySideElement
extends AbstractFormElement
{
32 * @var array Result array given returned by render() - This property is a helper until class is properly refactored
34 protected $resultArray = array();
37 * Render side by side element.
39 * @return array As defined in initializeResultArray() of AbstractNode
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'];
49 if ($this->isGlobalReadonly() ||
$config['readOnly']) {
50 $disabled = ' disabled="disabled"';
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);
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') . ' ]';
62 $html = $this->getSingleField_typeSelect_multiple($table, $field, $row, $parameterArray, $config, $selItems, $noMatchingLabel);
66 $altItem = '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" />';
67 $html = $this->renderWizards(array($html, $altItem), $config['wizards'], $table, $row, $field, $parameterArray, $parameterArray['itemFormElName'], $specConf);
69 $this->resultArray
['html'] = $html;
70 return $this->resultArray
;
74 * Creates a multiple-selector box (two boxes, side-by-side)
76 * @param string $table See getSingleField_typeSelect()
77 * @param string $field See getSingleField_typeSelect()
78 * @param array $row See getSingleField_typeSelect()
79 * @param array $parameterArray See getSingleField_typeSelect()
80 * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
81 * @param array $selItems Items available for selection
82 * @param string $noMatchingLabel Label for no-matching-value
83 * @return string The HTML code for the item
85 protected function getSingleField_typeSelect_multiple($table, $field, $row, $parameterArray, $config, $selItems, $noMatchingLabel) {
86 $languageService = $this->getLanguageService();
89 if ($this->isGlobalReadonly() ||
$config['readOnly']) {
90 $disabled = ' disabled="disabled"';
92 // Setting this hidden field (as a flag that JavaScript can read out)
94 $item .= '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '_mul" value="' . ($config['multiple'] ?
1 : 0) . '" />';
96 // Set max and min items:
97 $maxitems = MathUtility
::forceIntegerInRange($config['maxitems'], 0);
101 $minitems = MathUtility
::forceIntegerInRange($config['minitems'], 0);
102 // Register the required number of elements:
103 $this->resultArray
['requiredElements'][$parameterArray['itemFormElName']] = array(
106 'imgName' => $table . '_' . $row['uid'] . '_' . $field
108 $tabAndInlineStack = $this->globalOptions
['tabAndInlineStack'];
109 if (!empty($tabAndInlineStack) && preg_match('/^(.+\\])\\[(\\w+)\\]$/', $parameterArray['itemFormElName'], $match)) {
111 $this->resultArray
['requiredNested'][$parameterArray['itemFormElName']] = array(
113 'level' => $tabAndInlineStack,
116 // Get "removeItems":
117 $removeItems = GeneralUtility
::trimExplode(',', $parameterArray['fieldTSConfig']['removeItems'], TRUE);
118 // Get the array with selected items:
119 $itemArray = GeneralUtility
::trimExplode(',', $parameterArray['itemFormElValue'], TRUE);
121 // Possibly filter some items:
122 $itemArray = ArrayUtility
::keepItemsInArray(
124 $parameterArray['fieldTSConfig']['keepItems'],
126 $parts = explode('|', $value, 2);
127 return rawurldecode($parts[0]);
131 // Perform modification of the selected items array:
132 foreach ($itemArray as $tk => $tv) {
133 $tvP = explode('|', $tv, 2);
134 $evalValue = $tvP[0];
135 $isRemoved = in_array($evalValue, $removeItems)
136 ||
$config['type'] == 'select' && $config['authMode']
137 && !$this->getBackendUserAuthentication()->checkAuthMode($table, $field, $evalValue, $config['authMode']);
138 if ($isRemoved && !$parameterArray['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
139 $tvP[1] = rawurlencode(@sprintf
($noMatchingLabel, $evalValue));
141 if (isset($parameterArray['fieldTSConfig']['altLabels.'][$evalValue])) {
142 $tvP[1] = rawurlencode($languageService->sL($parameterArray['fieldTSConfig']['altLabels.'][$evalValue]));
144 if (isset($parameterArray['fieldTSConfig']['altIcons.'][$evalValue])) {
145 $tvP[2] = $parameterArray['fieldTSConfig']['altIcons.'][$evalValue];
149 // Case: flexform, default values supplied, no label provided (bug #9795)
150 foreach ($selItems as $selItem) {
151 if ($selItem[1] == $tvP[0]) {
152 $tvP[1] = html_entity_decode($selItem[0]);
157 $itemArray[$tk] = implode('|', $tvP);
160 // size must be at least two, as there are always maxitems > 1 (see parent function)
161 if (isset($config['size'])) {
162 $size = (int)$config['size'];
166 $size = $config['autoSizeMax'] ? MathUtility
::forceIntegerInRange(count($itemArray) +
1, MathUtility
::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size;
169 $filterTextfield = '';
170 $filterSelectbox = '';
172 // Create option tags:
174 $styleAttrValue = '';
175 foreach ($selItems as $p) {
176 if ($config['iconsInOptionTags']) {
177 $styleAttrValue = FormEngineUtility
::optionTagStyle($p[2]);
179 $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"'
180 . ($styleAttrValue ?
' style="' . htmlspecialchars($styleAttrValue) . '"' : '')
181 . ' title="' . $p[0] . '">' . $p[0] . '</option>';
183 // Put together the selector box:
184 $selector_itemListStyle = isset($config['itemListStyle'])
185 ?
' style="' . htmlspecialchars($config['itemListStyle']) . '"'
187 $sOnChange = implode('', $parameterArray['fieldChangeFunc']);
189 $multiSelectId = str_replace('.', '', uniqid('tceforms-multiselect-', TRUE));
191 <select data-relatedfieldname="' . htmlspecialchars($parameterArray['itemFormElName']) . '" data-exclusivevalues="'
192 . htmlspecialchars($config['exclusiveKeys']) . '" id="' . $multiSelectId . '" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '_sel" '
193 . ' class="form-control t3js-formengine-select-itemstoselect" '
194 . ($size ?
' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars($sOnChange) . '"'
195 . $parameterArray['onFocus'] . $selector_itemListStyle . '>
200 // enable filter functionality via a text field
201 if ($config['enableMultiSelectFilterTextfield']) {
203 <span class="input-group input-group-sm">
204 <span class="input-group-addon">
205 <span class="fa fa-filter"></span>
207 <input class="t3js-formengine-multiselect-filter-textfield form-control" value="" />
211 // enable filter functionality via a select
212 if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) {
213 $filterDropDownOptions = array();
214 foreach ($config['multiSelectFilterItems'] as $optionElement) {
215 $optionValue = $languageService->sL(isset($optionElement[1]) && $optionElement[1] != '' ?
$optionElement[1]
216 : $optionElement[0]);
217 $filterDropDownOptions[] = '<option value="' . htmlspecialchars($languageService->sL($optionElement[0])) . '">'
218 . htmlspecialchars($optionValue) . '</option>';
220 $filterSelectbox = '<select class="form-control input-sm t3js-formengine-multiselect-filter-dropdown">
222 ', $filterDropDownOptions) . '
227 if (!empty(trim($filterSelectbox)) && !empty(trim($filterTextfield))) {
228 $filterSelectbox = '<div class="form-multigroup-item form-multigroup-element">' . $filterSelectbox . '</div>';
229 $filterTextfield = '<div class="form-multigroup-item form-multigroup-element">' . $filterTextfield . '</div>';
230 $selectBoxFilterContents = '<div class="t3js-formengine-multiselect-filter-container form-multigroup-wrap">' . $filterSelectbox . $filterTextfield . '</div>';
232 $selectBoxFilterContents = trim($filterSelectbox . ' ' . $filterTextfield);
235 // Pass to "dbFileIcons" function:
238 'autoSizeMax' => MathUtility
::forceIntegerInRange($config['autoSizeMax'], 0),
239 'style' => isset($config['selectedListStyle'])
240 ?
' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
242 'dontShowMoveIcons' => $maxitems <= 1,
243 'maxitems' => $maxitems,
246 'selector' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.selected'),
247 'items' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.items'),
248 'selectorbox' => $selectBoxFilterContents,
251 'rightbox' => $itemsToSelect,
252 'readOnly' => $disabled
254 $item .= $this->dbFileIcons($parameterArray['itemFormElName'], '', '', $itemArray, '', $params, $parameterArray['onFocus']);
259 * @return BackendUserAuthentication
261 protected function getBackendUserAuthentication() {
262 return $GLOBALS['BE_USER'];