[TASK] Replace sprite icon "actions-system-shortcut-new" with IconFactory
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Backend / ToolbarItems / ShortcutToolbarItem.php
1 <?php
2 namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
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\Module\ModuleLoader;
18 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
19 use TYPO3\CMS\Backend\Utility\BackendUtility;
20 use TYPO3\CMS\Backend\Utility\IconUtility;
21 use TYPO3\CMS\Core\Database\PreparedStatement;
22 use TYPO3\CMS\Core\Http\AjaxRequestHandler;
23 use TYPO3\CMS\Core\Imaging\Icon;
24 use TYPO3\CMS\Core\Imaging\IconFactory;
25 use TYPO3\CMS\Core\Page\PageRenderer;
26 use TYPO3\CMS\Core\Utility\GeneralUtility;
27 use TYPO3\CMS\Core\Utility\MathUtility;
28 use TYPO3\CMS\Core\Utility\PathUtility;
29
30 /**
31 * Class to render the shortcut menu
32 */
33 class ShortcutToolbarItem implements ToolbarItemInterface {
34
35 /**
36 * @const integer Number of super global group
37 */
38 const SUPERGLOBAL_GROUP = -100;
39
40 /**
41 * @var string
42 */
43 public $perms_clause;
44
45 /**
46 * @var array
47 */
48 public $fieldArray;
49
50 /**
51 * All available shortcuts
52 *
53 * @var array
54 */
55 protected $shortcuts;
56
57 /**
58 * @var array
59 */
60 protected $shortcutGroups;
61
62 /**
63 * Labels of all groups.
64 * If value is 1, the system will try to find a label in the locallang array.
65 *
66 * @var array
67 */
68 protected $groupLabels;
69
70 /**
71 * @var IconFactory
72 */
73 protected $iconFactory;
74
75 /**
76 * Constructor
77 */
78 public function __construct() {
79 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
80 if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX) {
81 $this->getLanguageService()->includeLLFile('EXT:lang/locallang_misc.xlf');
82 // Needed to get the correct icons when reloading the menu after saving it
83 $loadModules = GeneralUtility::makeInstance(ModuleLoader::class);
84 $loadModules->load($GLOBALS['TBE_MODULES']);
85 }
86
87 // By default, 5 groups are set
88 $this->shortcutGroups = array(
89 1 => '1',
90 2 => '1',
91 3 => '1',
92 4 => '1',
93 5 => '1'
94 );
95 $this->shortcutGroups = $this->initShortcutGroups();
96 $this->shortcuts = $this->initShortcuts();
97
98 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/ShortcutMenu');
99 }
100
101 /**
102 * Checks whether the user has access to this toolbar item
103 *
104 * @return bool TRUE if user has access, FALSE if not
105 */
106 public function checkAccess() {
107 return (bool)$this->getBackendUser()->getTSConfigVal('options.enableBookmarks');
108 }
109
110 /**
111 * Render shortcut icon
112 *
113 * @return string HTML
114 */
115 public function getItem() {
116 $title = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarks', TRUE);
117 return '<span title="' . $title . '">' . $this->iconFactory->getIcon('apps-toolbar-menu-shortcut', Icon::SIZE_SMALL)->render() . '</span>';
118 }
119
120 /**
121 * Render drop down content
122 *
123 * @return string HTML
124 */
125 public function getDropDown() {
126 $languageService = $this->getLanguageService();
127 $shortcutGroup = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarksGroup', TRUE);
128 $shortcutEdit = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarksEdit', TRUE);
129 $shortcutDelete = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarksDelete', TRUE);
130 $editIcon = '<a href="#" class="dropdown-list-link-edit shortcut-edit" ' . $shortcutEdit . '>'
131 . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL) . '</a>';
132 $deleteIcon = '<a href="#" class="dropdown-list-link-delete shortcut-delete" title="' . $shortcutDelete . '">'
133 . $this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL) . '</a>';
134
135 $shortcutMenu[] = '<ul class="dropdown-list">';
136
137 // Render shortcuts with no group (group id = 0) first
138 $noGroupShortcuts = $this->getShortcutsByGroup(0);
139 foreach ($noGroupShortcuts as $shortcut) {
140
141 $shortcutMenu[] = '
142 <li class="shortcut" data-shortcutid="' . (int)$shortcut['raw']['uid'] . '">
143 <a class="dropdown-list-link dropdown-link-list-add-editdelete" href="#" onclick="' . htmlspecialchars($shortcut['action']) . ' return false;">' .
144 $shortcut['icon'] . ' ' .
145 htmlspecialchars($shortcut['label']) .
146 '</a>
147 ' . $editIcon . $deleteIcon . '
148 </li>';
149 }
150 // Now render groups and the contained shortcuts
151 $groups = $this->getGroupsFromShortcuts();
152 krsort($groups, SORT_NUMERIC);
153 foreach ($groups as $groupId => $groupLabel) {
154 if ($groupId != 0) {
155 $shortcutGroup = '';
156 if (count($shortcutMenu) > 1) {
157 $shortcutGroup .= '<li class="divider"></li>';
158 }
159 $shortcutGroup .= '
160 <li class="dropdown-header" id="shortcut-group-' . (int)$groupId . '">
161 ' . $groupLabel . '
162 </li>';
163 $shortcuts = $this->getShortcutsByGroup($groupId);
164 $i = 0;
165 foreach ($shortcuts as $shortcut) {
166 $i++;
167 $shortcutGroup .= '
168 <li class="shortcut" data-shortcutid="' . (int)$shortcut['raw']['uid'] . '" data-shortcutgroup="' . (int)$groupId . '">
169 <a class="dropdown-list-link dropdown-link-list-add-editdelete" href="#" onclick="' . htmlspecialchars($shortcut['action']) . ' return false;">' .
170 $shortcut['icon'] . ' ' .
171 htmlspecialchars($shortcut['label']) .
172 '</a>
173 ' . $editIcon . $deleteIcon . '
174 </li>';
175 }
176 $shortcutMenu[] = $shortcutGroup;
177 }
178 }
179 $shortcutMenu[] = '</ul>';
180
181 if (count($shortcutMenu) === 2) {
182 // No shortcuts added yet, show a small help message how to add shortcuts
183 $title = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarks', TRUE);
184 $icon = '<span title="' . $title . '">' . $this->iconFactory->getIcon('actions-system-shortcut-new', Icon::SIZE_SMALL) . '</span>';
185 $label = str_replace('%icon%', $icon, $languageService->sL('LLL:EXT:lang/locallang_misc.xlf:bookmarkDescription'));
186 $compiledShortcutMenu = '<p>' . $label . '</p>';
187 } else {
188 $compiledShortcutMenu = implode(LF, $shortcutMenu);
189 }
190
191 return $compiledShortcutMenu;
192 }
193
194 /**
195 * Renders the menu so that it can be returned as response to an AJAX call
196 *
197 * @param array $params Array of parameters from the AJAX interface, currently unused
198 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
199 * @return void
200 */
201 public function renderAjaxMenu($params = array(), AjaxRequestHandler $ajaxObj = NULL) {
202 $menuContent = $this->getDropDown();
203 $ajaxObj->addContent('shortcutMenu', $menuContent);
204 }
205
206 /**
207 * This toolbar item needs no additional attributes
208 *
209 * @return array
210 */
211 public function getAdditionalAttributes() {
212 return array();
213 }
214
215 /**
216 * This item has a drop down
217 *
218 * @return bool
219 */
220 public function hasDropDown() {
221 return TRUE;
222 }
223
224 /**
225 * Retrieves the shortcuts for the current user
226 *
227 * @return array Array of shortcuts
228 */
229 protected function initShortcuts() {
230 $databaseConnection = $this->getDatabaseConnection();
231 $globalGroupIdList = implode(',', array_keys($this->getGlobalShortcutGroups()));
232 $backendUser = $this->getBackendUser();
233 $res = $databaseConnection->exec_SELECTquery(
234 '*',
235 'sys_be_shortcuts',
236 '(userid = ' . (int)$backendUser->user['uid'] . ' AND sc_group>=0) OR sc_group IN (' . $globalGroupIdList . ')',
237 '',
238 'sc_group,sorting'
239 );
240 // Traverse shortcuts
241 $lastGroup = 0;
242 $shortcuts = array();
243 while ($row = $databaseConnection->sql_fetch_assoc($res)) {
244 $shortcut = array('raw' => $row);
245
246 list($row['module_name'], $row['M_module_name']) = explode('|', $row['module_name']);
247
248 $queryParts = parse_url($row['url']);
249 $queryParameters = GeneralUtility::explodeUrl2Array($queryParts['query'], 1);
250 if ($row['module_name'] === 'xMOD_alt_doc.php' && is_array($queryParameters['edit'])) {
251 $shortcut['table'] = key($queryParameters['edit']);
252 $shortcut['recordid'] = key($queryParameters['edit'][$shortcut['table']]);
253 if ($queryParameters['edit'][$shortcut['table']][$shortcut['recordid']] === 'edit') {
254 $shortcut['type'] = 'edit';
255 } elseif ($queryParameters['edit'][$shortcut['table']][$shortcut['recordid']] === 'new') {
256 $shortcut['type'] = 'new';
257 }
258 if (substr($shortcut['recordid'], -1) === ',') {
259 $shortcut['recordid'] = substr($shortcut['recordid'], 0, -1);
260 }
261 } else {
262 $shortcut['type'] = 'other';
263 }
264 // Check for module access
265 $moduleName = $row['M_module_name'] ?: $row['module_name'];
266 if (!$backendUser->isAdmin()) {
267 if (!isset($this->getLanguageService()->moduleLabels['tabs_images'][$moduleName . '_tab'])) {
268 // Nice hack to check if the user has access to this module
269 // - otherwise the translation label would not have been loaded :-)
270 continue;
271 }
272 $pageId = $this->getLinkedPageId($row['url']);
273 if (MathUtility::canBeInterpretedAsInteger($pageId)) {
274 // Check for webmount access
275 if (!$backendUser->isInWebMount($pageId)) {
276 continue;
277 }
278 // Check for record access
279 $pageRow = BackendUtility::getRecord('pages', $pageId);
280 if (!$backendUser->doesUserHaveAccess($pageRow, ($perms = 1))) {
281 continue;
282 }
283 }
284 }
285 $moduleParts = explode('_', $moduleName);
286 $shortcutGroup = (int)$row['sc_group'];
287 if ($shortcutGroup && $lastGroup !== $shortcutGroup && $shortcutGroup !== self::SUPERGLOBAL_GROUP) {
288 $shortcut['groupLabel'] = $this->getShortcutGroupLabel($shortcutGroup);
289 }
290 $lastGroup = $shortcutGroup;
291
292 if ($row['description']) {
293 $shortcut['label'] = $row['description'];
294 } else {
295 $shortcut['label'] = GeneralUtility::fixed_lgd_cs(rawurldecode($queryParts['query']), 150);
296 }
297 $shortcut['group'] = $shortcutGroup;
298 $shortcut['icon'] = $this->getShortcutIcon($row, $shortcut);
299 $shortcut['iconTitle'] = $this->getShortcutIconTitle($shortcut['label'], $row['module_name'], $row['M_module_name']);
300 $shortcut['action'] = 'jump(' . GeneralUtility::quoteJSvalue($this->getTokenUrl($row['url'])) . ',' . GeneralUtility::quoteJSvalue($moduleName) . ',' . GeneralUtility::quoteJSvalue($moduleParts[0]) . ', ' . (int)$pageId . ');';
301
302 $shortcuts[] = $shortcut;
303 }
304 return $shortcuts;
305 }
306
307 /**
308 * Adds the correct token, if the url is an index.php script
309 *
310 * @param string $url
311 * @return string
312 */
313 protected function getTokenUrl($url) {
314 $parsedUrl = parse_url($url);
315 parse_str($parsedUrl['query'], $parameters);
316
317 // parse the returnUrl and replace the module token of it
318 if (isset($parameters['returnUrl'])) {
319 $parsedReturnUrl = parse_url($parameters['returnUrl']);
320 parse_str($parsedReturnUrl['query'], $returnUrlParameters);
321 if (strpos($parsedReturnUrl['path'], 'index.php') !== FALSE && isset($returnUrlParameters['M'])) {
322 $module = $returnUrlParameters['M'];
323 $returnUrl = BackendUtility::getModuleUrl($module, $returnUrlParameters);
324 $parameters['returnUrl'] = $returnUrl;
325 $url = $parsedUrl['path'] . '?' . http_build_query($parameters);
326 }
327 }
328
329 if (strpos($parsedUrl['path'], 'index.php') !== FALSE && isset($parameters['M'])) {
330 $module = $parameters['M'];
331 $url = BackendUtility::getModuleUrl($module, $parameters);
332 }
333 return $url;
334 }
335
336 /**
337 * Gets shortcuts for a specific group
338 *
339 * @param int $groupId Group Id
340 * @return array Array of shortcuts that matched the group
341 */
342 protected function getShortcutsByGroup($groupId) {
343 $shortcuts = array();
344 foreach ($this->shortcuts as $shortcut) {
345 if ($shortcut['group'] == $groupId) {
346 $shortcuts[] = $shortcut;
347 }
348 }
349 return $shortcuts;
350 }
351
352 /**
353 * Gets a shortcut by its uid
354 *
355 * @param int $shortcutId Shortcut id to get the complete shortcut for
356 * @return mixed An array containing the shortcut's data on success or FALSE on failure
357 */
358 protected function getShortcutById($shortcutId) {
359 $returnShortcut = FALSE;
360 foreach ($this->shortcuts as $shortcut) {
361 if ($shortcut['raw']['uid'] == (int)$shortcutId) {
362 $returnShortcut = $shortcut;
363 continue;
364 }
365 }
366 return $returnShortcut;
367 }
368
369 /**
370 * Gets the available shortcut groups from default groups, user TSConfig, and global groups
371 *
372 * @return array
373 */
374 protected function initShortcutGroups() {
375 $languageService = $this->getLanguageService();
376 $backendUser = $this->getBackendUser();
377 // Groups from TSConfig
378 $bookmarkGroups = $backendUser->getTSConfigProp('options.bookmarkGroups');
379 if (is_array($bookmarkGroups) && !empty($bookmarkGroups)) {
380 foreach ($bookmarkGroups as $groupId => $label) {
381 if (!empty($label)) {
382 $this->shortcutGroups[$groupId] = (string)$label;
383 } elseif ($backendUser->isAdmin()) {
384 unset($this->shortcutGroups[$groupId]);
385 }
386 }
387 }
388 // Generate global groups, all global groups have negative IDs.
389 if (!empty($this->shortcutGroups)) {
390 $groups = $this->shortcutGroups;
391 foreach ($groups as $groupId => $groupLabel) {
392 $this->shortcutGroups[$groupId * -1] = $groupLabel;
393 }
394 }
395 // Group -100 is kind of superglobal and can't be changed.
396 $this->shortcutGroups[self::SUPERGLOBAL_GROUP] = 1;
397 // Add labels
398 foreach ($this->shortcutGroups as $groupId => $groupLabel) {
399 $groupId = (int)$groupId;
400 $label = $groupLabel;
401 if ($groupLabel == '1') {
402 $label = $languageService->sL('LLL:EXT:lang/locallang_misc.xlf:bookmark_group_' . abs($groupId), TRUE);
403 if (empty($label)) {
404 // Fallback label
405 $label = $languageService->getLL('bookmark_group', TRUE) . ' ' . abs($groupId);
406 }
407 }
408 if ($groupId < 0) {
409 // Global group
410 $label = $languageService->sL('LLL:EXT:lang/locallang_misc.xlf:bookmark_global', TRUE) . ': ' . (!empty($label) ? $label : abs($groupId));
411 if ($groupId === self::SUPERGLOBAL_GROUP) {
412 $label = $languageService->getLL('bookmark_global', TRUE) . ': ' . $languageService->getLL('bookmark_all', TRUE);
413 }
414 }
415 $this->shortcutGroups[$groupId] = $label;
416 }
417 return $this->shortcutGroups;
418 }
419
420 /**
421 * gets the available shortcut groups, renders a form so it can be saved lateron
422 *
423 * @param array $params Array of parameters from the AJAX interface, currently unused
424 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
425 * @return void
426 */
427 public function getAjaxShortcutEditForm($params = array(), AjaxRequestHandler $ajaxObj = NULL) {
428 $selectedShortcutId = (int)GeneralUtility::_GP('shortcutId');
429 $selectedShortcutGroupId = (int)GeneralUtility::_GP('shortcutGroup');
430 $selectedShortcut = $this->getShortcutById($selectedShortcutId);
431
432 $shortcutGroups = $this->shortcutGroups;
433 if (!$this->getBackendUser()->isAdmin()) {
434 foreach ($shortcutGroups as $groupId => $groupName) {
435 if ((int)$groupId < 0) {
436 unset($shortcutGroups[$groupId]);
437 }
438 }
439 }
440
441 // build the form
442 $content = '
443 <form class="shortcut-form" role="form">
444 <div class="form-group">
445 <input type="text" class="form-control" name="shortcut-title" value="' . htmlspecialchars($selectedShortcut['label']) . '">
446 </div>';
447
448 $content .= '
449 <div class="form-group">
450 <select class="form-control" name="shortcut-group">';
451 foreach ($shortcutGroups as $shortcutGroupId => $shortcutGroupTitle) {
452 $content .= '<option value="' . (int)$shortcutGroupId . '"' . ($selectedShortcutGroupId == $shortcutGroupId ? ' selected="selected"' : '') . '>' . htmlspecialchars($shortcutGroupTitle) . '</option>';
453 }
454 $content .= '
455 </select>
456 </div>
457 <input type="button" class="btn btn-default shortcut-form-cancel" value="Cancel">
458 <input type="button" class="btn btn-success shortcut-form-save" value="Save">
459 </form>';
460
461 $ajaxObj->addContent('data', $content);
462 }
463
464 /**
465 * Deletes a shortcut through an AJAX call
466 *
467 * @param array $params Array of parameters from the AJAX interface, currently unused
468 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
469 * @return void
470 */
471 public function deleteAjaxShortcut($params = array(), AjaxRequestHandler $ajaxObj = NULL) {
472 $databaseConnection = $this->getDatabaseConnection();
473 $shortcutId = (int)GeneralUtility::_POST('shortcutId');
474 $fullShortcut = $this->getShortcutById($shortcutId);
475 $ajaxReturn = 'failed';
476 if ($fullShortcut['raw']['userid'] == $this->getBackendUser()->user['uid']) {
477 $databaseConnection->exec_DELETEquery('sys_be_shortcuts', 'uid = ' . $shortcutId);
478 if ($databaseConnection->sql_affected_rows() == 1) {
479 $ajaxReturn = 'deleted';
480 }
481 }
482 $ajaxObj->addContent('delete', $ajaxReturn);
483 }
484
485 /**
486 * Creates a shortcut through an AJAX call
487 *
488 * @param array $params Array of parameters from the AJAX interface, currently unused
489 * @param AjaxRequestHandler $ajaxObj Oject of type AjaxRequestHandler
490 *
491 * @return void
492 */
493 public function createAjaxShortcut($params = array(), AjaxRequestHandler $ajaxObj = NULL) {
494 $languageService = $this->getLanguageService();
495
496 // Default name
497 $shortcutName = 'Shortcut';
498 $shortcutNamePrepend = '';
499 $url = GeneralUtility::_POST('url');
500
501 // Determine shortcut type
502 $url = rawurldecode($url);
503 $queryParts = parse_url($url);
504 $queryParameters = GeneralUtility::explodeUrl2Array($queryParts['query'], TRUE);
505
506 // Proceed only if no scheme is defined, as URL is expected to be relative
507 if (empty($queryParts['scheme'])) {
508 if (is_array($queryParameters['edit'])) {
509 $shortcut['table'] = key($queryParameters['edit']);
510 $shortcut['recordid'] = key($queryParameters['edit'][$shortcut['table']]);
511 $shortcut['pid'] = BackendUtility::getRecord($shortcut['table'], $shortcut['recordid'])['pid'];
512 if ($queryParameters['edit'][$shortcut['table']][$shortcut['recordid']] == 'edit') {
513 $shortcut['type'] = 'edit';
514 $shortcutNamePrepend = $languageService->getLL('shortcut_edit', TRUE);
515 } elseif ($queryParameters['edit'][$shortcut['table']][$shortcut['recordid']] == 'new') {
516 $shortcut['type'] = 'new';
517 $shortcutNamePrepend = $languageService->getLL('shortcut_create', TRUE);
518 }
519 } else {
520 $shortcut['type'] = 'other';
521 $shortcut['table'] = '';
522 $shortcut['recordid'] = 0;
523 }
524
525 // Lookup the title of this page and use it as default description
526 $pageId = (int)($shortcut['pid'] ?: ($shortcut['recordid'] ?: $this->getLinkedPageId($url)));
527 if ($pageId) {
528 $page = BackendUtility::getRecord('pages', $pageId);
529
530 if (!empty($page)) {
531 // Set the name to the title of the page
532 if ($shortcut['type'] === 'other') {
533 $shortcutName = $page['title'];
534 } else {
535 $shortcutName = $shortcutNamePrepend . ' ' . $languageService->sL($GLOBALS['TCA'][$shortcut['table']]['ctrl']['title']) . ' (' . $page['title'] . ')';
536 }
537 }
538 } else {
539 $dirName = urldecode($pageId);
540
541 if (preg_match('/\\/$/', $dirName)) {
542 // If $pageId is a string and ends with a slash,
543 // assume it is a fileadmin reference and set
544 // the description to the basename of that path
545 $shortcutName .= ' ' . basename($dirName);
546 }
547 }
548
549 $this->tryAddingTheShortcut($ajaxObj, $url, $shortcutName);
550 }
551 }
552
553 /**
554 * Try to adding a shortcut
555 *
556 * @param AjaxRequestHandler $ajaxObj Oject of type AjaxRequestHandler
557 * @param string $url
558 * @param string $shortcutName
559 *
560 * @return void
561 */
562 protected function tryAddingTheShortcut(AjaxRequestHandler $ajaxObj, $url, $shortcutName) {
563 $module = GeneralUtility::_POST('module');
564 $shortcutCreated = 'failed';
565
566 if (!empty($module) && !empty($url)) {
567 $shortcutCreated = 'alreadyExists';
568
569 if (!BackendUtility::shortcutExists($url)) {
570 $shortcutCreated = $this->addShortcut($url, $shortcutName, $module);
571 }
572 }
573
574 $ajaxObj->addContent('create', $shortcutCreated);
575 }
576
577 /**
578 * Add a shortcut now with some user stuffs
579 *
580 * @param string $url
581 * @param string $shortcutName
582 * @param string $module
583 *
584 * @return string
585 */
586 protected function addShortcut($url, $shortcutName, $module) {
587 // Shorts
588 $db = $this->getDatabaseConnection();
589 $lS = $this->getLanguageService();
590
591 if ($shortcutName === 'Shortcut' && !empty($lS->moduleLabels['labels'][$module . '_tablabel'])) {
592 $shortcutName = $lS->moduleLabels['labels'][$module . '_tablabel'];
593 }
594
595 $motherModule = GeneralUtility::_POST('motherModName');
596 $fieldValues = [
597 'userid' => $this->getBackendUser()->user['uid'],
598 'module_name' => $module . '|' . $motherModule,
599 'url' => $url,
600 'description' => $shortcutName,
601 'sorting' => $GLOBALS['EXEC_TIME']
602 ];
603
604 $db->exec_INSERTquery('sys_be_shortcuts', $fieldValues);
605
606 $shortcutCreated = 'failed';
607 if ($db->sql_affected_rows() === 1) {
608 $shortcutCreated = 'success';
609 }
610
611 return $shortcutCreated;
612 }
613
614 /**
615 * Exists already a shortcut entry for this TYPO3 url?
616 *
617 * @param string $url
618 *
619 * @return bool
620 */
621 protected function shortcutExists($url) {
622 $statement = $this->getDatabaseConnection()->prepare_SELECTquery(
623 'uid',
624 'sys_be_shortcuts',
625 'userid = :userid AND url = :url'
626 );
627
628 $statement->bindValues([
629 ':userid' => $this->getBackendUser()->user['uid'],
630 ':url' => $url
631 ]);
632
633 $statement->execute();
634 $rows = $statement->fetch(PreparedStatement::FETCH_ASSOC);
635 $statement->free();
636
637 return !empty($rows);
638 }
639
640 /**
641 * Gets called when a shortcut is changed, checks whether the user has
642 * permissions to do so and saves the changes if everything is ok
643 *
644 * @param array $params Array of parameters from the AJAX interface, currently unused
645 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
646 * @return void
647 */
648 public function setAjaxShortcut($params = array(), AjaxRequestHandler $ajaxObj = NULL) {
649 $databaseConnection = $this->getDatabaseConnection();
650 $backendUser = $this->getBackendUser();
651 $shortcutId = (int)GeneralUtility::_POST('shortcutId');
652 $shortcutName = strip_tags(GeneralUtility::_POST('shortcutTitle'));
653 $shortcutGroupId = (int)GeneralUtility::_POST('shortcutGroup');
654 // Users can only modify their own shortcuts (except admins)
655 $addUserWhere = !$backendUser->isAdmin() ? ' AND userid=' . (int)$backendUser->user['uid'] : '';
656 $fieldValues = array(
657 'description' => $shortcutName,
658 'sc_group' => $shortcutGroupId
659 );
660 if ($fieldValues['sc_group'] < 0 && !$backendUser->isAdmin()) {
661 $fieldValues['sc_group'] = 0;
662 }
663 $databaseConnection->exec_UPDATEquery('sys_be_shortcuts', 'uid=' . $shortcutId . $addUserWhere, $fieldValues);
664 $affectedRows = $databaseConnection->sql_affected_rows();
665 if ($affectedRows == 1) {
666 $ajaxObj->addContent('shortcut', $shortcutName);
667 } else {
668 $ajaxObj->addContent('shortcut', 'failed');
669 }
670 $ajaxObj->setContentFormat('plain');
671 }
672
673 /**
674 * Gets the label for a shortcut group
675 *
676 * @param int $groupId A shortcut group id
677 * @return string The shortcut group label, can be an empty string if no group was found for the id
678 */
679 protected function getShortcutGroupLabel($groupId) {
680 return isset($this->shortcutGroups[$groupId]) ? $this->shortcutGroups[$groupId] : '';
681 }
682
683 /**
684 * Gets a list of global groups, shortcuts in these groups are available to all users
685 *
686 * @return array Array of global groups
687 */
688 protected function getGlobalShortcutGroups() {
689 $globalGroups = array();
690 foreach ($this->shortcutGroups as $groupId => $groupLabel) {
691 if ($groupId < 0) {
692 $globalGroups[$groupId] = $groupLabel;
693 }
694 }
695 return $globalGroups;
696 }
697
698 /**
699 * runs through the available shortcuts an collects their groups
700 *
701 * @return array Array of groups which have shortcuts
702 */
703 protected function getGroupsFromShortcuts() {
704 $groups = array();
705 foreach ($this->shortcuts as $shortcut) {
706 $groups[$shortcut['group']] = $this->shortcutGroups[$shortcut['group']];
707 }
708 return array_unique($groups);
709 }
710
711 /**
712 * Gets the icon for the shortcut
713 *
714 * @param array $row
715 * @param array $shortcut
716 * @return string Shortcut icon as img tag
717 */
718 protected function getShortcutIcon($row, $shortcut) {
719 $databaseConnection = $this->getDatabaseConnection();
720 $languageService = $this->getLanguageService();
721 $titleAttribute = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.shortcut', TRUE);
722 switch ($row['module_name']) {
723 case 'xMOD_alt_doc.php':
724 $table = $shortcut['table'];
725 $recordid = $shortcut['recordid'];
726 $icon = '';
727 if ($shortcut['type'] == 'edit') {
728 // Creating the list of fields to include in the SQL query:
729 $selectFields = $this->fieldArray;
730 $selectFields[] = 'uid';
731 $selectFields[] = 'pid';
732 if ($table == 'pages') {
733 $selectFields[] = 'module';
734 $selectFields[] = 'extendToSubpages';
735 $selectFields[] = 'doktype';
736 }
737 if (is_array($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) {
738 $selectFields = array_merge($selectFields, $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']);
739 }
740 if ($GLOBALS['TCA'][$table]['ctrl']['type']) {
741 $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['type'];
742 }
743 if ($GLOBALS['TCA'][$table]['ctrl']['typeicon_column']) {
744 $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_column'];
745 }
746 if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
747 $selectFields[] = 't3ver_state';
748 }
749 // Unique list!
750 $selectFields = array_unique($selectFields);
751 $permissionClause = $table === 'pages' && $this->perms_clause ? ' AND ' . $this->perms_clause : '';
752 $sqlQueryParts = array(
753 'SELECT' => implode(',', $selectFields),
754 'FROM' => $table,
755 'WHERE' => 'uid IN (' . $recordid . ') ' . $permissionClause . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table)
756 );
757 $result = $databaseConnection->exec_SELECT_queryArray($sqlQueryParts);
758 $row = $databaseConnection->sql_fetch_assoc($result);
759 $icon = IconUtility::getSpriteIconForRecord($table, (array)$row, array('title' => $titleAttribute));
760 } elseif ($shortcut['type'] == 'new') {
761 $icon = IconUtility::getSpriteIconForRecord($table, array(), array('title' => $titleAttribute));
762 }
763 break;
764 case 'file_edit':
765 $icon = '<span title="' . $titleAttribute . '">' . $this->iconFactory->getIcon('mimetypes-text-html', Icon::SIZE_SMALL)->render() . '</span>';
766 break;
767 case 'wizard_rte':
768 $icon = '<span title="' . $titleAttribute . '">' . $this->iconFactory->getIcon('mimetypes-word', Icon::SIZE_SMALL)->render() . '</span>';
769 break;
770 default:
771 if ($languageService->moduleLabels['tabs_images'][$row['module_name'] . '_tab']) {
772 $icon = $languageService->moduleLabels['tabs_images'][$row['module_name'] . '_tab'];
773 // Change icon of fileadmin references - otherwise it doesn't differ with Web->List
774 $icon = str_replace('mod/file/list/list.gif', 'mod/file/file.gif', $icon);
775 if (GeneralUtility::isAbsPath($icon)) {
776 $icon = '../' . PathUtility::stripPathSitePrefix($icon);
777 }
778 // @todo: hardcoded width as we don't have a way to address module icons with an API yet.
779 $icon = '<img src="' . htmlspecialchars($icon) . '" alt="' . $titleAttribute . '" width="16">';
780 } else {
781 $icon = IconUtility::getSpriteIcon('empty-empty', array('title' => $titleAttribute));
782 }
783 }
784 return $icon;
785 }
786
787 /**
788 * Returns title for the shortcut icon
789 *
790 * @param string $shortcutLabel Shortcut label
791 * @param string $moduleName Backend module name (key)
792 * @param string $parentModuleName Parent module label
793 * @return string Title for the shortcut icon
794 */
795 protected function getShortcutIconTitle($shortcutLabel, $moduleName, $parentModuleName = '') {
796 $languageService = $this->getLanguageService();
797 if (substr($moduleName, 0, 5) == 'xMOD_') {
798 $title = substr($moduleName, 5);
799 } else {
800 $splitModuleName = explode('_', $moduleName);
801 $title = $languageService->moduleLabels['tabs'][$splitModuleName[0] . '_tab'];
802 if (count($splitModuleName) > 1) {
803 $title .= '>' . $languageService->moduleLabels['tabs'][($moduleName . '_tab')];
804 }
805 }
806 if ($parentModuleName) {
807 $title .= ' (' . $parentModuleName . ')';
808 }
809 $title .= ': ' . $shortcutLabel;
810 return $title;
811 }
812
813 /**
814 * Return the ID of the page in the URL if found.
815 *
816 * @param string $url The URL of the current shortcut link
817 * @return string If a page ID was found, it is returned. Otherwise: 0
818 */
819 protected function getLinkedPageId($url) {
820 return preg_replace('/.*[\\?&]id=([^&]+).*/', '$1', $url);
821 }
822
823 /**
824 * Position relative to others, live search should be very right
825 *
826 * @return int
827 */
828 public function getIndex() {
829 return 20;
830 }
831
832 /**
833 * Returns the current BE user.
834 *
835 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
836 */
837 protected function getBackendUser() {
838 return $GLOBALS['BE_USER'];
839 }
840
841 /**
842 * Returns current PageRenderer
843 *
844 * @return PageRenderer
845 */
846 protected function getPageRenderer() {
847 return GeneralUtility::makeInstance(PageRenderer::class);
848 }
849
850 /**
851 * Returns LanguageService
852 *
853 * @return \TYPO3\CMS\Lang\LanguageService
854 */
855 protected function getLanguageService() {
856 return $GLOBALS['LANG'];
857 }
858
859 /**
860 * Return DatabaseConnection
861 *
862 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
863 */
864 protected function getDatabaseConnection() {
865 return $GLOBALS['TYPO3_DB'];
866 }
867
868 }