TYPO3 CMS  TYPO3_7-6
Clipboard.php
Go to the documentation of this file.
1 <?php
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 
26 
30 class Clipboard
31 {
35  public $numberTabs = 3;
36 
58  public $clipData = [];
59 
63  public $changed = 0;
64 
68  public $current = '';
69 
73  public $lockToNormal = 0;
74 
80  public $fileMode = 0;
81 
85  protected $iconFactory;
86 
90  public function __construct()
91  {
92  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
93  }
94 
95  /*****************************************
96  *
97  * Initialize
98  *
99  ****************************************/
105  public function initializeClipboard()
106  {
107  // Get data
108  $clipData = $this->getBackendUser()->getModuleData('clipboard', $this->getBackendUser()->getTSConfigVal('options.saveClipboard') ? '' : 'ses');
109  // NumberTabs
110  $clNP = $this->getBackendUser()->getTSConfigVal('options.clipboardNumberPads');
111  if (MathUtility::canBeInterpretedAsInteger($clNP) && $clNP >= 0) {
112  $this->numberTabs = MathUtility::forceIntegerInRange($clNP, 0, 20);
113  }
114  // Resets/reinstates the clipboard pads
115  $this->clipData['normal'] = is_array($clipData['normal']) ? $clipData['normal'] : [];
116  for ($a = 1; $a <= $this->numberTabs; $a++) {
117  $this->clipData['tab_' . $a] = is_array($clipData['tab_' . $a]) ? $clipData['tab_' . $a] : [];
118  }
119  // Setting the current pad pointer ($this->current))
120  $this->clipData['current'] = ($this->current = isset($this->clipData[$clipData['current']]) ? $clipData['current'] : 'normal');
121  }
122 
130  public function lockToNormal()
131  {
132  $this->lockToNormal = 1;
133  $this->current = 'normal';
134  }
135 
148  public function setCmd($cmd)
149  {
150  if (is_array($cmd['el'])) {
151  foreach ($cmd['el'] as $k => $v) {
152  if ($this->current == 'normal') {
153  unset($this->clipData['normal']);
154  }
155  if ($v) {
156  $this->clipData[$this->current]['el'][$k] = $v;
157  } else {
158  $this->removeElement($k);
159  }
160  $this->changed = 1;
161  }
162  }
163  // Change clipboard pad (if not locked to normal)
164  if ($cmd['setP']) {
165  $this->setCurrentPad($cmd['setP']);
166  }
167  // Remove element (value = item ident: DB; '[tablename]|[uid]' FILE: '_FILE|[shortmd5 hash of path]'
168  if ($cmd['remove']) {
169  $this->removeElement($cmd['remove']);
170  $this->changed = 1;
171  }
172  // Remove all on current pad (value = pad-ident)
173  if ($cmd['removeAll']) {
174  $this->clipData[$cmd['removeAll']] = [];
175  $this->changed = 1;
176  }
177  // Set copy mode of the tab
178  if (isset($cmd['setCopyMode'])) {
179  $this->clipData[$this->current]['mode'] = $this->isElements() ? ($cmd['setCopyMode'] ? 'copy' : '') : '';
180  $this->changed = 1;
181  }
182  }
183 
190  public function setCurrentPad($padIdent)
191  {
192  // Change clipboard pad (if not locked to normal)
193  if (!$this->lockToNormal && $this->current != $padIdent) {
194  if (isset($this->clipData[$padIdent])) {
195  $this->clipData['current'] = ($this->current = $padIdent);
196  }
197  if ($this->current != 'normal' || !$this->isElements()) {
198  $this->clipData[$this->current]['mode'] = '';
199  }
200  // Setting mode to default (move) if no items on it or if not 'normal'
201  $this->changed = 1;
202  }
203  }
204 
211  public function endClipboard()
212  {
213  if ($this->changed) {
214  $this->saveClipboard();
215  }
216  $this->changed = 0;
217  }
218 
227  public function cleanUpCBC($CBarr, $table, $removeDeselected = 0)
228  {
229  if (is_array($CBarr)) {
230  foreach ($CBarr as $k => $v) {
231  $p = explode('|', $k);
232  if ((string)$p[0] != (string)$table || $removeDeselected && !$v) {
233  unset($CBarr[$k]);
234  }
235  }
236  }
237  return $CBarr;
238  }
239 
240  /*****************************************
241  *
242  * Clipboard HTML renderings
243  *
244  ****************************************/
250  public function printClipboard()
251  {
252  $languageService = $this->getLanguageService();
253  $out = [];
254  $elementCount = count($this->elFromTable($this->fileMode ? '_FILE' : ''));
255  // Copymode Selector menu
256  $copymodeUrl = GeneralUtility::linkThisScript();
257  $moveLabel = htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_misc.xlf:moveElements'));
258  $copyLabel = htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_misc.xlf:copyElements'));
259 
260  $copymodeSelector = '
261  <div class="btn-group">
262  <button class="btn btn-default dropdown-toggle" type="button" id="copymodeSelector" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
263  ' . ($this->currentMode() === 'copy' ? $copyLabel : $moveLabel) . '
264  <span class="caret"></span>
265  </button>
266  <ul class="dropdown-menu" aria-labelledby="copymodeSelector">
267  <li><a href="#" onclick="document.getElementById(\'clipboard_form\').method=\'POST\'; document.getElementById(\'clipboard_form\').action=' . htmlspecialchars(GeneralUtility::quoteJSvalue($copymodeUrl . '&CB[setCopyMode]=')) . '; document.getElementById(\'clipboard_form\').submit(); return true;">' . $moveLabel . '</a></li>
268  <li><a href="#" onclick="document.getElementById(\'clipboard_form\').method=\'POST\'; document.getElementById(\'clipboard_form\').action=' . htmlspecialchars(GeneralUtility::quoteJSvalue($copymodeUrl . '&CB[setCopyMode]=1')) . '; document.getElementById(\'clipboard_form\').submit(); return true;">' . $copyLabel . '</a></li>
269  </ul>
270  </div>
271  ';
272 
273  $deleteLink = '';
274  $menuSelector = '';
275  if ($elementCount) {
276  $removeAllUrl = GeneralUtility::linkThisScript(['CB' => ['removeAll' => $this->current]]);
277 
278  // Selector menu + clear button
279  $optionArray = [];
280  // Import / Export link:
281  if (ExtensionManagementUtility::isLoaded('impexp')) {
282  $url = BackendUtility::getModuleUrl('xMOD_tximpexp', $this->exportClipElementParameters());
283  $optionArray[] = '<li><a href="' . htmlspecialchars($url) . '">' . $this->clLabel('export', 'rm') . '</a></li>';
284  }
285  // Edit:
286  if (!$this->fileMode) {
287  $optionArray[] = '<li><a href="#" onclick="' . htmlspecialchars(('window.location.href=' . GeneralUtility::quoteJSvalue($this->editUrl() . '&returnUrl=') . '+top.rawurlencode(window.location.href);')) . '">' . $this->clLabel('edit', 'rm') . '</a></li>';
288  }
289 
290  // Delete referenced elements:
291  $confirmationCheck = false;
292  if ($this->getBackendUser()->jsConfirmation(JsConfirmation::DELETE)) {
293  $confirmationCheck = true;
294  }
295  $confirmationMessage = sprintf(
296  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.deleteClip'),
297  $elementCount
298  );
299  $title = $languageService
300  ->sL('LLL:EXT:lang/locallang_core.xlf:labels.clipboard.delete_elements');
301  $returnUrl = $this->deleteUrl(1, ($this->fileMode ? 1 : 0));
302  $btnOkText = $languageService
303  ->sL('LLL:EXT:lang/locallang_alt_doc.xlf:buttons.confirm.delete_elements.yes');
304  $btnCancelText = $languageService
305  ->sL('LLL:EXT:lang/locallang_alt_doc.xlf:buttons.confirm.delete_elements.no');
306  $optionArray[] = '<li><a'
307  . (($confirmationCheck) ? ' class="t3js-modal-trigger"' : '')
308  . ' href="' . htmlspecialchars($returnUrl) . '"'
309  . ' data-severity="warning"'
310  . ' data-button-close-text="' . htmlspecialchars($btnCancelText) . '"'
311  . ' data-button-ok-text="' . htmlspecialchars($btnOkText) . '"'
312  . ' data-content="' . htmlspecialchars($confirmationMessage) . '"'
313  . ' data-title="' . htmlspecialchars($title) . '">'
314  . htmlspecialchars($title) . '</a></li>';
315 
316  // Clear clipboard
317  $optionArray[] = '<li><a href="' . htmlspecialchars($removeAllUrl) . '#clip_head">' . $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.clipboard.clear_clipboard', true) . '</a></li>';
318  $deleteLink = '<a class="btn btn-danger" href="' . htmlspecialchars($removeAllUrl) . '#clip_head" title="' . $languageService->sL('LLL:EXT:lang/locallang_core.xlf:buttons.clear', true) . '">' . $this->iconFactory->getIcon('actions-document-close', Icon::SIZE_SMALL)->render(SvgIconProvider::MARKUP_IDENTIFIER_INLINE) . '</a>';
319 
320  // menuSelector
321  $menuSelector = '
322  <div class="btn-group">
323  <button class="btn btn-default dropdown-toggle" type="button" id="menuSelector" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
324  ' . $this->clLabel('menu', 'rm') . '
325  <span class="caret"></span>
326  </button>
327  <ul class="dropdown-menu" aria-labelledby="menuSelector">
328  ' . implode('', $optionArray) . '
329  </ul>
330  </div>
331  ';
332  }
333 
334  $out[] = '
335  <tr>
336  <td colspan="2" nowrap="nowrap" width="95%">' . $copymodeSelector . ' ' . $menuSelector . '</td>
337  <td nowrap="nowrap" class="col-control">' . $deleteLink . '</td>
338  </tr>';
339 
340  // Print header and content for the NORMAL tab:
341  // check for current item so it can be wrapped in strong tag
342  $current = ($this->current == 'normal');
343  $out[] = '
344  <tr>
345  <td colspan="3"><a href="' . htmlspecialchars(GeneralUtility::linkThisScript(['CB' => ['setP' => 'normal']])) . '#clip_head" title="' . $this->clLabel('normal-description') . '">'
346  . '<span class="t3-icon fa ' . ($current ? 'fa-check-circle' : 'fa-circle-o') . '"></span>'
347  . $this->padTitleWrap($this->clLabel('normal'), 'normal', $current)
348  . '</a></td>
349  </tr>';
350  if ($this->current == 'normal') {
351  $out = array_merge($out, $this->printContentFromTab('normal'));
352  }
353  // Print header and content for the NUMERIC tabs:
354  for ($a = 1; $a <= $this->numberTabs; $a++) {
355  // check for current item so it can be wrapped in strong tag
356  $current = ($this->current == 'tab_' . $a);
357  $out[] = '
358  <tr>
359  <td colspan="3"><a href="' . htmlspecialchars(GeneralUtility::linkThisScript(['CB' => ['setP' => ('tab_' . $a)]])) . '#clip_head" title="' . $this->clLabel('cliptabs-description') . '">'
360  . '<span class="t3-icon fa ' . ($current ? 'fa-check-circle' : 'fa-circle-o') . '"></span>'
361  . $this->padTitleWrap(sprintf($this->clLabel('cliptabs-name'), $a), ('tab_' . $a), $current)
362  . '</a></td>
363  </tr>';
364  if ($this->current == 'tab_' . $a) {
365  $out = array_merge($out, $this->printContentFromTab('tab_' . $a));
366  }
367  }
368  // Wrap accumulated rows in a table:
369  $output = '<a name="clip_head"></a>
370 
371  <!--
372  TYPO3 Clipboard:
373  -->
374  <div class="row">
375  <div class="col-sm-12">
376  <div class="panel panel-default">
377  <div class="panel-heading">' . BackendUtility::wrapInHelp('xMOD_csh_corebe', 'list_clipboard', $this->clLabel('clipboard', 'buttons')) . '</div>
378  <table class="table">
379  ' . implode('', $out) . '
380  </table>
381  </div>
382  </div>
383  </div>
384  ';
385  // Wrap in form tag:
386  $output = '<form action="" id="clipboard_form">' . $output . '</form>';
387  // Return the accumulated content:
388  return $output;
389  }
390 
398  public function printContentFromTab($pad)
399  {
400  $lines = [];
401  if (is_array($this->clipData[$pad]['el'])) {
402  foreach ($this->clipData[$pad]['el'] as $k => $v) {
403  if ($v) {
404  list($table, $uid) = explode('|', $k);
405  $bgColClass = $table == '_FILE' && $this->fileMode || $table != '_FILE' && !$this->fileMode ? 'bgColor4-20' : 'bgColor4';
406  // Rendering files/directories on the clipboard
407  if ($table == '_FILE') {
408  $fileObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($v);
409  if ($fileObject) {
410  $thumb = '';
411  $folder = $fileObject instanceof \TYPO3\CMS\Core\Resource\Folder;
412  $size = $folder ? '' : '(' . GeneralUtility::formatSize($fileObject->getSize()) . 'bytes)';
413  $icon = '<span title="' . htmlspecialchars($fileObject->getName() . ' ' . $size) . '">' . $this->iconFactory->getIconForResource($fileObject, Icon::SIZE_SMALL)->render() . '</span>';
414  if (!$folder && GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileObject->getExtension())) {
415  $processedFile = $fileObject->process(\TYPO3\CMS\Core\Resource\ProcessedFile::CONTEXT_IMAGEPREVIEW, []);
416  if ($processedFile) {
417  $thumbUrl = $processedFile->getPublicUrl(true);
418  $thumb = '<br /><img src="' . htmlspecialchars($thumbUrl) . '" ' .
419  'width="' . $processedFile->getProperty('width') . '" ' .
420  'height="' . $processedFile->getProperty('height') . '" ' .
421  'title="' . htmlspecialchars($fileObject->getName()) . '" alt="" />';
422  }
423  }
424  $lines[] = '
425  <tr>
426  <td nowrap="nowrap" class="col-icon">' . $icon . '</td>
427  <td nowrap="nowrap" width="95%">' . $this->linkItemText(htmlspecialchars(GeneralUtility::fixed_lgd_cs($fileObject->getName(), $this->getBackendUser()->uc['titleLen'])), $fileObject->getName()) . ($pad == 'normal' ? ' <strong>(' . ($this->clipData['normal']['mode'] == 'copy' ? $this->clLabel('copy', 'cm') : $this->clLabel('cut', 'cm')) . ')</strong>' : '') . '&nbsp;' . $thumb . '</td>
428  <td nowrap="nowrap" class="col-control">
429  <div class="btn-group">
430  <a class="btn btn-default" href="#" onclick="' . htmlspecialchars(('top.launchView(' . GeneralUtility::quoteJSvalue($table) . ', ' . GeneralUtility::quoteJSvalue($v) . '); return false;')) . '"title="' . $this->clLabel('info', 'cm') . '">' . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render() . '</a>' . '<a class="btn btn-default" href="' . htmlspecialchars($this->removeUrl('_FILE', GeneralUtility::shortmd5($v))) . '#clip_head" title="' . $this->clLabel('removeItem') . '">' . $this->iconFactory->getIcon('actions-selection-delete', Icon::SIZE_SMALL)->render() . '</a>
431  </div>
432  </td>
433  </tr>';
434  } else {
435  // If the file did not exist (or is illegal) then it is removed from the clipboard immediately:
436  unset($this->clipData[$pad]['el'][$k]);
437  $this->changed = 1;
438  }
439  } else {
440  // Rendering records:
441  $rec = BackendUtility::getRecordWSOL($table, $uid);
442  if (is_array($rec)) {
443  $lines[] = '
444  <tr>
445  <td nowrap="nowrap" class="col-icon">' . $this->linkItemText($this->iconFactory->getIconForRecord($table, $rec, Icon::SIZE_SMALL)->render(), $rec, $table) . '</td>
446  <td nowrap="nowrap" width="95%">' . $this->linkItemText(htmlspecialchars(GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $rec), $this->getBackendUser()->uc['titleLen'])), $rec, $table) . ($pad == 'normal' ? ' <strong>(' . ($this->clipData['normal']['mode'] == 'copy' ? $this->clLabel('copy', 'cm') : $this->clLabel('cut', 'cm')) . ')</strong>' : '') . '&nbsp;</td>
447  <td nowrap="nowrap" class="col-control">
448  <div class="btn-group">
449  <a class="btn btn-default" href="#" onclick="' . htmlspecialchars(('top.launchView(' . GeneralUtility::quoteJSvalue($table) . ', \'' . (int)$uid . '\'); return false;')) . '" title="' . $this->clLabel('info', 'cm') . '">' . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render() . '</a>' . '<a class="btn btn-default" href="' . htmlspecialchars($this->removeUrl($table, $uid)) . '#clip_head" title="' . $this->clLabel('removeItem') . '">' . $this->iconFactory->getIcon('actions-selection-delete', Icon::SIZE_SMALL)->render() . '</a>
450  </div>
451  </td>
452  </tr>';
453  $localizationData = $this->getLocalizations($table, $rec, $bgColClass, $pad);
454  if ($localizationData) {
455  $lines[] = $localizationData;
456  }
457  } else {
458  unset($this->clipData[$pad]['el'][$k]);
459  $this->changed = 1;
460  }
461  }
462  }
463  }
464  }
465  $this->endClipboard();
466  return $lines;
467  }
468 
474  public function hasElements()
475  {
476  foreach ($this->clipData as $data) {
477  if (isset($data['el']) && is_array($data['el']) && !empty($data['el'])) {
478  return true;
479  }
480  }
481 
482  return false;
483  }
484 
494  public function getLocalizations($table, $parentRec, $bgColClass, $pad)
495  {
496  $lines = [];
497  $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl'];
498  if ($table != 'pages' && BackendUtility::isTableLocalizable($table) && !$tcaCtrl['transOrigPointerTable']) {
499  $where = [];
500  $where[] = $tcaCtrl['transOrigPointerField'] . '=' . (int)$parentRec['uid'];
501  $where[] = $tcaCtrl['languageField'] . '<>0';
502  if (isset($tcaCtrl['delete']) && $tcaCtrl['delete']) {
503  $where[] = $tcaCtrl['delete'] . '=0';
504  }
505  if (isset($tcaCtrl['versioningWS']) && $tcaCtrl['versioningWS']) {
506  $where[] = 't3ver_wsid=' . $parentRec['t3ver_wsid'];
507  }
508  $rows = $this->getDatabaseConnection()->exec_SELECTgetRows('*', $table, implode(' AND ', $where));
509  if (is_array($rows)) {
510  $modeData = '';
511  if ($pad == 'normal') {
512  $mode = $this->clipData['normal']['mode'] == 'copy' ? 'copy' : 'cut';
513  $modeData = ' <strong>(' . $this->clLabel($mode, 'cm') . ')</strong>';
514  }
515  foreach ($rows as $rec) {
516  $lines[] = '
517  <tr>
518  <td nowrap="nowrap" class="col-icon">' . $this->iconFactory->getIconForRecord($table, $rec, Icon::SIZE_SMALL)->render() . '</td>
519  <td nowrap="nowrap" width="95%">' . htmlspecialchars(GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $rec), $this->getBackendUser()->uc['titleLen'])) . $modeData . '</td>
520  <td nowrap="nowrap" class="col-control"></td>
521  </tr>';
522  }
523  }
524  }
525  return implode('', $lines);
526  }
527 
537  public function padTitleWrap($str, $pad, $active)
538  {
539  $el = count($this->elFromTable($this->fileMode ? '_FILE' : '', $pad));
540  if ($el) {
541  $str .= ' (' . ($pad == 'normal' ? ($this->clipData['normal']['mode'] == 'copy' ? $this->clLabel('copy', 'cm') : $this->clLabel('cut', 'cm')) : htmlspecialchars($el)) . ')';
542  }
543  if ($active === true) {
544  return '<strong>' . $str . '</strong>';
545  } else {
546  return '<span class="text-muted">' . $str . '</span>';
547  }
548  }
549 
558  public function linkItemText($str, $rec, $table = '')
559  {
560  if (is_array($rec) && $table) {
561  if ($this->fileMode) {
562  $str = '<span class="text-muted">' . $str . '</span>';
563  } else {
564  $str = '<a href="' . htmlspecialchars(BackendUtility::getModuleUrl('web_list', ['id' => $rec['pid']])) . '">' . $str . '</a>';
565  }
566  } elseif (file_exists($rec)) {
567  if (!$this->fileMode) {
568  $str = '<span class="text-muted">' . $str . '</span>';
569  } else {
570  if (ExtensionManagementUtility::isLoaded('filelist')) {
571  $str = '<a href="' . htmlspecialchars(BackendUtility::getModuleUrl('file_list', ['id' => dirname($rec)])) . '">' . $str . '</a>';
572  }
573  }
574  }
575  return $str;
576  }
577 
588  public function selUrlDB($table, $uid, $copy = 0, $deselect = 0, $baseArray = [])
589  {
590  $CB = ['el' => [rawurlencode($table . '|' . $uid) => $deselect ? 0 : 1]];
591  if ($copy) {
592  $CB['setCopyMode'] = 1;
593  }
594  $baseArray['CB'] = $CB;
595  return GeneralUtility::linkThisScript($baseArray);
596  }
597 
607  public function selUrlFile($path, $copy = 0, $deselect = 0, $baseArray = [])
608  {
609  $CB = ['el' => [rawurlencode('_FILE|' . GeneralUtility::shortmd5($path)) => $deselect ? '' : $path]];
610  if ($copy) {
611  $CB['setCopyMode'] = 1;
612  }
613  $baseArray['CB'] = $CB;
614  return GeneralUtility::linkThisScript($baseArray);
615  }
616 
628  public function pasteUrl($table, $uid, $setRedirect = true, array $update = null)
629  {
630  $urlParameters = [
631  'vC' => $this->getBackendUser()->veriCode(),
632  'prErr' => 1,
633  'uPT' => 1,
634  'CB[paste]' => $table . '|' . $uid,
635  'CB[pad]' => $this->current
636  ];
637  if ($setRedirect) {
638  $urlParameters['redirect'] = GeneralUtility::linkThisScript(['CB' => '']);
639  }
640  if (is_array($update)) {
641  $urlParameters['CB[update]'] = $update;
642  }
643  return BackendUtility::getModuleUrl($table === '_FILE' ? 'tce_file' : 'tce_db', $urlParameters);
644  }
645 
653  public function deleteUrl($setRedirect = 1, $file = 0)
654  {
655  $urlParameters = [
656  'vC' => $this->getBackendUser()->veriCode(),
657  'prErr' => 1,
658  'uPT' => 1,
659  'CB[delete]' => 1,
660  'CB[pad]' => $this->current
661  ];
662  if ($setRedirect) {
663  $urlParameters['redirect'] = GeneralUtility::linkThisScript(['CB' => '']);
664  }
665  return BackendUtility::getModuleUrl($file ? 'tce_file' : 'tce_db', $urlParameters);
666  }
667 
675  public function editUrl()
676  {
677  $parameters = [];
678  // All records
679  $elements = $this->elFromTable('');
680  foreach ($elements as $tP => $value) {
681  list($table, $uid) = explode('|', $tP);
682  $parameters['edit[' . $table . '][' . $uid . ']'] = 'edit';
683  }
684  return BackendUtility::getModuleUrl('record_edit', $parameters);
685  }
686 
695  public function removeUrl($table, $uid)
696  {
697  return GeneralUtility::linkThisScript(['CB' => ['remove' => $table . '|' . $uid]]);
698  }
699 
710  public function confirmMsg($table, $rec, $type, $clElements, $columnLabel = '')
711  {
712  $message = $this->confirmMsgText($table, $rec, $type, $clElements, $columnLabel);
713  if (!empty($message)) {
714  $message = 'confirm(' . GeneralUtility::quoteJSvalue($message) . ');';
715  }
716  return $message;
717  }
718 
729  public function confirmMsgText($table, $rec, $type, $clElements, $columnLabel = '')
730  {
731  if ($this->getBackendUser()->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE)) {
732  $labelKey = 'LLL:EXT:lang/locallang_core.xlf:mess.' . ($this->currentMode() == 'copy' ? 'copy' : 'move') . ($this->current == 'normal' ? '' : 'cb') . '_' . $type;
733  $msg = $this->getLanguageService()->sL($labelKey . ($columnLabel ? '_colPos': ''));
734  if ($table == '_FILE') {
735  $thisRecTitle = basename($rec);
736  if ($this->current == 'normal') {
737  $selItem = reset($clElements);
738  $selRecTitle = basename($selItem);
739  } else {
740  $selRecTitle = count($clElements);
741  }
742  } else {
743  $thisRecTitle = $table == 'pages' && !is_array($rec) ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] : BackendUtility::getRecordTitle($table, $rec);
744  if ($this->current == 'normal') {
745  $selItem = $this->getSelectedRecord();
746  $selRecTitle = $selItem['_RECORD_TITLE'];
747  } else {
748  $selRecTitle = count($clElements);
749  }
750  }
751  // @TODO
752  // This can get removed as soon as the "_colPos" label is translated
753  // into all available locallang languages.
754  if (!$msg && $columnLabel) {
755  $thisRecTitle .= ' | ' . $columnLabel;
756  $msg = $this->getLanguageService()->sL($labelKey);
757  }
758 
759  // Message
760  $conf = sprintf(
761  $msg,
762  GeneralUtility::fixed_lgd_cs($selRecTitle, 30),
763  GeneralUtility::fixed_lgd_cs($thisRecTitle, 30),
764  GeneralUtility::fixed_lgd_cs($columnLabel, 30)
765  );
766  } else {
767  $conf = '';
768  }
769  return $conf;
770  }
771 
779  public function clLabel($key, $Akey = 'labels')
780  {
781  return htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:' . $Akey . '.' . $key));
782  }
783 
789  protected function exportClipElementParameters()
790  {
791  // Init
792  $pad = $this->current;
793  $params = [];
794  $params['tx_impexp']['action'] = 'export';
795  // Traverse items:
796  if (is_array($this->clipData[$pad]['el'])) {
797  foreach ($this->clipData[$pad]['el'] as $k => $v) {
798  if ($v) {
799  list($table, $uid) = explode('|', $k);
800  // Rendering files/directories on the clipboard
801  if ($table == '_FILE') {
802  if (file_exists($v) && GeneralUtility::isAllowedAbsPath($v)) {
803  $params['tx_impexp'][is_dir($v) ? 'dir' : 'file'][] = $v;
804  }
805  } else {
806  // Rendering records:
807  $rec = BackendUtility::getRecord($table, $uid);
808  if (is_array($rec)) {
809  $params['tx_impexp']['record'][] = $table . ':' . $uid;
810  }
811  }
812  }
813  }
814  }
815  return $params;
816  }
817 
818  /*****************************************
819  *
820  * Helper functions
821  *
822  ****************************************/
829  public function removeElement($el)
830  {
831  unset($this->clipData[$this->current]['el'][$el]);
832  $this->changed = 1;
833  }
834 
842  public function saveClipboard()
843  {
844  $this->getBackendUser()->pushModuleData('clipboard', $this->clipData);
845  }
846 
852  public function currentMode()
853  {
854  return $this->clipData[$this->current]['mode'] == 'copy' ? 'copy' : 'cut';
855  }
856 
863  public function cleanCurrent()
864  {
865  if (is_array($this->clipData[$this->current]['el'])) {
866  foreach ($this->clipData[$this->current]['el'] as $k => $v) {
867  list($table, $uid) = explode('|', $k);
868  if ($table != '_FILE') {
869  if (!$v || !is_array(BackendUtility::getRecord($table, $uid, 'uid'))) {
870  unset($this->clipData[$this->current]['el'][$k]);
871  $this->changed = 1;
872  }
873  } else {
874  if (!$v) {
875  unset($this->clipData[$this->current]['el'][$k]);
876  $this->changed = 1;
877  } else {
878  try {
879  ResourceFactory::getInstance()->retrieveFileOrFolderObject($v);
880  } catch (\TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException $e) {
881  // The file has been deleted in the meantime, so just remove it silently
882  unset($this->clipData[$this->current]['el'][$k]);
883  }
884  }
885  }
886  }
887  }
888  }
889 
897  public function elFromTable($matchTable = '', $pad = '')
898  {
899  $pad = $pad ? $pad : $this->current;
900  $list = [];
901  if (is_array($this->clipData[$pad]['el'])) {
902  foreach ($this->clipData[$pad]['el'] as $k => $v) {
903  if ($v) {
904  list($table, $uid) = explode('|', $k);
905  if ($table != '_FILE') {
906  if ((!$matchTable || (string)$table == (string)$matchTable) && $GLOBALS['TCA'][$table]) {
907  $list[$k] = $pad == 'normal' ? $v : $uid;
908  }
909  } else {
910  if ((string)$table == (string)$matchTable) {
911  $list[$k] = $v;
912  }
913  }
914  }
915  }
916  }
917  return $list;
918  }
919 
928  public function isSelected($table, $uid)
929  {
930  $k = $table . '|' . $uid;
931  return $this->clipData[$this->current]['el'][$k] ? ($this->current == 'normal' ? $this->currentMode() : 1) : '';
932  }
933 
943  public function getSelectedRecord($table = '', $uid = '')
944  {
945  if (!$table && !$uid) {
946  $elArr = $this->elFromTable('');
947  reset($elArr);
948  list($table, $uid) = explode('|', key($elArr));
949  }
950  if ($this->isSelected($table, $uid)) {
951  $selRec = BackendUtility::getRecordWSOL($table, $uid);
952  $selRec['_RECORD_TITLE'] = BackendUtility::getRecordTitle($table, $selRec);
953  return $selRec;
954  }
955  return [];
956  }
957 
963  public function isElements()
964  {
965  return is_array($this->clipData[$this->current]['el']) && !empty($this->clipData[$this->current]['el']);
966  }
967 
968  /*****************************************
969  *
970  * FOR USE IN tce_db.php:
971  *
972  ****************************************/
991  public function makePasteCmdArray($ref, $CMD, array $update = null)
992  {
993  list($pTable, $pUid) = explode('|', $ref);
994  $pUid = (int)$pUid;
995  // pUid must be set and if pTable is not set (that means paste ALL elements)
996  // the uid MUST be positive/zero (pointing to page id)
997  if ($pTable || $pUid >= 0) {
998  $elements = $this->elFromTable($pTable);
999  // So the order is preserved.
1000  $elements = array_reverse($elements);
1001  $mode = $this->currentMode() == 'copy' ? 'copy' : 'move';
1002  // Traverse elements and make CMD array
1003  foreach ($elements as $tP => $value) {
1004  list($table, $uid) = explode('|', $tP);
1005  if (!is_array($CMD[$table])) {
1006  $CMD[$table] = [];
1007  }
1008  if (is_array($update)) {
1009  $CMD[$table][$uid][$mode] = [
1010  'action' => 'paste',
1011  'target' => $pUid,
1012  'update' => $update,
1013  ];
1014  } else {
1015  $CMD[$table][$uid][$mode] = $pUid;
1016  }
1017  if ($mode == 'move') {
1018  $this->removeElement($tP);
1019  }
1020  }
1021  $this->endClipboard();
1022  }
1023  return $CMD;
1024  }
1025 
1032  public function makeDeleteCmdArray($CMD)
1033  {
1034  // all records
1035  $elements = $this->elFromTable('');
1036  foreach ($elements as $tP => $value) {
1037  list($table, $uid) = explode('|', $tP);
1038  if (!is_array($CMD[$table])) {
1039  $CMD[$table] = [];
1040  }
1041  $CMD[$table][$uid]['delete'] = 1;
1042  $this->removeElement($tP);
1043  }
1044  $this->endClipboard();
1045  return $CMD;
1046  }
1047 
1048  /*****************************************
1049  *
1050  * FOR USE IN tce_file.php:
1051  *
1052  ****************************************/
1061  public function makePasteCmdArray_file($ref, $FILE)
1062  {
1063  list($pTable, $pUid) = explode('|', $ref);
1064  $elements = $this->elFromTable('_FILE');
1065  $mode = $this->currentMode() == 'copy' ? 'copy' : 'move';
1066  // Traverse elements and make CMD array
1067  foreach ($elements as $tP => $path) {
1068  $FILE[$mode][] = ['data' => $path, 'target' => $pUid];
1069  if ($mode == 'move') {
1070  $this->removeElement($tP);
1071  }
1072  }
1073  $this->endClipboard();
1074  return $FILE;
1075  }
1076 
1083  public function makeDeleteCmdArray_file($FILE)
1084  {
1085  $elements = $this->elFromTable('_FILE');
1086  // Traverse elements and make CMD array
1087  foreach ($elements as $tP => $path) {
1088  $FILE['delete'][] = ['data' => $path];
1089  $this->removeElement($tP);
1090  }
1091  $this->endClipboard();
1092  return $FILE;
1093  }
1094 
1100  protected function getLanguageService()
1101  {
1102  return $GLOBALS['LANG'];
1103  }
1104 
1110  protected function getBackendUser()
1111  {
1112  return $GLOBALS['BE_USER'];
1113  }
1114 
1120  protected function getDatabaseConnection()
1121  {
1122  return $GLOBALS['TYPO3_DB'];
1123  }
1124 }
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
deleteUrl($setRedirect=1, $file=0)
Definition: Clipboard.php:653
cleanUpCBC($CBarr, $table, $removeDeselected=0)
Definition: Clipboard.php:227
static linkThisScript(array $getParams=[])
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
static fixed_lgd_cs($string, $chars, $appendString='...')
$uid
Definition: server.php:38
static formatSize($sizeInBytes, $labels='', $base=0)
linkItemText($str, $rec, $table='')
Definition: Clipboard.php:558
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
padTitleWrap($str, $pad, $active)
Definition: Clipboard.php:537
static getRecordWSOL($table, $uid, $fields=' *', $where='', $useDeleteClause=true, $unsetMovePointers=false)
elFromTable($matchTable='', $pad='')
Definition: Clipboard.php:897