[TASK] Refactor formengine required handling
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Element / SelectTreeElement.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\GeneralUtility;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Core\Utility\MathUtility;
20 use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
21 use TYPO3\CMS\Lang\LanguageService;
22 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
23 use TYPO3\CMS\Core\Tree\TableConfiguration\ExtJsArrayTreeRenderer;
24 use TYPO3\CMS\Core\Tree\TableConfiguration\TableConfigurationTree;
25 use TYPO3\CMS\Core\Tree\TableConfiguration\TreeDataProviderFactory;
26 use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
27 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
28 use TYPO3\CMS\Backend\Utility\IconUtility;
29
30 /**
31 * Render data as a tree.
32 *
33 * Typically rendered for config [type=select, renderMode=tree
34 */
35 class SelectTreeElement extends AbstractFormElement {
36
37 /**
38 * Render tree widget
39 *
40 * @return array As defined in initializeResultArray() of AbstractNode
41 */
42 public function render() {
43 $table = $this->globalOptions['table'];
44 $field = $this->globalOptions['fieldName'];
45 $row = $this->globalOptions['databaseRow'];
46 $parameterArray = $this->globalOptions['parameterArray'];
47
48 // Field configuration from TCA:
49 $config = $parameterArray['fieldConf']['config'];
50 $disabled = '';
51 if ($this->isGlobalReadonly() || $config['readOnly']) {
52 $disabled = ' disabled="disabled"';
53 }
54
55 $resultArray = $this->initializeResultArray();
56
57 // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
58 $specConf = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
59 $selItems = FormEngineUtility::getSelectItems($table, $field, $row, $parameterArray);
60
61 $html = $this->renderField($table, $field, $row, $parameterArray, $config, $selItems);
62
63 // Wizards:
64 if (!$disabled) {
65 $altItem = '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" />';
66 $html = $this->renderWizards(array($html, $altItem), $config['wizards'], $table, $row, $field, $parameterArray, $parameterArray['itemFormElName'], $specConf);
67 }
68 $resultArray['html'] = $html;
69 return $resultArray;
70 }
71
72 /**
73 * Renders the tree
74 *
75 * @param string $table The table name of the record
76 * @param string $field The field name which this element is supposed to edit
77 * @param array $row The record data array where the value(s) for the field can be found
78 * @param array $PA An array with additional configuration options.
79 * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience)
80 * @param array $possibleSelectboxItems Items available for selection
81 * @return string The HTML code for the TCEform field
82 */
83 protected function renderField($table, $field, $row, &$PA, $config, $possibleSelectboxItems) {
84 $backendUserAuthentication = $this->getBackendUserAuthentication();
85 $valueArray = array();
86 $selectedNodes = array();
87 if (!empty($PA['itemFormElValue'])) {
88 $valueArray = explode(',', $PA['itemFormElValue']);
89 }
90 if (count($valueArray)) {
91 foreach ($valueArray as $selectedValue) {
92 $temp = explode('|', $selectedValue);
93 $selectedNodes[] = $temp[0];
94 }
95 }
96 $allowedUids = array();
97 foreach ($possibleSelectboxItems as $item) {
98 if ((int)$item[1] > 0) {
99 $allowedUids[] = $item[1];
100 }
101 }
102 $treeDataProvider = TreeDataProviderFactory::getDataProvider($config, $table, $field, $row);
103 $treeDataProvider->setSelectedList(implode(',', $selectedNodes));
104 $treeDataProvider->setItemWhiteList($allowedUids);
105 $treeDataProvider->initializeTreeData();
106 $treeRenderer = GeneralUtility::makeInstance(ExtJsArrayTreeRenderer::class);
107 $tree = GeneralUtility::makeInstance(TableConfigurationTree::class);
108 $tree->setDataProvider($treeDataProvider);
109 $tree->setNodeRenderer($treeRenderer);
110 $treeData = $tree->render();
111 $itemArray = array();
112 if (is_array($PA['fieldConf']['config']['items'])) {
113 foreach ($PA['fieldConf']['config']['items'] as $additionalItem) {
114 if ($additionalItem[1] !== '--div--') {
115 $item = new \stdClass();
116 $item->uid = $additionalItem[1];
117 $item->text = $this->getLanguageService()->sL($additionalItem[0]);
118 $item->selectable = TRUE;
119 $item->leaf = TRUE;
120 $item->checked = in_array($additionalItem[1], $selectedNodes);
121 if (file_exists(PATH_typo3 . $additionalItem[3])) {
122 $item->icon = $additionalItem[3];
123 } elseif (trim($additionalItem[3]) !== '') {
124 $item->iconCls = IconUtility::getSpriteIconClasses($additionalItem[3]);
125 }
126 $itemArray[] = $item;
127 }
128 }
129 }
130 $itemArray[] = $treeData;
131 $treeData = json_encode($itemArray);
132 $id = md5($PA['itemFormElName']);
133 if (isset($PA['fieldConf']['config']['size']) && (int)$PA['fieldConf']['config']['size'] > 0) {
134 $height = (int)$PA['fieldConf']['config']['size'] * 20;
135 } else {
136 $height = 280;
137 }
138 $autoSizeMax = NULL;
139 if (isset($PA['fieldConf']['config']['autoSizeMax']) && (int)$PA['fieldConf']['config']['autoSizeMax'] > 0) {
140 $autoSizeMax = (int)$PA['fieldConf']['config']['autoSizeMax'] * 20;
141 }
142 $header = FALSE;
143 $expanded = FALSE;
144 $width = 280;
145 $appearance = $PA['fieldConf']['config']['treeConfig']['appearance'];
146 if (is_array($appearance)) {
147 $header = $appearance['showHeader'] ? TRUE : FALSE;
148 $expanded = $appearance['expandAll'] === TRUE;
149 if (isset($appearance['width'])) {
150 $width = (int)$appearance['width'];
151 }
152 }
153 $onChange = '';
154 if ($PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged']) {
155 $onChange = $PA['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
156 }
157 // Create a JavaScript code line which will ask the user to save/update the form due to changing the element.
158 // This is used for eg. "type" fields and others configured with "requestUpdate"
159 if (
160 !empty($GLOBALS['TCA'][$table]['ctrl']['type'])
161 && $field === $GLOBALS['TCA'][$table]['ctrl']['type']
162 || !empty($GLOBALS['TCA'][$table]['ctrl']['requestUpdate'])
163 && GeneralUtility::inList(str_replace(' ', '', $GLOBALS['TCA'][$table]['ctrl']['requestUpdate']), $field)
164 ) {
165 if ($backendUserAuthentication->jsConfirmation(JsConfirmation::TYPE_CHANGE)) {
166 $onChange .= 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && ' . 'TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
167 } else {
168 $onChange .= 'if (TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };';
169 }
170 }
171 /** @var $pageRenderer \TYPO3\CMS\Core\Page\PageRenderer */
172 $pageRenderer = $GLOBALS['SOBE']->doc->getPageRenderer();
173 $pageRenderer->loadExtJs();
174 $pageRenderer->addJsFile('sysext/backend/Resources/Public/JavaScript/tree.js');
175 $pageRenderer->addInlineLanguageLabelFile(ExtensionManagementUtility::extPath('lang') . 'locallang_csh_corebe.xlf', 'tcatree');
176 $pageRenderer->addExtOnReadyCode('
177 TYPO3.Components.Tree.StandardTreeItemData["' . $id . '"] = ' . $treeData . ';
178 var tree' . $id . ' = new TYPO3.Components.Tree.StandardTree({
179 id: "' . $id . '",
180 showHeader: ' . (int)$header . ',
181 onChange: "' . $onChange . '",
182 countSelectedNodes: ' . count($selectedNodes) . ',
183 width: ' . $width . ',
184 listeners: {
185 click: function(node, event) {
186 if (typeof(node.attributes.checked) == "boolean") {
187 node.attributes.checked = ! node.attributes.checked;
188 node.getUI().toggleCheck(node.attributes.checked);
189 }
190 },
191 dblclick: function(node, event) {
192 if (typeof(node.attributes.checked) == "boolean") {
193 node.attributes.checked = ! node.attributes.checked;
194 node.getUI().toggleCheck(node.attributes.checked);
195 }
196 },
197 checkchange: TYPO3.Components.Tree.TcaCheckChangeHandler,
198 collapsenode: function(node) {
199 if (node.id !== "root") {
200 top.TYPO3.Storage.Persistent.removeFromList("tcaTrees." + this.ucId, node.attributes.uid);
201 }
202 },
203 expandnode: function(node) {
204 if (node.id !== "root") {
205 top.TYPO3.Storage.Persistent.addToList("tcaTrees." + this.ucId, node.attributes.uid);
206 }
207 },
208 beforerender: function(treeCmp) {
209 // Check if that tree element is already rendered. It is appended on the first tceforms_inline call.
210 if (Ext.fly(treeCmp.getId())) {
211 return false;
212 }
213 }' . ($expanded ? ',
214 afterrender: function(treeCmp) {
215 treeCmp.expandAll();
216 }' : '') . '
217 },
218 tcaMaxItems: ' . ($PA['fieldConf']['config']['maxitems'] ? (int)$PA['fieldConf']['config']['maxitems'] : 99999) . ',
219 tcaSelectRecursiveAllowed: ' . ($appearance['allowRecursiveMode'] ? 'true' : 'false') . ',
220 tcaSelectRecursive: false,
221 tcaExclusiveKeys: "' . ($PA['fieldConf']['config']['exclusiveKeys'] ? $PA['fieldConf']['config']['exclusiveKeys'] : '') . '",
222 ucId: "' . md5(($table . '|' . $field)) . '",
223 selModel: TYPO3.Components.Tree.EmptySelectionModel,
224 disabled: ' . ($PA['fieldConf']['config']['readOnly'] || $this->isGlobalReadonly() ? 'true' : 'false') . '
225 });' . LF .
226 ($autoSizeMax
227 ? 'tree' . $id . '.bodyStyle = "max-height: ' . $autoSizeMax . 'px;min-height: ' . $height . 'px;";'
228 : 'tree' . $id . '.height = ' . $height . ';'
229 ) . LF .
230 '(function() {
231 tree' . $id . '.render("tree_' . $id . '");
232 }).defer(20);
233 ');
234 $formField = '
235 <div class="typo3-tceforms-tree">
236 <input class="treeRecord" type="hidden" name="' . htmlspecialchars($PA['itemFormElName']) . '" id="treeinput' . $id . '" value="' . htmlspecialchars($PA['itemFormElValue']) . '" />
237 </div>
238 <div id="tree_' . $id . '">
239
240 </div>';
241 return $formField;
242 }
243
244 /**
245 * @return LanguageService
246 */
247 protected function getLanguageService() {
248 return $GLOBALS['LANG'];
249 }
250
251 /**
252 * @return BackendUserAuthentication
253 */
254 protected function getBackendUserAuthentication() {
255 return $GLOBALS['BE_USER'];
256 }
257
258 }