[CLEANUP] Cleanup jumpToUrl() and unused JS in Backend
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / View / ModuleMenuView.php
1 <?php
2 namespace TYPO3\CMS\Backend\View;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2007-2013 Ingo Renner <ingo@typo3.org>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the text file GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29
30 use TYPO3\CMS\Backend\Utility\BackendUtility;
31 use TYPO3\CMS\Core\Utility\GeneralUtility;
32
33 /**
34 * class to render the TYPO3 backend menu for the modules
35 *
36 * @author Ingo Renner <ingo@typo3.org>
37 */
38 class ModuleMenuView {
39
40 /**
41 * Module loading object
42 *
43 * @var \TYPO3\CMS\Backend\Module\ModuleLoader
44 */
45 protected $moduleLoader;
46
47 protected $backPath;
48
49 protected $linkModules;
50
51 protected $loadedModules;
52
53 /**
54 * Constructor, initializes several variables
55 */
56 public function __construct() {
57 if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX) {
58 $GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_misc.xlf');
59 }
60 $this->backPath = '';
61 $this->linkModules = TRUE;
62 // Loads the backend modules available for the logged in user.
63 $this->moduleLoader = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Module\\ModuleLoader');
64 $this->moduleLoader->observeWorkspaces = TRUE;
65 $this->moduleLoader->load($GLOBALS['TBE_MODULES']);
66 $this->loadedModules = $this->moduleLoader->modules;
67 }
68
69 /**
70 * sets the path back to /typo3/
71 *
72 * @param string $backPath Path back to /typo3/
73 * @throws \InvalidArgumentException
74 * @return void
75 */
76 public function setBackPath($backPath) {
77 if (!is_string($backPath)) {
78 throw new \InvalidArgumentException('parameter $backPath must be of type string', 1193315266);
79 }
80 $this->backPath = $backPath;
81 }
82
83 /**
84 * loads the collapse states for the main modules from user's configuration (uc)
85 *
86 * @return array Collapse states
87 */
88 protected function getCollapsedStates() {
89 $collapsedStates = array();
90 if ($GLOBALS['BE_USER']->uc['moduleData']['moduleMenu']) {
91 $collapsedStates = $GLOBALS['BE_USER']->uc['moduleData']['moduleMenu'];
92 }
93 return $collapsedStates;
94 }
95
96 /**
97 * ModuleMenu Store loading data
98 *
99 * @param array $params
100 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj
101 * @return array
102 */
103 public function getModuleData($params, $ajaxObj) {
104 $data = array('success' => TRUE, 'root' => array());
105 $rawModuleData = $this->getRawModuleData();
106 $index = 0;
107 foreach ($rawModuleData as $moduleKey => $moduleData) {
108 $key = substr($moduleKey, 8);
109 $num = count($data['root']);
110 if ($moduleData['link'] != 'dummy.php' || $moduleData['link'] == 'dummy.php' && is_array($moduleData['subitems'])) {
111 $data['root'][$num]['key'] = $key;
112 $data['root'][$num]['menuState'] = $GLOBALS['BE_USER']->uc['moduleData']['menuState'][$moduleKey];
113 $data['root'][$num]['label'] = $moduleData['title'];
114 $data['root'][$num]['subitems'] = is_array($moduleData['subitems']) ? count($moduleData['subitems']) : 0;
115 if ($moduleData['link'] && $this->linkModules) {
116 $data['root'][$num]['link'] = 'top.goToModule(\'' . $moduleData['name'] . '\')';
117 }
118 // Traverse submodules
119 if (is_array($moduleData['subitems'])) {
120 foreach ($moduleData['subitems'] as $subKey => $subData) {
121 $data['root'][$num]['sub'][] = array(
122 'name' => $subData['name'],
123 'description' => $subData['description'],
124 'label' => $subData['title'],
125 'icon' => $subData['icon']['filename'],
126 'navframe' => $subData['parentNavigationFrameScript'],
127 'link' => $subData['link'],
128 'originalLink' => $subData['originalLink'],
129 'index' => $index++,
130 'navigationFrameScript' => $subData['navigationFrameScript'],
131 'navigationFrameScriptParam' => $subData['navigationFrameScriptParam'],
132 'navigationComponentId' => $subData['navigationComponentId']
133 );
134 }
135 }
136 }
137 }
138 if ($ajaxObj) {
139 $ajaxObj->setContent($data);
140 $ajaxObj->setContentFormat('jsonbody');
141 } else {
142 return $data;
143 }
144 }
145
146 /**
147 * Returns the loaded modules
148 *
149 * @return array Array of loaded modules
150 */
151 public function getLoadedModules() {
152 return $this->loadedModules;
153 }
154
155 /**
156 * saves the menu's toggle state in the backend user's uc
157 *
158 * @param array $params Array of parameters from the AJAX interface, currently unused
159 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
160 * @return void
161 */
162 public function saveMenuState($params, $ajaxObj) {
163 $menuItem = GeneralUtility::_POST('menuid');
164 $state = GeneralUtility::_POST('state') === 'true' ? 1 : 0;
165 $GLOBALS['BE_USER']->uc['moduleData']['menuState'][$menuItem] = $state;
166 $GLOBALS['BE_USER']->writeUC();
167 }
168
169 /**
170 * Reads User configuration from options.hideModules and removes
171 * modules from $this->loadedModules accordingly.
172 *
173 * @return void
174 */
175 protected function unsetHiddenModules() {
176 // Hide modules if set in userTS.
177 $hiddenModules = $GLOBALS['BE_USER']->getTSConfig('options.hideModules');
178 if (!empty($hiddenModules['value'])) {
179 $hiddenMainModules = GeneralUtility::trimExplode(',', $hiddenModules['value'], TRUE);
180 foreach ($hiddenMainModules as $hiddenMainModule) {
181 unset($this->loadedModules[$hiddenMainModule]);
182 }
183 }
184
185 // Hide sub-modules if set in userTS.
186 if (!empty($hiddenModules['properties']) && is_array($hiddenModules['properties'])) {
187 foreach ($hiddenModules['properties'] as $mainModuleName => $subModules) {
188 $hiddenSubModules = GeneralUtility::trimExplode(',', $subModules, TRUE);
189 foreach ($hiddenSubModules as $hiddenSubModule) {
190 unset($this->loadedModules[$mainModuleName]['sub'][$hiddenSubModule]);
191 }
192 }
193 }
194 }
195
196 /**
197 * gets the raw module data
198 *
199 * @return array Multi dimension array with module data
200 */
201 public function getRawModuleData() {
202 $modules = array();
203
204 // Unset modules that are meant to be hidden from the menu.
205 $this->unsetHiddenModules();
206
207 foreach ($this->loadedModules as $moduleName => $moduleData) {
208 $moduleLink = '';
209 if (!is_array($moduleData['sub'])) {
210 $moduleLink = $moduleData['script'];
211 }
212 $moduleLink = GeneralUtility::resolveBackPath($moduleLink);
213 $moduleKey = 'modmenu_' . $moduleName;
214 $moduleIcon = $this->getModuleIcon($moduleKey);
215 $modules[$moduleKey] = array(
216 'name' => $moduleName,
217 'title' => $GLOBALS['LANG']->moduleLabels['tabs'][$moduleName . '_tab'],
218 'onclick' => 'top.goToModule(\'' . $moduleName . '\');',
219 'icon' => $moduleIcon,
220 'link' => $moduleLink,
221 'description' => $GLOBALS['LANG']->moduleLabels['labels'][$moduleKey . 'label']
222 );
223 if (!is_array($moduleData['sub']) && $moduleData['script'] != 'dummy.php') {
224 // Work around for modules with own main entry, but being self the only submodule
225 $modules[$moduleKey]['subitems'][$moduleKey] = array(
226 'name' => $moduleName,
227 'title' => $GLOBALS['LANG']->moduleLabels['tabs'][$moduleName . '_tab'],
228 'onclick' => 'top.goToModule(\'' . $moduleName . '\');',
229 'icon' => $this->getModuleIcon($moduleName . '_tab'),
230 'link' => $moduleLink,
231 'originalLink' => $moduleLink,
232 'description' => $GLOBALS['LANG']->moduleLabels['labels'][$moduleKey . 'label'],
233 'navigationFrameScript' => NULL,
234 'navigationFrameScriptParam' => NULL,
235 'navigationComponentId' => NULL
236 );
237 } elseif (is_array($moduleData['sub'])) {
238 foreach ($moduleData['sub'] as $submoduleName => $submoduleData) {
239 if (isset($submoduleData['script'])) {
240 $submoduleLink = GeneralUtility::resolveBackPath($submoduleData['script']);
241 } else {
242 $submoduleLink = BackendUtility::getModuleUrl($submoduleData['name']);
243 }
244 $submoduleKey = $moduleName . '_' . $submoduleName . '_tab';
245 $submoduleIcon = $this->getModuleIcon($submoduleKey);
246 $submoduleDescription = $GLOBALS['LANG']->moduleLabels['labels'][$submoduleKey . 'label'];
247 $originalLink = $submoduleLink;
248 $modules[$moduleKey]['subitems'][$submoduleKey] = array(
249 'name' => $moduleName . '_' . $submoduleName,
250 'title' => $GLOBALS['LANG']->moduleLabels['tabs'][$submoduleKey],
251 'onclick' => 'top.goToModule(\'' . $moduleName . '_' . $submoduleName . '\');',
252 'icon' => $submoduleIcon,
253 'link' => $submoduleLink,
254 'originalLink' => $originalLink,
255 'description' => $submoduleDescription,
256 'navigationFrameScript' => $submoduleData['navFrameScript'],
257 'navigationFrameScriptParam' => $submoduleData['navFrameScriptParam'],
258 'navigationComponentId' => $submoduleData['navigationComponentId']
259 );
260 // if the main module has a navframe script, inherit to the submodule,
261 // but only if it is not disabled explicitly (option is set to FALSE)
262 if ($moduleData['navFrameScript'] && $submoduleData['inheritNavigationComponentFromMainModule'] !== FALSE) {
263 $modules[$moduleKey]['subitems'][$submoduleKey]['parentNavigationFrameScript'] = $moduleData['navFrameScript'];
264 }
265 }
266 }
267 }
268 return $modules;
269 }
270
271 /**
272 * gets the module icon and its size
273 *
274 * @param string $moduleKey Module key
275 * @return array Icon data array with 'filename', 'size', and 'html'
276 */
277 protected function getModuleIcon($moduleKey) {
278 $icon = array(
279 'filename' => '',
280 'size' => '',
281 'title' => '',
282 'html' => ''
283 );
284 $iconFileRelative = $this->getModuleIconRelative($GLOBALS['LANG']->moduleLabels['tabs_images'][$moduleKey]);
285 $iconFileAbsolute = $this->getModuleIconAbsolute($GLOBALS['LANG']->moduleLabels['tabs_images'][$moduleKey]);
286 $iconSizes = @getimagesize($iconFileAbsolute);
287 $iconTitle = $GLOBALS['LANG']->moduleLabels['tabs'][$moduleKey];
288 if (!empty($iconFileRelative)) {
289 $icon['filename'] = $iconFileRelative;
290 $icon['size'] = $iconSizes[3];
291 $icon['title'] = htmlspecialchars($iconTitle);
292 $icon['html'] = '<img src="' . $iconFileRelative . '" ' . $iconSizes[3] . ' title="' . htmlspecialchars($iconTitle) . '" alt="' . htmlspecialchars($iconTitle) . '" />';
293 }
294 return $icon;
295 }
296
297 /**
298 * Returns the filename readable for the script from PATH_typo3.
299 * That means absolute names are just returned while relative names are
300 * prepended with the path pointing back to typo3/ dir
301 *
302 * @param string $iconFilename Icon filename
303 * @return string Icon filename with absolute path
304 * @see getModuleIconRelative()
305 */
306 protected function getModuleIconAbsolute($iconFilename) {
307 if (!GeneralUtility::isAbsPath($iconFilename)) {
308 $iconFilename = $this->backPath . $iconFilename;
309 }
310 return $iconFilename;
311 }
312
313 /**
314 * Returns relative path to the icon filename for use in img-tags
315 *
316 * @param string $iconFilename Icon filename
317 * @return string Icon filename with relative path
318 * @see getModuleIconAbsolute()
319 */
320 protected function getModuleIconRelative($iconFilename) {
321 if (GeneralUtility::isAbsPath($iconFilename)) {
322 $iconFilename = '../' . \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix($iconFilename);
323 }
324 return $this->backPath . $iconFilename;
325 }
326
327 /**
328 * Appends a '?' if there is none in the string already
329 *
330 * @param string $link Link URL
331 * @return string Link URl appended with ? if there wasn't one
332 */
333 protected function appendQuestionmarkToLink($link) {
334 if (!strstr($link, '?')) {
335 $link .= '?';
336 }
337 return $link;
338 }
339
340 /**
341 * renders the logout button form
342 *
343 * @return string Html code snippet displaying the logout button
344 */
345 public function renderLogoutButton() {
346 $buttonLabel = $GLOBALS['BE_USER']->user['ses_backuserid'] ? 'LLL:EXT:lang/locallang_core.xlf:buttons.exit' : 'LLL:EXT:lang/locallang_core.xlf:buttons.logout';
347 $buttonForm = '
348 <form action="logout.php" target="_top">
349 <input type="submit" id="logout-submit-button" value="' . $GLOBALS['LANG']->sL($buttonLabel, TRUE) . '" />
350 </form>';
351 return $buttonForm;
352 }
353
354 /**
355 * turns linking of modules on or off
356 *
357 * @param boolean $linkModules Status for linking modules with a-tags, set to FALSE to turn lining off
358 * @throws \InvalidArgumentException
359 * @return void
360 */
361 public function setLinkModules($linkModules) {
362 if (!is_bool($linkModules)) {
363 throw new \InvalidArgumentException('parameter $linkModules must be of type bool', 1193326558);
364 }
365 $this->linkModules = $linkModules;
366 }
367
368 }