[CLEANUP] Make use of possible imports and remove unused ones
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / ClickMenu / ClickMenu.php
1 <?php
2 namespace TYPO3\CMS\Backend\ClickMenu;
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\Utility\BackendUtility;
18 use TYPO3\CMS\Backend\Utility\IconUtility;
19 use TYPO3\CMS\Core\Resource\Folder;
20 use TYPO3\CMS\Core\Resource\ResourceFactory;
21 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Backend\Clipboard\Clipboard;
24 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
25 use TYPO3\CMS\Lang\LanguageService;
26
27 /**
28 * Class for generating the click menu
29 *
30 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
31 * @internal
32 */
33 class ClickMenu {
34
35 /**
36 * Defines if the click menu is first level or second.
37 * Second means the click menu is triggered from another menu.
38 *
39 * @var int
40 */
41 public $cmLevel = 0;
42
43 /**
44 * Clipboard array (submitted by eg. pressing the paste button)
45 *
46 * @var bool
47 */
48 public $CB;
49
50 /**
51 * If set, the calling document should be in the listframe of a frameset.
52 *
53 * @var bool
54 */
55 public $listFrame = FALSE;
56
57 /**
58 * If set, the menu is about database records, not files. (set if part 2 [1] of the item-var is NOT blank)
59 *
60 * @var bool
61 */
62 public $isDBmenu = FALSE;
63
64 /**
65 * If TRUE, the "content" frame is always used for reference (when condensed mode is enabled)
66 *
67 * @var bool
68 */
69 public $alwaysContentFrame = FALSE;
70
71 /**
72 * Stores the parts of the input $item string, splitted by "|":
73 * [0] = table/file, [1] = uid/blank, [2] = flag: If set, listFrame,
74 * If "2" then "content frame" is forced [3] = ("+" prefix = disable
75 * all by default, enable these. Default is to disable) Items key list
76 *
77 * @var array
78 */
79 public $iParts = array();
80
81 /**
82 * Contains list of keywords of items to disable in the menu
83 *
84 * @var array
85 */
86 public $disabledItems = array();
87
88 /**
89 * If TRUE, Show icons on the left.
90 *
91 * @var bool
92 */
93 public $leftIcons = FALSE;
94
95 /**
96 * Array of classes to be used for user processing of the menu content.
97 * This is for the API of adding items to the menu from outside.
98 *
99 * @var array
100 */
101 public $extClassArray = array();
102
103 /**
104 * Set, when edit icon is drawn.
105 *
106 * @var bool
107 */
108 public $editPageIconSet = FALSE;
109
110 /**
111 * Set to TRUE, if editing of the element is OK.
112 *
113 * @var bool
114 */
115 public $editOK = FALSE;
116
117 /**
118 * The current record
119 *
120 * @var array
121 */
122 public $rec = array();
123
124 /**
125 * Clipboard set from the outside
126 * Declared as public for now, should become protected
127 * soon-ish
128 * @var Clipboard;
129 */
130 public $clipObj;
131
132 /**
133 * The current page record
134 * @var array
135 */
136 protected $pageinfo;
137
138 /**
139 * Language Service property. Used to access localized labels
140 *
141 * @var LanguageService
142 */
143 protected $languageService;
144
145 /**
146 * @var BackendUserAuthentication
147 */
148 protected $backendUser;
149
150 /**
151 * @param LanguageService $languageService Language Service to inject
152 * @param BackendUserAuthentication $backendUser
153 */
154 public function __construct(LanguageService $languageService = NULL, BackendUserAuthentication $backendUser = NULL) {
155 $this->languageService = $languageService ?: $GLOBALS['LANG'];
156 $this->backendUser = $backendUser ?: $GLOBALS['BE_USER'];
157 }
158
159 /**
160 * Initialize click menu
161 *
162 * @return string The clickmenu HTML content
163 */
164 public function init() {
165 $CMcontent = '';
166 // Setting GPvars:
167 $this->cmLevel = (int)GeneralUtility::_GP('cmLevel');
168 $this->CB = GeneralUtility::_GP('CB');
169
170 // Deal with Drag&Drop context menus
171 if ((string)GeneralUtility::_GP('dragDrop') !== '') {
172 return $this->printDragDropClickMenu(GeneralUtility::_GP('dragDrop'), GeneralUtility::_GP('srcId'), GeneralUtility::_GP('dstId'));
173 }
174 // Can be set differently as well
175 $this->iParts[0] = GeneralUtility::_GP('table');
176 $this->iParts[1] = GeneralUtility::_GP('uid');
177 $this->iParts[2] = GeneralUtility::_GP('listFr');
178 $this->iParts[3] = GeneralUtility::_GP('enDisItems');
179 // Setting flags:
180 if ($this->iParts[2]) {
181 $this->listFrame = TRUE;
182 }
183 if ($this->iParts[2] == 2) {
184 $this->alwaysContentFrame = TRUE;
185 }
186 if (isset($this->iParts[1]) && $this->iParts[1] !== '') {
187 $this->isDBmenu = TRUE;
188 }
189 $TSkey = ($this->isDBmenu ? 'page' : 'folder') . ($this->listFrame ? 'List' : 'Tree');
190 $this->disabledItems = GeneralUtility::trimExplode(',', $this->backendUser->getTSConfigVal('options.contextMenu.' . $TSkey . '.disableItems'), TRUE);
191 $this->leftIcons = (bool)$this->backendUser->getTSConfigVal('options.contextMenu.options.leftIcons');
192 // &cmLevel flag detected (2nd level menu)
193 if (!$this->cmLevel) {
194 // Make 1st level clickmenu:
195 if ($this->isDBmenu) {
196 $CMcontent = $this->printDBClickMenu($this->iParts[0], $this->iParts[1]);
197 } else {
198 $CMcontent = $this->printFileClickMenu($this->iParts[0]);
199 }
200 } else {
201 // Make 2nd level clickmenu (only for DBmenus)
202 if ($this->isDBmenu) {
203 $CMcontent = $this->printNewDBLevel($this->iParts[0], $this->iParts[1]);
204 }
205 }
206 // Return clickmenu content:
207 return $CMcontent;
208 }
209
210 /***************************************
211 *
212 * DATABASE
213 *
214 ***************************************/
215 /**
216 * Make 1st level clickmenu:
217 *
218 * @param string $table Table name
219 * @param int $uid UID for the current record.
220 * @return string HTML content
221 */
222 public function printDBClickMenu($table, $uid) {
223 $uid = (int)$uid;
224 // Get record:
225 $this->rec = BackendUtility::getRecordWSOL($table, $uid);
226 $menuItems = array();
227 $root = 0;
228 $DBmount = FALSE;
229 // Rootlevel
230 if ($table === 'pages' && $uid === 0) {
231 $root = 1;
232 }
233 // DB mount
234 if ($table === 'pages' && in_array($uid, $this->backendUser->returnWebmounts())) {
235 $DBmount = TRUE;
236 }
237 // Used to hide cut,copy icons for l10n-records
238 $l10nOverlay = FALSE;
239 // Should only be performed for overlay-records within the same table
240 if (BackendUtility::isTableLocalizable($table) && !isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'])) {
241 $l10nOverlay = (int)$this->rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0;
242 }
243 // If record found (or root), go ahead and fill the $menuItems array which will contain data for the elements to render.
244 if (is_array($this->rec) || $root) {
245 // Get permissions
246 $lCP = $this->backendUser->calcPerms(BackendUtility::getRecord('pages', $table === 'pages' ? $this->rec['uid'] : $this->rec['pid']));
247 // View
248 if (!in_array('view', $this->disabledItems)) {
249 if ($table === 'pages') {
250 $menuItems['view'] = $this->DB_view($uid);
251 }
252 if ($table === 'tt_content') {
253 $ws_rec = BackendUtility::getRecordWSOL($table, $this->rec['uid']);
254 $menuItems['view'] = $this->DB_view($ws_rec['pid']);
255 }
256 }
257 // Edit:
258 if (!$root && ($this->backendUser->isPSet($lCP, $table, 'edit') || $this->backendUser->isPSet($lCP, $table, 'editcontent'))) {
259 if (!in_array('edit', $this->disabledItems)) {
260 $menuItems['edit'] = $this->DB_edit($table, $uid);
261 }
262 $this->editOK = TRUE;
263 }
264 // New:
265 if (!in_array('new', $this->disabledItems) && $this->backendUser->isPSet($lCP, $table, 'new')) {
266 $menuItems['new'] = $this->DB_new($table, $uid);
267 }
268 // Info:
269 if (!in_array('info', $this->disabledItems) && !$root) {
270 $menuItems['info'] = $this->DB_info($table, $uid);
271 }
272 $menuItems['spacer1'] = 'spacer';
273 // Copy:
274 if (!in_array('copy', $this->disabledItems) && !$root && !$DBmount && !$l10nOverlay) {
275 $menuItems['copy'] = $this->DB_copycut($table, $uid, 'copy');
276 }
277 // Cut:
278 if (!in_array('cut', $this->disabledItems) && !$root && !$DBmount && !$l10nOverlay) {
279 $menuItems['cut'] = $this->DB_copycut($table, $uid, 'cut');
280 }
281 // Paste:
282 $elFromAllTables = count($this->clipObj->elFromTable(''));
283 if (!in_array('paste', $this->disabledItems) && $elFromAllTables) {
284 $selItem = $this->clipObj->getSelectedRecord();
285 $elInfo = array(
286 GeneralUtility::fixed_lgd_cs($selItem['_RECORD_TITLE'], $this->backendUser->uc['titleLen']),
287 $root ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] : GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $this->rec), $this->backendUser->uc['titleLen']),
288 $this->clipObj->currentMode()
289 );
290 if ($table === 'pages' && $lCP & 8) {
291 if ($elFromAllTables) {
292 $menuItems['pasteinto'] = $this->DB_paste('', $uid, 'into', $elInfo);
293 }
294 }
295 $elFromTable = count($this->clipObj->elFromTable($table));
296 if (!$root && !$DBmount && $elFromTable && $GLOBALS['TCA'][$table]['ctrl']['sortby']) {
297 $menuItems['pasteafter'] = $this->DB_paste($table, -$uid, 'after', $elInfo);
298 }
299 }
300 $localItems = array();
301 if (!$this->cmLevel && !in_array('moreoptions', $this->disabledItems, TRUE)) {
302 // Creating menu items here:
303 if ($this->editOK) {
304 $localItems[] = 'spacer';
305 $localItems['moreoptions'] = $this->linkItem(
306 $this->label('more'),
307 '',
308 'TYPO3.ClickMenu.fetch(' . GeneralUtility::quoteJSvalue(GeneralUtility::linkThisScript() . '&cmLevel=1&subname=moreoptions') . ');return false;',
309 FALSE,
310 TRUE
311 );
312 $menuItemHideUnhideAllowed = FALSE;
313 $hiddenField = '';
314 // Check if column for disabled is defined
315 if (isset($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'])) {
316 $hiddenField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
317 if (
318 $hiddenField !== '' && !empty($GLOBALS['TCA'][$table]['columns'][$hiddenField]['exclude'])
319 && $this->backendUser->check('non_exclude_fields', $table . ':' . $hiddenField)
320 ) {
321 $menuItemHideUnhideAllowed = TRUE;
322 }
323 }
324 if ($menuItemHideUnhideAllowed && !in_array('hide', $this->disabledItems, TRUE)) {
325 $localItems['hide'] = $this->DB_hideUnhide($table, $this->rec, $hiddenField);
326 }
327 $anyEnableColumnsFieldAllowed = FALSE;
328 // Check if columns are defined
329 if (isset($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) {
330 $columnsToCheck = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns'];
331 if ($table === 'pages' && !empty($columnsToCheck)) {
332 $columnsToCheck[] = 'extendToSubpages';
333 }
334 foreach ($columnsToCheck as $currentColumn) {
335 if (
336 !empty($GLOBALS['TCA'][$table]['columns'][$currentColumn]['exclude'])
337 && $this->backendUser->check('non_exclude_fields', $table . ':' . $currentColumn)
338 ) {
339 $anyEnableColumnsFieldAllowed = TRUE;
340 }
341 }
342 }
343 if ($anyEnableColumnsFieldAllowed && !in_array('edit_access', $this->disabledItems, TRUE)) {
344 $localItems['edit_access'] = $this->DB_editAccess($table, $uid);
345 }
346 if ($table === 'pages' && $this->editPageIconSet && !in_array('edit_pageproperties', $this->disabledItems, TRUE)) {
347 $localItems['edit_pageproperties'] = $this->DB_editPageProperties($uid);
348 }
349 }
350 // Find delete element among the input menu items and insert the local items just before that:
351 $c = 0;
352 $deleteFound = FALSE;
353 foreach ($menuItems as $key => $value) {
354 $c++;
355 if ($key === 'delete') {
356 $deleteFound = TRUE;
357 break;
358 }
359 }
360 if ($deleteFound) {
361 // .. subtract two... (delete item + its spacer element...)
362 $c -= 2;
363 // and insert the items just before the delete element.
364 array_splice($menuItems, $c, 0, $localItems);
365 } else {
366 $menuItems = array_merge($menuItems, $localItems);
367 }
368 }
369
370 // Delete:
371 $elInfo = array(GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $this->rec), $this->backendUser->uc['titleLen']));
372 if (!in_array('delete', $this->disabledItems) && !$root && !$DBmount && $this->backendUser->isPSet($lCP, $table, 'delete')) {
373 $menuItems['spacer2'] = 'spacer';
374 $menuItems['delete'] = $this->DB_delete($table, $uid, $elInfo);
375 }
376 if (!in_array('history', $this->disabledItems)) {
377 $menuItems['history'] = $this->DB_history($table, $uid, $elInfo);
378 }
379 }
380 // Adding external elements to the menuItems array
381 $menuItems = $this->processingByExtClassArray($menuItems, $table, $uid);
382 // Processing by external functions?
383 $menuItems = $this->externalProcessingOfDBMenuItems($menuItems);
384 if (!is_array($this->rec)) {
385 $this->rec = array();
386 }
387 // Return the printed elements:
388 return $this->printItems($menuItems, $root ? IconUtility::getSpriteIcon('apps-pagetree-root') . htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']) : IconUtility::getSpriteIconForRecord($table, $this->rec, array('title' => htmlspecialchars(BackendUtility::getRecordIconAltText($this->rec, $table)))) . BackendUtility::getRecordTitle($table, $this->rec, TRUE));
389 }
390
391 /**
392 * Make 2nd level clickmenu (only for DBmenus)
393 *
394 * @param string $table Table name
395 * @param int $uid UID for the current record.
396 * @return string HTML content
397 */
398 public function printNewDBLevel($table, $uid) {
399 $localItems = [];
400 $uid = (int)$uid;
401 // Setting internal record to the table/uid :
402 $this->rec = BackendUtility::getRecordWSOL($table, $uid);
403 $menuItems = array();
404 $root = 0;
405 // Rootlevel
406 if ($table === 'pages' && $uid === 0) {
407 $root = 1;
408 }
409 // If record was found, check permissions and get menu items.
410 if (is_array($this->rec) || $root) {
411 $lCP = $this->backendUser->calcPerms(BackendUtility::getRecord('pages', $table === 'pages' ? $this->rec['uid'] : $this->rec['pid']));
412 // Edit:
413 if (!$root && ($this->backendUser->isPSet($lCP, $table, 'edit') || $this->backendUser->isPSet($lCP, $table, 'editcontent'))) {
414 $this->editOK = TRUE;
415 }
416 $menuItems = $this->processingByExtClassArray($menuItems, $table, $uid);
417 }
418
419 $subname = GeneralUtility::_GP('subname');
420 if ($subname === 'moreoptions') {
421 // If the page can be edited, then show this:
422 if ($this->editOK) {
423 if (($table === 'pages' || $table === 'tt_content') && !in_array('move_wizard', $this->disabledItems, TRUE)) {
424 $localItems['move_wizard'] = $this->DB_moveWizard($table, $uid, $this->rec);
425 }
426 if (($table === 'pages' || $table === 'tt_content') && !in_array('new_wizard', $this->disabledItems, TRUE)) {
427 $localItems['new_wizard'] = $this->DB_newWizard($table, $uid, $this->rec);
428 }
429 if ($table === 'pages' && !in_array('perms', $this->disabledItems, TRUE) && $this->backendUser->check('modules', 'system_BeuserTxPermission')) {
430 $localItems['perms'] = $this->DB_perms($table, $uid, $this->rec);
431 }
432 if (!in_array('db_list', $this->disabledItems, TRUE) && $this->backendUser->check('modules', 'web_list')) {
433 $localItems['db_list'] = $this->DB_db_list($table, $uid, $this->rec);
434 }
435 }
436 // Temporary mount point item:
437 if ($table === 'pages') {
438 $localItems['temp_mount_point'] = $this->DB_tempMountPoint($uid);
439 }
440 // Merge the locally created items into the current menu items passed to this function.
441 $menuItems = array_merge($menuItems, $localItems);
442 }
443
444 // Return the printed elements:
445 if (!is_array($menuItems)) {
446 $menuItems = array();
447 }
448 return $this->printItems($menuItems, $root ? IconUtility::getSpriteIcon('apps-pagetree-root') . htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']) : IconUtility::getSpriteIconForRecord($table, $this->rec, array('title' => htmlspecialchars(BackendUtility::getRecordIconAltText($this->rec, $table)))) . BackendUtility::getRecordTitle($table, $this->rec, TRUE));
449 }
450
451 /**
452 * Processing the $menuItems array (for extension classes) (DATABASE RECORDS)
453 *
454 * @param array $menuItems Array for manipulation.
455 * @return array Processed $menuItems array
456 */
457 public function externalProcessingOfDBMenuItems($menuItems) {
458 return $menuItems;
459 }
460
461 /**
462 * Processing the $menuItems array by external classes (typ. adding items)
463 *
464 * @param array $menuItems Array for manipulation.
465 * @param string $table Table name
466 * @param int $uid UID for the current record.
467 * @return array Processed $menuItems array
468 */
469 public function processingByExtClassArray($menuItems, $table, $uid) {
470 if (is_array($this->extClassArray)) {
471 foreach ($this->extClassArray as $conf) {
472 $obj = GeneralUtility::makeInstance($conf['name']);
473 $menuItems = $obj->main($this, $menuItems, $table, $uid);
474 }
475 }
476 return $menuItems;
477 }
478
479 /**
480 * Returning JavaScript for the onClick event linking to the input URL.
481 *
482 * @param string $url The URL relative to TYPO3_mainDir
483 * @param string $retUrl The return_url-parameter
484 * @param bool $hideCM If set, the "hideCM()" will be called
485 * @param string $overrideLoc If set, gives alternative location to load in (for example top frame or somewhere else)
486 * @return string JavaScript for an onClick event.
487 */
488 public function urlRefForCM($url, $retUrl = '', $hideCM = TRUE, $overrideLoc = '') {
489 $loc = 'top.content.list_frame';
490 return ($overrideLoc ? 'var docRef=' . $overrideLoc : 'var docRef=(top.content.list_frame)?top.content.list_frame:' . $loc)
491 . '; docRef.location.href=top.TS.PATH_typo3+\'' . $url . '\'' . ($retUrl ? '+\'&' . $retUrl . '=\'+top.rawurlencode('
492 . $this->frameLocation('docRef.document') . '.pathname+' . $this->frameLocation('docRef.document') . '.search)' : '')
493 . ';';
494 }
495
496 /**
497 * Adding CM element for Clipboard "copy" and "cut"
498 *
499 * @param string $table Table name
500 * @param int $uid UID for the current record.
501 * @param string $type Type: "copy" or "cut
502 * @return array Item array, element in $menuItems
503 * @internal
504 */
505 public function DB_copycut($table, $uid, $type) {
506 $isSel = '';
507 if ($this->clipObj->current === 'normal') {
508 $isSel = $this->clipObj->isSelected($table, $uid);
509 }
510 $addParam = array();
511 if ($this->listFrame) {
512 $addParam['reloadListFrame'] = $this->alwaysContentFrame ? 2 : 1;
513 }
514 return $this->linkItem($this->label($type), IconUtility::getSpriteIcon('actions-edit-' . $type . ($isSel === $type ? '-release' : '')), 'TYPO3.ClickMenu.fetch(' . GeneralUtility::quoteJSvalue($this->clipObj->selUrlDB($table, $uid, ($type === 'copy' ? 1 : 0), ($isSel == $type), $addParam)) . ');return false;');
515 }
516
517 /**
518 * Adding CM element for Clipboard "paste into"/"paste after"
519 * NOTICE: $table and $uid should follow the special syntax for paste, see clipboard-class :: pasteUrl();
520 *
521 * @param string $table Table name
522 * @param int $uid UID for the current record. NOTICE: Special syntax!
523 * @param string $type Type: "into" or "after
524 * @param array $elInfo Contains instructions about whether to copy or cut an element.
525 * @return array Item array, element in $menuItems
526 * @see \TYPO3\CMS\Backend\Clipboard\Clipboard::pasteUrl()
527 * @internal
528 */
529 public function DB_paste($table, $uid, $type, $elInfo) {
530 $loc = 'top.content.list_frame';
531 if ($this->backendUser->jsConfirmation(2)) {
532 $conf = $loc . ' && confirm(' . GeneralUtility::quoteJSvalue(sprintf($this->languageService->sL(('LLL:EXT:lang/locallang_core.xlf:mess.' . ($elInfo[2] === 'copy' ? 'copy' : 'move') . '_' . $type)), $elInfo[0], $elInfo[1])) . ')';
533 } else {
534 $conf = $loc;
535 }
536 $editOnClick = 'if(' . $conf . '){' . $loc . '.location.href=top.TS.PATH_typo3+\'' . $this->clipObj->pasteUrl($table, $uid, 0) . '&redirect=\'+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search);}';
537 return $this->linkItem($this->label('paste' . $type), IconUtility::getSpriteIcon('actions-document-paste-' . $type), $editOnClick . 'return false;');
538 }
539
540 /**
541 * Adding CM element for Info
542 *
543 * @param string $table Table name
544 * @param int $uid UID for the current record.
545 * @return array Item array, element in $menuItems
546 * @internal
547 */
548 public function DB_info($table, $uid) {
549 return $this->linkItem($this->label('info'), IconUtility::getSpriteIcon('actions-document-info'), 'top.launchView(\'' . $table . '\', \'' . $uid . '\');');
550 }
551
552 /**
553 * Adding CM element for History
554 *
555 * @param string $table Table name
556 * @param int $uid UID for the current record.
557 * @return array Item array, element in $menuItems
558 * @internal
559 */
560 public function DB_history($table, $uid) {
561 $url = BackendUtility::getModuleUrl('record_history', array('element' => $table . ':' . $uid));
562 return $this->linkItem($this->languageService->makeEntities($this->languageService->getLL('CM_history')), IconUtility::getSpriteIcon('actions-document-history-open'), $this->urlRefForCM($url, 'returnUrl'), 0);
563 }
564
565 /**
566 * Adding CM element for Permission setting
567 *
568 * @param string $table Table name
569 * @param int $uid UID for the current record.
570 * @param array $rec The "pages" record with "perms_*" fields inside.
571 * @return array Item array, element in $menuItems
572 * @internal
573 */
574 public function DB_perms($table, $uid, $rec) {
575 if (!ExtensionManagementUtility::isLoaded('beuser')) {
576 return '';
577 }
578
579 $parameters = array(
580 'id' => $uid,
581 );
582
583 if ($rec['perms_userid'] == $this->backendUser->user['uid'] || $this->backendUser->isAdmin()) {
584 $parameters['return_id'] = $uid;
585 $parameters['edit'] = '1';
586 }
587
588 $url = BackendUtility::getModuleUrl('system_BeuserTxPermission', $parameters);
589 return $this->linkItem($this->languageService->makeEntities($this->languageService->getLL('CM_perms')), IconUtility::getSpriteIcon('status-status-locked'), $this->urlRefForCM($url), 0);
590 }
591
592 /**
593 * Adding CM element for DBlist
594 *
595 * @param string $table Table name
596 * @param int $uid UID for the current record.
597 * @param array $rec Record of the element (needs "pid" field if not pages-record)
598 * @return array Item array, element in $menuItems
599 * @internal
600 */
601 public function DB_db_list($table, $uid, $rec) {
602 $urlParams = array();
603 $urlParams['id'] = $table === 'pages' ? $uid : $rec['pid'];
604 $urlParams['table'] = $table === 'pages' ? '' : $table;
605 $url = BackendUtility::getModuleUrl('web_list', $urlParams, '', TRUE);
606 return $this->linkItem($this->languageService->makeEntities($this->languageService->getLL('CM_db_list')), IconUtility::getSpriteIcon('actions-system-list-open'), 'top.nextLoadModuleUrl=\'' . $url . '\';top.goToModule(\'web_list\', 1);', 0);
607 }
608
609 /**
610 * Adding CM element for Moving wizard
611 *
612 * @param string $table Table name
613 * @param int $uid UID for the current record.
614 * @param array $rec Record. Needed for tt-content elements which will have the sys_language_uid sent
615 * @return array Item array, element in $menuItems
616 * @internal
617 */
618 public function DB_moveWizard($table, $uid, $rec) {
619 // Hardcoded field for tt_content elements.
620 $url = 'move_el.php?table=' . $table . '&uid=' . $uid . ($table === 'tt_content' ? '&sys_language_uid=' . (int)$rec['sys_language_uid'] : '');
621 return $this->linkItem($this->languageService->makeEntities($this->languageService->getLL('CM_moveWizard' . ($table === 'pages' ? '_page' : ''))), IconUtility::getSpriteIcon('actions-' . ($table === 'pages' ? 'page' : 'document') . '-move'), $this->urlRefForCM($url, 'returnUrl'), 0);
622 }
623
624 /**
625 * Adding CM element for Create new wizard (either db_new.php or BackendUtility::getModuleUrl('new_content_element') or custom wizard)
626 *
627 * @param string $table Table name
628 * @param int $uid UID for the current record.
629 * @param array $rec Record.
630 * @return array Item array, element in $menuItems
631 * @internal
632 */
633 public function DB_newWizard($table, $uid, $rec) {
634 // If mod.web_list.newContentWiz.overrideWithExtension is set, use that extension's create new content wizard instead:
635 $tmpTSc = BackendUtility::getModTSconfig($this->pageinfo['uid'], 'mod.web_list');
636 $tmpTSc = $tmpTSc['properties']['newContentWiz.']['overrideWithExtension'];
637
638 $newContentWizScriptPath = ExtensionManagementUtility::isLoaded($tmpTSc) ? ExtensionManagementUtility::extRelPath($tmpTSc) . 'mod1/db_new_content_el.php?' : BackendUtility::getModuleUrl('new_content_element') . '&';
639 $url = $table === 'pages' ? 'db_new.php?id=' . $uid . '&pagesOnly=1' : $newContentWizScriptPath . 'id=' . $rec['pid'] . '&sys_language_uid=' . (int)$rec['sys_language_uid'];
640 return $this->linkItem($this->languageService->makeEntities($this->languageService->getLL('CM_newWizard')), IconUtility::getSpriteIcon('actions-' . ($table === 'pages' ? 'page' : 'document') . '-new'), $this->urlRefForCM($url, 'returnUrl'), 0);
641 }
642
643 /**
644 * Adding CM element for Editing of the access related fields of a table (disable, starttime, endtime, fe_groups)
645 *
646 * @param string $table Table name
647 * @param int $uid UID for the current record.
648 * @return array Item array, element in $menuItems
649 * @internal
650 */
651 public function DB_editAccess($table, $uid) {
652 $addParam = '&columnsOnly=' . rawurlencode((implode(',', $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']) . ($table === 'pages' ? ',extendToSubpages' : '')));
653 $url = 'alt_doc.php?edit[' . $table . '][' . $uid . ']=edit' . $addParam;
654 return $this->linkItem($this->languageService->makeEntities($this->languageService->getLL('CM_editAccess')), IconUtility::getSpriteIcon('actions-document-edit-access'), $this->urlRefForCM($url, 'returnUrl'), 1);
655 }
656
657 /**
658 * Adding CM element for edit page properties
659 *
660 * @param int $uid page uid to edit (PID)
661 * @return array Item array, element in $menuItems
662 * @internal
663 */
664 public function DB_editPageProperties($uid) {
665 $url = 'alt_doc.php?edit[pages][' . $uid . ']=edit';
666 return $this->linkItem($this->languageService->makeEntities($this->languageService->getLL('CM_editPageProperties')), IconUtility::getSpriteIcon('actions-page-open'), $this->urlRefForCM($url, 'returnUrl'), 1);
667 }
668
669 /**
670 * Adding CM element for regular editing of the element!
671 *
672 * @param string $table Table name
673 * @param int $uid UID for the current record.
674 * @return array Item array, element in $menuItems
675 * @internal
676 */
677 public function DB_edit($table, $uid) {
678 // If another module was specified, replace the default Page module with the new one
679 $newPageModule = trim($this->backendUser->getTSConfigVal('options.overridePageModule'));
680 $pageModule = BackendUtility::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
681 $editOnClick = '';
682 $loc = 'top.content.list_frame';
683 $addParam = '';
684 $theIcon = 'actions-document-open';
685 if ($this->iParts[0] === 'pages' && $this->iParts[1] && $this->backendUser->check('modules', $pageModule)) {
686 $this->editPageIconSet = TRUE;
687 if ($this->backendUser->uc['classicPageEditMode']) {
688 $addParam = '&editRegularContentFromId=' . (int)$this->iParts[1];
689 } else {
690 $editOnClick = 'if(' . $loc . '){' . $loc . '.location.href=top.TS.PATH_typo3+\'alt_doc.php?returnUrl=\'+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+\'&edit[' . $table . '][' . $uid . ']=edit' . $addParam . '\';}';
691 }
692 }
693 if (!$editOnClick) {
694 $editOnClick = 'if(' . $loc . '){' . $loc . '.location.href=top.TS.PATH_typo3+\'alt_doc.php?returnUrl=\'+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+\'&edit[' . $table . '][' . $uid . ']=edit' . $addParam . '\';}';
695 }
696 return $this->linkItem($this->label('edit'), IconUtility::getSpriteIcon($theIcon), $editOnClick . ';');
697 }
698
699 /**
700 * Adding CM element for regular Create new element
701 *
702 * @param string $table Table name
703 * @param int $uid UID for the current record.
704 * @return array Item array, element in $menuItems
705 * @internal
706 */
707 public function DB_new($table, $uid) {
708 $loc = 'top.content.list_frame';
709 $editOnClick = 'if(' . $loc . '){' . $loc . '.location.href=top.TS.PATH_typo3+\'' . ($this->listFrame ? 'alt_doc.php?returnUrl=\'+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+\'&edit[' . $table . '][-' . $uid . ']=new\'' : 'db_new.php?id=' . (int)$uid . '\'') . ';}';
710 return $this->linkItem($this->label('new'), IconUtility::getSpriteIcon('actions-' . ($table === 'pages' ? 'page' : 'document') . '-new'), $editOnClick . ';');
711 }
712
713 /**
714 * Adding CM element for Delete
715 *
716 * @param string $table Table name
717 * @param int $uid UID for the current record.
718 * @param array $elInfo Label for including in the confirmation message, EXT:lang/locallang_core.xlf:mess.delete
719 * @return array Item array, element in $menuItems
720 * @internal
721 */
722 public function DB_delete($table, $uid, $elInfo) {
723 $loc = 'top.content.list_frame';
724 if ($this->backendUser->jsConfirmation(4)) {
725 $conf = 'confirm(' . GeneralUtility::quoteJSvalue((sprintf($this->languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.delete'), $elInfo[0]) . BackendUtility::referenceCount($table, $uid, ' (There are %s reference(s) to this record!)') . BackendUtility::translationCount($table, $uid, (' ' . $this->languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.translationsOfRecord'))))) . ')';
726 } else {
727 $conf = '1==1';
728 }
729 $editOnClick = 'if(' . $loc . ' && ' . $conf . ' ){' . $loc . '.location.href=top.TS.PATH_typo3+\'tce_db.php?redirect=\'+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+\'' . '&cmd[' . $table . '][' . $uid . '][delete]=1&prErr=1&vC=' . $this->backendUser->veriCode() . BackendUtility::getUrlToken('tceAction') . '\';};';
730 if ($table === 'pages') {
731 $editOnClick .= 'top.nav.refresh.defer(500, top.nav);';
732 }
733 return $this->linkItem($this->label('delete'), IconUtility::getSpriteIcon('actions-edit-delete'), $editOnClick . 'return false;');
734 }
735
736 /**
737 * Adding CM element for View Page
738 *
739 * @param int $id Page uid (PID)
740 * @param string $anchor Anchor, if any
741 * @return array Item array, element in $menuItems
742 * @internal
743 */
744 public function DB_view($id, $anchor = '') {
745 return $this->linkItem($this->label('view'), IconUtility::getSpriteIcon('actions-document-view'), BackendUtility::viewOnClick($id, '', NULL, $anchor) . ';');
746 }
747
748 /**
749 * Adding element for setting temporary mount point.
750 *
751 * @param int $page_id Page uid (PID)
752 * @return array Item array, element in $menuItems
753 * @internal
754 */
755 public function DB_tempMountPoint($page_id) {
756 return $this->linkItem($this->label('tempMountPoint'), IconUtility::getSpriteIcon('apps-pagetree-page-mountpoint'), 'if (top.content.nav_frame) {
757 var node = top.TYPO3.Backend.NavigationContainer.PageTree.getSelected();
758 if (node === null) {
759 return false;
760 }
761
762 var useNode = {
763 attributes: {
764 nodeData: {
765 id: ' . (int)$page_id . '
766 }
767 }
768 };
769
770 node.ownerTree.commandProvider.mountAsTreeRoot(useNode, node.ownerTree);
771 }
772 ');
773 }
774
775 /**
776 * Adding CM element for hide/unhide of the input record
777 *
778 * @param string $table Table name
779 * @param array $rec Record array
780 * @param string $hideField Name of the hide field
781 * @return array Item array, element in $menuItems
782 * @internal
783 */
784 public function DB_hideUnhide($table, $rec, $hideField) {
785 return $this->DB_changeFlag($table, $rec, $hideField, $this->label(($rec[$hideField] ? 'un' : '') . 'hide'), 'hide');
786 }
787
788 /**
789 * Adding CM element for a flag field of the input record
790 *
791 * @param string $table Table name
792 * @param array $rec Record array
793 * @param string $flagField Name of the flag field
794 * @param string $title Menu item Title
795 * @return array Item array, element in $menuItems
796 */
797 public function DB_changeFlag($table, $rec, $flagField, $title) {
798 $uid = $rec['_ORIG_uid'] ?: $rec['uid'];
799 $loc = 'top.content.list_frame';
800 $editOnClick = 'if(' . $loc . '){' . $loc . '.location.href=top.TS.PATH_typo3+\'tce_db.php?redirect=\'' . '+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+\'' . '&data[' . $table . '][' . $uid . '][' . $flagField . ']=' . ($rec[$flagField] ? 0 : 1) . '&prErr=1&vC=' . $this->backendUser->veriCode() . BackendUtility::getUrlToken('tceAction') . '\';};';
801 if ($table === 'pages') {
802 $editOnClick .= 'top.nav.refresh.defer(500, top.nav);';
803 }
804 return $this->linkItem($title, IconUtility::getSpriteIcon('actions-edit-' . ($rec[$flagField] ? 'un' : '') . 'hide'), $editOnClick . 'return false;', 1);
805 }
806
807 /***************************************
808 *
809 * FILE
810 *
811 ***************************************/
812 /**
813 * Make 1st level clickmenu:
814 *
815 * @param string $combinedIdentifier The combined identifier
816 * @return string HTML content
817 * @see \TYPO3\CMS\Core\Resource\ResourceFactory::retrieveFileOrFolderObject()
818 */
819 public function printFileClickMenu($combinedIdentifier) {
820 $icon = '';
821 $identifier = '';
822 $menuItems = array();
823 $combinedIdentifier = rawurldecode($combinedIdentifier);
824 $fileObject = ResourceFactory::getInstance()
825 ->retrieveFileOrFolderObject($combinedIdentifier);
826 if ($fileObject) {
827 $folder = FALSE;
828 $isStorageRoot = FALSE;
829 $isOnline = TRUE;
830 $userMayViewStorage = FALSE;
831 $userMayEditStorage = FALSE;
832 $identifier = $fileObject->getCombinedIdentifier();
833 if ($fileObject instanceof Folder) {
834 $icon = IconUtility::getSpriteIconForResource($fileObject, array(
835 'class' => 'absmiddle',
836 'title' => htmlspecialchars($fileObject->getName())
837 ));
838 $folder = TRUE;
839 if ($fileObject->getIdentifier() === $fileObject->getStorage()->getRootLevelFolder()->getIdentifier()) {
840 $isStorageRoot = TRUE;
841 if ($this->backendUser->check('tables_select', 'sys_file_storage')) {
842 $userMayViewStorage = TRUE;
843 }
844 if ($this->backendUser->check('tables_modify', 'sys_file_storage')) {
845 $userMayEditStorage = TRUE;
846 }
847 }
848 if (!$fileObject->getStorage()->isOnline()) {
849 $isOnline = FALSE;
850 }
851 } else {
852 $icon = IconUtility::getSpriteIconForResource($fileObject, array(
853 'class' => 'absmiddle',
854 'title' => htmlspecialchars($fileObject->getName() . ' (' . GeneralUtility::formatSize($fileObject->getSize()) . ')')
855 ));
856 }
857 // Hide
858 if (!in_array('hide', $this->disabledItems) && $isStorageRoot && $userMayEditStorage) {
859 $record = BackendUtility::getRecord('sys_file_storage', $fileObject->getStorage()->getUid());
860 $menuItems['hide'] = $this->DB_changeFlag(
861 'sys_file_storage',
862 $record,
863 'is_online',
864 $this->label($record['is_online'] ? 'offline' : 'online'),
865 'hide'
866 );
867 }
868 // Edit
869 if (!in_array('edit', $this->disabledItems) && $fileObject->checkActionPermission('write')) {
870 if (!$folder && !$isStorageRoot && $fileObject->isIndexed() && $this->backendUser->check('tables_modify', 'sys_file_metadata')) {
871 $metaData = $fileObject->_getMetaData();
872 $menuItems['edit2'] = $this->DB_edit('sys_file_metadata', $metaData['uid']);
873 }
874 if (!$folder && GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], $fileObject->getExtension()) && $fileObject->checkActionPermission('write')) {
875 $menuItems['edit'] = $this->FILE_launch($identifier, 'file_edit', 'editcontent', 'actions-page-open');
876 } elseif ($isStorageRoot && $userMayEditStorage) {
877 $menuItems['edit'] = $this->DB_edit('sys_file_storage', $fileObject->getStorage()->getUid());
878 }
879 }
880 // Rename
881 if (!in_array('rename', $this->disabledItems) && !$isStorageRoot && $fileObject->checkActionPermission('rename')) {
882 $menuItems['rename'] = $this->FILE_launch($identifier, 'file_rename', 'rename', 'actions-edit-rename');
883 }
884 // Upload
885 if (!in_array('upload', $this->disabledItems) && $folder && $isOnline && $fileObject->checkActionPermission('write')) {
886 $menuItems['upload'] = $this->FILE_launch($identifier, 'file_upload', 'upload', 'actions-edit-upload');
887 }
888 // New
889 if (!in_array('new', $this->disabledItems) && $folder && $isOnline && $fileObject->checkActionPermission('write')) {
890 $menuItems['new'] = $this->FILE_launch($identifier, 'file_newfolder', 'new', 'actions-document-new');
891 }
892 // Info
893 if (!in_array('info', $this->disabledItems) && $fileObject->checkActionPermission('read')) {
894 if ($isStorageRoot && $userMayViewStorage) {
895 $menuItems['info'] = $this->DB_info('sys_file_storage', $fileObject->getStorage()->getUid());
896 } elseif (!$folder) {
897 $menuItems['info'] = $this->fileInfo($identifier);
898 }
899 }
900 $menuItems[] = 'spacer';
901 // Copy:
902 if (!in_array('copy', $this->disabledItems) && !$isStorageRoot && $fileObject->checkActionPermission('read')) {
903 $menuItems['copy'] = $this->FILE_copycut($identifier, 'copy');
904 }
905 // Cut:
906 if (!in_array('cut', $this->disabledItems) && !$isStorageRoot && $fileObject->checkActionPermission('move')) {
907 $menuItems['cut'] = $this->FILE_copycut($identifier, 'cut');
908 }
909 // Paste:
910 $elFromAllTables = count($this->clipObj->elFromTable('_FILE'));
911 if (!in_array('paste', $this->disabledItems) && $elFromAllTables && $folder && $fileObject->checkActionPermission('write')) {
912 $elArr = $this->clipObj->elFromTable('_FILE');
913 $selItem = reset($elArr);
914 $elInfo = array(
915 basename($selItem),
916 basename($identifier),
917 $this->clipObj->currentMode()
918 );
919 $menuItems['pasteinto'] = $this->FILE_paste($identifier, $selItem, $elInfo);
920 }
921 $menuItems[] = 'spacer';
922 // Delete:
923 if (!in_array('delete', $this->disabledItems) && $fileObject->checkActionPermission('delete')) {
924 if ($isStorageRoot && $userMayEditStorage) {
925 $elInfo = array(GeneralUtility::fixed_lgd_cs($fileObject->getStorage()->getName(), $this->backendUser->uc['titleLen']));
926 $menuItems['delete'] = $this->DB_delete('sys_file_storage', $fileObject->getStorage()->getUid(), $elInfo);
927 } elseif (!$isStorageRoot) {
928 $menuItems['delete'] = $this->FILE_delete($identifier);
929 }
930 }
931 }
932 // Adding external elements to the menuItems array
933 $menuItems = $this->processingByExtClassArray($menuItems, $identifier, 0);
934 // Processing by external functions?
935 $menuItems = $this->externalProcessingOfFileMenuItems($menuItems);
936 // Return the printed elements:
937 return $this->printItems($menuItems, $icon . $fileObject->getName());
938 }
939
940 /**
941 * Processing the $menuItems array (for extension classes) (FILES)
942 *
943 * @param array $menuItems Array for manipulation.
944 * @return array Processed $menuItems array
945 */
946 public function externalProcessingOfFileMenuItems($menuItems) {
947 return $menuItems;
948 }
949
950 /**
951 * Multi-function for adding an entry to the $menuItems array
952 *
953 * @param string $path Path to the file/directory (target)
954 * @param string $moduleName Script (deprecated) or module name (e.g. file_edit) to pass &target= to
955 * @param string $type "type" is the code which fetches the correct label for the element from "cm.
956 * @param string $iconName
957 * @param bool $noReturnUrl If set, the return URL parameter will not be set in the link
958 * @return array Item array, element in $menuItems
959 * @internal
960 */
961 public function FILE_launch($path, $moduleName, $type, $iconName, $noReturnUrl = FALSE) {
962 $loc = 'top.content.list_frame';
963
964 if (strpos($moduleName, '.php') !== FALSE) {
965 GeneralUtility::deprecationLog(
966 'Using a php file directly in ClickMenu is deprecated since TYPO3 CMS 7, and will be removed in CMS 8.'
967 . ' Register the class as module and use BackendUtility::getModuleUrl() to get the right link.'
968 . ' For examples how to do this see ext_tables.php of EXT:backend.'
969 );
970 $scriptUrl = $moduleName;
971 } else {
972 $scriptUrl = BackendUtility::getModuleUrl($moduleName);
973 }
974
975 $editOnClick = 'if(' . $loc . '){' . $loc . '.location.href=top.TS.PATH_typo3+' . GeneralUtility::quoteJSvalue($scriptUrl . '&target=' . rawurlencode($path)) . ($noReturnUrl ? '' : '+\'&returnUrl=\'+top.rawurlencode(' . $this->frameLocation($loc . '.document') . '.pathname+' . $this->frameLocation($loc . '.document') . '.search)') . ';}';
976 return $this->linkItem($this->label($type), IconUtility::getSpriteIcon($iconName), $editOnClick . 'top.nav.refresh();');
977 }
978
979 /**
980 * Returns element for copy or cut of files.
981 *
982 * @param string $path Path to the file/directory (target)
983 * @param string $type Type: "copy" or "cut
984 * @return array Item array, element in $menuItems
985 * @internal
986 */
987 public function FILE_copycut($path, $type) {
988 $isSel = '';
989 // Pseudo table name for use in the clipboard.
990 $table = '_FILE';
991 $uid = GeneralUtility::shortmd5($path);
992 if ($this->clipObj->current === 'normal') {
993 $isSel = $this->clipObj->isSelected($table, $uid);
994 }
995 $addParam = array();
996 if ($this->listFrame) {
997 $addParam['reloadListFrame'] = $this->alwaysContentFrame ? 2 : 1;
998 }
999 return $this->linkItem($this->label($type), IconUtility::getSpriteIcon('actions-edit-' . $type . ($isSel === $type ? '-release' : '')), 'TYPO3.ClickMenu.fetch(' . GeneralUtility::quoteJSvalue($this->clipObj->selUrlFile($path, ($type === 'copy' ? 1 : 0), ($isSel == $type), $addParam)) . ');return false;');
1000 }
1001
1002 /**
1003 * Creates element for deleting of target
1004 *
1005 * @param string $path Path to the file/directory (target)
1006 * @return array Item array, element in $menuItems
1007 * @internal
1008 */
1009 public function FILE_delete($path) {
1010 $loc = 'top.content.list_frame';
1011 if ($this->backendUser->jsConfirmation(4)) {
1012 $conf = 'confirm(' . GeneralUtility::quoteJSvalue((sprintf($this->languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.delete'), basename($path)) . BackendUtility::referenceCount('_FILE', $path, ' (There are %s reference(s) to this file!)'))) . ')';
1013 } else {
1014 $conf = '1==1';
1015 }
1016 $editOnClick = 'if(' . $loc . ' && ' . $conf . ' ){' . $loc . '.location.href=top.TS.PATH_typo3+\'tce_file.php?redirect=\'+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+\'' . '&file[delete][0][data]=' . rawurlencode($path) . '&vC=' . $this->backendUser->veriCode() . BackendUtility::getUrlToken('tceAction') . '\';};';
1017 return $this->linkItem($this->label('delete'), IconUtility::getSpriteIcon('actions-edit-delete'), $editOnClick . 'return false;');
1018 }
1019
1020 /**
1021 * Creates element for pasting files.
1022 *
1023 * @param string $path Path to the file/directory (target)
1024 * @param string $target target - NOT USED.
1025 * @param array $elInfo Various values for the labels.
1026 * @return array Item array, element in $menuItems
1027 * @internal
1028 */
1029 public function FILE_paste($path, $target, $elInfo) {
1030 $loc = 'top.content.list_frame';
1031 if ($this->backendUser->jsConfirmation(2)) {
1032 $conf = $loc . ' && confirm(' . GeneralUtility::quoteJSvalue(sprintf($this->languageService->sL(('LLL:EXT:lang/locallang_core.xlf:mess.' . ($elInfo[2] === 'copy' ? 'copy' : 'move') . '_into')), $elInfo[0], $elInfo[1])) . ')';
1033 } else {
1034 $conf = $loc;
1035 }
1036 $editOnClick = 'if(' . $conf . '){' . $loc . '.location.href=top.TS.PATH_typo3+\'' . $this->clipObj->pasteUrl('_FILE', $path, 0) . '&redirect=\'+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search); };top.nav.refresh();';
1037 return $this->linkItem($this->label('pasteinto'), IconUtility::getSpriteIcon('actions-document-paste-into'), $editOnClick . 'return false;');
1038 }
1039
1040 /**
1041 * Adding ClickMenu element for file info
1042 *
1043 * @param string $identifier The combined identifier of the file.
1044 * @return array Item array, element in $menuItems
1045 */
1046 protected function fileInfo($identifier) {
1047 return $this->DB_info('_FILE', $identifier);
1048 }
1049
1050 /***************************************
1051 *
1052 * DRAG AND DROP
1053 *
1054 ***************************************/
1055 /**
1056 * Make 1st level clickmenu:
1057 *
1058 * @param string $table The absolute path
1059 * @param int $srcId UID for the current record.
1060 * @param int $dstId Destination ID
1061 * @return string HTML content
1062 */
1063 public function printDragDropClickMenu($table, $srcId, $dstId) {
1064 $menuItems = array();
1065 // If the drag and drop menu should apply to PAGES use this set of menu items
1066 if ($table === 'pages') {
1067 // Move Into:
1068 $menuItems['movePage_into'] = $this->dragDrop_copymovepage($srcId, $dstId, 'move', 'into');
1069 // Move After:
1070 $menuItems['movePage_after'] = $this->dragDrop_copymovepage($srcId, $dstId, 'move', 'after');
1071 // Copy Into:
1072 $menuItems['copyPage_into'] = $this->dragDrop_copymovepage($srcId, $dstId, 'copy', 'into');
1073 // Copy After:
1074 $menuItems['copyPage_after'] = $this->dragDrop_copymovepage($srcId, $dstId, 'copy', 'after');
1075 }
1076 // If the drag and drop menu should apply to FOLDERS use this set of menu items
1077 if ($table === 'folders') {
1078 // Move Into:
1079 $menuItems['moveFolder_into'] = $this->dragDrop_copymovefolder($srcId, $dstId, 'move');
1080 // Copy Into:
1081 $menuItems['copyFolder_into'] = $this->dragDrop_copymovefolder($srcId, $dstId, 'copy');
1082 }
1083 // Adding external elements to the menuItems array
1084 $menuItems = $this->processingByExtClassArray($menuItems, 'dragDrop_' . $table, $srcId);
1085 // to extend this, you need to apply a Context Menu to a "virtual" table called "dragDrop_pages" or similar
1086 // Processing by external functions?
1087 $menuItems = $this->externalProcessingOfDBMenuItems($menuItems);
1088 // Return the printed elements:
1089 return $this->printItems($menuItems, IconUtility::getSpriteIconForRecord($table, $this->rec, array('title' => BackendUtility::getRecordTitle($table, $this->rec, TRUE))));
1090 }
1091
1092 /**
1093 * Processing the $menuItems array (for extension classes) (DRAG'N DROP)
1094 *
1095 * @param array $menuItems Array for manipulation.
1096 * @return array Processed $menuItems array
1097 */
1098 public function externalProcessingOfDragDropMenuItems($menuItems) {
1099 return $menuItems;
1100 }
1101
1102 /**
1103 * Adding CM element for Copying/Moving a Page Into/After from a drag & drop action
1104 *
1105 * @param int $srcUid source UID code for the record to modify
1106 * @param int $dstUid destination UID code for the record to modify
1107 * @param string $action Action code: either "move" or "copy
1108 * @param string $into Parameter code: either "into" or "after
1109 * @return array Item array, element in $menuItems
1110 * @internal
1111 */
1112 public function dragDrop_copymovepage($srcUid, $dstUid, $action, $into) {
1113 $negativeSign = $into === 'into' ? '' : '-';
1114 $loc = 'top.content.list_frame';
1115 $editOnClick = 'if(' . $loc . '){' . $loc . '.document.location=top.TS.PATH_typo3+"tce_db.php?redirect="+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+"' . '&cmd[pages][' . $srcUid . '][' . $action . ']=' . $negativeSign . $dstUid . '&prErr=1&vC=' . $this->backendUser->veriCode() . BackendUtility::getUrlToken('tceAction') . '";};top.nav.refresh();';
1116 return $this->linkItem($this->label($action . 'Page_' . $into), IconUtility::getSpriteIcon('actions-document-paste-' . $into), $editOnClick . 'return false;', 0);
1117 }
1118
1119 /**
1120 * Adding CM element for Copying/Moving a Folder Into from a drag & drop action
1121 *
1122 * @param string $srcPath source path for the record to modify
1123 * @param string $dstPath destination path for the records to modify
1124 * @param string $action Action code: either "move" or "copy
1125 * @return array Item array, element in $menuItems
1126 * @internal
1127 */
1128 public function dragDrop_copymovefolder($srcPath, $dstPath, $action) {
1129 $loc = 'top.content.list_frame';
1130 $editOnClick = 'if(' . $loc . '){' . $loc . '.document.location=top.TS.PATH_typo3+"tce_file.php?redirect="+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+"' . '&file[' . $action . '][0][data]=' . $srcPath . '&file[' . $action . '][0][target]=' . $dstPath . '&prErr=1&vC=' . $this->backendUser->veriCode() . BackendUtility::getUrlToken('tceAction') . '";};top.nav.refresh();';
1131 return $this->linkItem($this->label($action . 'Folder_into'), IconUtility::getSpriteIcon('apps-pagetree-drag-move-into'), $editOnClick . 'return false;', 0);
1132 }
1133
1134 /***************************************
1135 *
1136 * COMMON
1137 *
1138 **************************************/
1139 /**
1140 * Prints the items from input $menuItems array - as JS section for writing to the div-layers.
1141 *
1142 * @param array $menuItems Array
1143 * @return string HTML code
1144 */
1145 public function printItems($menuItems) {
1146 // Enable/Disable items
1147 $menuItems = $this->enableDisableItems($menuItems);
1148 // Clean up spacers
1149 $menuItems = $this->cleanUpSpacers($menuItems);
1150 // Adding JS part and return the content
1151 return $this->printLayerJScode($menuItems);
1152 }
1153
1154 /**
1155 * Create the JavaScript section
1156 *
1157 * @param array $menuItems The $menuItems array to print
1158 * @return string The JavaScript section which will print the content of the CM to the div-layer in the target frame.
1159 */
1160 public function printLayerJScode($menuItems) {
1161 // Clipboard must not be submitted - then it's probably a copy/cut situation.
1162 if ($this->isCMlayers()) {
1163 // Create the table displayed in the clickmenu layer:
1164 // Wrap the inner table in another table to create outer border:
1165 $CMtable = '
1166 <div class="typo3-CSM-wrapperCM">
1167 <table border="0" cellpadding="0" cellspacing="0" class="typo3-CSM">
1168 ' . implode('', $this->menuItemsForClickMenu($menuItems)) . '
1169 </table></div>';
1170 return '<data><clickmenu><htmltable><![CDATA[' . $CMtable . ']]></htmltable><cmlevel>' . $this->cmLevel . '</cmlevel></clickmenu></data>';
1171 }
1172 }
1173
1174 /**
1175 * Wrapping the input string in a table with background color 4 and a black border style.
1176 * For the pop-up menu
1177 *
1178 * @param string $str HTML content to wrap in table.
1179 * @return string
1180 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1181 */
1182 public function wrapColorTableCM($str) {
1183 GeneralUtility::logDeprecatedFunction();
1184 return '<div class="typo3-CSM-wrapperCM">
1185 ' . $str . '
1186 </div>';
1187 }
1188
1189 /**
1190 * Traverses the menuItems and generates an output array for implosion in the CM div-layers table.
1191 *
1192 * @param array $menuItems Array
1193 * @return array array for implosion in the CM div-layers table.
1194 */
1195 public function menuItemsForClickMenu($menuItems) {
1196 $out = array();
1197 foreach ($menuItems as $cc => $i) {
1198 // MAKE horizontal spacer
1199 if (is_string($i) && $i === 'spacer') {
1200 $out[] = '
1201 <tr style="height: 1px;" class="bgColor2">
1202 <td colspan="2"></td>
1203 </tr>';
1204 } else {
1205 // Just make normal element:
1206 $onClick = $i[3];
1207 $onClick = preg_replace('/return[[:space:]]+hideCM\\(\\)[[:space:]]*;/i', '', $onClick);
1208 $onClick = preg_replace('/return[[:space:]]+false[[:space:]]*;/i', '', $onClick);
1209 $onClick = preg_replace('/hideCM\\(\\);/i', '', $onClick);
1210 if (!$i[5]) {
1211 $onClick .= 'TYPO3.ClickMenu.hideAll();';
1212 }
1213 $CSM = ' oncontextmenu="this.click();return false;"';
1214 $out[] = '
1215 <tr class="typo3-CSM-itemRow" onclick="' . htmlspecialchars($onClick) . '"' . $CSM . '>
1216 ' . (!$this->leftIcons ? '<td class="typo3-CSM-item">' . $i[1] . '</td><td align="center">' . $i[2] . '</td>' : '<td align="center">' . $i[2] . '</td><td class="typo3-CSM-item">' . $i[1] . '</td>') . '
1217 </tr>';
1218 }
1219 }
1220 return $out;
1221 }
1222
1223 /**
1224 * Adds or inserts a menu item
1225 * Can be used to set the position of new menu entries within the list of existing menu entries. Has this syntax: [cmd]:[menu entry key],[cmd].... cmd can be "after", "before" or "top" (or blank/"bottom" which is default). If "after"/"before" then menu items will be inserted after/before the existing entry with [menu entry key] if found. "after-spacer" and "before-spacer" do the same, but inserts before or after an item and a spacer. If not found, the bottom of list. If "top" the items are inserted in the top of the list.
1226 *
1227 * @param array $menuItems Menu items array
1228 * @param array $newMenuItems Menu items array to insert
1229 * @param string $position Position command string. Has this syntax: [cmd]:[menu entry key],[cmd].... cmd can be "after", "before" or "top" (or blank/"bottom" which is default). If "after"/"before" then menu items will be inserted after/before the existing entry with [menu entry key] if found. "after-spacer" and "before-spacer" do the same, but inserts before or after an item and a spacer. If not found, the bottom of list. If "top" the items are inserted in the top of the list.
1230 * @return array Menu items array, processed.
1231 */
1232 public function addMenuItems($menuItems, $newMenuItems, $position = '') {
1233 if (is_array($newMenuItems)) {
1234 if ($position) {
1235 $posArr = GeneralUtility::trimExplode(',', $position, TRUE);
1236 foreach ($posArr as $pos) {
1237 list($place, $menuEntry) = GeneralUtility::trimExplode(':', $pos, TRUE);
1238 list($place, $placeExtra) = GeneralUtility::trimExplode('-', $place, TRUE);
1239 // Bottom
1240 $pointer = count($menuItems);
1241 $found = FALSE;
1242 if ($place) {
1243 switch (strtolower($place)) {
1244 case 'after':
1245 case 'before':
1246 if ($menuEntry) {
1247 $p = 1;
1248 reset($menuItems);
1249 while (TRUE) {
1250 if ((string)key($menuItems) === $menuEntry) {
1251 $pointer = $p;
1252 $found = TRUE;
1253 break;
1254 }
1255 if (!next($menuItems)) {
1256 break;
1257 }
1258 $p++;
1259 }
1260 if (!$found) {
1261 break;
1262 }
1263 if ($place === 'before') {
1264 $pointer--;
1265 if ($placeExtra === 'spacer' and prev($menuItems) === 'spacer') {
1266 $pointer--;
1267 }
1268 } elseif ($place === 'after') {
1269 if ($placeExtra === 'spacer' and next($menuItems) === 'spacer') {
1270 $pointer++;
1271 }
1272 }
1273 }
1274 break;
1275 default:
1276 if (strtolower($place) === 'top') {
1277 $pointer = 0;
1278 } else {
1279 $pointer = count($menuItems);
1280 }
1281 $found = TRUE;
1282 }
1283 }
1284 if ($found) {
1285 break;
1286 }
1287 }
1288 }
1289 $pointer = max(0, $pointer);
1290 $menuItemsBefore = array_slice($menuItems, 0, $pointer ?: 0);
1291 $menuItemsAfter = array_slice($menuItems, $pointer);
1292 $menuItems = $menuItemsBefore + $newMenuItems + $menuItemsAfter;
1293 }
1294 return $menuItems;
1295 }
1296
1297 /**
1298 * Creating an array with various elements for the clickmenu entry
1299 *
1300 * @param string $str The label, htmlspecialchar'ed already
1301 * @param string $icon <img>-tag for the icon
1302 * @param string $onClick JavaScript onclick event for label/icon
1303 * @param int $onlyCM ==1 and the element will NOT appear in clickmenus in the topframe (unless clickmenu is totally unavailable)! ==2 and the item will NEVER appear in top frame. (This is mostly for "less important" options since the top frame is not capable of holding so many elements horizontally)
1304 * @param bool $dontHide If set, the clickmenu layer will not hide itself onclick - used for secondary menus to appear...
1305 * @return array $menuItem entry with 6 numerical entries: [0] is the HTML for display of the element with link and icon an mouseover etc., [1]-[5] is simply the input params passed through!
1306 */
1307 public function linkItem($str, $icon, $onClick, $onlyCM = 0, $dontHide = 0) {
1308 $onClick = str_replace('top.loadTopMenu', 'showClickmenu_raw', $onClick);
1309 return array(
1310 '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' . $str . $icon . '</a>',
1311 $str,
1312 $icon,
1313 $onClick,
1314 $onlyCM,
1315 $dontHide
1316 );
1317 }
1318
1319 /**
1320 * Returns the input string IF not a user setting has disabled display of icons.
1321 *
1322 * @param string $iconCode The icon-image tag
1323 * @return string The icon-image tag prefixed with space char IF the icon should be printed at all due to user settings
1324 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1325 */
1326 public function excludeIcon($iconCode) {
1327 GeneralUtility::logDeprecatedFunction();
1328 return $this->backendUser->uc['noMenuMode'] && $this->backendUser->uc['noMenuMode'] !== 'icons' ? '' : ' ' . $iconCode;
1329 }
1330
1331 /**
1332 * Enabling / Disabling items based on list provided from GET var ($this->iParts[3])
1333 *
1334 * @param array $menuItems Menu items array
1335 * @return array Menu items array, processed.
1336 */
1337 public function enableDisableItems($menuItems) {
1338 if ($this->iParts[3]) {
1339 // Detect "only" mode: (only showing listed items)
1340 if ($this->iParts[3][0] === '+') {
1341 $this->iParts[3] = substr($this->iParts[3], 1);
1342 $only = TRUE;
1343 } else {
1344 $only = FALSE;
1345 }
1346 // Do filtering:
1347 // Transfer ONLY elements which are mentioned (or are spacers)
1348 if ($only) {
1349 $newMenuArray = array();
1350 foreach ($menuItems as $key => $value) {
1351 if (GeneralUtility::inList($this->iParts[3], $key) || is_string($value) && $value === 'spacer') {
1352 $newMenuArray[$key] = $value;
1353 }
1354 }
1355 $menuItems = $newMenuArray;
1356 } else {
1357 // Traverse all elements except those listed (just unsetting them):
1358 $elements = GeneralUtility::trimExplode(',', $this->iParts[3], TRUE);
1359 foreach ($elements as $value) {
1360 unset($menuItems[$value]);
1361 }
1362 }
1363 }
1364 // Return processed menu items:
1365 return $menuItems;
1366 }
1367
1368 /**
1369 * Clean up spacers; Will remove any spacers in the start/end of menu items array plus any duplicates.
1370 *
1371 * @param array $menuItems Menu items array
1372 * @return array Menu items array, processed.
1373 */
1374 public function cleanUpSpacers($menuItems) {
1375 // Remove doubles:
1376 $prevItemWasSpacer = FALSE;
1377 foreach ($menuItems as $key => $value) {
1378 if (is_string($value) && $value === 'spacer') {
1379 if ($prevItemWasSpacer) {
1380 unset($menuItems[$key]);
1381 }
1382 $prevItemWasSpacer = TRUE;
1383 } else {
1384 $prevItemWasSpacer = FALSE;
1385 }
1386 }
1387 // Remove first:
1388 reset($menuItems);
1389 $key = key($menuItems);
1390 $value = current($menuItems);
1391 if (is_string($value) && $value === 'spacer') {
1392 unset($menuItems[$key]);
1393 }
1394 // Remove last:
1395 end($menuItems);
1396 $key = key($menuItems);
1397 $value = current($menuItems);
1398 if (is_string($value) && $value === 'spacer') {
1399 unset($menuItems[$key]);
1400 }
1401 // Return processed menu items:
1402 return $menuItems;
1403 }
1404
1405 /**
1406 * Get label from locallang_core.xlf:cm.*
1407 *
1408 * @param string $label The "cm."-suffix to get.
1409 * @return string
1410 */
1411 public function label($label) {
1412 return $this->languageService->makeEntities($this->languageService->sL('LLL:EXT:lang/locallang_core.xlf:cm.' . $label, TRUE));
1413 }
1414
1415 /**
1416 * Returns TRUE if there should be writing to the div-layers (commands sent to clipboard MUST NOT write to div-layers)
1417 *
1418 * @return bool
1419 */
1420 public function isCMlayers() {
1421 return !$this->CB;
1422 }
1423
1424 /**
1425 * Appends ".location" to input string
1426 *
1427 * @param string $str Input string, probably a JavaScript document reference
1428 * @return string
1429 */
1430 public function frameLocation($str) {
1431 return $str . '.location';
1432 }
1433
1434 }