TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
FileList.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Filelist;
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 
38 
43 {
49  public $iLimit = 40;
50 
56  public $thumbs = false;
57 
63  public $spaceIcon;
64 
70  public $fixedL = 30;
71 
77  public $clickMenus = 1;
78 
84  public $sort = '';
85 
91  public $sortRev = 1;
92 
96  public $firstElementNumber = 0;
97 
101  public $clipBoard = 0;
102 
106  public $bigControlPanel = 0;
107 
111  public $JScode = '';
112 
116  public $HTMLcode = '';
117 
121  public $totalbytes = 0;
122 
126  public $dirs = [];
127 
131  public $files = [];
132 
136  public $path = '';
137 
141  protected $folderObject;
142 
148  public $eCounter = 0;
149 
153  public $totalItems = '';
154 
158  public $CBnames = [];
159 
163  public $clipObj;
164 
168  protected $resourceFactory;
169 
174  {
175  $this->resourceFactory = $resourceFactory;
176  }
177 
181  protected $iconFactory;
182 
187 
194  {
195  parent::__construct();
196  $this->fileListController = $fileListController;
197  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
198 
199  $modTSconfig = BackendUtility::getModTSconfig(0, 'options.file_list');
200  if (!empty($modTSconfig['properties']['filesPerPage'])) {
201  $this->iLimit = MathUtility::forceIntegerInRange($modTSconfig['properties']['filesPerPage'], 1);
202  }
203  }
204 
216  public function start(Folder $folderObject, $pointer, $sort, $sortRev, $clipBoard = false, $bigControlPanel = false)
217  {
218  $this->folderObject = $folderObject;
219  $this->counter = 0;
220  $this->totalbytes = 0;
221  $this->JScode = '';
222  $this->HTMLcode = '';
223  $this->path = $folderObject->getReadablePath();
224  $this->sort = $sort;
225  $this->sortRev = $sortRev;
226  $this->firstElementNumber = $pointer;
227  $this->clipBoard = $clipBoard;
228  $this->bigControlPanel = $bigControlPanel;
229  // Setting the maximum length of the filenames to the user's settings or minimum 30 (= $this->fixedL)
230  $this->fixedL = max($this->fixedL, $this->getBackendUser()->uc['titleLen']);
231  $this->getLanguageService()->includeLLFile('EXT:lang/Resources/Private/Language/locallang_common.xlf');
232  $this->resourceFactory = ResourceFactory::getInstance();
233  }
234 
240  public function generateList()
241  {
242  $this->HTMLcode .= $this->getTable('fileext,tstamp,size,rw,_REF_');
243  }
244 
254  public function linkClipboardHeaderIcon($string, $_, $cmd, $warning = '')
255  {
256  $jsCode = 'document.dblistForm.cmd.value=' . GeneralUtility::quoteJSvalue($cmd)
257  . ';document.dblistForm.submit();';
258 
259  $attributes = [];
260  if ($warning) {
261  $attributes['class'] = 'btn btn-default t3js-modal-trigger';
262  $attributes['data-href'] = 'javascript:' . $jsCode;
263  $attributes['data-severity'] = 'warning';
264  $attributes['data-content'] = $warning;
265  } else {
266  $attributes['class'] = 'btn btn-default';
267  $attributes['onclick'] = $jsCode . 'return false;';
268  }
269 
270  $attributesString = '';
271  foreach ($attributes as $key => $value) {
272  $attributesString .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
273  }
274  return '<a href="#" ' . $attributesString . '>' . $string . '</a>';
275  }
276 
283  public function getTable($rowlist)
284  {
285  // prepare space icon
286  $this->spaceIcon = '<span class="btn btn-default disabled">' . $this->iconFactory->getIcon('empty-empty', Icon::SIZE_SMALL)->render() . '</span>';
287 
288  // @todo use folder methods directly when they support filters
289  $storage = $this->folderObject->getStorage();
290  $storage->resetFileAndFolderNameFiltersToDefault();
291 
292  // Only render the contents of a browsable storage
293  if ($this->folderObject->getStorage()->isBrowsable()) {
294  try {
295  $foldersCount = $storage->countFoldersInFolder($this->folderObject);
296  $filesCount = $storage->countFilesInFolder($this->folderObject);
297  } catch (InsufficientFolderAccessPermissionsException $e) {
298  $foldersCount = 0;
299  $filesCount = 0;
300  }
301 
302  if ($foldersCount <= $this->firstElementNumber) {
303  $foldersFrom = false;
304  $foldersNum = false;
305  } else {
306  $foldersFrom = $this->firstElementNumber;
307  if ($this->firstElementNumber + $this->iLimit > $foldersCount) {
308  $foldersNum = $foldersCount - $this->firstElementNumber;
309  } else {
310  $foldersNum = $this->iLimit;
311  }
312  }
313  if ($foldersCount >= $this->firstElementNumber + $this->iLimit) {
314  $filesFrom = false;
315  $filesNum = false;
316  } else {
317  if ($this->firstElementNumber <= $foldersCount) {
318  $filesFrom = 0;
319  $filesNum = $this->iLimit - $foldersNum;
320  } else {
321  $filesFrom = $this->firstElementNumber - $foldersCount;
322  if ($filesFrom + $this->iLimit > $filesCount) {
323  $filesNum = $filesCount - $filesFrom;
324  } else {
325  $filesNum = $this->iLimit;
326  }
327  }
328  }
329 
330  $folders = $storage->getFoldersInFolder($this->folderObject, $foldersFrom, $foldersNum, true, false, trim($this->sort), (bool)$this->sortRev);
331  $files = $this->folderObject->getFiles($filesFrom, $filesNum, Folder::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, false, trim($this->sort), (bool)$this->sortRev);
332  $this->totalItems = $foldersCount + $filesCount;
333  // Adds the code of files/dirs
334  $out = '';
335  $titleCol = 'file';
336  // Cleaning rowlist for duplicates and place the $titleCol as the first column always!
337  $rowlist = '_LOCALIZATION_,' . $rowlist;
338  $rowlist = GeneralUtility::rmFromList($titleCol, $rowlist);
339  $rowlist = GeneralUtility::uniqueList($rowlist);
340  $rowlist = $rowlist ? $titleCol . ',' . $rowlist : $titleCol;
341  if ($this->clipBoard) {
342  $rowlist = str_replace('_LOCALIZATION_,', '_LOCALIZATION_,_CLIPBOARD_,', $rowlist);
343  $this->addElement_tdCssClass['_CLIPBOARD_'] = 'col-clipboard';
344  }
345  if ($this->bigControlPanel) {
346  $rowlist = str_replace('_LOCALIZATION_,', '_LOCALIZATION_,_CONTROL_,', $rowlist);
347  $this->addElement_tdCssClass['_CONTROL_'] = 'col-control';
348  }
349  $this->fieldArray = explode(',', $rowlist);
350 
351  // Add classes to table cells
352  $this->addElement_tdCssClass[$titleCol] = 'col-title col-responsive';
353  $this->addElement_tdCssClass['_LOCALIZATION_'] = 'col-localizationa';
354 
355  $folders = ListUtility::resolveSpecialFolderNames($folders);
356 
357  $iOut = '';
358  // Directories are added
359  $this->eCounter = $this->firstElementNumber;
360  list(, $code) = $this->fwd_rwd_nav();
361  $iOut .= $code;
362 
363  $iOut .= $this->formatDirList($folders);
364  // Files are added
365  $iOut .= $this->formatFileList($files);
366 
367  $this->eCounter = $this->firstElementNumber + $this->iLimit < $this->totalItems
368  ? $this->firstElementNumber + $this->iLimit
369  : -1;
370  list(, $code) = $this->fwd_rwd_nav();
371  $iOut .= $code;
372 
373  // Header line is drawn
374  $theData = [];
375  foreach ($this->fieldArray as $v) {
376  if ($v == '_CLIPBOARD_' && $this->clipBoard) {
377  $cells = [];
378  $table = '_FILE';
379  $elFromTable = $this->clipObj->elFromTable($table);
380  if (!empty($elFromTable) && $this->folderObject->checkActionPermission('write')) {
381  $addPasteButton = true;
382  $elToConfirm = [];
383  foreach ($elFromTable as $key => $element) {
384  $clipBoardElement = $this->resourceFactory->retrieveFileOrFolderObject($element);
385  if ($clipBoardElement instanceof Folder && $clipBoardElement->getStorage()->isWithinFolder($clipBoardElement, $this->folderObject)) {
386  $addPasteButton = false;
387  }
388  $elToConfirm[$key] = $clipBoardElement->getName();
389  }
390  if ($addPasteButton) {
391  $cells[] = '<a class="btn btn-default t3js-modal-trigger"' .
392  ' href="' . htmlspecialchars($this->clipObj->pasteUrl(
393  '_FILE',
394  $this->folderObject->getCombinedIdentifier()
395  )) . '"'
396  . ' data-content="' . htmlspecialchars($this->clipObj->confirmMsgText(
397  '_FILE',
398  $this->path,
399  'into',
400  $elToConfirm
401  )) . '"'
402  . ' data-severity="warning"'
403  . ' data-title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_paste')) . '"'
404  . ' title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_paste')) . '">'
405  . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)
406  ->render()
407  . '</a>';
408  }
409  }
410  if ($this->clipObj->current !== 'normal' && $iOut) {
411  $cells[] = $this->linkClipboardHeaderIcon('<span title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_selectMarked')) . '">' . $this->iconFactory->getIcon('actions-edit-copy', Icon::SIZE_SMALL)->render() . '</span>', $table, 'setCB');
412  $cells[] = $this->linkClipboardHeaderIcon('<span title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_deleteMarked')) . '">' . $this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL)->render(), $table, 'delete', $this->getLanguageService()->getLL('clip_deleteMarkedWarning'));
413  $onClick = 'checkOffCB(' . GeneralUtility::quoteJSvalue(implode(',', $this->CBnames)) . ', this); return false;';
414  $cells[] = '<a class="btn btn-default" rel="" href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_markRecords')) . '">' . $this->iconFactory->getIcon('actions-document-select', Icon::SIZE_SMALL)->render() . '</a>';
415  }
416  $theData[$v] = implode('', $cells);
417  } else {
418  // Normal row:
419  $theT = $this->linkWrapSort(htmlspecialchars($this->getLanguageService()->getLL('c_' . $v)), $this->folderObject->getCombinedIdentifier(), $v);
420  $theData[$v] = $theT;
421  }
422  }
423 
424  $out .= '<thead>' . $this->addElement(1, '', $theData, '', '', '', 'th') . '</thead>';
425  $out .= '<tbody>' . $iOut . '</tbody>';
426  // half line is drawn
427  // finish
428  $out = '
429  <!--
430  Filelist table:
431  -->
432  <div class="table-fit">
433  <table class="table table-striped table-hover" id="typo3-filelist">
434  ' . $out . '
435  </table>
436  </div>';
437  } else {
439  $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('storageNotBrowsableMessage'), $this->getLanguageService()->getLL('storageNotBrowsableTitle'), FlashMessage::INFO);
441  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
443  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
444  $defaultFlashMessageQueue->enqueue($flashMessage);
445  $out = '';
446  }
447  return $out;
448  }
449 
457  protected function getLinkToParentFolder(Folder $currentFolder)
458  {
459  $levelUp = '';
460  try {
461  $currentStorage = $currentFolder->getStorage();
462  $parentFolder = $currentFolder->getParentFolder();
463  if ($parentFolder->getIdentifier() !== $currentFolder->getIdentifier() && $currentStorage->isWithinFileMountBoundaries($parentFolder)) {
464  $levelUp = $this->linkWrapDir(
465  '<span title="' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.upOneLevel')) . '">'
466  . $this->iconFactory->getIcon('actions-view-go-up', Icon::SIZE_SMALL)->render()
467  . '</span>',
468  $parentFolder
469  );
470  }
471  } catch (\Exception $e) {
472  }
473  return $levelUp;
474  }
475 
481  public function getFolderInfo()
482  {
483  if ($this->counter == 1) {
484  $fileLabel = htmlspecialchars($this->getLanguageService()->getLL('file'));
485  } else {
486  $fileLabel = htmlspecialchars($this->getLanguageService()->getLL('files'));
487  }
488  return $this->counter . ' ' . $fileLabel . ', ' . GeneralUtility::formatSize($this->totalbytes, htmlspecialchars($this->getLanguageService()->getLL('byteSizeUnits')));
489  }
490 
497  public function formatDirList(array $folders)
498  {
499  $out = '';
500  foreach ($folders as $folderName => $folderObject) {
501  $role = $folderObject->getRole();
502  if ($role === FolderInterface::ROLE_PROCESSING) {
503  // don't show processing-folder
504  continue;
505  }
506  if ($role !== FolderInterface::ROLE_DEFAULT) {
507  $displayName = '<strong>' . htmlspecialchars($folderName) . '</strong>';
508  } else {
509  $displayName = htmlspecialchars($folderName);
510  }
511 
512  $isLocked = $folderObject instanceof InaccessibleFolder;
513  $isWritable = $folderObject->checkActionPermission('write');
514 
515  // Initialization
516  $this->counter++;
517 
518  // The icon with link
519  $theIcon = '<span title="' . htmlspecialchars($folderName) . '">' . $this->iconFactory->getIconForResource($folderObject, Icon::SIZE_SMALL)->render() . '</span>';
520  if (!$isLocked && $this->clickMenus) {
521  $theIcon = BackendUtility::wrapClickMenuOnIcon($theIcon, $folderObject->getCombinedIdentifier());
522  }
523 
524  // Preparing and getting the data-array
525  $theData = [];
526  if ($isLocked) {
527  foreach ($this->fieldArray as $field) {
528  $theData[$field] = '';
529  }
530  $theData['file'] = $displayName;
531  } else {
532  foreach ($this->fieldArray as $field) {
533  switch ($field) {
534  case 'size':
535  try {
536  $numFiles = $folderObject->getFileCount();
538  $numFiles = 0;
539  }
540  $theData[$field] = $numFiles . ' ' . htmlspecialchars($this->getLanguageService()->getLL(($numFiles === 1 ? 'file' : 'files')));
541  break;
542  case 'rw':
543  $theData[$field] = '<strong class="text-danger">' . htmlspecialchars($this->getLanguageService()->getLL('read')) . '</strong>' . (!$isWritable ? '' : '<strong class="text-danger">' . htmlspecialchars($this->getLanguageService()->getLL('write')) . '</strong>');
544  break;
545  case 'fileext':
546  $theData[$field] = htmlspecialchars($this->getLanguageService()->getLL('folder'));
547  break;
548  case 'tstamp':
549  $tstamp = $folderObject->getModificationTime();
550  $theData[$field] = $tstamp ? BackendUtility::date($tstamp) : '-';
551  break;
552  case 'file':
553  $theData[$field] = $this->linkWrapDir($displayName, $folderObject);
554  break;
555  case '_CONTROL_':
556  $theData[$field] = $this->makeEdit($folderObject);
557  break;
558  case '_CLIPBOARD_':
559  $theData[$field] = $this->makeClip($folderObject);
560  break;
561  case '_REF_':
562  $theData[$field] = $this->makeRef($folderObject);
563  break;
564  default:
565  $theData[$field] = GeneralUtility::fixed_lgd_cs($theData[$field], $this->fixedL);
566  }
567  }
568  }
569  $out .= $this->addElement(1, $theIcon, $theData);
570  }
571  return $out;
572  }
573 
581  public function linkWrapDir($title, Folder $folderObject)
582  {
583  $href = BackendUtility::getModuleUrl('file_FilelistList', ['id' => $folderObject->getCombinedIdentifier()]);
584  $onclick = ' onclick="' . htmlspecialchars(('top.document.getElementsByName("navigation")[0].contentWindow.Tree.highlightActiveItem("file","folder' . GeneralUtility::md5int($folderObject->getCombinedIdentifier()) . '_"+top.fsMod.currentBank)')) . '"';
585  // Sometimes $code contains plain HTML tags. In such a case the string should not be modified!
586  if ((string)$title === strip_tags($title)) {
587  return '<a href="' . htmlspecialchars($href) . '"' . $onclick . ' title="' . htmlspecialchars($title) . '">' . $title . '</a>';
588  } else {
589  return '<a href="' . htmlspecialchars($href) . '"' . $onclick . '>' . $title . '</a>';
590  }
591  }
592 
600  public function linkWrapFile($code, File $fileObject)
601  {
602  try {
603  if ($fileObject instanceof File && $fileObject->isIndexed() && $fileObject->checkActionPermission('write') && $this->getBackendUser()->check('tables_modify', 'sys_file_metadata')) {
604  $metaData = $fileObject->_getMetaData();
605  $urlParameters = [
606  'edit' => [
607  'sys_file_metadata' => [
608  $metaData['uid'] => 'edit'
609  ]
610  ],
611  'returnUrl' => $this->listURL()
612  ];
613  $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
614  $title = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.editMetadata'));
615  $code = '<a class="responsive-title" href="' . htmlspecialchars($url) . '" title="' . $title . '">' . $code . '</a>';
616  }
617  } catch (\Exception $e) {
618  // intentional fall-through
619  }
620  return $code;
621  }
622 
634  public function listURL($altId = '', $table = '-1', $exclList = '')
635  {
637  'target' => rawurlencode($this->folderObject->getCombinedIdentifier()),
638  'imagemode' => $this->thumbs
639  ]);
640  }
641 
648  public function formatFileList(array $files)
649  {
650  $out = '';
651  // first two keys are "0" (default) and "-1" (multiple), after that comes the "other languages"
652  $allSystemLanguages = GeneralUtility::makeInstance(TranslationConfigurationProvider::class)->getSystemLanguages();
653  $systemLanguages = array_filter($allSystemLanguages, function ($languageRecord) {
654  if ($languageRecord['uid'] === -1 || $languageRecord['uid'] === 0 || !$this->getBackendUser()->checkLanguageAccess($languageRecord['uid'])) {
655  return false;
656  } else {
657  return true;
658  }
659  });
660 
661  foreach ($files as $fileObject) {
662  // Initialization
663  $this->counter++;
664  $this->totalbytes += $fileObject->getSize();
665  $ext = $fileObject->getExtension();
666  $fileName = trim($fileObject->getName());
667  // The icon with link
668  $theIcon = '<span title="' . htmlspecialchars($fileName . ' [' . (int)$fileObject->getUid() . ']') . '">'
669  . $this->iconFactory->getIconForResource($fileObject, Icon::SIZE_SMALL)->render() . '</span>';
670  if ($this->clickMenus) {
671  $theIcon = BackendUtility::wrapClickMenuOnIcon($theIcon, $fileObject->getCombinedIdentifier());
672  }
673  // Preparing and getting the data-array
674  $theData = [];
675  foreach ($this->fieldArray as $field) {
676  switch ($field) {
677  case 'size':
678  $theData[$field] = GeneralUtility::formatSize($fileObject->getSize(), htmlspecialchars($this->getLanguageService()->getLL('byteSizeUnits')));
679  break;
680  case 'rw':
681  $theData[$field] = '' . (!$fileObject->checkActionPermission('read') ? ' ' : '<strong class="text-danger">' . htmlspecialchars($this->getLanguageService()->getLL('read')) . '</strong>') . (!$fileObject->checkActionPermission('write') ? '' : '<strong class="text-danger">' . htmlspecialchars($this->getLanguageService()->getLL('write')) . '</strong>');
682  break;
683  case 'fileext':
684  $theData[$field] = strtoupper($ext);
685  break;
686  case 'tstamp':
687  $theData[$field] = BackendUtility::date($fileObject->getModificationTime());
688  break;
689  case '_CONTROL_':
690  $theData[$field] = $this->makeEdit($fileObject);
691  break;
692  case '_CLIPBOARD_':
693  $theData[$field] = $this->makeClip($fileObject);
694  break;
695  case '_LOCALIZATION_':
696  if (!empty($systemLanguages) && $fileObject->isIndexed() && $fileObject->checkActionPermission('write') && $this->getBackendUser()->check('tables_modify', 'sys_file_metadata')) {
697  $metaDataRecord = $fileObject->_getMetaData();
698  $translations = $this->getTranslationsForMetaData($metaDataRecord);
699  $languageCode = '';
700 
701  foreach ($systemLanguages as $language) {
702  $languageId = $language['uid'];
703  $flagIcon = $language['flagIcon'];
704  if (array_key_exists($languageId, $translations)) {
705  $title = htmlspecialchars(sprintf($this->getLanguageService()->getLL('editMetadataForLanguage'), $language['title']));
706  // @todo the overlay for the flag needs to be added ($flagIcon . '-overlay')
707  $urlParameters = [
708  'edit' => [
709  'sys_file_metadata' => [
710  $translations[$languageId]['uid'] => 'edit'
711  ]
712  ],
713  'returnUrl' => $this->listURL()
714  ];
715  $flagButtonIcon = $this->iconFactory->getIcon($flagIcon, Icon::SIZE_SMALL, 'overlay-edit')->render();
716  $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
717  $languageCode .= '<a href="' . htmlspecialchars($url) . '" class="btn btn-default" title="' . $title . '">'
718  . $flagButtonIcon . '</a>';
719  } else {
720  $parameters = [
721  'justLocalized' => 'sys_file_metadata:' . $metaDataRecord['uid'] . ':' . $languageId,
722  'returnUrl' => $this->listURL()
723  ];
724  $returnUrl = BackendUtility::getModuleUrl('record_edit', $parameters);
726  '&cmd[sys_file_metadata][' . $metaDataRecord['uid'] . '][localize]=' . $languageId,
727  $returnUrl
728  );
729  $flagButtonIcon = '<span title="' . htmlspecialchars(sprintf($this->getLanguageService()->getLL('createMetadataForLanguage'), $language['title'])) . '">' . $this->iconFactory->getIcon($flagIcon, Icon::SIZE_SMALL, 'overlay-new')->render() . '</span>';
730  $languageCode .= '<a href="' . htmlspecialchars($href) . '" class="btn btn-default">' . $flagButtonIcon . '</a> ';
731  }
732  }
733 
734  // Hide flag button bar when not translated yet
735  $theData[$field] = ' <div class="localisationData btn-group" data-fileid="' . $fileObject->getUid() . '"' .
736  (empty($translations) ? ' style="display: none;"' : '') . '>' . $languageCode . '</div>';
737  $theData[$field] .= '<a class="btn btn-default filelist-translationToggler" data-fileid="' . $fileObject->getUid() . '">' .
738  '<span title="' . htmlspecialchars($this->getLanguageService()->getLL('translateMetadata')) . '">'
739  . $this->iconFactory->getIcon('mimetypes-x-content-page-language-overlay', Icon::SIZE_SMALL)->render() . '</span>'
740  . '</a>';
741  }
742  break;
743  case '_REF_':
744  $theData[$field] = $this->makeRef($fileObject);
745  break;
746  case 'file':
747  // Edit metadata of file
748  $theData[$field] = $this->linkWrapFile(htmlspecialchars($fileName), $fileObject);
749 
750  if ($fileObject->isMissing()) {
751  $theData[$field] .= '<span class="label label-danger label-space-left">'
752  . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:warning.file_missing'))
753  . '</span>';
754  // Thumbnails?
755  } elseif ($this->thumbs && ($this->isImage($ext) || $this->isMediaFile($ext))) {
756  $processedFile = $fileObject->process(ProcessedFile::CONTEXT_IMAGEPREVIEW, []);
757  if ($processedFile) {
758  $thumbUrl = $processedFile->getPublicUrl(true);
759  $theData[$field] .= '<br /><img src="' . $thumbUrl . '" ' .
760  'width="' . $processedFile->getProperty('width') . '" ' .
761  'height="' . $processedFile->getProperty('height') . '" ' .
762  'title="' . htmlspecialchars($fileName) . '" alt="" />';
763  }
764  }
765  break;
766  default:
767  $theData[$field] = '';
768  if ($fileObject->hasProperty($field)) {
769  $theData[$field] = htmlspecialchars(GeneralUtility::fixed_lgd_cs($fileObject->getProperty($field), $this->fixedL));
770  }
771  }
772  }
773  $out .= $this->addElement(1, $theIcon, $theData);
774  }
775  return $out;
776  }
777 
784  protected function getTranslationsForMetaData($metaDataRecord)
785  {
786  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_file_metadata');
787  $queryBuilder->getRestrictions()->removeAll();
788  $translationRecords = $queryBuilder->select('*')
789  ->from('sys_file_metadata')
790  ->where(
791  $queryBuilder->expr()->eq(
792  $GLOBALS['TCA']['sys_file_metadata']['ctrl']['transOrigPointerField'],
793  $queryBuilder->createNamedParameter($metaDataRecord['uid'], \PDO::PARAM_INT)
794  ),
795  $queryBuilder->expr()->gt(
796  $GLOBALS['TCA']['sys_file_metadata']['ctrl']['languageField'],
797  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
798  )
799  )
800  ->execute()
801  ->fetchAll();
802 
803  $translations = [];
804  foreach ($translationRecords as $record) {
805  $translations[$record[$GLOBALS['TCA']['sys_file_metadata']['ctrl']['languageField']]] = $record;
806  }
807  return $translations;
808  }
809 
816  public function isImage($ext)
817  {
818  return GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], strtolower($ext));
819  }
820 
827  public function isMediaFile($ext)
828  {
829  return GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'], strtolower($ext));
830  }
831 
840  public function linkWrapSort($code, $folderIdentifier, $col)
841  {
842  $params = ['id' => $folderIdentifier, 'SET' => [ 'sort' => $col ]];
843 
844  if ($this->sort === $col) {
845  // Check reverse sorting
846  $params['SET']['reverse'] = ($this->sortRev ? '0' : '1');
847  $sortArrow = $this->iconFactory->getIcon('status-status-sorting-light-' . ($this->sortRev ? 'desc' : 'asc'), Icon::SIZE_SMALL)->render();
848  } else {
849  $params['SET']['reverse'] = 0;
850  $sortArrow = '';
851  }
852  $href = BackendUtility::getModuleUrl('file_FilelistList', $params);
853  return '<a href="' . htmlspecialchars($href) . '">' . $code . ' ' . $sortArrow . '</a>';
854  }
855 
862  public function makeClip($fileOrFolderObject)
863  {
864  if (!$fileOrFolderObject->checkActionPermission('read')) {
865  return '';
866  }
867  $cells = [];
868  $fullIdentifier = $fileOrFolderObject->getCombinedIdentifier();
869  $fullName = $fileOrFolderObject->getName();
870  $md5 = GeneralUtility::shortMD5($fullIdentifier);
871  // For normal clipboard, add copy/cut buttons:
872  if ($this->clipObj->current === 'normal') {
873  $isSel = $this->clipObj->isSelected('_FILE', $md5);
874  $copyTitle = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.copy'));
875  $cutTitle = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.cut'));
876  $copyIcon = $this->iconFactory->getIcon('actions-edit-copy', Icon::SIZE_SMALL)->render();
877  $cutIcon = $this->iconFactory->getIcon('actions-edit-cut', Icon::SIZE_SMALL)->render();
878 
879  if ($isSel === 'copy') {
880  $copyIcon = $this->iconFactory->getIcon('actions-edit-copy-release', Icon::SIZE_SMALL)->render();
881  } elseif ($isSel === 'cut') {
882  $cutIcon = $this->iconFactory->getIcon('actions-edit-cut-release', Icon::SIZE_SMALL)->render();
883  }
884 
885  $cells[] = '<a class="btn btn-default"" href="' . htmlspecialchars($this->clipObj->selUrlFile($fullIdentifier, 1, ($isSel === 'copy'))) . '" title="' . $copyTitle . '">' . $copyIcon . '</a>';
886  // we can only cut if file can be moved
887  if ($fileOrFolderObject->checkActionPermission('move')) {
888  $cells[] = '<a class="btn btn-default" href="' . htmlspecialchars($this->clipObj->selUrlFile($fullIdentifier, 0, ($isSel === 'cut'))) . '" title="' . $cutTitle . '">' . $cutIcon . '</a>';
889  } else {
890  $cells[] = $this->spaceIcon;
891  }
892  } else {
893  // For numeric pads, add select checkboxes:
894  $n = '_FILE|' . $md5;
895  $this->CBnames[] = $n;
896  $checked = $this->clipObj->isSelected('_FILE', $md5) ? ' checked="checked"' : '';
897  $cells[] = '<input type="hidden" name="CBH[' . $n . ']" value="0" /><label class="btn btn-default btn-checkbox"><input type="checkbox" name="CBC[' . $n . ']" value="' . htmlspecialchars($fullIdentifier) . '" ' . $checked . ' /><span class="t3-icon fa"></span></label>';
898  }
899  // Display PASTE button, if directory:
900  $elFromTable = $this->clipObj->elFromTable('_FILE');
901  if ($fileOrFolderObject instanceof Folder && !empty($elFromTable) && $fileOrFolderObject->checkActionPermission('write')) {
902  $addPasteButton = true;
903  $elToConfirm = [];
904  foreach ($elFromTable as $key => $element) {
905  $clipBoardElement = $this->resourceFactory->retrieveFileOrFolderObject($element);
906  if ($clipBoardElement instanceof Folder && $clipBoardElement->getStorage()->isWithinFolder($clipBoardElement, $fileOrFolderObject)) {
907  $addPasteButton = false;
908  }
909  $elToConfirm[$key] = $clipBoardElement->getName();
910  }
911  if ($addPasteButton) {
912  $cells[] = '<a class="btn btn-default t3js-modal-trigger" '
913  . ' href="' . htmlspecialchars($this->clipObj->pasteUrl('_FILE', $fullIdentifier)) . '"'
914  . ' data-content="' . htmlspecialchars($this->clipObj->confirmMsgText('_FILE', $fullName, 'into', $elToConfirm)) . '"'
915  . ' data-severity="warning"'
916  . ' data-title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_pasteInto')) . '"'
917  . ' title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_pasteInto')) . '"'
918  . '>'
919  . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render()
920  . '</a>';
921  }
922  }
923  // Compile items into a DIV-element:
924  return ' <div class="btn-group" role="group">' . implode('', $cells) . '</div>';
925  }
926 
933  public function makeEdit($fileOrFolderObject)
934  {
935  $cells = [];
936  $fullIdentifier = $fileOrFolderObject->getCombinedIdentifier();
937 
938  // Edit file content (if editable)
939  if ($fileOrFolderObject instanceof File && $fileOrFolderObject->checkActionPermission('write') && GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], $fileOrFolderObject->getExtension())) {
940  $url = BackendUtility::getModuleUrl('file_edit', ['target' => $fullIdentifier]);
941  $editOnClick = 'top.list_frame.location.href=' . GeneralUtility::quoteJSvalue($url) . '+\'&returnUrl=\'+top.rawurlencode(top.list_frame.document.location.pathname+top.list_frame.document.location.search);return false;';
942  $cells['edit'] = '<a href="#" class="btn btn-default" onclick="' . htmlspecialchars($editOnClick) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.editcontent') . '">'
943  . $this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render()
944  . '</a>';
945  } else {
946  $cells['edit'] = $this->spaceIcon;
947  }
948  if ($fileOrFolderObject instanceof File) {
949  $fileUrl = $fileOrFolderObject->getPublicUrl(true);
950  if ($fileUrl) {
951  $aOnClick = 'return top.openUrlInWindow(' . GeneralUtility::quoteJSvalue($fileUrl) . ', \'WebFile\');';
952  $cells['view'] = '<a href="#" class="btn btn-default" onclick="' . htmlspecialchars($aOnClick) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.view') . '">' . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render() . '</a>';
953  } else {
954  $cells['view'] = $this->spaceIcon;
955  }
956  } else {
957  $cells['view'] = $this->spaceIcon;
958  }
959 
960  // replace file
961  if ($fileOrFolderObject instanceof File && $fileOrFolderObject->checkActionPermission('replace')) {
962  $url = BackendUtility::getModuleUrl('file_replace', ['target' => $fullIdentifier, 'uid' => $fileOrFolderObject->getUid()]);
963  $replaceOnClick = 'top.list_frame.location.href = ' . GeneralUtility::quoteJSvalue($url) . '+\'&returnUrl=\'+top.rawurlencode(top.list_frame.document.location.pathname+top.list_frame.document.location.search);return false;';
964  $cells['replace'] = '<a href="#" class="btn btn-default" onclick="' . $replaceOnClick . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.replace') . '">' . $this->iconFactory->getIcon('actions-edit-replace', Icon::SIZE_SMALL)->render() . '</a>';
965  }
966 
967  // rename the file
968  if ($fileOrFolderObject->checkActionPermission('rename')) {
969  $url = BackendUtility::getModuleUrl('file_rename', ['target' => $fullIdentifier]);
970  $renameOnClick = 'top.list_frame.location.href = ' . GeneralUtility::quoteJSvalue($url) . '+\'&returnUrl=\'+top.rawurlencode(top.list_frame.document.location.pathname+top.list_frame.document.location.search);return false;';
971  $cells['rename'] = '<a href="#" class="btn btn-default" onclick="' . htmlspecialchars($renameOnClick) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.rename') . '">' . $this->iconFactory->getIcon('actions-edit-rename', Icon::SIZE_SMALL)->render() . '</a>';
972  } else {
973  $cells['rename'] = $this->spaceIcon;
974  }
975  if ($fileOrFolderObject->checkActionPermission('read')) {
976  $infoOnClick = '';
977  if ($fileOrFolderObject instanceof Folder) {
978  $infoOnClick = 'top.launchView( \'_FOLDER\', ' . GeneralUtility::quoteJSvalue($fullIdentifier) . ');return false;';
979  } elseif ($fileOrFolderObject instanceof File) {
980  $infoOnClick = 'top.launchView( \'_FILE\', ' . GeneralUtility::quoteJSvalue($fullIdentifier) . ');return false;';
981  }
982  $cells['info'] = '<a href="#" class="btn btn-default" onclick="' . htmlspecialchars($infoOnClick) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.info') . '">' . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render() . '</a>';
983  } else {
984  $cells['info'] = $this->spaceIcon;
985  }
986 
987  // delete the file
988  if ($fileOrFolderObject->checkActionPermission('delete')) {
989  $identifier = $fileOrFolderObject->getIdentifier();
990  if ($fileOrFolderObject instanceof Folder) {
991  $referenceCountText = BackendUtility::referenceCount('_FILE', $identifier, ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.referencesToFolder'));
992  $deleteType = 'delete_folder';
993  } else {
994  $referenceCountText = BackendUtility::referenceCount('sys_file', $fileOrFolderObject->getUid(), ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.referencesToFile'));
995  $deleteType = 'delete_file';
996  }
997 
998  if ($this->getBackendUser()->jsConfirmation(JsConfirmation::DELETE)) {
999  $confirmationCheck = '1';
1000  } else {
1001  $confirmationCheck = '0';
1002  }
1003 
1004  $deleteUrl = BackendUtility::getModuleUrl('tce_file');
1005  $confirmationMessage = sprintf($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:mess.delete'), $fileOrFolderObject->getName()) . $referenceCountText;
1006  $title = $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.delete');
1007  $cells['delete'] = '<a href="#" class="btn btn-default t3js-filelist-delete" data-content="' . htmlspecialchars($confirmationMessage)
1008  . '" data-check="' . $confirmationCheck
1009  . '" data-delete-url="' . htmlspecialchars($deleteUrl)
1010  . '" data-title="' . htmlspecialchars($title)
1011  . '" data-identifier="' . htmlspecialchars($fileOrFolderObject->getCombinedIdentifier())
1012  . '" data-veri-code="' . $this->getBackendUser()->veriCode()
1013  . '" data-delete-type="' . $deleteType
1014  . '" title="' . htmlspecialchars($title) . '">'
1015  . $this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL)->render() . '</a>';
1016  } else {
1017  $cells['delete'] = $this->spaceIcon;
1018  }
1019 
1020  // Hook for manipulating edit icons.
1021  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['fileList']['editIconsHook'])) {
1022  $cells['__fileOrFolderObject'] = $fileOrFolderObject;
1023  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['fileList']['editIconsHook'] as $classData) {
1024  $hookObject = GeneralUtility::getUserObj($classData);
1025  if (!$hookObject instanceof FileListEditIconHookInterface) {
1026  throw new \UnexpectedValueException(
1027  $classData . ' must implement interface ' . FileListEditIconHookInterface::class,
1028  1235225797
1029  );
1030  }
1031  $hookObject->manipulateEditIcons($cells, $this);
1032  }
1033  unset($cells['__fileOrFolderObject']);
1034  }
1035  // Compile items into a DIV-element:
1036  return '<div class="btn-group">' . implode('', $cells) . '</div>';
1037  }
1038 
1045  public function makeRef($fileOrFolderObject)
1046  {
1047  if ($fileOrFolderObject instanceof FolderInterface) {
1048  return '-';
1049  }
1050  // Look up the file in the sys_refindex.
1051  // Exclude sys_file_metadata records as these are no use references
1052  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
1053  $referenceCount = $queryBuilder->count('*')
1054  ->from('sys_refindex')
1055  ->where(
1056  $queryBuilder->expr()->eq('deleted', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)),
1057  $queryBuilder->expr()->eq(
1058  'ref_table',
1059  $queryBuilder->createNamedParameter('sys_file', \PDO::PARAM_STR)
1060  ),
1061  $queryBuilder->expr()->eq(
1062  'ref_uid',
1063  $queryBuilder->createNamedParameter($fileOrFolderObject->getUid(), \PDO::PARAM_INT)
1064  ),
1065  $queryBuilder->expr()->neq(
1066  'tablename',
1067  $queryBuilder->createNamedParameter('sys_file_metadata', \PDO::PARAM_STR)
1068  )
1069  )
1070  ->execute()
1071  ->fetchColumn();
1072 
1073  return $this->generateReferenceToolTip($referenceCount, '\'_FILE\', ' . GeneralUtility::quoteJSvalue($fileOrFolderObject->getCombinedIdentifier()));
1074  }
1075 
1081  protected function getLanguageService()
1082  {
1083  return $GLOBALS['LANG'];
1084  }
1085 
1091  protected function getBackendUser()
1092  {
1093  return $GLOBALS['BE_USER'];
1094  }
1095 }
makeClip($fileOrFolderObject)
Definition: FileList.php:862
linkWrapDir($title, Folder $folderObject)
Definition: FileList.php:581
injectResourceFactory(ResourceFactory $resourceFactory)
Definition: FileList.php:173
generateReferenceToolTip($references, $launchViewParameter= '')
linkClipboardHeaderIcon($string, $_, $cmd, $warning= '')
Definition: FileList.php:254
addElement($h, $icon, $data, $rowParams= '', $_= '', $_2= '', $colType= 'td')
listURL($altId= '', $table= '-1', $exclList= '')
Definition: FileList.php:634
getTranslationsForMetaData($metaDataRecord)
Definition: FileList.php:784
static formatSize($sizeInBytes, $labels= '', $base=0)
static getLinkToDataHandlerAction($parameters, $redirectUrl= '')
linkWrapSort($code, $folderIdentifier, $col)
Definition: FileList.php:840
formatDirList(array $folders)
Definition: FileList.php:497
formatFileList(array $files)
Definition: FileList.php:648
start(Folder $folderObject, $pointer, $sort, $sortRev, $clipBoard=false, $bigControlPanel=false)
Definition: FileList.php:216
static uniqueList($in_list, $secondParameter=null)
static linkThisScript(array $getParams=[])
getLinkToParentFolder(Folder $currentFolder)
Definition: FileList.php:457
makeEdit($fileOrFolderObject)
Definition: FileList.php:933
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
static wrapClickMenuOnIcon($content, $table, $uid=0, $listFrame=true, $addParams= '', $enDisItems= '', $returnTagParameters=false)
static referenceCount($table, $ref, $msg= '', $count=null)
__construct(FileListController $fileListController)
Definition: FileList.php:193
linkWrapFile($code, File $fileObject)
Definition: FileList.php:600
makeRef($fileOrFolderObject)
Definition: FileList.php:1045