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