7a938de27e5cbe02915a88174acad32065823e41
2 /***************************************************************
5 * (c) 2007 Ingo Renner <ingo@typo3.org>
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
30 * class to render the TYPO3 backend menu for the modules
32 * @author Ingo Renner <ingo@typo3.org>
39 * module loading object
41 * @var t3lib_loadModules
43 protected $moduleLoader;
47 private $loadedModules;
48 private $fsMod; //TODO find a more descriptive name, left over from alt_menu_functions
51 * constructor, initializes several variables
55 public function __construct() {
58 $this->fsMod
= array();
59 $this->linkModules
= true;
61 // Loads the backend modules available for the logged in user.
62 $this->moduleLoader
= t3lib_div
::makeInstance('t3lib_loadModules');
63 $this->moduleLoader
->observeWorkspaces
= true;
64 $this->moduleLoader
->load($GLOBALS['TBE_MODULES']);
65 $this->loadedModules
= $this->moduleLoader
->modules
;
70 * sets the path back to /typo3/
72 * @param string path back to /typo3/
75 public function setBackPath($backPath) {
76 if(!is_string($backPath)) {
77 throw new InvalidArgumentException('parameter $backPath must be of type string', 1193315266);
80 $this->backPath
= $backPath;
84 * loads the collapse states for the main modules from user's configuration (uc)
86 * @return array collapse states
88 private function getCollapsedStates() {
90 $collapsedStates = array();
91 if($GLOBALS['BE_USER']->uc
['moduleData']['moduleMenu']) {
92 $collapsedStates = $GLOBALS['BE_USER']->uc
['moduleData']['moduleMenu'];
95 return $collapsedStates;
99 * returns the loaded modules
101 * @return array array of loaded modules
103 public function getLoadedModules() {
104 return $this->loadedModules
;
108 * renders the backend menu as unordered list
110 * @return string menu html code to use in the backend
112 public function render() {
114 $onBlur = $GLOBALS['CLIENT']['FORMSTYLE'] ?
'this.blur();' : '';
116 $rawModuleData = $this->getRawModuleData();
118 foreach($rawModuleData as $moduleKey => $moduleData) {
120 $moduleLabel = $moduleData['title'];
121 if($moduleData['link'] && $this->linkModules
) {
122 $moduleLabel = '<a href="#" onclick="top.goToModule(\''.$moduleData['name'].'\');'.$onBlur.'return false;">'.$moduleLabel.'</a>';
125 $menu .= '<li><div>'.$moduleData['icon']['html'].' '.$moduleLabel.'</div>';
127 // traverse submodules
128 if(is_array($moduleData['subitems'])) {
129 $menu .= $this->renderSubModules($moduleData['subitems']);
132 $menu .= '</li>'."\n";
135 return '<ul id="typo3-menu">'."\n".$menu.'</ul>'."\n";
141 * @param array array of (sub)module data
142 * @return string (sub)module html code
144 public function renderSubModules($modules) {
146 $onBlur = $GLOBALS['CLIENT']['FORMSTYLE'] ?
'this.blur();' : '';
148 foreach($modules as $moduleKey => $moduleData) {
149 // Setting additional JavaScript
150 $additionalJavascript = '';
151 if($moduleData['parentNavigationFrameScript']) {
152 $parentModuleName = substr($moduleData['name'], 0, strpos($moduleData['name'], '_'));
153 $additionalJavascript = "+'&id='+top.rawurlencode(top.fsMod.recentIds['".$parentModuleName."'])";
156 if($moduleData['link'] && $this->linkModules
) {
158 $onClickString = htmlspecialchars('top.goToModule(\''.$moduleData['name'].'\');'.$onBlur.'return false;');
159 $submoduleLink = '<a href="#" onclick="'.$onClickString.'" title="'.$moduleData['description'].'">'
160 .$moduleData['icon']['html'].' '
161 .'<span>'.htmlspecialchars($moduleData['title']).'</span>'
165 $moduleMenu .= '<li>'.$submoduleLink.'</li>'."\n";
168 return '<ul>'."\n".$moduleMenu.'</ul>'."\n";
172 * gets the raw module data
174 * @return array multi dimension array with module data
176 public function getRawModuleData() {
179 // Remove the 'doc' module?
180 if($GLOBALS['BE_USER']->getTSConfigVal('options.disableDocModuleInAB')) {
181 unset($this->loadedModules
['doc']);
184 foreach($this->loadedModules
as $moduleName => $moduleData) {
185 $moduleNavigationFramePrefix = $this->getNavigationFramePrefix($moduleData);
187 if($moduleNavigationFramePrefix) {
188 $this->fsMod
[$moduleName] = 'fsMod.recentIds["'.$moduleName.'"]="";';
192 if(!is_array($moduleData['sub'])) {
193 $moduleLink = $moduleData['script'];
195 $moduleLink = t3lib_div
::resolveBackPath($moduleLink);
197 $moduleKey = $moduleName.'_tab';
198 $moduleCssId = 'ID_'.t3lib_div
::md5int($moduleName);
199 $moduleIcon = $this->getModuleIcon($moduleKey);
201 if($moduleLink && $moduleNavigationFramePrefix) {
202 $moduleLink = $moduleNavigationFramePrefix.rawurlencode($moduleLink);
205 $modules[$moduleKey] = array(
206 'name' => $moduleName,
207 'title' => $GLOBALS['LANG']->moduleLabels
['tabs'][$moduleKey],
208 'onclick' => 'top.goToModule(\''.$moduleName.'\');',
209 'cssId' => $moduleCssId,
210 'icon' => $moduleIcon,
211 'link' => $moduleLink,
212 'prefix' => $moduleNavigationFramePrefix
215 if(is_array($moduleData['sub'])) {
217 foreach($moduleData['sub'] as $submoduleName => $submoduleData) {
218 $submoduleLink = t3lib_div
::resolveBackPath($submoduleData['script']);
219 $submoduleNavigationFramePrefix = $this->getNavigationFramePrefix($moduleData, $submoduleData);
221 $submoduleKey = $moduleName.'_'.$submoduleName.'_tab';
222 $submoduleCssId = 'ID_'.t3lib_div
::md5int($moduleName.'_'.$submoduleName);
223 $submoduleIcon = $this->getModuleIcon($submoduleKey);
224 $submoduleDescription = $GLOBALS['LANG']->moduleLabels
['labels'][$submoduleKey.'label'];
226 $originalLink = $submoduleLink;
227 if($submoduleLink && $submoduleNavigationFramePrefix) {
228 $submoduleLink = $submoduleNavigationFramePrefix.rawurlencode($submoduleLink);
231 $modules[$moduleKey]['subitems'][$submoduleKey] = array(
232 'name' => $moduleName.'_'.$submoduleName,
233 'title' => $GLOBALS['LANG']->moduleLabels
['tabs'][$submoduleKey],
234 'onclick' => 'top.goToModule(\''.$moduleName.'_'.$submoduleName.'\');',
235 'cssId' => $submoduleCssId,
236 'icon' => $submoduleIcon,
237 'link' => $submoduleLink,
238 'originalLink' => $originalLink,
239 'prefix' => $submoduleNavigationFramePrefix,
240 'description' => $submoduleDescription
243 if($moduleData['navFrameScript']) {
244 $modules[$moduleKey]['subitems'][$submoduleKey]['parentNavigationFrameScript'] = $moduleData['navFrameScript'];
254 * gets the module icon and its size
256 * @param string module key
257 * @return array icon data array with 'filename', 'size', and 'html'
259 private function getModuleIcon($moduleKey) {
261 $iconFileRelative = $this->getModuleIconRelative($GLOBALS['LANG']->moduleLabels
['tabs_images'][$moduleKey]);
262 $iconFileAbsolute = $this->getModuleIconAbsolute($GLOBALS['LANG']->moduleLabels
['tabs_images'][$moduleKey]);
263 $iconSizes = @getimagesize
($iconFileAbsolute);
264 $iconTitle = $GLOBALS['LANG']->moduleLabels
['tabs'][$moduleKey];
266 $icon['filename'] = $iconFileRelative;
267 $icon['size'] = $iconSizes[3];
268 $icon['title'] = htmlspecialchars($iconTitle);
269 $icon['html'] = '<img src="'.$iconFileRelative.'" '.$iconSizes[3].' title="'.htmlspecialchars($iconTitle).'" alt="'.htmlspecialchars($iconTitle).'" />';
275 * Returns the filename readable for the script from PATH_typo3.
276 * That means absolute names are just returned while relative names are
277 * prepended with the path pointing back to typo3/ dir
279 * @param string icon filename
280 * @return string icon filename with absolute path
281 * @see getModuleIconRelative()
283 private function getModuleIconAbsolute($iconFilename) {
285 if(!t3lib_div
::isAbsPath($iconFilename)) {
286 $iconFilename = $this->backPath
.$iconFilename;
289 return $iconFilename;
293 * Returns relative path to the icon filename for use in img-tags
295 * @param string icon filename
296 * @return string icon filename with relative path
297 * @see getModuleIconAbsolute()
299 private function getModuleIconRelative($iconFilename) {
300 if(t3lib_div
::isAbsPath($iconFilename)) {
301 $iconFilename = '../'.substr($iconFilename, strlen(PATH_site
));
304 return $this->backPath
.$iconFilename;
308 * Returns a prefix used to call the navigation frame with parameters which then will call the scripts defined in the modules info array.
310 * @param array module data array
311 * @param array submodule data array
312 * @return string result URL string
314 private function getNavigationFramePrefix($moduleData, $subModuleData = array()) {
317 $navigationFrameScript = $moduleData['navFrameScript'];
318 if($subModuleData['navFrameScript']) {
319 $navigationFrameScript = $subModuleData['navFrameScript'];
322 $navigationFrameParameter = $moduleData['navFrameScriptParam'];
323 if($subModuleData['navFrameScriptParam']) {
324 $navigationFrameParameter = $subModuleData['navFrameScriptParam'];
327 if($navigationFrameScript) {
328 $navigationFrameScript = t3lib_div
::resolveBackPath($navigationFrameScript);
329 $navigationFrameScript = $this->appendQuestionmarkToLink($navigationFrameScript);
331 if($GLOBALS['BE_USER']->uc
['condensedMode']) {
332 $prefix = $navigationFrameScript.$navigationFrameParameter.'¤tSubScript=';
334 $prefix = 'alt_mod_frameset.php?'
335 .'fW="+top.TS.navFrameWidth+"'
336 .'&nav="+top.TS.PATH_typo3+"'
337 .rawurlencode($navigationFrameScript.$navigationFrameParameter)
346 * generates javascript code to switch between modules
348 * @return string javascript code snippet to switch modules
350 public function getGotoModuleJavascript() {
352 $moduleJavascriptCommands = array();
353 $rawModuleData = $this->getRawModuleData();
355 foreach($rawModuleData as $mainModuleKey => $mainModuleData) {
356 if($mainModuleData['subitems']) {
357 foreach($mainModuleData['subitems'] as $subModuleKey => $subModuleData) {
359 $parentModuleName = substr($subModuleData['name'], 0, strpos($subModuleData['name'], '_'));
360 $javascriptCommand = '';
362 // Setting additional JavaScript if frameset script:
363 $additionalJavascript = '';
364 if($subModuleData['parentNavigationFrameScript']) {
365 $additionalJavascript = "+'&id='+top.rawurlencode(top.fsMod.recentIds['".$parentModuleName."'])";
368 if($subModuleData['link'] && $this->linkModules
) {
369 // For condensed mode, send &cMR parameter to frameset script.
370 if($additionalJavascript && $GLOBALS['BE_USER']->uc
['condensedMode']) {
371 $additionalJavascript .= "+(cMR?'&cMR=1':'')";
374 $javascriptCommand = '
375 top.content.location=top.getModuleUrl(top.TS.PATH_typo3+"'.$this->appendQuestionmarkToLink($subModuleData['link']).'"'.$additionalJavascript.'+additionalGetVariables);
376 top.fsMod.currentMainLoaded="'.$parentModuleName.'";
379 if($subModuleData['navFrameScript']) {
380 $javascriptCommand .= '
381 top.currentSubScript="'.$subModuleData['originalLink'].'";';
384 if(!$GLOBALS['BE_USER']->uc
['condensedMode'] && $subModuleData['parentNavigationFrameScript']) {
385 $additionalJavascript = "+'&id='+top.rawurlencode(top.fsMod.recentIds['".$parentModuleName."'])";
387 $submoduleNavigationFrameScript = $subModuleData['navigationFrameScript'] ?
$subModuleData['navigationFrameScript'] : $subModuleData['parentNavigationFrameScript'];
388 $submoduleNavigationFrameScript = t3lib_div
::resolveBackPath($submoduleNavigationFrameScript);
390 // add GET parameters for sub module to the navigation script
391 $submoduleNavigationFrameScript = $this->appendQuestionmarkToLink($submoduleNavigationFrameScript).$subModuleData['navigationFrameScript'];
393 $javascriptCommand = '
394 if (top.content.list_frame && top.fsMod.currentMainLoaded=="'.$parentModuleName.'") {
395 top.currentSubScript="'.$subModuleData['originalLink'].'";
396 top.content.list_frame.location=top.getModuleUrl(top.TS.PATH_typo3+"'.$this->appendQuestionmarkToLink($subModuleData['originalLink']).'"'.$additionalJavascript.'+additionalGetVariables);
397 if(top.currentSubNavScript!="'.$submoduleNavigationFrameScript.'") {
398 top.currentSubNavScript="'.$submoduleNavigationFrameScript.'";
399 top.content.nav_frame.location=top.getModuleUrl(top.TS.PATH_typo3+"'.$submoduleNavigationFrameScript.'");
402 top.content.location=top.TS.PATH_typo3+(
403 top.nextLoadModuleUrl?
404 "'.($subModuleData['prefix'] ?
$this->appendQuestionmarkToLink($subModuleData['link']).'&exScript=' : '').'listframe_loader.php":
405 "'.$this->appendQuestionmarkToLink($subModuleData['link']).'"'.$additionalJavascript.'+additionalGetVariables
407 top.fsMod.currentMainLoaded="'.$parentModuleName.'";
408 top.currentSubScript="'.$subModuleData['originalLink'].'";
413 $javascriptCommand .= '
414 top.highlightModuleMenuItem("'.$subModuleData['cssId'].'");
416 $moduleJavascriptCommands[] = "case '".$subModuleData['name']."': \n ".$javascriptCommand." \n break;";
419 } elseif(!$mainModuleData['subitems'] && !empty($mainModuleData['link'])) {
420 // main module has no sub modules but instead is linked itself (doc module)
421 $javascriptCommand = '
422 top.content.location=top.getModuleUrl(top.TS.PATH_typo3+"'.$this->appendQuestionmarkToLink($mainModuleData['link']).'"+additionalGetVariables);
423 top.highlightModuleMenuItem("'.$mainModuleData['cssId'].'", 1);
425 $moduleJavascriptCommands[] = "case '".$mainModuleData['name']."': \n ".$javascriptCommand." \n break;";
431 * Function used to switch switch module.
433 var currentModuleLoaded = "";
434 function goToModule(modName,cMR_flag,addGetVars) { //
435 var additionalGetVariables = "";
436 if (addGetVars) additionalGetVariables = addGetVars;
439 if (cMR_flag) cMR = 1;
441 currentModuleLoaded = modName;
444 ."\n".implode("\n", $moduleJavascriptCommands)."\n".'
448 return $javascriptCode;
452 * Appends a '?' if there is none in the string already
454 * @param string Link URL
455 * @return string link URl appended with ? if there wasn't one
457 private function appendQuestionmarkToLink($link) {
458 if(!strstr($link, '?')) {
466 * renders the logout button form
468 * @return string html code snippet displaying the logout button
470 public function renderLogoutButton() {
471 $buttonLabel = $GLOBALS['BE_USER']->user
['ses_backuserid'] ?
'LLL:EXT:lang/locallang_core.php:buttons.exit' : 'LLL:EXT:lang/locallang_core.php:buttons.logout';
474 <form action="logout.php" target="_top">
475 <input type="submit" value="'.$GLOBALS['LANG']->sL($buttonLabel, 1).'" />
482 * turns linking of modules on or off
484 * @param boolean status for linking modules with a-tags, set to false to turn lining off
486 public function setLinkModules($linkModules) {
487 if(!is_bool($linkModules)) {
488 throw new InvalidArgumentException('parameter $linkModules must be of type bool', 1193326558);
491 $this->linkModules
= $linkModules;
495 * gets the frameset (leftover) helper
497 * @return array array of javascript snippets
499 public function getFsMod() {
505 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['typo3/classes/class.modulemenu.php']) {
506 include_once($TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['typo3/classes/class.modulemenu.php']);