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