ClickMenu.php 58.8 KB
Newer Older
1
2
3
<?php
namespace TYPO3\CMS\Backend\ClickMenu;

4
/*
5
 * This file is part of the TYPO3 CMS project.
6
 *
7
8
9
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
10
 *
11
12
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
13
 *
14
15
 * The TYPO3 project - inspiring people to share!
 */
16

17
use TYPO3\CMS\Backend\Clipboard\Clipboard;
18
use TYPO3\CMS\Backend\Utility\BackendUtility;
19
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
20
21
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
22
use TYPO3\CMS\Core\Resource\Folder;
Nicole Cordes's avatar
Nicole Cordes committed
23
use TYPO3\CMS\Core\Resource\ResourceFactory;
24
25
use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
use TYPO3\CMS\Core\Type\Bitmask\Permission;
Nicole Cordes's avatar
Nicole Cordes committed
26
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
27
use TYPO3\CMS\Core\Utility\GeneralUtility;
28
use TYPO3\CMS\Lang\LanguageService;
29
30
31
32
33
34
35

/**
 * Class for generating the click menu
 * @internal
 */
class ClickMenu {

36
37
38
39
40
41
	/**
	 * Defines if the click menu is first level or second.
	 * Second means the click menu is triggered from another menu.
	 *
	 * @var int
	 */
42
43
	public $cmLevel = 0;

44
45
46
47
48
	/**
	 * Clipboard array (submitted by eg. pressing the paste button)
	 *
	 * @var bool
	 */
49
50
	public $CB;

51
52
53
54
55
56
	/**
	 * If set, the calling document should be in the listframe of a frameset.
	 *
	 * @var bool
	 */
	public $listFrame = FALSE;
57

58
59
60
61
62
63
	/**
	 * If set, the menu is about database records, not files. (set if part 2 [1] of the item-var is NOT blank)
	 *
	 * @var bool
	 */
	public $isDBmenu = FALSE;
64

65
66
67
68
69
70
	/**
	 * If TRUE, the "content" frame is always used for reference (when condensed mode is enabled)
	 *
	 * @var bool
	 */
	public $alwaysContentFrame = FALSE;
71

72
73
74
75
76
77
78
79
	/**
	 * Stores the parts of the input $item string, splitted by "|":
	 * [0] = table/file, [1] = uid/blank, [2] = flag: If set, listFrame,
	 * If "2" then "content frame" is forced  [3] = ("+" prefix = disable
	 * all by default, enable these. Default is to disable) Items key list
	 *
	 * @var array
	 */
80
81
	public $iParts = array();

82
83
84
85
86
	/**
	 * Contains list of keywords of items to disable in the menu
	 *
	 * @var array
	 */
87
88
	public $disabledItems = array();

89
90
91
92
93
94
	/**
	 * If TRUE, Show icons on the left.
	 *
	 * @var bool
	 */
	public $leftIcons = FALSE;
95

96
97
98
99
100
101
	/**
	 * Array of classes to be used for user processing of the menu content.
	 * This is for the API of adding items to the menu from outside.
	 *
	 * @var array
	 */
102
103
	public $extClassArray = array();

104
105
106
107
108
109
	/**
	 * Set, when edit icon is drawn.
	 *
	 * @var bool
	 */
	public $editPageIconSet = FALSE;
110

111
112
113
114
115
116
	/**
	 * Set to TRUE, if editing of the element is OK.
	 *
	 * @var bool
	 */
	public $editOK = FALSE;
117

118
119
120
121
122
	/**
	 * The current record
	 *
	 * @var array
	 */
123
124
	public $rec = array();

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
	/**
	 * Clipboard set from the outside
	 * Declared as public for now, should become protected
	 * soon-ish
	 * @var Clipboard;
	 */
	public $clipObj;

	/**
	 * The current page record
	 * @var array
	 */
	protected $pageinfo;

	/**
	 * Language Service property. Used to access localized labels
	 *
	 * @var LanguageService
	 */
	protected $languageService;

	/**
	 * @var BackendUserAuthentication
	 */
	protected $backendUser;

151
152
153
154
155
	/**
	 * @var IconFactory
	 */
	protected $iconFactory;

156
157
158
159
160
	/**
	 * @param LanguageService $languageService Language Service to inject
	 * @param BackendUserAuthentication $backendUser
	 */
	public function __construct(LanguageService $languageService = NULL, BackendUserAuthentication $backendUser = NULL) {
161
162
		$this->languageService = $languageService ?: $GLOBALS['LANG'];
		$this->backendUser = $backendUser ?: $GLOBALS['BE_USER'];
163
		$this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
164
	}
165

166
167
168
169
170
171
	/**
	 * Initialize click menu
	 *
	 * @return string The clickmenu HTML content
	 */
	public function init() {
172
		$CMcontent = '';
173
		// Setting GPvars:
174
		$this->cmLevel = (int)GeneralUtility::_GP('cmLevel');
175
		$this->CB = GeneralUtility::_GP('CB');
176

177
		// Deal with Drag&Drop context menus
178
179
		if ((string)GeneralUtility::_GP('dragDrop') !== '') {
			return $this->printDragDropClickMenu(GeneralUtility::_GP('dragDrop'), GeneralUtility::_GP('srcId'), GeneralUtility::_GP('dstId'));
180
181
182
183
184
185
186
187
		}
		// Can be set differently as well
		$this->iParts[0] = GeneralUtility::_GP('table');
		$this->iParts[1] = GeneralUtility::_GP('uid');
		$this->iParts[2] = GeneralUtility::_GP('listFr');
		$this->iParts[3] = GeneralUtility::_GP('enDisItems');
		// Setting flags:
		if ($this->iParts[2]) {
188
			$this->listFrame = TRUE;
189
		}
190
		if ($this->iParts[2] == 2) {
191
			$this->alwaysContentFrame = TRUE;
192
		}
193
		if (isset($this->iParts[1]) && $this->iParts[1] !== '') {
194
			$this->isDBmenu = TRUE;
195
196
		}
		$TSkey = ($this->isDBmenu ? 'page' : 'folder') . ($this->listFrame ? 'List' : 'Tree');
197
198
		$this->disabledItems = GeneralUtility::trimExplode(',', $this->backendUser->getTSConfigVal('options.contextMenu.' . $TSkey . '.disableItems'), TRUE);
		$this->leftIcons = (bool)$this->backendUser->getTSConfigVal('options.contextMenu.options.leftIcons');
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
		// &cmLevel flag detected (2nd level menu)
		if (!$this->cmLevel) {
			// Make 1st level clickmenu:
			if ($this->isDBmenu) {
				$CMcontent = $this->printDBClickMenu($this->iParts[0], $this->iParts[1]);
			} else {
				$CMcontent = $this->printFileClickMenu($this->iParts[0]);
			}
		} else {
			// Make 2nd level clickmenu (only for DBmenus)
			if ($this->isDBmenu) {
				$CMcontent = $this->printNewDBLevel($this->iParts[0], $this->iParts[1]);
			}
		}
		// Return clickmenu content:
		return $CMcontent;
	}

	/***************************************
	 *
	 * DATABASE
	 *
	 ***************************************/
	/**
	 * Make 1st level clickmenu:
	 *
	 * @param string $table Table name
226
	 * @param int $uid UID for the current record.
227
228
229
	 * @return string HTML content
	 */
	public function printDBClickMenu($table, $uid) {
230
		$uid = (int)$uid;
231
		// Get record:
Nicole Cordes's avatar
Nicole Cordes committed
232
		$this->rec = BackendUtility::getRecordWSOL($table, $uid);
233
234
235
236
		$menuItems = array();
		$root = 0;
		$DBmount = FALSE;
		// Rootlevel
237
		if ($table === 'pages' && $uid === 0) {
238
239
240
			$root = 1;
		}
		// DB mount
241
		if ($table === 'pages' && in_array($uid, $this->backendUser->returnWebmounts())) {
242
243
244
245
246
			$DBmount = TRUE;
		}
		// Used to hide cut,copy icons for l10n-records
		$l10nOverlay = FALSE;
		// Should only be performed for overlay-records within the same table
Nicole Cordes's avatar
Nicole Cordes committed
247
		if (BackendUtility::isTableLocalizable($table) && !isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'])) {
248
			$l10nOverlay = (int)$this->rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0;
249
250
251
252
		}
		// If record found (or root), go ahead and fill the $menuItems array which will contain data for the elements to render.
		if (is_array($this->rec) || $root) {
			// Get permissions
253
			$lCP = $this->backendUser->calcPerms(BackendUtility::getRecord('pages', $table === 'pages' ? $this->rec['uid'] : $this->rec['pid']));
254
255
			// View
			if (!in_array('view', $this->disabledItems)) {
256
				if ($table === 'pages') {
257
258
					$menuItems['view'] = $this->DB_view($uid);
				}
259
				if ($table === 'tt_content') {
Nicole Cordes's avatar
Nicole Cordes committed
260
					$ws_rec = BackendUtility::getRecordWSOL($table, $this->rec['uid']);
261
262
263
264
					$menuItems['view'] = $this->DB_view($ws_rec['pid']);
				}
			}
			// Edit:
265
			if (!$root && ($this->backendUser->isPSet($lCP, $table, 'edit') || $this->backendUser->isPSet($lCP, $table, 'editcontent'))) {
266
267
268
				if (!in_array('edit', $this->disabledItems)) {
					$menuItems['edit'] = $this->DB_edit($table, $uid);
				}
269
				$this->editOK = TRUE;
270
271
			}
			// New:
272
			if (!in_array('new', $this->disabledItems) && $this->backendUser->isPSet($lCP, $table, 'new')) {
273
274
275
276
277
278
279
280
				$menuItems['new'] = $this->DB_new($table, $uid);
			}
			// Info:
			if (!in_array('info', $this->disabledItems) && !$root) {
				$menuItems['info'] = $this->DB_info($table, $uid);
			}
			$menuItems['spacer1'] = 'spacer';
			// Copy:
281
			if (!in_array('copy', $this->disabledItems) && !$root && !$DBmount && !$l10nOverlay) {
282
283
284
				$menuItems['copy'] = $this->DB_copycut($table, $uid, 'copy');
			}
			// Cut:
285
			if (!in_array('cut', $this->disabledItems) && !$root && !$DBmount && !$l10nOverlay) {
286
287
288
289
290
291
292
				$menuItems['cut'] = $this->DB_copycut($table, $uid, 'cut');
			}
			// Paste:
			$elFromAllTables = count($this->clipObj->elFromTable(''));
			if (!in_array('paste', $this->disabledItems) && $elFromAllTables) {
				$selItem = $this->clipObj->getSelectedRecord();
				$elInfo = array(
293
294
					GeneralUtility::fixed_lgd_cs($selItem['_RECORD_TITLE'], $this->backendUser->uc['titleLen']),
					$root ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] : GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $this->rec), $this->backendUser->uc['titleLen']),
295
296
					$this->clipObj->currentMode()
				);
297
				if ($table === 'pages' && $lCP & Permission::PAGE_NEW) {
298
299
300
301
302
					if ($elFromAllTables) {
						$menuItems['pasteinto'] = $this->DB_paste('', $uid, 'into', $elInfo);
					}
				}
				$elFromTable = count($this->clipObj->elFromTable($table));
303
				if (!$root && !$DBmount && $elFromTable && $GLOBALS['TCA'][$table]['ctrl']['sortby']) {
304
305
306
					$menuItems['pasteafter'] = $this->DB_paste($table, -$uid, 'after', $elInfo);
				}
			}
307
308
309
310
311
312
313
			$localItems = array();
			if (!$this->cmLevel && !in_array('moreoptions', $this->disabledItems, TRUE)) {
				// Creating menu items here:
				if ($this->editOK) {
					$localItems[] = 'spacer';
					$localItems['moreoptions'] = $this->linkItem(
						$this->label('more'),
314
						'',
315
						'TYPO3.ClickMenu.fetch(' . GeneralUtility::quoteJSvalue(GeneralUtility::linkThisScript() . '&cmLevel=1&subname=moreoptions') . ');return false;',
316
317
318
319
320
321
322
323
324
						FALSE,
						TRUE
					);
					$menuItemHideUnhideAllowed = FALSE;
					$hiddenField = '';
					// Check if column for disabled is defined
					if (isset($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'])) {
						$hiddenField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
						if (
325
							$hiddenField !== '' && !empty($GLOBALS['TCA'][$table]['columns'][$hiddenField]['exclude'])
326
							&& $this->backendUser->check('non_exclude_fields', $table . ':' . $hiddenField)
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
						) {
							$menuItemHideUnhideAllowed = TRUE;
						}
					}
					if ($menuItemHideUnhideAllowed && !in_array('hide', $this->disabledItems, TRUE)) {
						$localItems['hide'] = $this->DB_hideUnhide($table, $this->rec, $hiddenField);
					}
					$anyEnableColumnsFieldAllowed = FALSE;
					// Check if columns are defined
					if (isset($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) {
						$columnsToCheck = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns'];
						if ($table === 'pages' && !empty($columnsToCheck)) {
							$columnsToCheck[] = 'extendToSubpages';
						}
						foreach ($columnsToCheck as $currentColumn) {
							if (
								!empty($GLOBALS['TCA'][$table]['columns'][$currentColumn]['exclude'])
344
								&& $this->backendUser->check('non_exclude_fields', $table . ':' . $currentColumn)
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
							) {
								$anyEnableColumnsFieldAllowed = TRUE;
							}
						}
					}
					if ($anyEnableColumnsFieldAllowed && !in_array('edit_access', $this->disabledItems, TRUE)) {
						$localItems['edit_access'] = $this->DB_editAccess($table, $uid);
					}
					if ($table === 'pages' && $this->editPageIconSet && !in_array('edit_pageproperties', $this->disabledItems, TRUE)) {
						$localItems['edit_pageproperties'] = $this->DB_editPageProperties($uid);
					}
				}
				// Find delete element among the input menu items and insert the local items just before that:
				$c = 0;
				$deleteFound = FALSE;
				foreach ($menuItems as $key => $value) {
					$c++;
					if ($key === 'delete') {
						$deleteFound = TRUE;
						break;
					}
				}
				if ($deleteFound) {
					// .. subtract two... (delete item + its spacer element...)
					$c -= 2;
					// and insert the items just before the delete element.
					array_splice($menuItems, $c, 0, $localItems);
				} else {
					$menuItems = array_merge($menuItems, $localItems);
				}
			}

377
			// Delete:
378
379
			$elInfo = array(GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $this->rec), $this->backendUser->uc['titleLen']));
			if (!in_array('delete', $this->disabledItems) && !$root && !$DBmount && $this->backendUser->isPSet($lCP, $table, 'delete')) {
380
381
382
383
384
385
386
387
388
389
390
391
392
393
				$menuItems['spacer2'] = 'spacer';
				$menuItems['delete'] = $this->DB_delete($table, $uid, $elInfo);
			}
			if (!in_array('history', $this->disabledItems)) {
				$menuItems['history'] = $this->DB_history($table, $uid, $elInfo);
			}
		}
		// Adding external elements to the menuItems array
		$menuItems = $this->processingByExtClassArray($menuItems, $table, $uid);
		// Processing by external functions?
		$menuItems = $this->externalProcessingOfDBMenuItems($menuItems);
		if (!is_array($this->rec)) {
			$this->rec = array();
		}
394

395
		// Return the printed elements:
396
		return $this->printItems($menuItems);
397
398
399
400
401
402
	}

	/**
	 * Make 2nd level clickmenu (only for DBmenus)
	 *
	 * @param string $table Table name
403
	 * @param int $uid UID for the current record.
404
405
406
	 * @return string HTML content
	 */
	public function printNewDBLevel($table, $uid) {
407
		$localItems = [];
408
		$uid = (int)$uid;
409
		// Setting internal record to the table/uid :
Nicole Cordes's avatar
Nicole Cordes committed
410
		$this->rec = BackendUtility::getRecordWSOL($table, $uid);
411
412
413
		$menuItems = array();
		$root = 0;
		// Rootlevel
414
		if ($table === 'pages' && $uid === 0) {
415
416
417
418
			$root = 1;
		}
		// If record was found, check permissions and get menu items.
		if (is_array($this->rec) || $root) {
419
			$lCP = $this->backendUser->calcPerms(BackendUtility::getRecord('pages', $table === 'pages' ? $this->rec['uid'] : $this->rec['pid']));
420
			// Edit:
421
			if (!$root && ($this->backendUser->isPSet($lCP, $table, 'edit') || $this->backendUser->isPSet($lCP, $table, 'editcontent'))) {
422
				$this->editOK = TRUE;
423
424
425
			}
			$menuItems = $this->processingByExtClassArray($menuItems, $table, $uid);
		}
426
427
428
429
430
431
432
433
434
435
436

		$subname = GeneralUtility::_GP('subname');
		if ($subname === 'moreoptions') {
			// If the page can be edited, then show this:
			if ($this->editOK) {
				if (($table === 'pages' || $table === 'tt_content') && !in_array('move_wizard', $this->disabledItems, TRUE)) {
					$localItems['move_wizard'] = $this->DB_moveWizard($table, $uid, $this->rec);
				}
				if (($table === 'pages' || $table === 'tt_content') && !in_array('new_wizard', $this->disabledItems, TRUE)) {
					$localItems['new_wizard'] = $this->DB_newWizard($table, $uid, $this->rec);
				}
437
				if ($table === 'pages' && !in_array('perms', $this->disabledItems, TRUE) && $this->backendUser->check('modules', 'system_BeuserTxPermission')) {
438
439
					$localItems['perms'] = $this->DB_perms($table, $uid, $this->rec);
				}
440
				if (!in_array('db_list', $this->disabledItems, TRUE) && $this->backendUser->check('modules', 'web_list')) {
441
442
443
444
445
446
447
448
449
450
451
					$localItems['db_list'] = $this->DB_db_list($table, $uid, $this->rec);
				}
			}
			// Temporary mount point item:
			if ($table === 'pages') {
				$localItems['temp_mount_point'] = $this->DB_tempMountPoint($uid);
			}
			// Merge the locally created items into the current menu items passed to this function.
			$menuItems = array_merge($menuItems, $localItems);
		}

452
453
454
455
		// Return the printed elements:
		if (!is_array($menuItems)) {
			$menuItems = array();
		}
456
		return $this->printItems($menuItems);
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
	}

	/**
	 * Processing the $menuItems array (for extension classes) (DATABASE RECORDS)
	 *
	 * @param array $menuItems Array for manipulation.
	 * @return array Processed $menuItems array
	 */
	public function externalProcessingOfDBMenuItems($menuItems) {
		return $menuItems;
	}

	/**
	 * Processing the $menuItems array by external classes (typ. adding items)
	 *
	 * @param array $menuItems Array for manipulation.
	 * @param string $table Table name
474
	 * @param int $uid UID for the current record.
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
	 * @return array Processed $menuItems array
	 */
	public function processingByExtClassArray($menuItems, $table, $uid) {
		if (is_array($this->extClassArray)) {
			foreach ($this->extClassArray as $conf) {
				$obj = GeneralUtility::makeInstance($conf['name']);
				$menuItems = $obj->main($this, $menuItems, $table, $uid);
			}
		}
		return $menuItems;
	}

	/**
	 * Returning JavaScript for the onClick event linking to the input URL.
	 *
	 * @param string $url The URL relative to TYPO3_mainDir
	 * @param string $retUrl The return_url-parameter
492
	 * @param bool $hideCM If set, the "hideCM()" will be called
493
494
495
	 * @param string $overrideLoc If set, gives alternative location to load in (for example top frame or somewhere else)
	 * @return string JavaScript for an onClick event.
	 */
496
	public function urlRefForCM($url, $retUrl = '', $hideCM = TRUE, $overrideLoc = '') {
497
		$loc = 'top.content.list_frame';
498
		return ($overrideLoc ? 'var docRef=' . $overrideLoc : 'var docRef=(top.content.list_frame)?top.content.list_frame:' . $loc)
499
			. '; docRef.location.href=' . GeneralUtility::quoteJSvalue($url) . ($retUrl ? '+' . GeneralUtility::quoteJSvalue('&' . $retUrl . '=') . '+top.rawurlencode('
500
			. $this->frameLocation('docRef.document') . '.pathname+' . $this->frameLocation('docRef.document') . '.search)' : '')
501
			. ';';
502
503
504
505
506
507
	}

	/**
	 * Adding CM element for Clipboard "copy" and "cut"
	 *
	 * @param string $table Table name
508
	 * @param int $uid UID for the current record.
509
510
511
512
513
	 * @param string $type Type: "copy" or "cut
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_copycut($table, $uid, $type) {
514
		$isSel = '';
515
		if ($this->clipObj->current === 'normal') {
516
517
518
519
520
521
			$isSel = $this->clipObj->isSelected($table, $uid);
		}
		$addParam = array();
		if ($this->listFrame) {
			$addParam['reloadListFrame'] = $this->alwaysContentFrame ? 2 : 1;
		}
522
523
524
525
526
527
		$icon = $this->iconFactory->getIcon('actions-edit-' . $type . ($isSel === $type ? '-release' : ''), Icon::SIZE_SMALL)->render();
		return $this->linkItem(
			$this->label($type),
			$icon,
			'TYPO3.ClickMenu.fetch(' . GeneralUtility::quoteJSvalue($this->clipObj->selUrlDB($table, $uid, ($type === 'copy' ? 1 : 0), ($isSel == $type), $addParam)) . ');return false;'
		);
528
529
530
531
532
533
534
	}

	/**
	 * Adding CM element for Clipboard "paste into"/"paste after"
	 * NOTICE: $table and $uid should follow the special syntax for paste, see clipboard-class :: pasteUrl();
	 *
	 * @param string $table Table name
535
	 * @param int $uid UID for the current record. NOTICE: Special syntax!
536
537
538
	 * @param string $type Type: "into" or "after
	 * @param array $elInfo Contains instructions about whether to copy or cut an element.
	 * @return array Item array, element in $menuItems
Christian Kuhn's avatar
Christian Kuhn committed
539
	 * @see \TYPO3\CMS\Backend\Clipboard\Clipboard::pasteUrl()
540
541
542
543
	 * @internal
	 */
	public function DB_paste($table, $uid, $type, $elInfo) {
		$loc = 'top.content.list_frame';
544
		if ($this->backendUser->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE)) {
545
			$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])) . ')';
546
547
548
		} else {
			$conf = $loc;
		}
549
		$editOnClick = 'if(' . $conf . '){' . $loc . '.location.href=' . GeneralUtility::quoteJSvalue($this->clipObj->pasteUrl($table, $uid, 0) . '&redirect=') . '+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search);}';
550
551
552
553
554
		return $this->linkItem(
			$this->label('paste' . $type),
			$this->iconFactory->getIcon('actions-document-paste-' . $type, Icon::SIZE_SMALL)->render(),
			$editOnClick . 'return false;'
		);
555
556
557
558
559
560
	}

	/**
	 * Adding CM element for Info
	 *
	 * @param string $table Table name
561
	 * @param int $uid UID for the current record.
562
563
564
565
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_info($table, $uid) {
566
567
568
569
570
		return $this->linkItem(
			$this->label('info'),
			$this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render(),
			'top.launchView(' . GeneralUtility::quoteJSvalue($table) . ', ' . GeneralUtility::quoteJSvalue($uid) . ');'
		);
571
572
573
574
575
576
	}

	/**
	 * Adding CM element for History
	 *
	 * @param string $table Table name
577
	 * @param int $uid UID for the current record.
578
579
580
581
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_history($table, $uid) {
582
		$url = BackendUtility::getModuleUrl('record_history', array('element' => $table . ':' . $uid));
583
584
585
586
587
		return $this->linkItem(
			$this->languageService->makeEntities($this->languageService->getLL('CM_history')),
			$this->iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render(),
			$this->urlRefForCM($url, 'returnUrl')
		);
588
589
590
591
592
593
	}

	/**
	 * Adding CM element for Permission setting
	 *
	 * @param string $table Table name
594
	 * @param int $uid UID for the current record.
595
596
597
598
599
	 * @param array $rec The "pages" record with "perms_*" fields inside.
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_perms($table, $uid, $rec) {
600
		if (!ExtensionManagementUtility::isLoaded('beuser')) {
601
602
			return '';
		}
603
604
605
606
607

		$parameters = array(
			'id' => $uid,
		);

608
		if ($rec['perms_userid'] == $this->backendUser->user['uid'] || $this->backendUser->isAdmin()) {
609
610
611
612
			$parameters['return_id'] = $uid;
			$parameters['edit'] = '1';
		}

613
		$url = BackendUtility::getModuleUrl('system_BeuserTxPermission', $parameters);
614
615
616
617
618
		return $this->linkItem(
			$this->languageService->makeEntities($this->languageService->getLL('CM_perms')),
			$this->iconFactory->getIcon('status-status-locked', Icon::SIZE_SMALL)->render(),
			$this->urlRefForCM($url)
		);
619
620
621
622
623
624
	}

	/**
	 * Adding CM element for DBlist
	 *
	 * @param string $table Table name
625
	 * @param int $uid UID for the current record.
626
627
628
629
630
631
	 * @param array $rec Record of the element (needs "pid" field if not pages-record)
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_db_list($table, $uid, $rec) {
		$urlParams = array();
632
633
		$urlParams['id'] = $table === 'pages' ? $uid : $rec['pid'];
		$urlParams['table'] = $table === 'pages' ? '' : $table;
Nicole Cordes's avatar
Nicole Cordes committed
634
		$url = BackendUtility::getModuleUrl('web_list', $urlParams, '', TRUE);
635
636
		return $this->linkItem(
			$this->languageService->makeEntities($this->languageService->getLL('CM_db_list')),
637
638
			$this->iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render(),
			'top.nextLoadModuleUrl=' . GeneralUtility::quoteJSvalue($url) . ';top.goToModule(\'web_list\', 1);'
639
		);
640
641
642
643
644
645
	}

	/**
	 * Adding CM element for Moving wizard
	 *
	 * @param string $table Table name
646
	 * @param int $uid UID for the current record.
647
648
649
650
651
652
	 * @param array $rec Record. Needed for tt-content elements which will have the sys_language_uid sent
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_moveWizard($table, $uid, $rec) {
		// Hardcoded field for tt_content elements.
653
654
		$url = BackendUtility::getModuleUrl('move_element') . '&table=' . $table . '&uid=' . $uid;
		$url .= ($table === 'tt_content' ? '&sys_language_uid=' . (int)$rec['sys_language_uid'] : '');
655
656
657
658
659
		return $this->linkItem(
			$this->languageService->makeEntities($this->languageService->getLL('CM_moveWizard' . ($table === 'pages' ? '_page' : ''))),
			$this->iconFactory->getIcon('actions-' . ($table === 'pages' ? 'page' : 'document') . '-move', Icon::SIZE_SMALL)->render(),
			$this->urlRefForCM($url, 'returnUrl')
		);
660
661
662
	}

	/**
663
	 * Adding CM element for Create new wizard (either BackendUtility::getModuleUrl('db_new') or BackendUtility::getModuleUrl('new_content_element') or custom wizard)
664
665
	 *
	 * @param string $table Table name
666
	 * @param int $uid UID for the current record.
667
668
669
670
671
672
	 * @param array $rec Record.
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_newWizard($table, $uid, $rec) {
		//  If mod.web_list.newContentWiz.overrideWithExtension is set, use that extension's create new content wizard instead:
Nicole Cordes's avatar
Nicole Cordes committed
673
		$tmpTSc = BackendUtility::getModTSconfig($this->pageinfo['uid'], 'mod.web_list');
674
		$tmpTSc = $tmpTSc['properties']['newContentWiz.']['overrideWithExtension'];
675
676

		$newContentWizScriptPath = ExtensionManagementUtility::isLoaded($tmpTSc) ? ExtensionManagementUtility::extRelPath($tmpTSc) . 'mod1/db_new_content_el.php?' : BackendUtility::getModuleUrl('new_content_element') . '&';
677
		$url = $table === 'pages' ? BackendUtility::getModuleUrl('db_new', ['id' => $uid, 'pagesOnly' => 1]) : $newContentWizScriptPath . 'id=' . $rec['pid'] . '&sys_language_uid=' . (int)$rec['sys_language_uid'];
678
679
680
681
682
		return $this->linkItem(
			$this->languageService->makeEntities($this->languageService->getLL('CM_newWizard')),
			$this->iconFactory->getIcon(($table === 'pages' ? 'actions-page-new' : 'actions-document-new'), Icon::SIZE_SMALL)->render(),
			$this->urlRefForCM($url, 'returnUrl')
		);
683
684
685
686
687
688
	}

	/**
	 * Adding CM element for Editing of the access related fields of a table (disable, starttime, endtime, fe_groups)
	 *
	 * @param string $table Table name
689
	 * @param int $uid UID for the current record.
690
691
692
693
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_editAccess($table, $uid) {
694
695
696
697
		$url = BackendUtility::getModuleUrl('record_edit', array(
			'columnsOnly' => rawurlencode((implode(',', $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']) . ($table === 'pages' ? ',extendToSubpages' : ''))),
			'edit[' . $table . '][' . $uid . ']' => 'edit'
		));
698
699
700
701
702
703
		return $this->linkItem(
			$this->languageService->makeEntities($this->languageService->getLL('CM_editAccess')),
			$this->iconFactory->getIcon('actions-document-edit-access', Icon::SIZE_SMALL)->render(),
			$this->urlRefForCM($url, 'returnUrl'),
			1
		);
704
705
706
707
708
	}

	/**
	 * Adding CM element for edit page properties
	 *
709
	 * @param int $uid page uid to edit (PID)
710
711
712
713
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_editPageProperties($uid) {
714
715
716
		$url = BackendUtility::getModuleUrl('record_edit', array(
			'edit[pages][' . $uid . ']' => 'edit'
		));
717
718
719
720
721
722
		return $this->linkItem(
			$this->languageService->makeEntities($this->languageService->getLL('CM_editPageProperties')),
			$this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render(),
			$this->urlRefForCM($url, 'returnUrl'),
			1
		);
723
724
725
726
727
728
	}

	/**
	 * Adding CM element for regular editing of the element!
	 *
	 * @param string $table Table name
729
	 * @param int $uid UID for the current record.
730
731
732
733
734
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_edit($table, $uid) {
		// If another module was specified, replace the default Page module with the new one
735
		$newPageModule = trim($this->backendUser->getTSConfigVal('options.overridePageModule'));
Nicole Cordes's avatar
Nicole Cordes committed
736
		$pageModule = BackendUtility::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
737
		$loc = 'top.content.list_frame';
738
		$theIcon = $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render();
739
740
741
742
743

		$link = BackendUtility::getModuleUrl('record_edit', array(
			'edit[' . $table . '][' . $uid . ']' => 'edit'
		));

744
		if ($this->iParts[0] === 'pages' && $this->iParts[1] && $this->backendUser->check('modules', $pageModule)) {
745
			$this->editPageIconSet = TRUE;
746
		}
747
		$editOnClick = 'if(' . $loc . '){' . $loc . '.location.href=' . GeneralUtility::quoteJSvalue($link . '&returnUrl=') . '+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search);}';
748
		return $this->linkItem($this->label('edit'), $theIcon, $editOnClick . ';');
749
750
751
752
753
754
	}

	/**
	 * Adding CM element for regular Create new element
	 *
	 * @param string $table Table name
755
	 * @param int $uid UID for the current record.
756
757
758
759
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_new($table, $uid) {
760
761
762
		$frame = 'top.content.list_frame';
		$location = $this->frameLocation($frame . '.document');
		$module = $this->listFrame
763
764
			? GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('record_edit', array('edit[' . $table . '][-' . $uid . ']' => 'new')) . '&returnUrl=') . '+top.rawurlencode(' . $location . '.pathname+' . $location . '.search)'
			: GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('db_new', array('id' => (int)$uid)));
765
		$editOnClick = 'if(' . $frame . '){' . $frame . '.location.href=' . $module . ';}';
766
		$icon = $this->iconFactory->getIcon('actions-' . ($table === 'pages' ? 'page' : 'document') . '-new', Icon::SIZE_SMALL)->render();
767
		return $this->linkItem($this->label('new'), $icon, $editOnClick);
768
769
770
771
772
773
	}

	/**
	 * Adding CM element for Delete
	 *
	 * @param string $table Table name
774
	 * @param int $uid UID for the current record.
775
	 * @param array $elInfo Label for including in the confirmation message, EXT:lang/locallang_core.xlf:mess.delete
776
777
778
779
780
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_delete($table, $uid, $elInfo) {
		$loc = 'top.content.list_frame';
781
		if ($this->backendUser->jsConfirmation(JsConfirmation::DELETE)) {
782
			$conf = 'confirm(' . GeneralUtility::quoteJSvalue(sprintf($this->languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.delete'), $elInfo[0]) . BackendUtility::referenceCount($table, $uid, ' ' . $this->languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.referencesToRecord')) . BackendUtility::translationCount($table, $uid, (' ' . $this->languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.translationsOfRecord')))) . ')';
783
784
785
		} else {
			$conf = '1==1';
		}
786
		$editOnClick = 'if(' . $loc . ' && ' . $conf . ' ){' . $loc . '.location.href=' .
787
788
789
			GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('tce_db') . '&redirect=') . '+top.rawurlencode(' .
			$this->frameLocation($loc . '.document') . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+' .
			GeneralUtility::quoteJSvalue(
790
				'&cmd[' . $table . '][' . $uid . '][delete]=1&prErr=1&vC=' . $this->backendUser->veriCode()
791
			) . ';};';
792
793
794
		if ($table === 'pages') {
			$editOnClick .= 'top.nav.refresh.defer(500, top.nav);';
		}
795
796
797
798
799
		return $this->linkItem(
			$this->label('delete'),
			$this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL)->render(),
			$editOnClick . 'return false;'
		);
800
801
802
803
804
	}

	/**
	 * Adding CM element for View Page
	 *
805
	 * @param int $id Page uid (PID)
806
807
808
809
810
	 * @param string $anchor Anchor, if any
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_view($id, $anchor = '') {
811
		$icon = $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render();
812
		return $this->linkItem($this->label('view'), $icon, BackendUtility::viewOnClick($id, '', NULL, $anchor) . ';');
813
814
815
816
817
	}

	/**
	 * Adding element for setting temporary mount point.
	 *
818
	 * @param int $page_id Page uid (PID)
819
820
821
822
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_tempMountPoint($page_id) {
823
824
825
826
		return $this->linkItem(
			$this->label('tempMountPoint'),
			$this->iconFactory->getIcon('apps-pagetree-page-mountpoint', Icon::SIZE_SMALL)->render(),
			'if (top.content.nav_frame) {
827
828
829
830
831
832
833
834
				var node = top.TYPO3.Backend.NavigationContainer.PageTree.getSelected();
				if (node === null) {
					return false;
				}

				var useNode = {
					attributes: {
						nodeData: {
835
							id: ' . (int)$page_id . '
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
						}
					}
				};

				node.ownerTree.commandProvider.mountAsTreeRoot(useNode, node.ownerTree);
			}
			');
	}

	/**
	 * Adding CM element for hide/unhide of the input record
	 *
	 * @param string $table Table name
	 * @param array $rec Record array
	 * @param string $hideField Name of the hide field
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function DB_hideUnhide($table, $rec, $hideField) {
		return $this->DB_changeFlag($table, $rec, $hideField, $this->label(($rec[$hideField] ? 'un' : '') . 'hide'), 'hide');
	}

	/**
	 * Adding CM element for a flag field of the input record
	 *
	 * @param string $table Table name
	 * @param array $rec Record array
	 * @param string $flagField Name of the flag field
	 * @param string $title Menu item Title
	 * @return array Item array, element in $menuItems
	 */
867
	public function DB_changeFlag($table, $rec, $flagField, $title) {
868
		$uid = $rec['_ORIG_uid'] ?: $rec['uid'];
869
		$loc = 'top.content.list_frame';
870
		$editOnClick = 'if(' . $loc . '){' . $loc . '.location.href=' .
871
			GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('tce_db') . '&redirect=') . '+top.rawurlencode(' .
872
			$this->frameLocation($loc . '.document') . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+' .
873
			GeneralUtility::quoteJSvalue(
874
				'&data[' . $table . '][' . $uid . '][' . $flagField . ']=' . ($rec[$flagField] ? 0 : 1) . '&prErr=1&vC=' . $this->backendUser->veriCode()
875
			) . ';};';
876
877
878
		if ($table === 'pages') {
			$editOnClick .= 'top.nav.refresh.defer(500, top.nav);';
		}
879
880
881
882
883
884
		return $this->linkItem(
			$title,
			$this->iconFactory->getIcon('actions-edit-' . ($rec[$flagField] ? 'un' : '') . 'hide', Icon::SIZE_SMALL)->render(),
			$editOnClick . 'return false;',
			1
		);
885
886
887
888
889
890
891
892
893
894
895
896
	}

	/***************************************
	 *
	 * FILE
	 *
	 ***************************************/
	/**
	 * Make 1st level clickmenu:
	 *
	 * @param string $combinedIdentifier The combined identifier
	 * @return string HTML content
897
	 * @see \TYPO3\CMS\Core\Resource\ResourceFactory::retrieveFileOrFolderObject()
898
899
	 */
	public function printFileClickMenu($combinedIdentifier) {
900
901
		$icon = '';
		$identifier = '';
902
903
		$menuItems = array();
		$combinedIdentifier = rawurldecode($combinedIdentifier);
Nicole Cordes's avatar
Nicole Cordes committed
904
		$fileObject = ResourceFactory::getInstance()
905
906
907
				->retrieveFileOrFolderObject($combinedIdentifier);
		if ($fileObject) {
			$folder = FALSE;
908
909
910
911
			$isStorageRoot = FALSE;
			$isOnline = TRUE;
			$userMayViewStorage = FALSE;
			$userMayEditStorage = FALSE;
912
			$identifier = $fileObject->getCombinedIdentifier();
913
			if ($fileObject instanceof Folder) {
914
				$icon = '<span title="' . htmlspecialchars($fileObject->getName()) . '" class="absmiddle">'
915
					. $this->iconFactory->getIconForResource($fileObject, Icon::SIZE_SMALL)->render()
916
					. '</span>';
917
				$folder = TRUE;
918
919
				if ($fileObject->getIdentifier() === $fileObject->getStorage()->getRootLevelFolder()->getIdentifier()) {
					$isStorageRoot = TRUE;
920
					if ($this->backendUser->check('tables_select', 'sys_file_storage')) {
921
922
						$userMayViewStorage = TRUE;
					}
923
					if ($this->backendUser->check('tables_modify', 'sys_file_storage')) {
924
925
926
927
928
929
						$userMayEditStorage = TRUE;
					}
				}
				if (!$fileObject->getStorage()->isOnline()) {
					$isOnline = FALSE;
				}
930
			} else {
931
932
				$title = $fileObject->getName() . ' (' . GeneralUtility::formatSize($fileObject->getSize()) . ')';
				$icon = '<span class="absmiddle" title="' . htmlspecialchars($title). '">'
933
					. $this->iconFactory->getIconForResource($fileObject, Icon::SIZE_SMALL)->render()
934
					.'</span>';
935
			}
936
937
938
939
940
941
942
943
944
945
946
			// Hide
			if (!in_array('hide', $this->disabledItems) && $isStorageRoot && $userMayEditStorage) {
				$record = BackendUtility::getRecord('sys_file_storage', $fileObject->getStorage()->getUid());
				$menuItems['hide'] = $this->DB_changeFlag(
					'sys_file_storage',
					$record,
					'is_online',
					$this->label($record['is_online'] ? 'offline' : 'online'),
					'hide'
				);
			}
947
			// Edit
948
			if (!in_array('edit', $this->disabledItems) && $fileObject->checkActionPermission('write')) {
949
				if (!$folder && !$isStorageRoot && $fileObject->isIndexed() && $this->backendUser->check('tables_modify', 'sys_file_metadata')) {
950
951
952
					$metaData = $fileObject->_getMetaData();
					$menuItems['edit2'] = $this->DB_edit('sys_file_metadata', $metaData['uid']);
				}
953
				if (!$folder && GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], $fileObject->getExtension()) && $fileObject->checkActionPermission('write')) {
954
					$menuItems['edit'] = $this->FILE_launch($identifier, 'file_edit', 'editcontent', 'actions-page-open');
955
956
957
				} elseif ($isStorageRoot && $userMayEditStorage) {
					$menuItems['edit'] = $this->DB_edit('sys_file_storage', $fileObject->getStorage()->getUid());
				}
958
959
			}
			// Rename
960
			if (!in_array('rename', $this->disabledItems) && !$isStorageRoot && $fileObject->checkActionPermission('rename')) {
961
				$menuItems['rename'] = $this->FILE_launch($identifier, 'file_rename', 'rename', 'actions-edit-rename');
962
963
			}
			// Upload
964
			if (!in_array('upload', $this->disabledItems) && $folder && $isOnline && $fileObject->checkActionPermission('write')) {
965
				$menuItems['upload'] = $this->FILE_launch($identifier, 'file_upload', 'upload', 'actions-edit-upload');
966
967
			}
			// New
968
			if (!in_array('new', $this->disabledItems) && $folder && $isOnline && $fileObject->checkActionPermission('write')) {
969
				$menuItems['new'] = $this->FILE_launch($identifier, 'file_newfolder', 'new', 'actions-document-new');
970
971
			}
			// Info
972
			if (!in_array('info', $this->disabledItems) && $fileObject->checkActionPermission('read')) {
973
974
975
976
977
				if ($isStorageRoot && $userMayViewStorage) {
					$menuItems['info'] = $this->DB_info('sys_file_storage', $fileObject->getStorage()->getUid());
				} elseif (!$folder) {
					$menuItems['info'] = $this->fileInfo($identifier);
				}
978
979
980
			}
			$menuItems[] = 'spacer';
			// Copy:
981
			if (!in_array('copy', $this->disabledItems) && !$isStorageRoot && $fileObject->checkActionPermission('read')) {
982
983
984
				$menuItems['copy'] = $this->FILE_copycut($identifier, 'copy');
			}
			// Cut:
985
			if (!in_array('cut', $this->disabledItems) && !$isStorageRoot && $fileObject->checkActionPermission('move')) {
986
987
988
989
				$menuItems['cut'] = $this->FILE_copycut($identifier, 'cut');
			}
			// Paste:
			$elFromAllTables = count($this->clipObj->elFromTable('_FILE'));
990
			if (!in_array('paste', $this->disabledItems) && $elFromAllTables && $folder && $fileObject->checkActionPermission('write')) {
991
992
				$elArr = $this->clipObj->elFromTable('_FILE');
				$selItem = reset($elArr);
993
994
				$clickedFileOrFolder = ResourceFactory::getInstance()->retrieveFileOrFolderObject($combinedIdentifier);
				$fileOrFolderInClipBoard = ResourceFactory::getInstance()->retrieveFileOrFolderObject($selItem);
995
				$elInfo = array(
996
					$fileOrFolderInClipBoard->getName(),
997
					$clickedFileOrFolder->getName(),
998
999
					$this->clipObj->currentMode()
				);
1000
1001
1002
				if (!$fileOrFolderInClipBoard instanceof Folder || !$fileOrFolderInClipBoard->getStorage()->isWithinFolder($fileOrFolderInClipBoard, $clickedFileOrFolder)) {
					$menuItems['pasteinto'] = $this->FILE_paste($identifier, $selItem, $elInfo);
				}
1003
1004
1005
			}
			$menuItems[] = 'spacer';
			// Delete:
1006
			if (!in_array('delete', $this->disabledItems) && $fileObject->checkActionPermission('delete')) {
1007
				if ($isStorageRoot && $userMayEditStorage) {
1008
					$elInfo = array(GeneralUtility::fixed_lgd_cs($fileObject->getStorage()->getName(), $this->backendUser->uc['titleLen']));
1009
1010
1011
1012
					$menuItems['delete'] = $this->DB_delete('sys_file_storage', $fileObject->getStorage()->getUid(), $elInfo);
				} elseif (!$isStorageRoot) {
					$menuItems['delete'] = $this->FILE_delete($identifier);
				}
1013
1014
1015
1016
1017
1018
1019
			}
		}
		// Adding external elements to the menuItems array
		$menuItems = $this->processingByExtClassArray($menuItems, $identifier, 0);
		// Processing by external functions?
		$menuItems = $this->externalProcessingOfFileMenuItems($menuItems);
		// Return the printed elements:
1020
		return $this->printItems($menuItems);
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
	}

	/**
	 * Processing the $menuItems array (for extension classes) (FILES)
	 *
	 * @param array $menuItems Array for manipulation.
	 * @return array Processed $menuItems array
	 */
	public function externalProcessingOfFileMenuItems($menuItems) {
		return $menuItems;
	}

	/**
	 * Multi-function for adding an entry to the $menuItems array
	 *
	 * @param string $path Path to the file/directory (target)
1037
	 * @param string $moduleName Script (deprecated) or module name (e.g. file_edit) to pass &target= to
1038
	 * @param string $type "type" is the code which fetches the correct label for the element from "cm.
1039
	 * @param string $iconName
1040
	 * @param bool $noReturnUrl If set, the return URL parameter will not be set in the link
1041
1042
1043
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
1044
	public function FILE_launch($path, $moduleName, $type, $iconName, $noReturnUrl = FALSE) {
1045
		$loc = 'top.content.list_frame';
1046
1047
1048

		if (strpos($moduleName, '.php') !== FALSE) {
			GeneralUtility::deprecationLog(
1049
				'Using a php file directly in ClickMenu is deprecated since TYPO3 CMS 7, and will be removed in CMS 8.'
1050
1051
1052
1053
1054
1055
1056
1057
				. ' Register the class as module and use BackendUtility::getModuleUrl() to get the right link.'
				. ' For examples how to do this see ext_tables.php of EXT:backend.'
			);
			$scriptUrl = $moduleName;
		} else {
			$scriptUrl = BackendUtility::getModuleUrl($moduleName);
		}

1058
		$editOnClick = 'if(' . $loc . '){' . $loc . '.location.href=' . GeneralUtility::quoteJSvalue($scriptUrl . '&target=' . rawurlencode($path)) . ($noReturnUrl ? '' : '+\'&returnUrl=\'+top.rawurlencode(' . $this->frameLocation($loc . '.document') . '.pathname+' . $this->frameLocation($loc . '.document') . '.search)') . ';}';
1059
1060
1061
1062
1063
		return $this->linkItem(
			$this->label($type),
			$this->iconFactory->getIcon($iconName, Icon::SIZE_SMALL)->render(),
			$editOnClick . 'top.nav.refresh();'
		);
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
	}

	/**
	 * Returns element for copy or cut of files.
	 *
	 * @param string $path Path to the file/directory (target)
	 * @param string $type Type: "copy" or "cut
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function FILE_copycut($path, $type) {
1075
		$isSel = '';
1076
1077
1078
		// Pseudo table name for use in the clipboard.
		$table = '_FILE';
		$uid = GeneralUtility::shortmd5($path);
1079
		if ($this->clipObj->current === 'normal') {
1080
1081
1082
1083
1084
1085
			$isSel = $this->clipObj->isSelected($table, $uid);
		}
		$addParam = array();
		if ($this->listFrame) {
			$addParam['reloadListFrame'] = $this->alwaysContentFrame ? 2 : 1;
		}
1086
1087
1088
1089
1090
		return $this->linkItem(
			$this->label($type),
			$this->iconFactory->getIcon('actions-edit-' . $type . ($isSel === $type ? '-release' : ''), Icon::SIZE_SMALL)->render(),
			'TYPO3.ClickMenu.fetch(' . GeneralUtility::quoteJSvalue($this->clipObj->selUrlFile($path, ($type === 'copy' ? 1 : 0), ($isSel == $type), $addParam)) . ');return false;'
		);
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
	}

	/**
	 * Creates element for deleting of target
	 *
	 * @param string $path Path to the file/directory (target)
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function FILE_delete($path) {
		$loc = 'top.content.list_frame';
1102
		if ($this->backendUser->jsConfirmation(JsConfirmation::DELETE)) {
1103
			$conf = 'confirm(' . GeneralUtility::quoteJSvalue((sprintf($this->languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.delete'), basename($path)) . BackendUtility::referenceCount('_FILE', $path, ' ' . $this->languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.referencesToFile')))) . ')';
1104
1105
1106
		} else {
			$conf = '1==1';
		}
1107
		$editOnClick = 'if(' . $loc . ' && ' . $conf . ' ){' . $loc . '.location.href=' .
1108
1109
1110
			GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('tce_file') . '&redirect=') . '+top.rawurlencode(' .
			$this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+' .
			GeneralUtility::quoteJSvalue(
1111
				'&file[delete][0][data]=' . rawurlencode($path) . '&vC=' . $this->backendUser->veriCode()
1112
			) . ';};';
1113
1114
1115
1116
1117
		return $this->linkItem(
			$this->label('delete'),
			$this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL)->render(),
			$editOnClick . 'return false;'
		);
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
	}

	/**
	 * Creates element for pasting files.
	 *
	 * @param string $path Path to the file/directory (target)
	 * @param string $target target - NOT USED.
	 * @param array $elInfo Various values for the labels.
	 * @return array Item array, element in $menuItems
	 * @internal
	 */
	public function FILE_paste($path, $target, $elInfo) {
		$loc = 'top.content.list_frame';
1131
		if ($this->backendUser->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE)) {
1132
			$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])) . ')';
1133
1134
1135
		} else {
			$conf = $loc;
		}
1136
		$editOnClick = 'if(' . $conf . '){' . $loc . '.location.href=' . GeneralUtility::quoteJSvalue($this->clipObj->pasteUrl('_FILE', $path, 0) . '&redirect=') . '+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search);  };top.nav.refresh();';
1137
1138
1139
1140
1141
		return $this->linkItem(
			$this->label('pasteinto'),
			$this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render(),
			$editOnClick . 'return false;'
		);
1142
1143
	}