TYPO3  7.6
backend/Classes/ClickMenu/ClickMenu.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Backend\ClickMenu;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
29 
34 class ClickMenu
35 {
42  public $cmLevel = 0;
43 
49  public $CB;
50 
56  public $listFrame = false;
57 
63  public $isDBmenu = false;
64 
70  public $alwaysContentFrame = false;
71 
80  public $iParts = array();
81 
87  public $disabledItems = array();
88 
94  public $leftIcons = false;
95 
102  public $extClassArray = array();
103 
109  public $editPageIconSet = false;
110 
116  public $editOK = false;
117 
123  public $rec = array();
124 
131  public $clipObj;
132 
137  protected $pageinfo;
138 
144  protected $languageService;
145 
149  protected $backendUser;
150 
154  protected $iconFactory;
155 
161  {
162  $this->languageService = $languageService ?: $GLOBALS['LANG'];
163  $this->backendUser = $backendUser ?: $GLOBALS['BE_USER'];
164  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
165  }
166 
172  public function init()
173  {
174  $CMcontent = '';
175  // Setting GPvars:
176  $this->cmLevel = (int)GeneralUtility::_GP('cmLevel');
177  $this->CB = GeneralUtility::_GP('CB');
178 
179  // Deal with Drag&Drop context menus
180  if ((string)GeneralUtility::_GP('dragDrop') !== '') {
181  return $this->printDragDropClickMenu(GeneralUtility::_GP('dragDrop'), GeneralUtility::_GP('srcId'), GeneralUtility::_GP('dstId'));
182  }
183  // Can be set differently as well
184  $this->iParts[0] = GeneralUtility::_GP('table');
185  $this->iParts[1] = GeneralUtility::_GP('uid');
186  $this->iParts[2] = GeneralUtility::_GP('listFr');
187  $this->iParts[3] = GeneralUtility::_GP('enDisItems');
188  // Setting flags:
189  if ($this->iParts[2]) {
190  $this->listFrame = true;
191  }
192  if ($this->iParts[2] == 2) {
193  $this->alwaysContentFrame = true;
194  }
195  if (isset($this->iParts[1]) && $this->iParts[1] !== '') {
196  $this->isDBmenu = true;
197  }
198  $TSkey = ($this->isDBmenu ? 'page' : 'folder') . ($this->listFrame ? 'List' : 'Tree');
199  $this->disabledItems = GeneralUtility::trimExplode(',', $this->backendUser->getTSConfigVal('options.contextMenu.' . $TSkey . '.disableItems'), true);
200  $this->leftIcons = (bool)$this->backendUser->getTSConfigVal('options.contextMenu.options.leftIcons');
201  // &cmLevel flag detected (2nd level menu)
202  if (!$this->cmLevel) {
203  // Make 1st level clickmenu:
204  if ($this->isDBmenu) {
205  $CMcontent = $this->printDBClickMenu($this->iParts[0], $this->iParts[1]);
206  } else {
207  $CMcontent = $this->printFileClickMenu($this->iParts[0]);
208  }
209  } else {
210  // Make 2nd level clickmenu (only for DBmenus)
211  if ($this->isDBmenu) {
212  $CMcontent = $this->printNewDBLevel($this->iParts[0], $this->iParts[1]);
213  }
214  }
215  // Return clickmenu content:
216  return $CMcontent;
217  }
218 
219  /***************************************
220  *
221  * DATABASE
222  *
223  ***************************************/
231  public function printDBClickMenu($table, $uid)
232  {
233  $uid = (int)$uid;
234  // Get record:
235  $this->rec = BackendUtility::getRecordWSOL($table, $uid);
236  $menuItems = array();
237  $root = 0;
238  $DBmount = false;
239  // Rootlevel
240  if ($table === 'pages' && $uid === 0) {
241  $root = 1;
242  }
243  // DB mount
244  if ($table === 'pages' && in_array($uid, $this->backendUser->returnWebmounts())) {
245  $DBmount = true;
246  }
247  // Used to hide cut,copy icons for l10n-records
248  $l10nOverlay = false;
249  // Should only be performed for overlay-records within the same table
250  if (BackendUtility::isTableLocalizable($table) && !isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'])) {
251  $l10nOverlay = (int)$this->rec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0;
252  }
253  // If record found (or root), go ahead and fill the $menuItems array which will contain data for the elements to render.
254  if (is_array($this->rec) || $root) {
255  // Get permissions
256  $lCP = $this->backendUser->calcPerms(BackendUtility::getRecord('pages', $table === 'pages' ? $this->rec['uid'] : $this->rec['pid']));
257  // View
258  if (!in_array('view', $this->disabledItems, true)) {
259  if ($table === 'pages') {
260  $menuItems['view'] = $this->DB_view($uid);
261  }
262  if ($table === 'tt_content') {
263  $ws_rec = BackendUtility::getRecordWSOL($table, $this->rec['uid']);
264  $menuItems['view'] = $this->DB_view($ws_rec['pid']);
265  }
266  }
267  // Edit:
268  if (!$root && ($this->backendUser->isPSet($lCP, $table, 'edit') || $this->backendUser->isPSet($lCP, $table, 'editcontent'))) {
269  if (!in_array('edit', $this->disabledItems, true)) {
270  $menuItems['edit'] = $this->DB_edit($table, $uid);
271  }
272  $this->editOK = true;
273  }
274  // New:
275  if (!in_array('new', $this->disabledItems, true) && $this->backendUser->isPSet($lCP, $table, 'new')) {
276  $menuItems['new'] = $this->DB_new($table, $uid);
277  }
278  // Info:
279  if (!in_array('info', $this->disabledItems, true) && !$root) {
280  $menuItems['info'] = $this->DB_info($table, $uid);
281  }
282  $menuItems['spacer1'] = 'spacer';
283  // Copy:
284  if (!in_array('copy', $this->disabledItems, true) && !$root && !$DBmount && !$l10nOverlay) {
285  $menuItems['copy'] = $this->DB_copycut($table, $uid, 'copy');
286  }
287  // Cut:
288  if (!in_array('cut', $this->disabledItems, true) && !$root && !$DBmount && !$l10nOverlay) {
289  $menuItems['cut'] = $this->DB_copycut($table, $uid, 'cut');
290  }
291  // Paste:
292  $elFromAllTables = count($this->clipObj->elFromTable(''));
293  if (!in_array('paste', $this->disabledItems, true) && $elFromAllTables) {
294  $selItem = $this->clipObj->getSelectedRecord();
295  $elInfo = array(
296  GeneralUtility::fixed_lgd_cs($selItem['_RECORD_TITLE'], $this->backendUser->uc['titleLen']),
297  $root ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] : GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $this->rec), $this->backendUser->uc['titleLen']),
298  $this->clipObj->currentMode()
299  );
300  if ($table === 'pages' && $lCP & Permission::PAGE_NEW) {
301  if ($elFromAllTables) {
302  $menuItems['pasteinto'] = $this->DB_paste('', $uid, 'into', $elInfo);
303  }
304  }
305  $elFromTable = count($this->clipObj->elFromTable($table));
306  if (!$root && !$DBmount && $elFromTable && $GLOBALS['TCA'][$table]['ctrl']['sortby']) {
307  $menuItems['pasteafter'] = $this->DB_paste($table, -$uid, 'after', $elInfo);
308  }
309  }
310 
311  // Delete:
312  $elInfo = array(GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $this->rec), $this->backendUser->uc['titleLen']));
313  if (!in_array('delete', $this->disabledItems, true) && !$root && !$DBmount && $this->backendUser->isPSet($lCP, $table, 'delete')) {
314  $menuItems['spacer2'] = 'spacer';
315  $menuItems['delete'] = $this->DB_delete($table, $uid, $elInfo);
316  }
317  if (!in_array('history', $this->disabledItems, true)) {
318  $menuItems['history'] = $this->DB_history($table, $uid, $elInfo);
319  }
320 
321  $localItems = array();
322  if (!$this->cmLevel && !in_array('moreoptions', $this->disabledItems, true)) {
323  // Creating menu items here:
324  if ($this->editOK) {
325  $localItems['spacer3'] = 'spacer';
326  $localItems['moreoptions'] = $this->linkItem(
327  $this->label('more'),
328  '',
329  'TYPO3.ClickMenu.fetch(' . GeneralUtility::quoteJSvalue(GeneralUtility::linkThisScript() . '&cmLevel=1&subname=moreoptions') . ');return false;',
330  false,
331  true
332  );
333  $menuItemHideUnhideAllowed = false;
334  $hiddenField = '';
335  // Check if column for disabled is defined
336  if (isset($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'])) {
337  $hiddenField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
338  if (
339  $hiddenField !== '' && !empty($GLOBALS['TCA'][$table]['columns'][$hiddenField]['exclude'])
340  && $this->backendUser->check('non_exclude_fields', $table . ':' . $hiddenField)
341  ) {
342  $menuItemHideUnhideAllowed = true;
343  }
344  }
345  if ($menuItemHideUnhideAllowed && !in_array('hide', $this->disabledItems, true)) {
346  $localItems['hide'] = $this->DB_hideUnhide($table, $this->rec, $hiddenField);
347  }
348  $anyEnableColumnsFieldAllowed = false;
349  // Check if columns are defined
350  if (isset($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) {
351  $columnsToCheck = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns'];
352  if ($table === 'pages' && !empty($columnsToCheck)) {
353  $columnsToCheck[] = 'extendToSubpages';
354  }
355  foreach ($columnsToCheck as $currentColumn) {
356  if (
357  !empty($GLOBALS['TCA'][$table]['columns'][$currentColumn]['exclude'])
358  && $this->backendUser->check('non_exclude_fields', $table . ':' . $currentColumn)
359  ) {
360  $anyEnableColumnsFieldAllowed = true;
361  }
362  }
363  }
364  if ($anyEnableColumnsFieldAllowed && !in_array('edit_access', $this->disabledItems, true)) {
365  $localItems['edit_access'] = $this->DB_editAccess($table, $uid);
366  }
367  if ($table === 'pages' && $this->editPageIconSet && !in_array('edit_pageproperties', $this->disabledItems, true)) {
368  $localItems['edit_pageproperties'] = $this->DB_editPageProperties($uid);
369  }
370  }
371  // Find delete element among the input menu items and insert the local items just before that:
372  $c = 0;
373  $deleteFound = false;
374  foreach ($menuItems as $key => $value) {
375  $c++;
376  if ($key === 'delete') {
377  $deleteFound = true;
378  break;
379  }
380  }
381  if ($deleteFound) {
382  // .. subtract two... (delete item + its spacer element...)
383  $c -= 2;
384  // and insert the items just before the delete element.
385  array_splice($menuItems, $c, 0, $localItems);
386  } else {
387  $menuItems = array_merge($menuItems, $localItems);
388  }
389  }
390  }
391  // Adding external elements to the menuItems array
392  $menuItems = $this->processingByExtClassArray($menuItems, $table, $uid);
393  // Processing by external functions?
394  $menuItems = $this->externalProcessingOfDBMenuItems($menuItems);
395  if (!is_array($this->rec)) {
396  $this->rec = array();
397  }
398 
399  // Return the printed elements:
400  return $this->printItems($menuItems);
401  }
402 
410  public function printNewDBLevel($table, $uid)
411  {
412  $localItems = [];
413  $uid = (int)$uid;
414  // Setting internal record to the table/uid :
415  $this->rec = BackendUtility::getRecordWSOL($table, $uid);
416  $menuItems = array();
417  $root = 0;
418  // Rootlevel
419  if ($table === 'pages' && $uid === 0) {
420  $root = 1;
421  }
422  // If record was found, check permissions and get menu items.
423  if (is_array($this->rec) || $root) {
424  $lCP = $this->backendUser->calcPerms(BackendUtility::getRecord('pages', $table === 'pages' ? $this->rec['uid'] : $this->rec['pid']));
425  // Edit:
426  if (!$root && ($this->backendUser->isPSet($lCP, $table, 'edit') || $this->backendUser->isPSet($lCP, $table, 'editcontent'))) {
427  $this->editOK = true;
428  }
429  $menuItems = $this->processingByExtClassArray($menuItems, $table, $uid);
430  }
431 
432  $subname = GeneralUtility::_GP('subname');
433  if ($subname === 'moreoptions') {
434  // If the page can be edited, then show this:
435  if ($this->editOK) {
436  if (($table === 'pages' || $table === 'tt_content') && !in_array('move_wizard', $this->disabledItems, true)) {
437  $localItems['move_wizard'] = $this->DB_moveWizard($table, $uid, $this->rec);
438  }
439  if (($table === 'pages' || $table === 'tt_content') && !in_array('new_wizard', $this->disabledItems, true)) {
440  $localItems['new_wizard'] = $this->DB_newWizard($table, $uid, $this->rec);
441  }
442  if ($table === 'pages' && !in_array('perms', $this->disabledItems, true) && $this->backendUser->check('modules', 'system_BeuserTxPermission')) {
443  $localItems['perms'] = $this->DB_perms($table, $uid, $this->rec);
444  }
445  if (!in_array('db_list', $this->disabledItems, true) && $this->backendUser->check('modules', 'web_list')) {
446  $localItems['db_list'] = $this->DB_db_list($table, $uid, $this->rec);
447  }
448  }
449  // Temporary mount point item:
450  if ($table === 'pages') {
451  $localItems['temp_mount_point'] = $this->DB_tempMountPoint($uid);
452  }
453  // Merge the locally created items into the current menu items passed to this function.
454  $menuItems = array_merge($menuItems, $localItems);
455  }
456 
457  // Return the printed elements:
458  if (!is_array($menuItems)) {
459  $menuItems = array();
460  }
461  return $this->printItems($menuItems);
462  }
463 
470  public function externalProcessingOfDBMenuItems($menuItems)
471  {
472  return $menuItems;
473  }
474 
483  public function processingByExtClassArray($menuItems, $table, $uid)
484  {
485  if (is_array($this->extClassArray)) {
486  foreach ($this->extClassArray as $conf) {
487  $obj = GeneralUtility::makeInstance($conf['name']);
488  $menuItems = $obj->main($this, $menuItems, $table, $uid);
489  }
490  }
491  return $menuItems;
492  }
493 
503  public function urlRefForCM($url, $retUrl = '', $hideCM = true, $overrideLoc = '')
504  {
505  $loc = 'top.content.list_frame';
506  return ($overrideLoc ? 'var docRef=' . $overrideLoc : 'var docRef=(top.content.list_frame)?top.content.list_frame:' . $loc)
507  . '; docRef.location.href=' . GeneralUtility::quoteJSvalue($url) . ($retUrl ? '+' . GeneralUtility::quoteJSvalue('&' . $retUrl . '=') . '+top.rawurlencode('
508  . $this->frameLocation('docRef.document') . '.pathname+' . $this->frameLocation('docRef.document') . '.search)' : '')
509  . ';';
510  }
511 
521  public function DB_copycut($table, $uid, $type)
522  {
523  $isSel = '';
524  if ($this->clipObj->current === 'normal') {
525  $isSel = $this->clipObj->isSelected($table, $uid);
526  }
527  $addParam = array();
528  if ($this->listFrame) {
529  $addParam['reloadListFrame'] = $this->alwaysContentFrame ? 2 : 1;
530  }
531  $icon = $this->iconFactory->getIcon('actions-edit-' . $type . ($isSel === $type ? '-release' : ''), Icon::SIZE_SMALL)->render();
532  return $this->linkItem(
533  $this->label($type),
534  $icon,
535  'TYPO3.ClickMenu.fetch(' . GeneralUtility::quoteJSvalue($this->clipObj->selUrlDB($table, $uid, ($type === 'copy' ? 1 : 0), ($isSel == $type), $addParam)) . ');return false;'
536  );
537  }
538 
551  public function DB_paste($table, $uid, $type, $elInfo)
552  {
553  $loc = 'top.content.list_frame';
554  if ($this->backendUser->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE)) {
555  $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])) . ')';
556  } else {
557  $conf = $loc;
558  }
559  $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);}';
560  return $this->linkItem(
561  $this->label('paste' . $type),
562  $this->iconFactory->getIcon('actions-document-paste-' . $type, Icon::SIZE_SMALL)->render(),
563  $editOnClick . 'return false;'
564  );
565  }
566 
575  public function DB_info($table, $uid)
576  {
577  return $this->linkItem(
578  $this->label('info'),
579  $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render(),
580  'top.launchView(' . GeneralUtility::quoteJSvalue($table) . ', ' . GeneralUtility::quoteJSvalue($uid) . ');'
581  );
582  }
583 
592  public function DB_history($table, $uid)
593  {
594  $url = BackendUtility::getModuleUrl('record_history', array('element' => $table . ':' . $uid));
595  return $this->linkItem(
596  $this->languageService->makeEntities($this->languageService->getLL('CM_history')),
597  $this->iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render(),
598  $this->urlRefForCM($url, 'returnUrl')
599  );
600  }
601 
611  public function DB_perms($table, $uid, $rec)
612  {
613  if (!ExtensionManagementUtility::isLoaded('beuser')) {
614  return '';
615  }
616 
617  $parameters = array(
618  'id' => $uid,
619  );
620 
621  if ($rec['perms_userid'] == $this->backendUser->user['uid'] || $this->backendUser->isAdmin()) {
622  $parameters['return_id'] = $uid;
623  $parameters['edit'] = '1';
624  }
625 
626  $url = BackendUtility::getModuleUrl('system_BeuserTxPermission', $parameters);
627  return $this->linkItem(
628  $this->languageService->makeEntities($this->languageService->getLL('CM_perms')),
629  $this->iconFactory->getIcon('status-status-locked', Icon::SIZE_SMALL)->render(),
630  $this->urlRefForCM($url)
631  );
632  }
633 
643  public function DB_db_list($table, $uid, $rec)
644  {
645  $urlParams = array();
646  $urlParams['id'] = $table === 'pages' ? $uid : $rec['pid'];
647  $urlParams['table'] = $table === 'pages' ? '' : $table;
648  $url = BackendUtility::getModuleUrl('web_list', $urlParams, '', true);
649  return $this->linkItem(
650  $this->languageService->makeEntities($this->languageService->getLL('CM_db_list')),
651  $this->iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render(),
652  'top.nextLoadModuleUrl=' . GeneralUtility::quoteJSvalue($url) . ';top.goToModule(\'web_list\', 1);'
653  );
654  }
655 
665  public function DB_moveWizard($table, $uid, $rec)
666  {
667  // Hardcoded field for tt_content elements.
668  $url = BackendUtility::getModuleUrl('move_element') . '&table=' . $table . '&uid=' . $uid;
669  $url .= ($table === 'tt_content' ? '&sys_language_uid=' . (int)$rec['sys_language_uid'] : '');
670  return $this->linkItem(
671  $this->languageService->makeEntities($this->languageService->getLL('CM_moveWizard' . ($table === 'pages' ? '_page' : ''))),
672  $this->iconFactory->getIcon('actions-' . ($table === 'pages' ? 'page' : 'document') . '-move', Icon::SIZE_SMALL)->render(),
673  $this->urlRefForCM($url, 'returnUrl')
674  );
675  }
676 
686  public function DB_newWizard($table, $uid, $rec)
687  {
688  if ($table === 'pages') {
689  $url = BackendUtility::getModuleUrl('db_new', ['id' => $uid, 'pagesOnly' => 1]);
690  } else {
691  // If mod.newContentElementWizard.override is set, use a custom module instead
692  $tsConfig = BackendUtility::getModTSconfig($this->pageinfo['uid'], 'mod');
693  $newContentWizardModuleName = $tsConfig['properties']['newContentElementWizard.']['override'] ?: 'new_content_element';
694  $url = BackendUtility::getModuleUrl($newContentWizardModuleName, ['id' => $rec['pid'], 'sys_language_uid' => (int)$rec['sys_language_uid']]);
695  }
696  return $this->linkItem(
697  $this->languageService->makeEntities($this->languageService->getLL('CM_newWizard')),
698  $this->iconFactory->getIcon(($table === 'pages' ? 'actions-page-new' : 'actions-document-new'), Icon::SIZE_SMALL)->render(),
699  $this->urlRefForCM($url, 'returnUrl')
700  );
701  }
702 
711  public function DB_editAccess($table, $uid)
712  {
713  $url = BackendUtility::getModuleUrl('record_edit', array(
714  'columnsOnly' => rawurlencode((implode(',', $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']) . ($table === 'pages' ? ',extendToSubpages' : ''))),
715  'edit[' . $table . '][' . $uid . ']' => 'edit'
716  ));
717  return $this->linkItem(
718  $this->languageService->makeEntities($this->languageService->getLL('CM_editAccess')),
719  $this->iconFactory->getIcon('actions-document-edit-access', Icon::SIZE_SMALL)->render(),
720  $this->urlRefForCM($url, 'returnUrl'),
721  1
722  );
723  }
724 
732  public function DB_editPageProperties($uid)
733  {
734  $url = BackendUtility::getModuleUrl('record_edit', array(
735  'edit[pages][' . $uid . ']' => 'edit'
736  ));
737  return $this->linkItem(
738  $this->languageService->makeEntities($this->languageService->getLL('CM_editPageProperties')),
739  $this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render(),
740  $this->urlRefForCM($url, 'returnUrl'),
741  1
742  );
743  }
744 
753  public function DB_edit($table, $uid)
754  {
755  // If another module was specified, replace the default Page module with the new one
756  $newPageModule = trim($this->backendUser->getTSConfigVal('options.overridePageModule'));
757  $pageModule = BackendUtility::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
758  $loc = 'top.content.list_frame';
759  $theIcon = $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render();
760 
761  $link = BackendUtility::getModuleUrl('record_edit', array(
762  'edit[' . $table . '][' . $uid . ']' => 'edit'
763  ));
764 
765  if ($this->iParts[0] === 'pages' && $this->iParts[1] && $this->backendUser->check('modules', $pageModule)) {
766  $this->editPageIconSet = true;
767  }
768  $editOnClick = 'if(' . $loc . '){' . $loc . '.location.href=' . GeneralUtility::quoteJSvalue($link . '&returnUrl=') . '+top.rawurlencode(' . $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search);}';
769  return $this->linkItem($this->label('edit'), $theIcon, $editOnClick . ';');
770  }
771 
780  public function DB_new($table, $uid)
781  {
782  $frame = 'top.content.list_frame';
783  $location = $this->frameLocation($frame . '.document');
784  $module = $this->listFrame
785  ? GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('record_edit', array('edit[' . $table . '][-' . $uid . ']' => 'new')) . '&returnUrl=') . '+top.rawurlencode(' . $location . '.pathname+' . $location . '.search)'
786  : GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('db_new', array('id' => (int)$uid)));
787  $editOnClick = 'if(' . $frame . '){' . $frame . '.location.href=' . $module . ';}';
788  $icon = $this->iconFactory->getIcon('actions-' . ($table === 'pages' ? 'page' : 'document') . '-new', Icon::SIZE_SMALL)->render();
789  return $this->linkItem($this->label('new'), $icon, $editOnClick);
790  }
791 
801  public function DB_delete($table, $uid, $elInfo)
802  {
803  $loc = 'top.content.list_frame';
804  if ($this->backendUser->jsConfirmation(JsConfirmation::DELETE)) {
805  $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')))) . ')';
806  } else {
807  $conf = '1==1';
808  }
809  $editOnClick = 'if(' . $loc . ' && ' . $conf . ' ){' . $loc . '.location.href=' .
810  GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('tce_db') . '&redirect=') . '+top.rawurlencode(' .
811  $this->frameLocation($loc . '.document') . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+' .
813  '&cmd[' . $table . '][' . $uid . '][delete]=1&prErr=1&vC=' . $this->backendUser->veriCode()
814  ) . ';};';
815  if ($table === 'pages') {
816  $editOnClick .= 'top.nav.refresh.defer(500, top.nav);';
817  }
818  return $this->linkItem(
819  $this->label('delete'),
820  $this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL)->render(),
821  $editOnClick . 'return false;'
822  );
823  }
824 
833  public function DB_view($id, $anchor = '')
834  {
835  $icon = $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render();
836  return $this->linkItem($this->label('view'), $icon, BackendUtility::viewOnClick($id, '', null, $anchor) . ';');
837  }
838 
846  public function DB_tempMountPoint($page_id)
847  {
848  return $this->linkItem(
849  $this->label('tempMountPoint'),
850  $this->iconFactory->getIcon('apps-pagetree-page-mountpoint', Icon::SIZE_SMALL)->render(),
851  'if (top.content.nav_frame) {
852  var node = top.TYPO3.Backend.NavigationContainer.PageTree.getSelected();
853  if (node === null) {
854  return false;
855  }
856 
857  var useNode = {
858  attributes: {
859  nodeData: {
860  id: ' . (int)$page_id . '
861  }
862  }
863  };
864 
865  node.ownerTree.commandProvider.mountAsTreeRoot(useNode, node.ownerTree);
866  }
867  ');
868  }
869 
879  public function DB_hideUnhide($table, $rec, $hideField)
880  {
881  return $this->DB_changeFlag($table, $rec, $hideField, $this->label(($rec[$hideField] ? 'un' : '') . 'hide'), 'hide');
882  }
883 
893  public function DB_changeFlag($table, $rec, $flagField, $title)
894  {
895  $uid = $rec['_ORIG_uid'] ?: $rec['uid'];
896  $loc = 'top.content.list_frame';
897  $editOnClick = 'if(' . $loc . '){' . $loc . '.location.href=' .
898  GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('tce_db') . '&redirect=') . '+top.rawurlencode(' .
899  $this->frameLocation($loc . '.document') . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+' .
901  '&data[' . $table . '][' . $uid . '][' . $flagField . ']=' . ($rec[$flagField] ? 0 : 1) . '&prErr=1&vC=' . $this->backendUser->veriCode()
902  ) . ';};';
903  if ($table === 'pages') {
904  $editOnClick .= 'top.nav.refresh.defer(500, top.nav);';
905  }
906  return $this->linkItem(
907  $title,
908  $this->iconFactory->getIcon('actions-edit-' . ($rec[$flagField] ? 'un' : '') . 'hide', Icon::SIZE_SMALL)->render(),
909  $editOnClick . 'return false;',
910  1
911  );
912  }
913 
914  /***************************************
915  *
916  * FILE
917  *
918  ***************************************/
926  public function printFileClickMenu($combinedIdentifier)
927  {
928  $icon = '';
929  $identifier = '';
930  $menuItems = array();
931  $combinedIdentifier = rawurldecode($combinedIdentifier);
932  $fileObject = ResourceFactory::getInstance()
933  ->retrieveFileOrFolderObject($combinedIdentifier);
934  if ($fileObject) {
935  $folder = false;
936  $isStorageRoot = false;
937  $isOnline = true;
938  $userMayViewStorage = false;
939  $userMayEditStorage = false;
940  $identifier = $fileObject->getCombinedIdentifier();
941  if ($fileObject instanceof Folder) {
942  $icon = '<span title="' . htmlspecialchars($fileObject->getName()) . '" class="absmiddle">'
943  . $this->iconFactory->getIconForResource($fileObject, Icon::SIZE_SMALL)->render()
944  . '</span>';
945  $folder = true;
946  if ($fileObject->getIdentifier() === $fileObject->getStorage()->getRootLevelFolder()->getIdentifier()) {
947  $isStorageRoot = true;
948  if ($this->backendUser->check('tables_select', 'sys_file_storage')) {
949  $userMayViewStorage = true;
950  }
951  if ($this->backendUser->check('tables_modify', 'sys_file_storage')) {
952  $userMayEditStorage = true;
953  }
954  }
955  if (!$fileObject->getStorage()->isOnline()) {
956  $isOnline = false;
957  }
958  } else {
959  $title = $fileObject->getName() . ' (' . GeneralUtility::formatSize($fileObject->getSize()) . ')';
960  $icon = '<span class="absmiddle" title="' . htmlspecialchars($title) . '">'
961  . $this->iconFactory->getIconForResource($fileObject, Icon::SIZE_SMALL)->render()
962  . '</span>';
963  }
964  // Hide
965  if (!in_array('hide', $this->disabledItems, true) && $isStorageRoot && $userMayEditStorage) {
966  $record = BackendUtility::getRecord('sys_file_storage', $fileObject->getStorage()->getUid());
967  $menuItems['hide'] = $this->DB_changeFlag(
968  'sys_file_storage',
969  $record,
970  'is_online',
971  $this->label($record['is_online'] ? 'offline' : 'online'),
972  'hide'
973  );
974  }
975  // Edit
976  if (!in_array('edit', $this->disabledItems, true) && $fileObject->checkActionPermission('write')) {
977  if (!$folder && !$isStorageRoot && $fileObject->isIndexed() && $this->backendUser->check('tables_modify', 'sys_file_metadata')) {
978  $metaData = $fileObject->_getMetaData();
979  $menuItems['edit2'] = $this->DB_edit('sys_file_metadata', $metaData['uid']);
980  }
981  if (!$folder && GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], $fileObject->getExtension()) && $fileObject->checkActionPermission('write')) {
982  $menuItems['edit'] = $this->FILE_launch($identifier, 'file_edit', 'editcontent', 'actions-page-open');
983  } elseif ($isStorageRoot && $userMayEditStorage) {
984  $menuItems['edit'] = $this->DB_edit('sys_file_storage', $fileObject->getStorage()->getUid());
985  }
986  }
987  // Rename
988  if (!in_array('rename', $this->disabledItems, true) && !$isStorageRoot && $fileObject->checkActionPermission('rename')) {
989  $menuItems['rename'] = $this->FILE_launch($identifier, 'file_rename', 'rename', 'actions-edit-rename');
990  }
991  // Upload
992  if (!in_array('upload', $this->disabledItems, true) && $folder && $isOnline && $fileObject->checkActionPermission('write')) {
993  $menuItems['upload'] = $this->FILE_launch($identifier, 'file_upload', 'upload', 'actions-edit-upload');
994  }
995  // New
996  if (!in_array('new', $this->disabledItems, true) && $folder && $isOnline && $fileObject->checkActionPermission('write')) {
997  $menuItems['new'] = $this->FILE_launch($identifier, 'file_newfolder', 'new', 'actions-document-new');
998  }
999  // Info
1000  if (!in_array('info', $this->disabledItems, true) && $fileObject->checkActionPermission('read')) {
1001  if ($isStorageRoot && $userMayViewStorage) {
1002  $menuItems['info'] = $this->DB_info('sys_file_storage', $fileObject->getStorage()->getUid());
1003  } elseif (!$folder) {
1004  $menuItems['info'] = $this->fileInfo($identifier);
1005  }
1006  }
1007  $menuItems[] = 'spacer';
1008  // Copy:
1009  if (!in_array('copy', $this->disabledItems, true) && !$isStorageRoot && $fileObject->checkActionPermission('read')) {
1010  $menuItems['copy'] = $this->FILE_copycut($identifier, 'copy');
1011  }
1012  // Cut:
1013  if (!in_array('cut', $this->disabledItems, true) && !$isStorageRoot && $fileObject->checkActionPermission('move')) {
1014  $menuItems['cut'] = $this->FILE_copycut($identifier, 'cut');
1015  }
1016  // Paste:
1017  $elFromAllTables = count($this->clipObj->elFromTable('_FILE'));
1018  if (!in_array('paste', $this->disabledItems, true) && $elFromAllTables && $folder && $fileObject->checkActionPermission('write')) {
1019  $elArr = $this->clipObj->elFromTable('_FILE');
1020  $selItem = reset($elArr);
1021  $clickedFileOrFolder = ResourceFactory::getInstance()->retrieveFileOrFolderObject($combinedIdentifier);
1022  $fileOrFolderInClipBoard = ResourceFactory::getInstance()->retrieveFileOrFolderObject($selItem);
1023  $elInfo = array(
1024  $fileOrFolderInClipBoard->getName(),
1025  $clickedFileOrFolder->getName(),
1026  $this->clipObj->currentMode()
1027  );
1028  if (!$fileOrFolderInClipBoard instanceof Folder || !$fileOrFolderInClipBoard->getStorage()->isWithinFolder($fileOrFolderInClipBoard, $clickedFileOrFolder)) {
1029  $menuItems['pasteinto'] = $this->FILE_paste($identifier, $selItem, $elInfo);
1030  }
1031  }
1032  $menuItems[] = 'spacer';
1033  // Delete:
1034  if (!in_array('delete', $this->disabledItems, true) && $fileObject->checkActionPermission('delete')) {
1035  if ($isStorageRoot && $userMayEditStorage) {
1036  $elInfo = array(GeneralUtility::fixed_lgd_cs($fileObject->getStorage()->getName(), $this->backendUser->uc['titleLen']));
1037  $menuItems['delete'] = $this->DB_delete('sys_file_storage', $fileObject->getStorage()->getUid(), $elInfo);
1038  } elseif (!$isStorageRoot) {
1039  $menuItems['delete'] = $this->FILE_delete($identifier);
1040  }
1041  }
1042  }
1043  // Adding external elements to the menuItems array
1044  $menuItems = $this->processingByExtClassArray($menuItems, $identifier, 0);
1045  // Processing by external functions?
1046  $menuItems = $this->externalProcessingOfFileMenuItems($menuItems);
1047  // Return the printed elements:
1048  return $this->printItems($menuItems);
1049  }
1050 
1057  public function externalProcessingOfFileMenuItems($menuItems)
1058  {
1059  return $menuItems;
1060  }
1061 
1073  public function FILE_launch($path, $moduleName, $type, $iconName, $noReturnUrl = false)
1074  {
1075  $loc = 'top.content.list_frame';
1076 
1077  if (strpos($moduleName, '.php') !== false) {
1079  'Using a php file directly in ClickMenu is deprecated since TYPO3 CMS 7, and will be removed in CMS 8.'
1080  . ' Register the class as module and use BackendUtility::getModuleUrl() to get the right link.'
1081  . ' For examples how to do this see ext_tables.php of EXT:backend.'
1082  );
1083  $scriptUrl = $moduleName;
1084  } else {
1085  $scriptUrl = BackendUtility::getModuleUrl($moduleName);
1086  }
1087 
1088  $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)') . ';}';
1089  return $this->linkItem(
1090  $this->label($type),
1091  $this->iconFactory->getIcon($iconName, Icon::SIZE_SMALL)->render(),
1092  $editOnClick . 'top.nav.refresh();'
1093  );
1094  }
1095 
1104  public function FILE_copycut($path, $type)
1105  {
1106  $isSel = '';
1107  // Pseudo table name for use in the clipboard.
1108  $table = '_FILE';
1109  $uid = GeneralUtility::shortmd5($path);
1110  if ($this->clipObj->current === 'normal') {
1111  $isSel = $this->clipObj->isSelected($table, $uid);
1112  }
1113  $addParam = array();
1114  if ($this->listFrame) {
1115  $addParam['reloadListFrame'] = $this->alwaysContentFrame ? 2 : 1;
1116  }
1117  return $this->linkItem(
1118  $this->label($type),
1119  $this->iconFactory->getIcon('actions-edit-' . $type . ($isSel === $type ? '-release' : ''), Icon::SIZE_SMALL)->render(),
1120  'TYPO3.ClickMenu.fetch(' . GeneralUtility::quoteJSvalue($this->clipObj->selUrlFile($path, ($type === 'copy' ? 1 : 0), ($isSel == $type), $addParam)) . ');return false;'
1121  );
1122  }
1123 
1131  public function FILE_delete($path)
1132  {
1133  $loc = 'top.content.list_frame';
1134  if ($this->backendUser->jsConfirmation(JsConfirmation::DELETE)) {
1135  $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')))) . ')';
1136  } else {
1137  $conf = '1==1';
1138  }
1139  $editOnClick = 'if(' . $loc . ' && ' . $conf . ' ){' . $loc . '.location.href=' .
1140  GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('tce_file') . '&redirect=') . '+top.rawurlencode(' .
1141  $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+' .
1143  '&file[delete][0][data]=' . rawurlencode($path) . '&vC=' . $this->backendUser->veriCode()
1144  ) . ';};';
1145  return $this->linkItem(
1146  $this->label('delete'),
1147  $this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL)->render(),
1148  $editOnClick . 'return false;'
1149  );
1150  }
1151 
1161  public function FILE_paste($path, $target, $elInfo)
1162  {
1163  $loc = 'top.content.list_frame';
1164  if ($this->backendUser->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE)) {
1165  $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])) . ')';
1166  } else {
1167  $conf = $loc;
1168  }
1169  $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();';
1170  return $this->linkItem(
1171  $this->label('pasteinto'),
1172  $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render(),
1173  $editOnClick . 'return false;'
1174  );
1175  }
1176 
1183  protected function fileInfo($identifier)
1184  {
1185  return $this->DB_info('_FILE', $identifier);
1186  }
1187 
1188  /***************************************
1189  *
1190  * DRAG AND DROP
1191  *
1192  ***************************************/
1201  public function printDragDropClickMenu($table, $srcId, $dstId)
1202  {
1203  $menuItems = array();
1204  // If the drag and drop menu should apply to PAGES use this set of menu items
1205  if ($table === 'pages') {
1206  // Move Into:
1207  $menuItems['movePage_into'] = $this->dragDrop_copymovepage($srcId, $dstId, 'move', 'into');
1208  // Move After:
1209  $menuItems['movePage_after'] = $this->dragDrop_copymovepage($srcId, $dstId, 'move', 'after');
1210  // Copy Into:
1211  $menuItems['copyPage_into'] = $this->dragDrop_copymovepage($srcId, $dstId, 'copy', 'into');
1212  // Copy After:
1213  $menuItems['copyPage_after'] = $this->dragDrop_copymovepage($srcId, $dstId, 'copy', 'after');
1214  }
1215  // If the drag and drop menu should apply to FOLDERS use this set of menu items
1216  if ($table === 'folders') {
1217  // Move Into:
1218  $menuItems['moveFolder_into'] = $this->dragDrop_copymovefolder($srcId, $dstId, 'move');
1219  // Copy Into:
1220  $menuItems['copyFolder_into'] = $this->dragDrop_copymovefolder($srcId, $dstId, 'copy');
1221  }
1222  // Adding external elements to the menuItems array
1223  $menuItems = $this->processingByExtClassArray($menuItems, 'dragDrop_' . $table, $srcId);
1224  // to extend this, you need to apply a Context Menu to a "virtual" table called "dragDrop_pages" or similar
1225  // Processing by external functions?
1226  $menuItems = $this->externalProcessingOfDBMenuItems($menuItems);
1227  // Return the printed elements:
1228  return $this->printItems($menuItems);
1229  }
1230 
1237  public function externalProcessingOfDragDropMenuItems($menuItems)
1238  {
1239  return $menuItems;
1240  }
1241 
1252  public function dragDrop_copymovepage($srcUid, $dstUid, $action, $into)
1253  {
1254  $negativeSign = $into === 'into' ? '' : '-';
1255  $loc = 'top.content.list_frame';
1256  $editOnClick = 'if(' . $loc . '){' . $loc . '.document.location=' .
1257  GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('tce_db') . '&redirect=') . '+top.rawurlencode(' .
1258  $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+' .
1260  '&cmd[pages][' . $srcUid . '][' . $action . ']=' . $negativeSign . $dstUid . '&prErr=1&vC=' .
1261  $this->backendUser->veriCode()
1262  ) . ';};top.nav.refresh();';
1263  return $this->linkItem(
1264  $this->label($action . 'Page_' . $into),
1265  $this->iconFactory->getIcon('actions-document-paste-' . $into, Icon::SIZE_SMALL)->render(),
1266  $editOnClick . 'return false;'
1267  );
1268  }
1269 
1279  public function dragDrop_copymovefolder($srcPath, $dstPath, $action)
1280  {
1281  $loc = 'top.content.list_frame';
1282  $editOnClick = 'if(' . $loc . '){' . $loc . '.document.location=' .
1283  GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('tce_file') . '&redirect=') . '+top.rawurlencode(' .
1284  $this->frameLocation(($loc . '.document')) . '.pathname+' . $this->frameLocation(($loc . '.document')) . '.search)+' .
1286  '&file[' . $action . '][0][data]=' . $srcPath . '&file[' . $action . '][0][target]=' . $dstPath . '&prErr=1&vC=' .
1287  $this->backendUser->veriCode()
1288  ) . ';};top.nav.refresh();';
1289  return $this->linkItem(
1290  $this->label($action . 'Folder_into'),
1291  $this->iconFactory->getIcon('apps-pagetree-drag-move-into', Icon::SIZE_SMALL)->render(),
1292  $editOnClick . 'return false;'
1293  );
1294  }
1295 
1296  /***************************************
1297  *
1298  * COMMON
1299  *
1300  **************************************/
1307  public function printItems($menuItems)
1308  {
1309  // Enable/Disable items
1310  $menuItems = $this->enableDisableItems($menuItems);
1311  // Clean up spacers
1312  $menuItems = $this->cleanUpSpacers($menuItems);
1313  // Adding JS part and return the content
1314  return $this->printLayerJScode($menuItems);
1315  }
1316 
1323  public function printLayerJScode($menuItems)
1324  {
1325  // Clipboard must not be submitted - then it's probably a copy/cut situation.
1326  if ($this->isCMlayers()) {
1327  // Create the table displayed in the clickmenu layer:
1328  // Wrap the inner table in another table to create outer border:
1329  $CMtable = '
1330  <div class="typo3-CSM-wrapperCM">
1331  <table border="0" cellpadding="0" cellspacing="0" class="typo3-CSM">
1332  ' . implode('', $this->menuItemsForClickMenu($menuItems)) . '
1333  </table></div>';
1334  return '<data><clickmenu><htmltable><![CDATA[' . $CMtable . ']]></htmltable><cmlevel>' . $this->cmLevel . '</cmlevel></clickmenu></data>';
1335  }
1336  }
1337 
1346  public function wrapColorTableCM($str)
1347  {
1349  return '<div class="typo3-CSM-wrapperCM">
1350  ' . $str . '
1351  </div>';
1352  }
1353 
1360  public function menuItemsForClickMenu($menuItems)
1361  {
1362  $out = array();
1363  foreach ($menuItems as $cc => $i) {
1364  // MAKE horizontal spacer
1365  if (is_string($i) && $i === 'spacer') {
1366  $out[] = '
1367  <tr style="height: 1px;" class="bgColor2">
1368  <td colspan="2"></td>
1369  </tr>';
1370  } else {
1371  // Just make normal element:
1372  $onClick = $i[3];
1373  $onClick = preg_replace('/return[[:space:]]+hideCM\\(\\)[[:space:]]*;/i', '', $onClick);
1374  $onClick = preg_replace('/return[[:space:]]+false[[:space:]]*;/i', '', $onClick);
1375  $onClick = preg_replace('/hideCM\\(\\);/i', '', $onClick);
1376  if (!$i[5]) {
1377  $onClick .= 'TYPO3.ClickMenu.hideAll();';
1378  }
1379  $CSM = ' oncontextmenu="this.click();return false;"';
1380  $out[] = '
1381  <tr class="typo3-CSM-itemRow" onclick="' . htmlspecialchars($onClick) . '"' . $CSM . '>
1382  ' . (!$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>') . '
1383  </tr>';
1384  }
1385  }
1386  return $out;
1387  }
1388 
1398  public function addMenuItems($menuItems, $newMenuItems, $position = '')
1399  {
1400  if (is_array($newMenuItems)) {
1401  if ($position) {
1402  $posArr = GeneralUtility::trimExplode(',', $position, true);
1403  foreach ($posArr as $pos) {
1404  list($place, $menuEntry) = GeneralUtility::trimExplode(':', $pos, true);
1405  list($place, $placeExtra) = GeneralUtility::trimExplode('-', $place, true);
1406  // Bottom
1407  $pointer = count($menuItems);
1408  $found = false;
1409  if ($place) {
1410  switch (strtolower($place)) {
1411  case 'after':
1412  case 'before':
1413  if ($menuEntry) {
1414  $p = 1;
1415  reset($menuItems);
1416  while (true) {
1417  if ((string)key($menuItems) === $menuEntry) {
1418  $pointer = $p;
1419  $found = true;
1420  break;
1421  }
1422  if (!next($menuItems)) {
1423  break;
1424  }
1425  $p++;
1426  }
1427  if (!$found) {
1428  break;
1429  }
1430  if ($place === 'before') {
1431  $pointer--;
1432  if ($placeExtra === 'spacer' and prev($menuItems) === 'spacer') {
1433  $pointer--;
1434  }
1435  } elseif ($place === 'after') {
1436  if ($placeExtra === 'spacer' and next($menuItems) === 'spacer') {
1437  $pointer++;
1438  }
1439  }
1440  }
1441  break;
1442  default:
1443  if (strtolower($place) === 'top') {
1444  $pointer = 0;
1445  } else {
1446  $pointer = count($menuItems);
1447  }
1448  $found = true;
1449  }
1450  }
1451  if ($found) {
1452  break;
1453  }
1454  }
1455  }
1456  $pointer = max(0, $pointer);
1457  $menuItemsBefore = array_slice($menuItems, 0, $pointer ?: 0);
1458  $menuItemsAfter = array_slice($menuItems, $pointer);
1459  $menuItems = $menuItemsBefore + $newMenuItems + $menuItemsAfter;
1460  }
1461  return $menuItems;
1462  }
1463 
1474  public function linkItem($str, $icon, $onClick, $onlyCM = 0, $dontHide = 0)
1475  {
1476  $onClick = str_replace('top.loadTopMenu', 'showClickmenu_raw', $onClick);
1477  return array(
1478  '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' . $str . $icon . '</a>',
1479  $str,
1480  $icon,
1481  $onClick,
1482  $onlyCM,
1483  $dontHide
1484  );
1485  }
1486 
1494  public function excludeIcon($iconCode)
1495  {
1497  return $this->backendUser->uc['noMenuMode'] && $this->backendUser->uc['noMenuMode'] !== 'icons' ? '' : ' ' . $iconCode;
1498  }
1499 
1506  public function enableDisableItems($menuItems)
1507  {
1508  if ($this->iParts[3]) {
1509  // Detect "only" mode: (only showing listed items)
1510  if ($this->iParts[3][0] === '+') {
1511  $this->iParts[3] = substr($this->iParts[3], 1);
1512  $only = true;
1513  } else {
1514  $only = false;
1515  }
1516  // Do filtering:
1517  // Transfer ONLY elements which are mentioned (or are spacers)
1518  if ($only) {
1519  $newMenuArray = array();
1520  foreach ($menuItems as $key => $value) {
1521  if (GeneralUtility::inList($this->iParts[3], $key) || is_string($value) && $value === 'spacer') {
1522  $newMenuArray[$key] = $value;
1523  }
1524  }
1525  $menuItems = $newMenuArray;
1526  } else {
1527  // Traverse all elements except those listed (just unsetting them):
1528  $elements = GeneralUtility::trimExplode(',', $this->iParts[3], true);
1529  foreach ($elements as $value) {
1530  unset($menuItems[$value]);
1531  }
1532  }
1533  }
1534  // Return processed menu items:
1535  return $menuItems;
1536  }
1537 
1544  public function cleanUpSpacers($menuItems)
1545  {
1546  // Remove doubles:
1547  $prevItemWasSpacer = false;
1548  foreach ($menuItems as $key => $value) {
1549  if (is_string($value) && $value === 'spacer') {
1550  if ($prevItemWasSpacer) {
1551  unset($menuItems[$key]);
1552  }
1553  $prevItemWasSpacer = true;
1554  } else {
1555  $prevItemWasSpacer = false;
1556  }
1557  }
1558  // Remove first:
1559  reset($menuItems);
1560  $key = key($menuItems);
1561  $value = current($menuItems);
1562  if (is_string($value) && $value === 'spacer') {
1563  unset($menuItems[$key]);
1564  }
1565  // Remove last:
1566  end($menuItems);
1567  $key = key($menuItems);
1568  $value = current($menuItems);
1569  if (is_string($value) && $value === 'spacer') {
1570  unset($menuItems[$key]);
1571  }
1572  // Return processed menu items:
1573  return $menuItems;
1574  }
1575 
1582  public function label($label)
1583  {
1584  return $this->languageService->makeEntities($this->languageService->sL('LLL:EXT:lang/locallang_core.xlf:cm.' . $label, true));
1585  }
1586 
1592  public function isCMlayers()
1593  {
1594  return !$this->CB;
1595  }
1596 
1603  public function frameLocation($str)
1604  {
1605  return $str . '.location';
1606  }
1607 }