2 namespace TYPO3\CMS\Filelist
;
5 * This file is part of the TYPO3 CMS project.
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.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 use TYPO3\CMS\Backend\Clipboard\Clipboard
;
18 use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider
;
19 use TYPO3\CMS\Backend\Routing\UriBuilder
;
20 use TYPO3\CMS\Backend\Utility\BackendUtility
;
21 use TYPO3\CMS\Core\Database\ConnectionPool
;
22 use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction
;
23 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
;
24 use TYPO3\CMS\Core\Imaging\Icon
;
25 use TYPO3\CMS\Core\Imaging\IconFactory
;
26 use TYPO3\CMS\Core\Messaging\FlashMessage
;
27 use TYPO3\CMS\Core\Messaging\FlashMessageService
;
28 use TYPO3\CMS\Core\
Resource\Exception\InsufficientFolderAccessPermissionsException
;
29 use TYPO3\CMS\Core\
Resource\File
;
30 use TYPO3\CMS\Core\
Resource\Folder
;
31 use TYPO3\CMS\Core\
Resource\FolderInterface
;
32 use TYPO3\CMS\Core\
Resource\InaccessibleFolder
;
33 use TYPO3\CMS\Core\
Resource\ProcessedFile
;
34 use TYPO3\CMS\Core\
Resource\ResourceFactory
;
35 use TYPO3\CMS\Core\
Resource\Utility\ListUtility
;
36 use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation
;
37 use TYPO3\CMS\Core\Utility\GeneralUtility
;
38 use TYPO3\CMS\Core\Utility\MathUtility
;
39 use TYPO3\CMS\Filelist\Configuration\ThumbnailConfiguration
;
40 use TYPO3\CMS\Filelist\Controller\FileListController
;
43 * Class for rendering of File>Filelist
48 * Default Max items shown
55 * Thumbnails on records containing files (pictures)
59 public $thumbs = false;
62 * Space icon used for alignment when no button is available
69 * Max length of strings
76 * The field to sort by
83 * Reverse sorting flag
92 public $firstElementNumber = 0;
97 public $clipBoard = 0;
102 public $bigControlPanel = 0;
110 * String with accumulated HTML content
114 public $HTMLcode = '';
119 public $totalbytes = 0;
137 * OBSOLETE - NOT USED ANYMORE. leftMargin
141 public $leftMargin = 0;
144 * This could be set to the total number of items. Used by the fwd_rew_navigation...
148 public $totalItems = '';
151 * Decides the columns shown. Filled with values that refers to the keys of the data-array. $this->fieldArray[0] is the title column.
155 public $fieldArray = [];
158 * Set to zero, if you don't want a left-margin with addElement function
162 public $setLMargin = 1;
165 * Contains page translation languages
169 public $pageOverlays = [];
172 * Counter increased for each element. Used to index elements for the JavaScript-code that transfers to the clipboard
179 * Contains sys language icons and titles
183 public $languageIconTitles = [];
190 public $thisScript = '';
193 * If set this is <td> CSS-classname for odd columns in addElement. Used with db_layout / pages section
197 public $oddColumnsCssClass = '';
200 * Counting the elements no matter what
204 public $eCounter = 0;
207 * @var TranslationConfigurationProvider
209 public $translateTools;
212 * Keys are fieldnames and values are td-parameters to add in addElement(), please use $addElement_tdCSSClass for CSS-classes;
216 public $addElement_tdParams = [];
221 public $no_noWrap = 0;
226 public $showIcon = 1;
229 * Keys are fieldnames and values are td-css-classes to add in addElement();
233 public $addElement_tdCssClass = [];
238 protected $folderObject;
243 public $CBnames = [];
246 * @var Clipboard $clipObj
251 * @var ResourceFactory
253 protected $resourceFactory;
258 protected $iconFactory;
266 * @var FileListController
268 protected $fileListController;
271 * @var ThumbnailConfiguration
273 protected $thumbnailConfiguration;
278 * @param FileListController $fileListController
280 public function __construct(FileListController
$fileListController)
282 if (isset($GLOBALS['BE_USER']->uc
['titleLen']) && $GLOBALS['BE_USER']->uc
['titleLen'] > 0) {
283 $this->fixedL
= $GLOBALS['BE_USER']->uc
['titleLen'];
285 $this->iconFactory
= GeneralUtility
::makeInstance(IconFactory
::class);
286 $this->getTranslateTools();
287 $this->determineScriptUrl();
288 $this->fileListController
= $fileListController;
289 $this->iconFactory
= GeneralUtility
::makeInstance(IconFactory
::class);
290 $this->thumbnailConfiguration
= GeneralUtility
::makeInstance(ThumbnailConfiguration
::class);
292 $modTSconfig = BackendUtility
::getModTSconfig(0, 'options.file_list');
293 if (!empty($modTSconfig['properties']['filesPerPage'])) {
294 $this->iLimit
= MathUtility
::forceIntegerInRange($modTSconfig['properties']['filesPerPage'], 1);
299 * @param ResourceFactory $resourceFactory
301 public function injectResourceFactory(ResourceFactory
$resourceFactory)
303 $this->resourceFactory
= $resourceFactory;
307 * Initialization of class
309 * @param Folder $folderObject The folder to work on
310 * @param int $pointer Pointer
311 * @param bool $sort Sorting column
312 * @param bool $sortRev Sorting direction
313 * @param bool $clipBoard
314 * @param bool $bigControlPanel Show clipboard flag
316 public function start(Folder
$folderObject, $pointer, $sort, $sortRev, $clipBoard = false, $bigControlPanel = false)
318 $this->folderObject
= $folderObject;
320 $this->totalbytes
= 0;
322 $this->HTMLcode
= '';
323 $this->path
= $folderObject->getReadablePath();
325 $this->sortRev
= $sortRev;
326 $this->firstElementNumber
= $pointer;
327 $this->clipBoard
= $clipBoard;
328 $this->bigControlPanel
= $bigControlPanel;
329 // Setting the maximum length of the filenames to the user's settings or minimum 30 (= $this->fixedL)
330 $this->fixedL
= max($this->fixedL
, $this->getBackendUser()->uc
['titleLen']);
331 $this->getLanguageService()->includeLLFile('EXT:lang/Resources/Private/Language/locallang_common.xlf');
332 $this->resourceFactory
= ResourceFactory
::getInstance();
336 * Reading files and directories, counting elements and generating the list in ->HTMLcode
338 public function generateList()
340 $this->HTMLcode
.= $this->getTable('fileext,tstamp,size,rw,_REF_');
344 * Wrapping input string in a link with clipboard command.
346 * @param string $string String to be linked - must be htmlspecialchar'ed / prepared before.
347 * @param string $_ unused
348 * @param string $cmd "cmd" value
349 * @param string $warning Warning for JS confirm message
350 * @return string Linked string
352 public function linkClipboardHeaderIcon($string, $_, $cmd, $warning = '')
354 $jsCode = 'document.dblistForm.cmd.value=' . GeneralUtility
::quoteJSvalue($cmd)
355 . ';document.dblistForm.submit();';
359 $attributes['class'] = 'btn btn-default t3js-modal-trigger';
360 $attributes['data-href'] = 'javascript:' . $jsCode;
361 $attributes['data-severity'] = 'warning';
362 $attributes['data-content'] = $warning;
364 $attributes['class'] = 'btn btn-default';
365 $attributes['onclick'] = $jsCode . 'return false;';
368 $attributesString = '';
369 foreach ($attributes as $key => $value) {
370 $attributesString .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
372 return '<a href="#" ' . $attributesString . '>' . $string . '</a>';
376 * Returns a table with directories and files listed.
378 * @param array $rowlist Array of files from path
379 * @return string HTML-table
381 public function getTable($rowlist)
383 // prepare space icon
384 $this->spaceIcon
= '<span class="btn btn-default disabled">' . $this->iconFactory
->getIcon('empty-empty', Icon
::SIZE_SMALL
)->render() . '</span>';
386 // @todo use folder methods directly when they support filters
387 $storage = $this->folderObject
->getStorage();
388 $storage->resetFileAndFolderNameFiltersToDefault();
390 // Only render the contents of a browsable storage
391 if ($this->folderObject
->getStorage()->isBrowsable()) {
393 $foldersCount = $storage->countFoldersInFolder($this->folderObject
);
394 $filesCount = $storage->countFilesInFolder($this->folderObject
);
395 } catch (InsufficientFolderAccessPermissionsException
$e) {
400 if ($foldersCount <= $this->firstElementNumber
) {
401 $foldersFrom = false;
404 $foldersFrom = $this->firstElementNumber
;
405 if ($this->firstElementNumber +
$this->iLimit
> $foldersCount) {
406 $foldersNum = $foldersCount - $this->firstElementNumber
;
408 $foldersNum = $this->iLimit
;
411 if ($foldersCount >= $this->firstElementNumber +
$this->iLimit
) {
415 if ($this->firstElementNumber
<= $foldersCount) {
417 $filesNum = $this->iLimit
- $foldersNum;
419 $filesFrom = $this->firstElementNumber
- $foldersCount;
420 if ($filesFrom +
$this->iLimit
> $filesCount) {
421 $filesNum = $filesCount - $filesFrom;
423 $filesNum = $this->iLimit
;
428 $folders = $storage->getFoldersInFolder($this->folderObject
, $foldersFrom, $foldersNum, true, false, trim($this->sort
), (bool)$this->sortRev
);
429 $files = $this->folderObject
->getFiles($filesFrom, $filesNum, Folder
::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS
, false, trim($this->sort
), (bool)$this->sortRev
);
430 $this->totalItems
= $foldersCount +
$filesCount;
431 // Adds the code of files/dirs
434 // Cleaning rowlist for duplicates and place the $titleCol as the first column always!
435 $rowlist = '_LOCALIZATION_,' . $rowlist;
436 $rowlist = GeneralUtility
::rmFromList($titleCol, $rowlist);
437 $rowlist = GeneralUtility
::uniqueList($rowlist);
438 $rowlist = $rowlist ?
$titleCol . ',' . $rowlist : $titleCol;
439 if ($this->clipBoard
) {
440 $rowlist = str_replace('_LOCALIZATION_,', '_LOCALIZATION_,_CLIPBOARD_,', $rowlist);
441 $this->addElement_tdCssClass
['_CLIPBOARD_'] = 'col-clipboard';
443 if ($this->bigControlPanel
) {
444 $rowlist = str_replace('_LOCALIZATION_,', '_LOCALIZATION_,_CONTROL_,', $rowlist);
445 $this->addElement_tdCssClass
['_CONTROL_'] = 'col-control';
447 $this->fieldArray
= explode(',', $rowlist);
449 // Add classes to table cells
450 $this->addElement_tdCssClass
[$titleCol] = 'col-title col-responsive';
451 $this->addElement_tdCssClass
['_LOCALIZATION_'] = 'col-localizationa';
453 $folders = ListUtility
::resolveSpecialFolderNames($folders);
456 // Directories are added
457 $this->eCounter
= $this->firstElementNumber
;
458 list(, $code) = $this->fwd_rwd_nav();
461 $iOut .= $this->formatDirList($folders);
463 $iOut .= $this->formatFileList($files);
465 $this->eCounter
= $this->firstElementNumber +
$this->iLimit
< $this->totalItems
466 ?
$this->firstElementNumber +
$this->iLimit
468 list(, $code) = $this->fwd_rwd_nav();
471 // Header line is drawn
473 foreach ($this->fieldArray
as $v) {
474 if ($v === '_CLIPBOARD_' && $this->clipBoard
) {
477 $elFromTable = $this->clipObj
->elFromTable($table);
478 if (!empty($elFromTable) && $this->folderObject
->checkActionPermission('write')) {
479 $addPasteButton = true;
481 foreach ($elFromTable as $key => $element) {
482 $clipBoardElement = $this->resourceFactory
->retrieveFileOrFolderObject($element);
483 if ($clipBoardElement instanceof Folder
&& $clipBoardElement->getStorage()->isWithinFolder($clipBoardElement, $this->folderObject
)) {
484 $addPasteButton = false;
486 $elToConfirm[$key] = $clipBoardElement->getName();
488 if ($addPasteButton) {
489 $cells[] = '<a class="btn btn-default t3js-modal-trigger"' .
490 ' href="' . htmlspecialchars($this->clipObj
->pasteUrl(
492 $this->folderObject
->getCombinedIdentifier()
494 . ' data-content="' . htmlspecialchars($this->clipObj
->confirmMsgText(
500 . ' data-severity="warning"'
501 . ' data-title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_paste')) . '"'
502 . ' title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_paste')) . '">'
503 . $this->iconFactory
->getIcon('actions-document-paste-into', Icon
::SIZE_SMALL
)
508 if ($this->clipObj
->current
!== 'normal' && $iOut) {
509 $cells[] = $this->linkClipboardHeaderIcon('<span title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_selectMarked')) . '">' . $this->iconFactory
->getIcon('actions-edit-copy', Icon
::SIZE_SMALL
)->render() . '</span>', $table, 'setCB');
510 $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'));
511 $onClick = 'checkOffCB(' . GeneralUtility
::quoteJSvalue(implode(',', $this->CBnames
)) . ', this); return false;';
512 $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>';
514 $theData[$v] = implode('', $cells);
517 $theT = $this->linkWrapSort(htmlspecialchars($this->getLanguageService()->getLL('c_' . $v)), $this->folderObject
->getCombinedIdentifier(), $v);
518 $theData[$v] = $theT;
522 $out .= '<thead>' . $this->addElement(1, '', $theData, '', '', '', 'th') . '</thead>';
523 $out .= '<tbody>' . $iOut . '</tbody>';
524 // half line is drawn
530 <div class="table-fit">
531 <table class="table table-striped table-hover" id="typo3-filelist">
536 /** @var $flashMessage FlashMessage */
537 $flashMessage = GeneralUtility
::makeInstance(FlashMessage
::class, $this->getLanguageService()->getLL('storageNotBrowsableMessage'), $this->getLanguageService()->getLL('storageNotBrowsableTitle'), FlashMessage
::INFO
);
538 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
539 $flashMessageService = GeneralUtility
::makeInstance(FlashMessageService
::class);
540 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
541 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
542 $defaultFlashMessageQueue->enqueue($flashMessage);
549 * Returns a table-row with the content from the fields in the input data array.
550 * OBS: $this->fieldArray MUST be set! (represents the list of fields to display)
552 * @param int $h Is an integer >=0 and denotes how tall an element is. Set to '0' makes a halv line, -1 = full line, set to 1 makes a 'join' and above makes 'line'
553 * @param string $icon Is the <img>+<a> of the record. If not supplied the first 'join'-icon will be a 'line' instead
554 * @param array $data Is the dataarray, record with the fields. Notice: These fields are (currently) NOT htmlspecialchar'ed before being wrapped in <td>-tags
555 * @param string $rowParams Is insert in the <tr>-tags. Must carry a ' ' as first character
556 * @param string $_ OBSOLETE - NOT USED ANYMORE. $lMargin is the leftMargin (int)
557 * @param string $_2 OBSOLETE - NOT USED ANYMORE. Is the HTML <img>-tag for an alternative 'gfx/ol/line.gif'-icon (used in the top)
558 * @param string $colType Defines the tag being used for the columns. Default is td.
560 * @return string HTML content for the table row
562 public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', $colType = 'td')
564 $colType = ($colType === 'th') ?
'th' : 'td';
565 $noWrap = $this->no_noWrap ?
'' : ' nowrap';
567 $l10nParent = isset($data['_l10nparent_']) ?
(int)$data['_l10nparent_'] : 0;
569 <!-- Element, begin: -->
570 <tr ' . $rowParams . ' data-uid="' . (int)$data['uid'] . '" data-l10nparent="' . $l10nParent . '">';
571 // Show icon and lines
572 if ($this->showIcon
) {
574 <' . $colType . ' class="col-icon nowrap">';
578 for ($a = 0; $a < $h; $a++
) {
586 $out .= '</' . $colType . '>
594 // __label is used as the label key to circumvent problems with uid used as label (see #67756)
595 // as it was introduced later on, check if it really exists before using it
596 $fields = $this->fieldArray
;
597 if ($colType === 'td' && array_key_exists('__label', $data)) {
598 $fields[0] = '__label';
600 // Traverse field array which contains the data to present:
601 foreach ($fields as $vKey) {
602 if (isset($data[$vKey])) {
604 $cssClass = $this->addElement_tdCssClass
[$lastKey];
605 if ($this->oddColumnsCssClass
&& $ccount %
2 == 0) {
606 $cssClass = implode(' ', [$this->addElement_tdCssClass
[$lastKey], $this->oddColumnsCssClass
]);
609 <' . $colType . ' class="' . $cssClass . $noWrap . '"' . $colsp . $this->addElement_tdParams
[$lastKey] . '>' . $data[$lastKey] . '</' . $colType . '>';
621 $colsp = ' colspan="' . $c . '"';
627 $cssClass = $this->addElement_tdCssClass
[$lastKey];
628 if ($this->oddColumnsCssClass
) {
629 $cssClass = implode(' ', [$this->addElement_tdCssClass
[$lastKey], $this->oddColumnsCssClass
]);
632 <' . $colType . ' class="' . $cssClass . $noWrap . '"' . $colsp . $this->addElement_tdParams
[$lastKey] . '>' . $data[$lastKey] . '</' . $colType . '>';
642 * Dummy function, used to write the top of a table listing.
644 public function writeTop()
649 * Creates a forward/reverse button based on the status of ->eCounter, ->firstElementNumber, ->iLimit
651 * @param string $table Table name
652 * @return array array([boolean], [HTML]) where [boolean] is 1 for reverse element, [HTML] is the table-row code for the element
654 public function fwd_rwd_nav($table = '')
657 if ($this->eCounter
>= $this->firstElementNumber
&& $this->eCounter
< $this->firstElementNumber +
$this->iLimit
) {
658 if ($this->firstElementNumber
&& $this->eCounter
== $this->firstElementNumber
) {
661 $titleCol = $this->fieldArray
[0];
662 $theData[$titleCol] = $this->fwd_rwd_HTML('fwd', $this->eCounter
, $table);
663 $code = $this->addElement(1, '', $theData, 'class="fwd_rwd_nav"');
667 if ($this->eCounter
== $this->firstElementNumber +
$this->iLimit
) {
670 $titleCol = $this->fieldArray
[0];
671 $theData[$titleCol] = $this->fwd_rwd_HTML('rwd', $this->eCounter
, $table);
672 $code = $this->addElement(1, '', $theData, 'class="fwd_rwd_nav"');
678 * Creates the button with link to either forward or reverse
680 * @param string $type Type: "fwd" or "rwd
681 * @param int $pointer Pointer
682 * @param string $table Table name
686 public function fwd_rwd_HTML($type, $pointer, $table = '')
689 $tParam = $table ?
'&table=' . rawurlencode($table) : '';
692 $href = $this->listURL() . '&pointer=' . ($pointer - $this->iLimit
) . $tParam;
693 $content = '<a href="' . htmlspecialchars($href) . '">' . $this->iconFactory
->getIcon(
696 )->render() . '</a> <i>[1 - ' . $pointer . ']</i>';
699 $href = $this->listURL() . '&pointer=' . $pointer . $tParam;
700 $content = '<a href="' . htmlspecialchars($href) . '">' . $this->iconFactory
->getIcon(
703 )->render() . '</a> <i>[' . ($pointer +
1) . ' - ' . $this->totalItems
. ']</i>';
710 * Returning JavaScript for ClipBoard functionality.
714 public function CBfunctions()
718 function checkOffCB(listOfCBnames, link) { //
719 var checkBoxes, flag, i;
720 var checkBoxes = listOfCBnames.split(",");
721 if (link.rel === "") {
722 link.rel = "allChecked";
728 for (i = 0; i < checkBoxes.length; i++) {
729 setcbValue(checkBoxes[i], flag);
733 function cbValue(CBname) { //
734 var CBfullName = "CBC["+CBname+"]";
735 return (document.dblistForm[CBfullName] && document.dblistForm[CBfullName].checked ? 1 : 0);
738 function setcbValue(CBname,flag) { //
739 CBfullName = "CBC["+CBname+"]";
740 if(document.dblistForm[CBfullName]) {
741 document.dblistForm[CBfullName].checked = flag ? "on" : 0;
749 * Initializes page languages and icons
751 public function initializeLanguages()
753 // Look up page overlays:
754 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)
755 ->getQueryBuilderForTable('pages');
756 $queryBuilder->getRestrictions()
758 ->add(GeneralUtility
::makeInstance(DeletedRestriction
::class))
759 ->add(GeneralUtility
::makeInstance(BackendWorkspaceRestriction
::class));
760 $result = $queryBuilder
764 $queryBuilder->expr()->andX(
765 $queryBuilder->expr()->eq('l10n_parent', $queryBuilder->createNamedParameter($this->id
, \PDO
::PARAM_INT
)),
766 $queryBuilder->expr()->gt(
768 $queryBuilder->createNamedParameter(0, \PDO
::PARAM_INT
)
774 $this->pageOverlays
= [];
775 while ($row = $result->fetch()) {
776 $this->pageOverlays
[$row['sys_language_uid']] = $row;
779 $this->languageIconTitles
= $this->getTranslateTools()->getSystemLanguages($this->id
);
783 * Return the icon for the language
785 * @param int $sys_language_uid Sys language uid
786 * @param bool $addAsAdditionalText If set to true, only the flag is returned
787 * @return string Language icon
789 public function languageFlag($sys_language_uid, $addAsAdditionalText = true)
792 $title = htmlspecialchars($this->languageIconTitles
[$sys_language_uid]['title']);
793 if ($this->languageIconTitles
[$sys_language_uid]['flagIcon']) {
794 $out .= '<span title="' . $title . '">' . $this->iconFactory
->getIcon(
795 $this->languageIconTitles
[$sys_language_uid]['flagIcon'],
797 )->render() . '</span>';
798 if (!$addAsAdditionalText) {
808 * If there is a parent folder and user has access to it, return an icon
809 * which is linked to the filelist of the parent folder.
811 * @param Folder $currentFolder
814 protected function getLinkToParentFolder(Folder
$currentFolder)
818 $currentStorage = $currentFolder->getStorage();
819 $parentFolder = $currentFolder->getParentFolder();
820 if ($parentFolder->getIdentifier() !== $currentFolder->getIdentifier() && $currentStorage->isWithinFileMountBoundaries($parentFolder)) {
821 $levelUp = $this->linkWrapDir(
822 '<span title="' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.upOneLevel')) . '">'
823 . $this->iconFactory
->getIcon('actions-view-go-up', Icon
::SIZE_SMALL
)->render()
828 } catch (\Exception
$e) {
834 * Gets the number of files and total size of a folder
838 public function getFolderInfo()
840 if ($this->counter
== 1) {
841 $fileLabel = htmlspecialchars($this->getLanguageService()->getLL('file'));
843 $fileLabel = htmlspecialchars($this->getLanguageService()->getLL('files'));
845 return $this->counter
. ' ' . $fileLabel . ', ' . GeneralUtility
::formatSize($this->totalbytes
, htmlspecialchars($this->getLanguageService()->getLL('byteSizeUnits')));
849 * This returns tablerows for the directories in the array $items['sorting'].
851 * @param Folder[] $folders Folders of \TYPO3\CMS\Core\Resource\Folder
852 * @return string HTML table rows.
854 public function formatDirList(array $folders)
857 foreach ($folders as $folderName => $folderObject) {
858 $role = $folderObject->getRole();
859 if ($role === FolderInterface
::ROLE_PROCESSING
) {
860 // don't show processing-folder
863 if ($role !== FolderInterface
::ROLE_DEFAULT
) {
864 $displayName = '<strong>' . htmlspecialchars($folderName) . '</strong>';
866 $displayName = htmlspecialchars($folderName);
869 $isLocked = $folderObject instanceof InaccessibleFolder
;
870 $isWritable = $folderObject->checkActionPermission('write');
875 // The icon with link
876 $theIcon = '<span title="' . htmlspecialchars($folderName) . '">' . $this->iconFactory
->getIconForResource($folderObject, Icon
::SIZE_SMALL
)->render() . '</span>';
878 $theIcon = BackendUtility
::wrapClickMenuOnIcon($theIcon, 'sys_file', $folderObject->getCombinedIdentifier());
881 // Preparing and getting the data-array
884 foreach ($this->fieldArray
as $field) {
885 $theData[$field] = '';
887 $theData['file'] = $displayName;
889 foreach ($this->fieldArray
as $field) {
893 $numFiles = $folderObject->getFileCount();
894 } catch (InsufficientFolderAccessPermissionsException
$e) {
897 $theData[$field] = $numFiles . ' ' . htmlspecialchars($this->getLanguageService()->getLL(($numFiles === 1 ?
'file' : 'files')));
900 $theData[$field] = '<strong class="text-danger">' . htmlspecialchars($this->getLanguageService()->getLL('read')) . '</strong>' . (!$isWritable ?
'' : '<strong class="text-danger">' . htmlspecialchars($this->getLanguageService()->getLL('write')) . '</strong>');
903 $theData[$field] = htmlspecialchars($this->getLanguageService()->getLL('folder'));
906 $tstamp = $folderObject->getModificationTime();
907 $theData[$field] = $tstamp ? BackendUtility
::date($tstamp) : '-';
910 $theData[$field] = $this->linkWrapDir($displayName, $folderObject);
913 $theData[$field] = $this->makeEdit($folderObject);
916 $theData[$field] = $this->makeClip($folderObject);
919 $theData[$field] = $this->makeRef($folderObject);
922 $theData[$field] = GeneralUtility
::fixed_lgd_cs($theData[$field], $this->fixedL
);
926 $out .= $this->addElement(1, $theIcon, $theData);
932 * Wraps the directory-titles
934 * @param string $title String to be wrapped in links
935 * @param Folder $folderObject Folder to work on
936 * @return string HTML
938 public function linkWrapDir($title, Folder
$folderObject)
940 $href = BackendUtility
::getModuleUrl('file_FilelistList', ['id' => $folderObject->getCombinedIdentifier()]);
941 $onclick = ' onclick="' . htmlspecialchars(('top.document.getElementsByName("navigation")[0].contentWindow.Tree.highlightActiveItem("file","folder' . GeneralUtility
::md5int($folderObject->getCombinedIdentifier()) . '_"+top.fsMod.currentBank)')) . '"';
942 // Sometimes $code contains plain HTML tags. In such a case the string should not be modified!
943 if ((string)$title === strip_tags($title)) {
944 return '<a href="' . htmlspecialchars($href) . '"' . $onclick . ' title="' . htmlspecialchars($title) . '">' . $title . '</a>';
946 return '<a href="' . htmlspecialchars($href) . '"' . $onclick . '>' . $title . '</a>';
950 * Wraps filenames in links which opens the metadata editor.
952 * @param string $code String to be wrapped in links
953 * @param File $fileObject File to be linked
954 * @return string HTML
956 public function linkWrapFile($code, File
$fileObject)
959 if ($fileObject instanceof File
&& $fileObject->isIndexed() && $fileObject->checkActionPermission('write') && $this->getBackendUser()->check('tables_modify', 'sys_file_metadata')) {
960 $metaData = $fileObject->_getMetaData();
963 'sys_file_metadata' => [
964 $metaData['uid'] => 'edit'
967 'returnUrl' => $this->listURL()
969 $url = BackendUtility
::getModuleUrl('record_edit', $urlParameters);
970 $title = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.editMetadata'));
971 $code = '<a class="responsive-title" href="' . htmlspecialchars($url) . '" title="' . $title . '">' . $code . '</a>';
973 } catch (\Exception
$e) {
974 // intentional fall-through
980 * Returns list URL; This is the URL of the current script with id and imagemode parameters, that's all.
981 * The URL however is not relative, otherwise GeneralUtility::sanitizeLocalUrl() would say that
982 * the URL would be invalid
984 * @param string $altId
985 * @param string $table Table name to display. Enter "-1" for the current table.
986 * @param string $exclList Comma separated list of fields NOT to include ("sortField", "sortRev" or "firstElementNumber")
990 public function listURL($altId = '', $table = '-1', $exclList = '')
992 return GeneralUtility
::linkThisScript([
993 'target' => rawurlencode($this->folderObject
->getCombinedIdentifier()),
994 'imagemode' => $this->thumbs
999 * This returns tablerows for the files in the array $items['sorting'].
1001 * @param File[] $files File items
1002 * @return string HTML table rows.
1004 public function formatFileList(array $files)
1007 // first two keys are "0" (default) and "-1" (multiple), after that comes the "other languages"
1008 $allSystemLanguages = GeneralUtility
::makeInstance(TranslationConfigurationProvider
::class)->getSystemLanguages();
1009 $systemLanguages = array_filter($allSystemLanguages, function ($languageRecord) {
1010 if ($languageRecord['uid'] === -1 ||
$languageRecord['uid'] === 0 ||
!$this->getBackendUser()->checkLanguageAccess($languageRecord['uid'])) {
1016 foreach ($files as $fileObject) {
1019 $this->totalbytes +
= $fileObject->getSize();
1020 $ext = $fileObject->getExtension();
1021 $fileName = trim($fileObject->getName());
1022 // The icon with link
1023 $theIcon = '<span title="' . htmlspecialchars($fileName . ' [' . (int)$fileObject->getUid() . ']') . '">'
1024 . $this->iconFactory
->getIconForResource($fileObject, Icon
::SIZE_SMALL
)->render() . '</span>';
1025 $theIcon = BackendUtility
::wrapClickMenuOnIcon($theIcon, 'sys_file', $fileObject->getCombinedIdentifier());
1026 // Preparing and getting the data-array
1028 foreach ($this->fieldArray
as $field) {
1031 $theData[$field] = GeneralUtility
::formatSize($fileObject->getSize(), htmlspecialchars($this->getLanguageService()->getLL('byteSizeUnits')));
1034 $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>');
1037 $theData[$field] = strtoupper($ext);
1040 $theData[$field] = BackendUtility
::date($fileObject->getModificationTime());
1043 $theData[$field] = $this->makeEdit($fileObject);
1046 $theData[$field] = $this->makeClip($fileObject);
1048 case '_LOCALIZATION_':
1049 if (!empty($systemLanguages) && $fileObject->isIndexed() && $fileObject->checkActionPermission('write') && $this->getBackendUser()->check('tables_modify', 'sys_file_metadata')) {
1050 $metaDataRecord = $fileObject->_getMetaData();
1051 $translations = $this->getTranslationsForMetaData($metaDataRecord);
1054 foreach ($systemLanguages as $language) {
1055 $languageId = $language['uid'];
1056 $flagIcon = $language['flagIcon'];
1057 if (array_key_exists($languageId, $translations)) {
1058 $title = htmlspecialchars(sprintf($this->getLanguageService()->getLL('editMetadataForLanguage'), $language['title']));
1059 // @todo the overlay for the flag needs to be added ($flagIcon . '-overlay')
1062 'sys_file_metadata' => [
1063 $translations[$languageId]['uid'] => 'edit'
1066 'returnUrl' => $this->listURL()
1068 $flagButtonIcon = $this->iconFactory
->getIcon($flagIcon, Icon
::SIZE_SMALL
, 'overlay-edit')->render();
1069 $url = BackendUtility
::getModuleUrl('record_edit', $urlParameters);
1070 $languageCode .= '<a href="' . htmlspecialchars($url) . '" class="btn btn-default" title="' . $title . '">'
1071 . $flagButtonIcon . '</a>';
1074 'justLocalized' => 'sys_file_metadata:' . $metaDataRecord['uid'] . ':' . $languageId,
1075 'returnUrl' => $this->listURL()
1077 $returnUrl = BackendUtility
::getModuleUrl('record_edit', $parameters);
1078 $href = BackendUtility
::getLinkToDataHandlerAction(
1079 '&cmd[sys_file_metadata][' . $metaDataRecord['uid'] . '][localize]=' . $languageId,
1082 $flagButtonIcon = '<span title="' . htmlspecialchars(sprintf($this->getLanguageService()->getLL('createMetadataForLanguage'), $language['title'])) . '">' . $this->iconFactory
->getIcon($flagIcon, Icon
::SIZE_SMALL
, 'overlay-new')->render() . '</span>';
1083 $languageCode .= '<a href="' . htmlspecialchars($href) . '" class="btn btn-default">' . $flagButtonIcon . '</a> ';
1087 // Hide flag button bar when not translated yet
1088 $theData[$field] = ' <div class="localisationData btn-group" data-fileid="' . $fileObject->getUid() . '"' .
1089 (empty($translations) ?
' style="display: none;"' : '') . '>' . $languageCode . '</div>';
1090 $theData[$field] .= '<a class="btn btn-default filelist-translationToggler" data-fileid="' . $fileObject->getUid() . '">' .
1091 '<span title="' . htmlspecialchars($this->getLanguageService()->getLL('translateMetadata')) . '">'
1092 . $this->iconFactory
->getIcon('mimetypes-x-content-page-language-overlay', Icon
::SIZE_SMALL
)->render() . '</span>'
1097 $theData[$field] = $this->makeRef($fileObject);
1100 // Edit metadata of file
1101 $theData[$field] = $this->linkWrapFile(htmlspecialchars($fileName), $fileObject);
1103 if ($fileObject->isMissing()) {
1104 $theData[$field] .= '<span class="label label-danger label-space-left">'
1105 . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:warning.file_missing'))
1108 } elseif ($this->thumbs
&& ($this->isImage($ext) ||
$this->isMediaFile($ext))) {
1109 $processedFile = $fileObject->process(
1110 ProcessedFile
::CONTEXT_IMAGEPREVIEW
,
1112 'width' => $this->thumbnailConfiguration
->getWidth(),
1113 'height' => $this->thumbnailConfiguration
->getHeight()
1116 if ($processedFile) {
1117 $thumbUrl = $processedFile->getPublicUrl(true);
1118 $theData[$field] .= '<br /><img src="' . $thumbUrl . '" ' .
1119 'width="' . $processedFile->getProperty('width') . '" ' .
1120 'height="' . $processedFile->getProperty('height') . '" ' .
1121 'title="' . htmlspecialchars($fileName) . '" alt="" />';
1126 $theData[$field] = '';
1127 if ($fileObject->hasProperty($field)) {
1128 $theData[$field] = htmlspecialchars(GeneralUtility
::fixed_lgd_cs($fileObject->getProperty($field), $this->fixedL
));
1132 $out .= $this->addElement(1, $theIcon, $theData);
1138 * Fetch the translations for a sys_file_metadata record
1140 * @param $metaDataRecord
1141 * @return array keys are the sys_language uids, values are the $rows
1143 protected function getTranslationsForMetaData($metaDataRecord)
1145 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('sys_file_metadata');
1146 $queryBuilder->getRestrictions()->removeAll();
1147 $translationRecords = $queryBuilder->select('*')
1148 ->from('sys_file_metadata')
1150 $queryBuilder->expr()->eq(
1151 $GLOBALS['TCA']['sys_file_metadata']['ctrl']['transOrigPointerField'],
1152 $queryBuilder->createNamedParameter($metaDataRecord['uid'], \PDO
::PARAM_INT
)
1154 $queryBuilder->expr()->gt(
1155 $GLOBALS['TCA']['sys_file_metadata']['ctrl']['languageField'],
1156 $queryBuilder->createNamedParameter(0, \PDO
::PARAM_INT
)
1163 foreach ($translationRecords as $record) {
1164 $translations[$record[$GLOBALS['TCA']['sys_file_metadata']['ctrl']['languageField']]] = $record;
1166 return $translations;
1170 * Returns TRUE if $ext is an image-extension according to $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
1172 * @param string $ext File extension
1175 public function isImage($ext)
1177 return GeneralUtility
::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], strtolower($ext));
1181 * Returns TRUE if $ext is an media-extension according to $GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext']
1183 * @param string $ext File extension
1186 public function isMediaFile($ext)
1188 return GeneralUtility
::inList($GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'], strtolower($ext));
1192 * Wraps the directory-titles ($code) in a link to filelist/Modules/Filelist/index.php (id=$path) and sorting commands...
1194 * @param string $code String to be wrapped
1195 * @param string $folderIdentifier ID (path)
1196 * @param string $col Sorting column
1197 * @return string HTML
1199 public function linkWrapSort($code, $folderIdentifier, $col)
1201 $params = ['id' => $folderIdentifier, 'SET' => [ 'sort' => $col ]];
1203 if ($this->sort
=== $col) {
1204 // Check reverse sorting
1205 $params['SET']['reverse'] = ($this->sortRev ?
'0' : '1');
1206 $sortArrow = $this->iconFactory
->getIcon('status-status-sorting-light-' . ($this->sortRev ?
'desc' : 'asc'), Icon
::SIZE_SMALL
)->render();
1208 $params['SET']['reverse'] = 0;
1211 $href = BackendUtility
::getModuleUrl('file_FilelistList', $params);
1212 return '<a href="' . htmlspecialchars($href) . '">' . $code . ' ' . $sortArrow . '</a>';
1216 * Creates the clipboard control pad
1218 * @param File|Folder $fileOrFolderObject Array with information about the file/directory for which to make the clipboard panel for the listing.
1219 * @return string HTML-table
1221 public function makeClip($fileOrFolderObject)
1223 if (!$fileOrFolderObject->checkActionPermission('read')) {
1227 $fullIdentifier = $fileOrFolderObject->getCombinedIdentifier();
1228 $fullName = $fileOrFolderObject->getName();
1229 $md5 = GeneralUtility
::shortMD5($fullIdentifier);
1230 // For normal clipboard, add copy/cut buttons:
1231 if ($this->clipObj
->current
=== 'normal') {
1232 $isSel = $this->clipObj
->isSelected('_FILE', $md5);
1233 $copyTitle = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.copy'));
1234 $cutTitle = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.cut'));
1235 $copyIcon = $this->iconFactory
->getIcon('actions-edit-copy', Icon
::SIZE_SMALL
)->render();
1236 $cutIcon = $this->iconFactory
->getIcon('actions-edit-cut', Icon
::SIZE_SMALL
)->render();
1238 if ($isSel === 'copy') {
1239 $copyIcon = $this->iconFactory
->getIcon('actions-edit-copy-release', Icon
::SIZE_SMALL
)->render();
1240 } elseif ($isSel === 'cut') {
1241 $cutIcon = $this->iconFactory
->getIcon('actions-edit-cut-release', Icon
::SIZE_SMALL
)->render();
1244 $cells[] = '<a class="btn btn-default"" href="' . htmlspecialchars($this->clipObj
->selUrlFile($fullIdentifier, 1, ($isSel === 'copy'))) . '" title="' . $copyTitle . '">' . $copyIcon . '</a>';
1245 // we can only cut if file can be moved
1246 if ($fileOrFolderObject->checkActionPermission('move')) {
1247 $cells[] = '<a class="btn btn-default" href="' . htmlspecialchars($this->clipObj
->selUrlFile($fullIdentifier, 0, ($isSel === 'cut'))) . '" title="' . $cutTitle . '">' . $cutIcon . '</a>';
1249 $cells[] = $this->spaceIcon
;
1252 // For numeric pads, add select checkboxes:
1253 $n = '_FILE|' . $md5;
1254 $this->CBnames
[] = $n;
1255 $checked = $this->clipObj
->isSelected('_FILE', $md5) ?
' checked="checked"' : '';
1256 $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>';
1258 // Display PASTE button, if directory:
1259 $elFromTable = $this->clipObj
->elFromTable('_FILE');
1260 if ($fileOrFolderObject instanceof Folder
&& !empty($elFromTable) && $fileOrFolderObject->checkActionPermission('write')) {
1261 $addPasteButton = true;
1263 foreach ($elFromTable as $key => $element) {
1264 $clipBoardElement = $this->resourceFactory
->retrieveFileOrFolderObject($element);
1265 if ($clipBoardElement instanceof Folder
&& $clipBoardElement->getStorage()->isWithinFolder($clipBoardElement, $fileOrFolderObject)) {
1266 $addPasteButton = false;
1268 $elToConfirm[$key] = $clipBoardElement->getName();
1270 if ($addPasteButton) {
1271 $cells[] = '<a class="btn btn-default t3js-modal-trigger" '
1272 . ' href="' . htmlspecialchars($this->clipObj
->pasteUrl('_FILE', $fullIdentifier)) . '"'
1273 . ' data-content="' . htmlspecialchars($this->clipObj
->confirmMsgText('_FILE', $fullName, 'into', $elToConfirm)) . '"'
1274 . ' data-severity="warning"'
1275 . ' data-title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_pasteInto')) . '"'
1276 . ' title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_pasteInto')) . '"'
1278 . $this->iconFactory
->getIcon('actions-document-paste-into', Icon
::SIZE_SMALL
)->render()
1282 // Compile items into a DIV-element:
1283 return ' <div class="btn-group" role="group">' . implode('', $cells) . '</div>';
1287 * Creates the edit control section
1289 * @param File|Folder $fileOrFolderObject Array with information about the file/directory for which to make the edit control section for the listing.
1290 * @return string HTML-table
1292 public function makeEdit($fileOrFolderObject)
1295 $fullIdentifier = $fileOrFolderObject->getCombinedIdentifier();
1296 $md5 = GeneralUtility
::shortMD5($fullIdentifier);
1297 $isSel = $this->clipObj
->isSelected('_FILE', $md5);
1299 // Edit file content (if editable)
1300 if ($fileOrFolderObject instanceof File
&& $fileOrFolderObject->checkActionPermission('write') && GeneralUtility
::inList($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], $fileOrFolderObject->getExtension())) {
1301 $url = BackendUtility
::getModuleUrl('file_edit', ['target' => $fullIdentifier]);
1302 $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;';
1303 $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') . '">'
1304 . $this->iconFactory
->getIcon('actions-page-open', Icon
::SIZE_SMALL
)->render()
1307 $cells['edit'] = $this->spaceIcon
;
1310 // Edit metadata of file
1311 if ($fileOrFolderObject instanceof File
&& $fileOrFolderObject->checkActionPermission('write') && $this->getBackendUser()->check('tables_modify', 'sys_file_metadata')) {
1312 $metaData = $fileOrFolderObject->_getMetaData();
1315 'sys_file_metadata' => [
1316 $metaData['uid'] => 'edit'
1319 'returnUrl' => $this->listURL()
1321 $url = BackendUtility
::getModuleUrl('record_edit', $urlParameters);
1322 $title = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.editMetadata'));
1323 $cells['metadata'] = '<a class="btn btn-default" href="' . htmlspecialchars($url) . '" title="' . $title . '">' . $this->iconFactory
->getIcon('actions-open', Icon
::SIZE_SMALL
)->render() . '</a>';
1327 if ($fileOrFolderObject instanceof File
) {
1328 $fileUrl = $fileOrFolderObject->getPublicUrl(true);
1330 $aOnClick = 'return top.openUrlInWindow(' . GeneralUtility
::quoteJSvalue($fileUrl) . ', \'WebFile\');';
1331 $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>';
1333 $cells['view'] = $this->spaceIcon
;
1336 $cells['view'] = $this->spaceIcon
;
1340 if ($fileOrFolderObject instanceof File
&& $fileOrFolderObject->checkActionPermission('replace')) {
1341 $url = BackendUtility
::getModuleUrl('file_replace', ['target' => $fullIdentifier, 'uid' => $fileOrFolderObject->getUid()]);
1342 $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;';
1343 $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>';
1347 if ($fileOrFolderObject->checkActionPermission('rename')) {
1348 $url = BackendUtility
::getModuleUrl('file_rename', ['target' => $fullIdentifier]);
1349 $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;';
1350 $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>';
1352 $cells['rename'] = $this->spaceIcon
;
1356 if ($fileOrFolderObject->getStorage()->checkUserActionPermission('add', 'File') && $fileOrFolderObject->checkActionPermission('write')) {
1357 if ($fileOrFolderObject instanceof Folder
) {
1358 $url = BackendUtility
::getModuleUrl('file_upload', ['target' => $fullIdentifier]);
1359 $uploadOnClick = '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;';
1360 $cells['upload'] = '<a href="#" class="btn btn-default" onclick="' . htmlspecialchars($uploadOnClick) . '" title="' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.upload')) . '">' . $this->iconFactory
->getIcon('actions-edit-upload', Icon
::SIZE_SMALL
)->render() . '</a>';
1364 if ($fileOrFolderObject->checkActionPermission('read')) {
1366 if ($fileOrFolderObject instanceof Folder
) {
1367 $infoOnClick = 'top.launchView( \'_FOLDER\', ' . GeneralUtility
::quoteJSvalue($fullIdentifier) . ');return false;';
1368 } elseif ($fileOrFolderObject instanceof File
) {
1369 $infoOnClick = 'top.launchView( \'_FILE\', ' . GeneralUtility
::quoteJSvalue($fullIdentifier) . ');return false;';
1371 $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>';
1373 $cells['info'] = $this->spaceIcon
;
1377 if ($fileOrFolderObject->checkActionPermission('copy') && $this->clipObj
->current
=== 'normal') {
1378 $copyTitle = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.copy'));
1379 $copyIcon = $this->iconFactory
->getIcon('actions-edit-copy', Icon
::SIZE_SMALL
)->render();
1381 if ($isSel === 'copy') {
1382 $copyIcon = $this->iconFactory
->getIcon('actions-edit-copy-release', Icon
::SIZE_SMALL
)->render();
1385 $cells['copy'] = '<a class="btn btn-default"" href="' . htmlspecialchars($this->clipObj
->selUrlFile($fullIdentifier, 1, ($isSel === 'copy'))) . '" title="' . $copyTitle . '">' . $copyIcon . '</a>';
1389 if ($fileOrFolderObject->checkActionPermission('move') && $this->clipObj
->current
=== 'normal') {
1390 $cutTitle = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.cut'));
1391 $cutIcon = $this->iconFactory
->getIcon('actions-edit-cut', Icon
::SIZE_SMALL
)->render();
1393 if ($isSel === 'cut') {
1394 $cutIcon = $this->iconFactory
->getIcon('actions-edit-cut-release', Icon
::SIZE_SMALL
)->render();
1397 $cells['cut'] = '<a class="btn btn-default" href="' . htmlspecialchars($this->clipObj
->selUrlFile($fullIdentifier, 0, ($isSel === 'cut'))) . '" title="' . $cutTitle . '">' . $cutIcon . '</a>';
1401 if ($fileOrFolderObject->checkActionPermission('delete')) {
1402 $identifier = $fileOrFolderObject->getIdentifier();
1403 if ($fileOrFolderObject instanceof Folder
) {
1404 $referenceCountText = BackendUtility
::referenceCount('_FILE', $identifier, ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.referencesToFolder'));
1405 $deleteType = 'delete_folder';
1407 $referenceCountText = BackendUtility
::referenceCount('sys_file', $fileOrFolderObject->getUid(), ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.referencesToFile'));
1408 $deleteType = 'delete_file';
1411 if ($this->getBackendUser()->jsConfirmation(JsConfirmation
::DELETE
)) {
1412 $confirmationCheck = '1';
1414 $confirmationCheck = '0';
1417 $deleteUrl = BackendUtility
::getModuleUrl('tce_file');
1418 $confirmationMessage = sprintf($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:mess.delete'), $fileOrFolderObject->getName()) . $referenceCountText;
1419 $title = $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.delete');
1420 $cells['delete'] = '<a href="#" class="btn btn-default t3js-filelist-delete" data-content="' . htmlspecialchars($confirmationMessage)
1421 . '" data-check="' . $confirmationCheck
1422 . '" data-delete-url="' . htmlspecialchars($deleteUrl)
1423 . '" data-title="' . htmlspecialchars($title)
1424 . '" data-identifier="' . htmlspecialchars($fileOrFolderObject->getCombinedIdentifier())
1425 . '" data-delete-type="' . $deleteType
1426 . '" title="' . htmlspecialchars($title) . '">'
1427 . $this->iconFactory
->getIcon('actions-edit-delete', Icon
::SIZE_SMALL
)->render() . '</a>';
1429 $cells['delete'] = $this->spaceIcon
;
1432 // Hook for manipulating edit icons.
1433 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['fileList']['editIconsHook'])) {
1434 $cells['__fileOrFolderObject'] = $fileOrFolderObject;
1435 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['fileList']['editIconsHook'] as $className) {
1436 $hookObject = GeneralUtility
::makeInstance($className);
1437 if (!$hookObject instanceof FileListEditIconHookInterface
) {
1438 throw new \
UnexpectedValueException(
1439 $className . ' must implement interface ' . FileListEditIconHookInterface
::class,
1443 $hookObject->manipulateEditIcons($cells, $this);
1445 unset($cells['__fileOrFolderObject']);
1447 // Compile items into a DIV-element:
1448 return '<div class="btn-group">' . implode('', $cells) . '</div>';
1452 * Make reference count
1454 * @param File|Folder $fileOrFolderObject Array with information about the file/directory for which to make the clipboard panel for the listing.
1455 * @return string HTML
1457 public function makeRef($fileOrFolderObject)
1459 if ($fileOrFolderObject instanceof FolderInterface
) {
1462 // Look up the file in the sys_refindex.
1463 // Exclude sys_file_metadata records as these are no use references
1464 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('sys_refindex');
1465 $referenceCount = $queryBuilder->count('*')
1466 ->from('sys_refindex')
1468 $queryBuilder->expr()->eq('deleted', $queryBuilder->createNamedParameter(0, \PDO
::PARAM_INT
)),
1469 $queryBuilder->expr()->eq(
1471 $queryBuilder->createNamedParameter('sys_file', \PDO
::PARAM_STR
)
1473 $queryBuilder->expr()->eq(
1475 $queryBuilder->createNamedParameter($fileOrFolderObject->getUid(), \PDO
::PARAM_INT
)
1477 $queryBuilder->expr()->neq(
1479 $queryBuilder->createNamedParameter('sys_file_metadata', \PDO
::PARAM_STR
)
1485 return $this->generateReferenceToolTip($referenceCount, '\'_FILE\', ' . GeneralUtility
::quoteJSvalue($fileOrFolderObject->getCombinedIdentifier()));
1489 * Returns an instance of LanguageService
1491 * @return \TYPO3\CMS\Core\Localization\LanguageService
1493 protected function getLanguageService()
1495 return $GLOBALS['LANG'];
1499 * Returns the current BE user.
1501 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
1503 protected function getBackendUser()
1505 return $GLOBALS['BE_USER'];
1509 * Sets the script url depending on being a module or script request
1511 protected function determineScriptUrl()
1513 if ($routePath = GeneralUtility
::_GP('route')) {
1514 $uriBuilder = GeneralUtility
::makeInstance(UriBuilder
::class);
1515 $this->thisScript
= (string)$uriBuilder->buildUriFromRoutePath($routePath);
1517 $this->thisScript
= GeneralUtility
::getIndpEnv('SCRIPT_NAME');
1524 protected function getThisScript()
1526 return strpos($this->thisScript
, '?') === false ?
$this->thisScript
. '?' : $this->thisScript
. '&';
1530 * Gets an instance of TranslationConfigurationProvider
1532 * @return TranslationConfigurationProvider
1534 protected function getTranslateTools()
1536 if (!isset($this->translateTools
)) {
1537 $this->translateTools
= GeneralUtility
::makeInstance(TranslationConfigurationProvider
::class);
1539 return $this->translateTools
;
1543 * Generates HTML code for a Reference tooltip out of
1544 * sys_refindex records you hand over
1546 * @param int $references number of records from sys_refindex table
1547 * @param string $launchViewParameter JavaScript String, which will be passed as parameters to top.launchView
1550 protected function generateReferenceToolTip($references, $launchViewParameter = '')
1555 $htmlCode = '<a href="#"';
1556 if ($launchViewParameter !== '') {
1557 $htmlCode .= ' onclick="' . htmlspecialchars(
1558 ('top.launchView(' . $launchViewParameter . '); return false;')
1561 $htmlCode .= ' title="' . htmlspecialchars(
1562 $this->getLanguageService()->sL(
1563 'LLL:EXT:backend/Resources/Private/Language/locallang.xlf:show_references'
1564 ) . ' (' . $references . ')'
1566 $htmlCode .= $references;
1567 $htmlCode .= '</a>';