[TASK] Call explicit render() on icon objects
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Element / SelectCheckBoxElement.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\Imaging\Icon;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Core\Utility\StringUtility;
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
21 use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
22
23 /**
24 * Creates a widget with check box elements.
25 *
26 * This is rendered for config type=select, renderMode=checkbox, maxitems > 1
27 */
28 class SelectCheckBoxElement extends AbstractFormElement {
29
30 /**
31 * Render check boxes
32 *
33 * @return array As defined in initializeResultArray() of AbstractNode
34 */
35 public function render() {
36 $html = [];
37 // Field configuration from TCA:
38 $parameterArray = $this->data['parameterArray'];
39 $config = $parameterArray['fieldConf']['config'];
40 $disabled = !empty($config['readOnly']);
41
42 $selItems = $config['items'];
43 if (!empty($selItems)) {
44 // Get values in an array (and make unique, which is fine because there can be no duplicates anyway):
45 $itemArray = array_flip($parameterArray['itemFormElValue']);
46
47 // Traverse the Array of selector box items:
48 $groups = array();
49 $currentGroup = 0;
50 $c = 0;
51 $sOnChange = '';
52 if (!$disabled) {
53 $sOnChange = implode('', $parameterArray['fieldChangeFunc']);
54 // Used to accumulate the JS needed to restore the original selection.
55 foreach ($selItems as $p) {
56 // Non-selectable element:
57 if ($p[1] === '--div--') {
58 $selIcon = '';
59 if (isset($p[2]) && $p[2] != 'empty-empty') {
60 $selIcon = FormEngineUtility::getIconHtml($p[2]);
61 }
62 $currentGroup++;
63 $groups[$currentGroup]['header'] = array(
64 'icon' => $selIcon,
65 'title' => htmlspecialchars($p[0])
66 );
67 } else {
68 // Check if some help text is available
69 // Since TYPO3 4.5 help text is expected to be an associative array
70 // with two key, "title" and "description"
71 // For the sake of backwards compatibility, we test if the help text
72 // is a string and use it as a description (this could happen if items
73 // are modified with an itemProcFunc)
74 $hasHelp = FALSE;
75 $help = '';
76 $helpArray = array();
77 if (!empty($p[3])) {
78 $hasHelp = TRUE;
79 if (is_array($p[3])) {
80 $helpArray = $p[3];
81 } else {
82 $helpArray['description'] = $p[3];
83 }
84 }
85 if ($hasHelp) {
86 $help = BackendUtility::wrapInHelp('', '', '', $helpArray);
87 }
88
89 // Selected or not by default:
90 $checked = 0;
91 if (isset($itemArray[$p[1]])) {
92 $checked = 1;
93 unset($itemArray[$p[1]]);
94 }
95
96 // Build item array
97 $groups[$currentGroup]['items'][] = array(
98 'id' => StringUtility::getUniqueId('select_checkbox_row_'),
99 'name' => $parameterArray['itemFormElName'] . '[' . $c . ']',
100 'value' => $p[1],
101 'checked' => $checked,
102 'disabled' => FALSE,
103 'class' => '',
104 'icon' => (!empty($p[2]) ? FormEngineUtility::getIconHtml($p[2]) : $this->iconFactory->getIcon('empty-empty', Icon::SIZE_SMALL)->render()),
105 'title' => htmlspecialchars($p[0], ENT_COMPAT, 'UTF-8', FALSE),
106 'help' => $help
107 );
108 $c++;
109 }
110 }
111 }
112 // Remaining values (invalid):
113 if (!empty($itemArray) && !$parameterArray['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
114 $currentGroup++;
115 // Creating the label for the "No Matching Value" entry.
116 $noMatchingLabel = isset($parameterArray['fieldTSConfig']['noMatchingValue_label'])
117 ? $this->getLanguageService()->sL($parameterArray['fieldTSConfig']['noMatchingValue_label'])
118 : '[ ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue') . ' ]';
119 foreach ($itemArray as $theNoMatchValue => $temp) {
120 // Build item array
121 $groups[$currentGroup]['items'][] = array(
122 'id' => StringUtility::getUniqueId('select_checkbox_row_'),
123 'name' => $parameterArray['itemFormElName'] . '[' . $c . ']',
124 'value' => $theNoMatchValue,
125 'checked' => 1,
126 'disabled' => $disabled,
127 'class' => 'danger',
128 'icon' => '',
129 'title' => htmlspecialchars(@sprintf($noMatchingLabel, $theNoMatchValue), ENT_COMPAT, 'UTF-8', FALSE),
130 'help' => ''
131 );
132 $c++;
133 }
134 }
135 // Add an empty hidden field which will send a blank value if all items are unselected.
136 $html[] = '<input type="hidden" class="select-checkbox" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" value="">';
137
138 // Building the checkboxes
139 foreach ($groups as $groupKey => $group) {
140 $groupId = htmlspecialchars($parameterArray['itemFormElID']) . '-group-' . $groupKey;
141 $html[] = '<div class="panel panel-default">';
142 if (is_array($group['header'])) {
143 $html[] = '<div class="panel-heading">';
144 $html[] = '<a data-toggle="collapse" href="#' . $groupId . '" aria-expanded="true" aria-controls="' . $groupId . '">';
145 $html[] = $group['header']['icon'];
146 $html[] = $group['header']['title'];
147 $html[] = '</a>';
148 $html[] = '</div>';
149 }
150 if (is_array($group['items']) && !empty($group['items'])) {
151 $tableRows = [];
152 $checkGroup = array();
153 $uncheckGroup = array();
154 $resetGroup = array();
155
156 // Render rows
157 foreach ($group['items'] as $item) {
158 $tableRows[] = '<tr class="' . $item['class'] . '">';
159 $tableRows[] = '<td class="col-checkbox">';
160 $tableRows[] = '<input type="checkbox" '
161 . 'id="' . $item['id'] . '" '
162 . 'name="' . htmlspecialchars($item['name']) . '" '
163 . 'value="' . htmlspecialchars($item['value']) . '" '
164 . 'onclick="' . htmlspecialchars($sOnChange) . '" '
165 . ($item['checked'] ? 'checked=checked ' : '')
166 . ($item['disabled'] ? 'disabled=disabled ' : '')
167 . $parameterArray['onFocus'] . '>';
168 $tableRows[] = '</td>';
169 $tableRows[] = '<td class="col-icon">';
170 $tableRows[] = '<label class="label-block" for="' . $item['id'] . '">' . $item['icon'] . '</label>';
171 $tableRows[] = '</td>';
172 $tableRows[] = '<td class="col-title">';
173 $tableRows[] = '<label class="label-block" for="' . $item['id'] . '">' . $item['title'] . '</label>';
174 $tableRows[] = '</td>';
175 $tableRows[] = '<td>' . $item['help'] . '</td>';
176 $tableRows[] = '</tr>';
177 $checkGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked=1;';
178 $uncheckGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked=0;';
179 $resetGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked=' . $item['checked'] . ';';
180 }
181
182 // Build toggle group checkbox
183 $toggleGroupCheckbox = '';
184 if (!empty($resetGroup)) {
185 $toggleGroupCheckbox = '<input type="checkbox" '
186 . 'class="checkbox" '
187 . 'onclick="if (checked) {' . htmlspecialchars(implode('', $checkGroup) . '} else {' . implode('', $uncheckGroup)) . '}">';
188 }
189
190 // Build reset group button
191 $resetGroupBtn = '';
192 if (!empty($resetGroup)) {
193 $title = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.revertSelection', TRUE);
194 $resetGroupBtn = '<a href="#" '
195 . 'class="btn btn-default" '
196 . 'onclick="' . implode('', $resetGroup) . ' return false;" '
197 . 'title="' . $title . '">'
198 . $this->iconFactory->getIcon('actions-edit-undo', Icon::SIZE_SMALL)->render() . ' '
199 . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.revertSelection') . '</a>';
200 }
201
202 $html[] = '<div id="' . $groupId . '" class="panel-collapse collapse in" role="tabpanel">';
203 $html[] = '<div class="table-fit">';
204 $html[] = '<table class="table table-transparent table-hover">';
205 $html[] = '<thead>';
206 $html[] = '<tr>';
207 $html[] = '<th class="col-checkbox">' . $toggleGroupCheckbox . '</th>';
208 $html[] = '<th class="col-icon"></th>';
209 $html[] = '<th class="text-right" colspan="2">' . $resetGroupBtn . '</th>';
210 $html[] = '</tr>';
211 $html[] = '</thead>';
212 $html[] = '<tbody>' . implode(LF, $tableRows) . '</tbody>';
213 $html[] = '</table>';
214 $html[] = '</div>';
215 $html[] = '</div>';
216 }
217 $html[] = '</div>';
218 }
219 }
220
221 if (!$disabled) {
222 $html = $this->renderWizards(
223 array(implode(LF, $html)),
224 $config['wizards'],
225 $this->data['tableName'],
226 $this->data['databaseRow'],
227 $this->data['fieldName'],
228 $parameterArray,
229 $parameterArray['itemFormElName'],
230 BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras'])
231 );
232 }
233
234 $resultArray = $this->initializeResultArray();
235 $resultArray['html'] = $html;
236
237 return $resultArray;
238 }
239
240 }