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 ***************************************************************/
28 if(TYPO3_REQUESTTYPE
& TYPO3_REQUESTTYPE_AJAX
) {
29 require_once('interfaces/interface.backend_toolbaritem.php');
30 require_once(PATH_t3lib
.'class.t3lib_loadmodules.php');
31 require_once(PATH_typo3
.'sysext/lang/lang.php');
33 $GLOBALS['LANG'] = t3lib_div
::makeInstance('language');
34 $GLOBALS['LANG']->init($GLOBALS['BE_USER']->uc
['lang']);
35 $GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_misc.xml');
37 // needed to get the correct icons when reloading the menu after saving it
38 $loadModules = t3lib_div
::makeInstance('t3lib_loadModules');
39 $loadModules->load($GLOBALS['TBE_MODULES']);
44 * class to render the shortcut menu
48 * @author Ingo Renner <ingo@typo3.org>
52 class ShortcutMenu
implements backend_toolbarItem
{
54 private $shortcutGroups;
57 * all available shortcuts
64 * labels of all groups.
65 * If value is 1, the system will try to find a label in the locallang array.
72 * reference back to the backend object
76 private $backendReference;
83 public function __construct() {
84 $this->shortcuts
= array();
86 // by default, 5 groups are set
87 $this->shortcutGroups
= array(
95 $this->shortcutGroups
= $this->initShortcutGroups();
96 $this->shortcuts
= $this->initShortcuts();
100 * sets the backend reference
102 * @param TYPO3backend backend object reference
104 public function setBackend(&$backendReference) {
105 $this->backendReference
= $backendReference;
109 * Creates the shortcut menu (default renderer)
111 * @return string workspace selector as HTML select
113 public function render() {
114 $this->addJavascriptToBackend();
116 $shortcutMenu = array();
118 $shortcutMenu[] = '<a href="#" class="toolbar-item"><img'.t3lib_iconWorks
::skinImg($this->backPath
, 'gfx/toolbar_shortcut.png', 'width="16" height="16"').' title="Shortcuts" alt="" /></a>';
119 $shortcutMenu[] = '<div class="toolbar-item-menu" style="display: none;">';
120 $shortcutMenu[] = $this->renderMenu();
121 $shortcutMenu[] = '</div>';
123 return implode("\n", $shortcutMenu);
127 * renders the pure contents of the menu
129 * @return string the menu's content
131 public function renderMenu() {
133 $groupIcon = '<img'.t3lib_iconWorks
::skinImg($this->backPath
, 'gfx/i/sysf.gif', 'width="18" height="16"').' title="Shortcut Group" alt="" />';
134 $editIcon = '<img'.t3lib_iconWorks
::skinImg($this->backPath
, 'gfx/edit2.gif', 'width="11" height="12"').' title="Edit Shortcut" alt=""';
135 $deleteIcon = '<img'.t3lib_iconWorks
::skinImg($this->backPath
, 'gfx/garbage.gif', 'width="11" height="12"').' title="Delete Shortcut" alt="" />';
137 $shortcutMenu[] = '<table border="0" cellspacing="0" cellpadding="0" class="shortcut-list">';
139 // render shortcuts with no group (group id = 0) first
140 $noGroupShortcuts = $this->getShortcutsByGroup(0);
141 foreach($noGroupShortcuts as $shortcut) {
143 <tr id="shortcut-'.$shortcut['raw']['uid'].'" class="shortcut">
144 <td class="shortcut-icon">'.$shortcut['icon'].'</td>
145 <td class="shortcut-label">
146 <a id="shortcut-label-'.$shortcut['raw']['uid'].'" href="" onclick="'.$shortcut['action'].'">'.$shortcut['label'].'</a>
148 <td class="shortcut-edit">'.$editIcon.' id="shortcut-edit-'.$shortcut['raw']['uid'].'" /></td>
149 <td class="shortcut-delete">'.$deleteIcon.'</td>
153 // now render groups and the contained shortcuts
154 $groups = $this->getGroupsFromShortcuts();
155 krsort($groups, SORT_NUMERIC
);
156 foreach($groups as $groupId => $groupLabel) {
159 <tr class="shortcut-group" id="shortcut-group-'.$groupId.'">
160 <td class="shortcut-group-icon">'.$groupIcon.'</td>
161 <td class="shortcut-group-label">'.$groupLabel.'</td>
162 <td colspan="2"> </td>
165 $shortcuts = $this->getShortcutsByGroup($groupId);
167 foreach($shortcuts as $shortcut) {
172 $firstRow = ' first-row';
176 <tr id="shortcut-'.$shortcut['raw']['uid'].'" class="shortcut'.$firstRow.'">
177 <td class="shortcut-icon">'.$shortcut['icon'].'</td>
178 <td class="shortcut-label">
179 <a id="shortcut-label-'.$shortcut['raw']['uid'].'" href="" onclick="'.$shortcut['action'].'">'.$shortcut['label'].'</a>
181 <td class="shortcut-edit">'.$editIcon.' id="shortcut-edit-'.$shortcut['raw']['uid'].'" /></td>
182 <td class="shortcut-delete">'.$deleteIcon.'</td>
186 $shortcutMenu[] = $shortcutGroup;
190 $shortcutMenu[] = '</table>';
191 $compiledShortcutMenu = implode("\n", $shortcutMenu);
193 return $compiledShortcutMenu;
197 * renders the menu so that it can be returned as response to an AJAX call
199 * @param array array of parameters from the AJAX interface, currently unused
200 * @param TYPO3AJAX object of type TYPO3AJAX
203 public function renderAjax($params = array(), TYPO3AJAX
&$ajaxObj = null) {
204 $menuContent = $this->renderMenu();
206 $ajaxObj->addContent('shortcutMenu', $menuContent);
210 * adds the neccessary javascript ot the backend
214 private function addJavascriptToBackend() {
215 $this->backendReference
->addJavascriptFile('typo3/js/shortcutmenu.js');
219 * returns additional attributes for the list item in the toolbar
221 * @return string list item HTML attibutes
223 public function getAdditionalAttributes() {
224 return ' id="shortcut-menu"';
228 * retrieves the shortcuts for the current user
230 * @return array array of shortcuts
232 private function initShortcuts() {
233 $shortcuts = array();
234 $globalGroups = $this->getGlobalShortcutGroups();
236 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
239 '((userid = '.$GLOBALS['BE_USER']->user
['uid'].' AND sc_group>=0) OR sc_group IN ('.implode(',', array_keys($globalGroups)).'))',
244 // Traverse shortcuts
245 while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
246 $shortcut = array('raw' => $row);
247 $moduleParts = explode('|', $row['module_name']);
248 $row['module_name'] = $moduleParts[0];
249 $row['M_module_name'] = $moduleParts[1];
250 $moduleParts = explode('_', $row['M_module_name'] ?
251 $row['M_module_name'] :
254 $queryParts = parse_url($row['url']);
256 // check for module access
257 if(!$GLOBALS['BE_USER']->isAdmin()) {
258 if(!isset($GLOBALS['LANG']->moduleLabels
['tabs_images'][implode('_', $moduleParts).'_tab'])) {
259 // nice hack to check if the user has access to this module
260 // - otherwise the translation label would not have been loaded :-)
264 $pageId = $this->getLinkedPageId($row['url']);
265 if(t3lib_div
::testInt($pageId)) {
266 // check for webmount access
267 if(!$GLOBALS['BE_USER']->isInWebMount($page_id)) {
271 // check for record access
272 $pageRow = t3lib_BEfunc
::getRecord('pages', $pageId);
273 if(!$GLOBALS['BE_USER']->doesUserHaveAccess($pageRow, $perms = 1)) {
279 $shortcutGroup = $row['sc_group'];
280 if($shortcutGroup && strcmp($lastGroup, $shortcutGroup) && ($shortcutGroup != -100)) {
281 $shortcut['groupLabel'] = $this->getShortcutGroupLabel($shortcutGroup);
284 if($row['description']) {
285 $shortcut['label'] = $row['description'];
287 $shortcut['label'] = t3lib_div
::fixed_lgd(rawurldecode($queryParts['query']), 150);
290 $shortcut['group'] = $shortcutGroup;
291 $shortcut['icon'] = $this->getShortcutIcon($row['module_name']);
292 $shortcut['iconTitle'] = $this->getShortcutIconTitle($shortcutLabel, $row['module_name'], $row['M_module_name']);
293 $shortcut['action'] = 'jump(unescape(\''.rawurlencode($row['url']).'\'),\''.implode('_',$moduleParts).'\',\''.$moduleParts[0].'\');';
295 $lastGroup = $row['sc_group'];
296 $shortcuts[] = $shortcut;
303 * gets shortcuts for a specific group
305 * @param integer group Id
306 * @return array array of shortcuts that matched the group
308 private function getShortcutsByGroup($groupId) {
309 $shortcuts = array();
311 foreach($this->shortcuts
as $shortcut) {
312 if($shortcut['group'] == $groupId) {
313 $shortcuts[] = $shortcut;
321 * gets a shortcut by its uid
323 * @param integer shortcut id to get the complete shortcut for
324 * @return mixed an array containing the shortcut's data on success or false on failure
326 private function getShortcutById($shortcutId) {
327 $returnShortcut = false;
329 foreach($this->shortcuts
as $shortcut) {
330 if($shortcut['raw']['uid'] == (int) $shortcutId) {
331 $returnShortcut = $shortcut;
336 return $returnShortcut;
340 * gets the available shortcut groups from default gropups, user TSConfig,
343 * @param array array of parameters from the AJAX interface, currently unused
344 * @param TYPO3AJAX object of type TYPO3AJAX
347 private function initShortcutGroups($params = array(), TYPO3AJAX
&$ajaxObj = null) {
348 // groups from TSConfig
349 $userShortcutGroups = $GLOBALS['BE_USER']->getTSConfig('options.shortcutGroups');
351 if(is_array($userShortcutGroups['properties']) && count($userShortcutGroups['properties'])) {
352 foreach($userShortcutGroups['properties'] as $groupId => $label) {
353 if(strcmp('', $label) && strcmp('0', $label)) {
354 $this->shortcutGroups
[$groupId] = (string) $label;
355 } elseif($GLOBALS['BE_USER']->isAdmin()) {
356 unset($this->shortcutGroups
[$groupId]);
361 // generate global groups, all global groups have negative IDs.
362 if(count($this->shortcutGroups
)) {
363 $groups = $this->shortcutGroups
;
364 foreach($groups as $groupId => $groupLabel) {
365 $this->shortcutGroups
[($groupId * -1)] = $groupLabel;
369 // group -100 is kind of superglobal and can't be changed.
370 $this->shortcutGroups
[-100] = 1;
373 foreach($this->shortcutGroups
as $groupId => $groupLabel) {
374 $label = $groupLabel;
376 if($groupLabel == '1') {
377 $label = $GLOBALS['LANG']->getLL('shortcut_group_'.abs($groupId), 1);
381 $label = $GLOBALS['LANG']->getLL('shortcut_group', 1).' '.abs($groupId);
387 $label = $GLOBALS['LANG']->getLL('shortcut_global', 1).': '.
393 if($groupId == -100) {
394 $label = $GLOBALS['LANG']->getLL('shortcut_global', 1).': '.$GLOBALS['LANG']->getLL('shortcut_all', 1);
398 $this->shortcutGroups
[$groupId] = $label;
401 return $this->shortcutGroups
;
405 * gets the available shortcut groups
407 * @param array array of parameters from the AJAX interface, currently unused
408 * @param TYPO3AJAX object of type TYPO3AJAX
411 public function getAjaxShortcutGroups($params = array(), TYPO3AJAX
&$ajaxObj = null) {
413 //TODO remove global (negative id) groups if the user is no admin !!!
415 $ajaxObj->addContent('shortcutGroups', $this->shortcutGroups
);
416 $ajaxObj->setContentFormat('json');
420 * deletes a shortcut through an AJAX call
422 * @param array array of parameters from the AJAX interface, currently unused
423 * @param TYPO3AJAX object of type TYPO3AJAX
426 public function deleteAjaxShortcut($params = array(), TYPO3AJAX
&$ajaxObj = null) {
427 $shortcutId = (int) t3lib_div
::_POST('shortcutId');
428 $fullShortcut = $this->getShortcutById($shortcutId);
429 $ajaxReturn = 'failed';
431 if($fullShortcut['raw']['userid'] == $GLOBALS['BE_USER']->user
['uid']) {
432 $GLOBALS['TYPO3_DB']->exec_DELETEquery(
437 if($GLOBALS['TYPO3_DB']->sql_affected_rows() == 1) {
438 $ajaxReturn = 'deleted';
442 $ajaxObj->addContent('delete', $ajaxReturn);
446 * creates a shortcut through an AJAX call
448 * @param array array of parameters from the AJAX interface, currently unused
449 * @param TYPO3AJAX object of type TYPO3AJAX
452 public function createAjaxShortcut($params = array(), TYPO3AJAX
&$ajaxObj = null) {
453 $shortcutCreated = 'failed';
454 $shortcutName = 'Shortcut'; // default name
456 $url = urldecode(t3lib_div
::_POST('url'));
457 $module = t3lib_div
::_POST('module');
458 $motherModule = t3lib_div
::_POST('motherModName');
460 // Lookup the title of this page and use it as default description
461 $pageId = $this->getLinkedPageId($url);
463 if(t3lib_div
::testInt($pageId)) {
464 $page = t3lib_BEfunc
::getRecord('pages', $pageId);
466 // set the name to the title of the page
467 $shortcutName = $page['title'];
470 if (preg_match('/\/$/', $pageId)) {
471 // if $pageId is a string and ends with a slash,
472 // assume it is a fileadmin reference and set
473 // the description to the basename of that path
474 $shortcutName = basename($pageId);
478 // adding the shortcut
479 if($module && $url) {
480 $fieldValues = array(
481 'userid' => $GLOBALS['BE_USER']->user
['uid'],
482 'module_name' => $module.'|'.$motherModule,
484 'description' => $shortcutName,
487 $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_be_shortcuts', $fieldValues);
489 if($GLOBALS['TYPO3_DB']->sql_affected_rows() == 1) {
490 $shortcutCreated = 'success';
494 $ajaxObj->addContent('create', $shortcutCreated);
498 * gets called when a shortcut is changed, checks whether the user has
499 * permissions to do so and saves the changes if everything is ok
501 * @param array array of parameters from the AJAX interface, currently unused
502 * @param TYPO3AJAX object of type TYPO3AJAX
505 public function setAjaxShortcut($params = array(), TYPO3AJAX
&$ajaxObj = null) {
507 $shortcutId = (int) t3lib_div
::_POST('shortcutId');
508 $shortcutName = strip_tags(t3lib_div
::_POST('value'));
509 $shortcutGroupId = (int) t3lib_div
::_POST('shortcut-group');
511 if($shortcutGroupId > 0 ||
$GLOBALS['BE_USER']->isAdmin()) {
512 // users can delete only their own shortcuts (except admins)
513 $addUserWhere = (!$GLOBALS['BE_USER']->isAdmin() ?
514 ' AND userid='.intval($GLOBALS['BE_USER']->user
['uid'])
518 $fieldValues = array(
519 'description' => $shortcutName,
520 'sc_group' => $shortcutGroupId
523 if($fieldValues['sc_group'] < 0 && !$GLOBALS['BE_USER']->isAdmin()) {
524 $fieldValues['sc_group'] = 0;
527 $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
529 'uid='.$shortcutId.$addUserWhere,
533 $affectedRows = $GLOBALS['TYPO3_DB']->sql_affected_rows();
534 if($affectedRows == 1) {
535 $ajaxObj->addContent('shortcut', $shortcutName);
537 $ajaxObj->addContent('shortcut', 'failed');
541 $ajaxObj->setContentFormat('plain');
545 * gets the label for a shortcut group
547 * @param integer a shortcut group id
548 * @return string the shortcut group label, can be an empty string if no group was found for the id
550 private function getShortcutGroupLabel($groupId) {
553 if($this->shortcutGroups
[$groupId]) {
554 $label = $this->shortcutGroups
[$groupId];
561 * gets a list of global groups, shortcuts in these groups are available to all users
563 * @return array array of global groups
565 private function getGlobalShortcutGroups() {
566 $globalGroups = array();
568 foreach($this->shortcutGroups
as $groupId => $groupLabel) {
570 $globalGroups[$groupId] = $groupLabel;
574 return $globalGroups;
578 * runs through the available shortcuts an collects their groups
580 * @return array array of groups which have shortcuts
582 private function getGroupsFromShortcuts() {
585 foreach($this->shortcuts
as $shortcut) {
586 $groups[$shortcut['group']] = $this->shortcutGroups
[$shortcut['group']];
589 return array_unique($groups);
593 * gets the icon for the shortcut
595 * @param string backend module name
596 * @return string shortcut icon as img tag
598 private function getShortcutIcon($moduleName) {
600 switch($moduleName) {
601 case 'xMOD_alt_doc.php':
602 $icon = 'gfx/edit2.gif';
604 case 'xMOD_file_edit.php':
605 $icon = 'gfx/edit_file.gif';
607 case 'xMOD_wizard_rte.php':
608 $icon = 'gfx/edit_rtewiz.gif';
611 if($GLOBALS['LANG']->moduleLabels
['tabs_images'][$moduleName.'_tab']) {
612 $icon = $GLOBALS['LANG']->moduleLabels
['tabs_images'][$moduleName.'_tab'];
614 // change icon of fileadmin references - otherwise it doesn't differ with Web->List
615 $icon = str_replace('mod/file/list/list.gif', 'mod/file/file.gif', $icon);
617 if(t3lib_div
::isAbsPath($icon)) {
618 $icon = '../'.substr($icon, strlen(PATH_site
));
621 $icon = 'gfx/dummy_module.gif';
625 $icon = '<img src="'.$icon.'" alt="shortcut icon" />';
631 * Returns title for the shortcut icon
633 * @param string shortcut label
634 * @param string backend module name (key)
635 * @param string parent module label
636 * @return string title for the shortcut icon
638 private function getShortcutIconTitle($shortcutLabel, $moduleName, $parentModuleName = '') {
641 if(substr($moduleName, 0, 5) == 'xMOD_') {
642 $title = substr($moduleName, 5);
644 $splitModuleName = explode('_', $moduleName);
645 $title = $GLOBALS['LANG']->moduleLabels
['tabs'][$splitModuleName[0].'_tab'];
647 if(count($splitModuleName) > 1) {
648 $title .= '>'.$GLOBALS['LANG']->moduleLabels
['tabs'][$moduleName.'_tab'];
652 if($parentModuleName) {
653 $title .= ' ('.$parentModuleName.')';
656 $title .= ': '.$shortcutLabel;
662 * Return the ID of the page in the URL if found.
664 * @param string The URL of the current shortcut link
665 * @return string If a page ID was found, it is returned. Otherwise: 0
667 private function getLinkedPageId($url) {
668 return preg_replace('/.*[\?&]id=([^&]+).*/', '$1', $url);
674 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['typo3/classes/class.shortcutmenu.php']) {
675 include_once($TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['typo3/classes/class.shortcutmenu.php']);