[FEATURE] Introduce file search in filelist module 84/42684/13
authorAlexander Schnitzler <git@alexanderschnitzler.de>
Mon, 17 Aug 2015 14:02:48 +0000 (16:02 +0200)
committerMathias Schreiber <mathias.schreiber@wmdb.de>
Sat, 12 Sep 2015 17:51:42 +0000 (19:51 +0200)
Introduces a basic recursive file search. As a first
implementation only searching by file name is possible.

Releases: master
Resolves: #69119
Change-Id: Id8db1aa9bfd1ae145fcf8f2d5196e64fd262ebb1
Reviewed-on: http://review.typo3.org/42684
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Daniel Maier <dani-maier@gmx.de>
Tested-by: Daniel Maier <dani-maier@gmx.de>
Reviewed-by: Mathias Schreiber <mathias.schreiber@wmdb.de>
Tested-by: Mathias Schreiber <mathias.schreiber@wmdb.de>
18 files changed:
typo3/sysext/core/Classes/Resource/FileRepository.php
typo3/sysext/core/Classes/Resource/Index/FileIndexRepository.php
typo3/sysext/core/Documentation/Changelog/master/Feature-69119-AddABasicSearchToTheFilelistModule.rst [new file with mode: 0644]
typo3/sysext/filelist/Classes/Controller/FileListController.php
typo3/sysext/filelist/Classes/FileFacade.php [new file with mode: 0644]
typo3/sysext/filelist/Classes/ViewHelpers/Link/ClickMenuOnIconViewHelper.php [new file with mode: 0644]
typo3/sysext/filelist/Classes/ViewHelpers/Uri/DeleteFileViewHelper.php [new file with mode: 0644]
typo3/sysext/filelist/Classes/ViewHelpers/Uri/EditFileContentViewHelper.php [new file with mode: 0644]
typo3/sysext/filelist/Classes/ViewHelpers/Uri/EditSysFileMetadataRecordViewHelper.php [new file with mode: 0644]
typo3/sysext/filelist/Classes/ViewHelpers/Uri/RenameFileViewHelper.php [new file with mode: 0644]
typo3/sysext/filelist/Classes/ViewHelpers/Uri/ReplaceFileViewHelper.php [new file with mode: 0644]
typo3/sysext/filelist/Resources/Private/Language/locallang.xlf [new file with mode: 0644]
typo3/sysext/filelist/Resources/Private/Partials/SearchForm.html [new file with mode: 0644]
typo3/sysext/filelist/Resources/Private/Templates/FileList/Index.html
typo3/sysext/filelist/Resources/Private/Templates/FileList/Search.html [new file with mode: 0644]
typo3/sysext/filelist/Resources/Public/JavaScript/FileList.js [new file with mode: 0644]
typo3/sysext/filelist/ext_tables.php
typo3/sysext/lang/locallang_mod_file_list.xlf

index 0e5174b..e90fd7c 100644 (file)
@@ -131,6 +131,39 @@ class FileRepository extends AbstractRepository {
        }
 
        /**
+        * Search for files by name in a given folder
+        *
+        * @param Folder $folder
+        * @param string $fileName
+        *
+        * @return File[]
+        */
+       public function searchByName(Folder $folder, $fileName) {
+               /** @var \TYPO3\CMS\Core\Resource\ResourceFactory $fileFactory */
+               $fileFactory = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\ResourceFactory::class);
+
+               $folders = $folder->getStorage()->getFoldersInFolder($folder, 0, 0, TRUE, TRUE);
+               $folders[$folder->getIdentifier()] = $folder;
+
+               $fileRecords = $this->getFileIndexRepository()->findByFolders($folders, FALSE);
+
+               $files = array();
+               foreach ($fileRecords as $fileRecord) {
+                       if (stristr($fileRecord['name'], $fileName) === FALSE) {
+                               continue;
+                       }
+
+                       try {
+                               $files[] = $fileFactory->getFileObject($fileRecord['uid'], $fileRecord);
+                       } catch (\TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException $ignoredException) {
+                               continue;
+                       }
+               }
+
+               return $files;
+       }
+
+       /**
         * Return a file index repository
         *
         * @return FileIndexRepository
index a1f5e69..51e169e 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 namespace TYPO3\CMS\Core\Resource\Index;
 
 /*
@@ -183,6 +182,44 @@ class FileIndexRepository implements SingletonInterface {
                );
                return $resultRows;
        }
+
+       /**
+        * Find all records for files in an array of Folders
+        *
+        * @param \TYPO3\CMS\Core\Resource\Folder[] $folders
+        * @param bool $includeMissing
+        * @return array|NULL
+        */
+       public function findByFolders(array $folders, $includeMissing = TRUE) {
+               $storageUids = [];
+               $folderIdentifiers = [];
+
+               foreach ($folders as $folder) {
+                       if (!$folder instanceof \TYPO3\CMS\Core\Resource\Folder) {
+                               continue;
+                       }
+
+                       $storageUids[] = (int)$folder->getStorage()->getUid();
+                       $folderIdentifiers[] = $folder->getHashedIdentifier();
+               }
+               $storageUids = array_unique($storageUids);
+               $folderIdentifiers = array_unique($folderIdentifiers);
+
+               $fileRecords = $this->getDatabaseConnection()->exec_SELECTgetRows(
+                       implode(',', $this->fields),
+                       $this->table,
+                       'folder_hash IN ( ' . implode(',', $this->getDatabaseConnection()->fullQuoteArray($folderIdentifiers, $this->table)) . ')' .
+                       ' AND storage IN (' . implode(',', $storageUids) . ')' .
+                       ($includeMissing ? '' : ' AND missing = 0'),
+                       '',
+                       '',
+                       '',
+                       'identifier'
+               );
+
+               return $fileRecords;
+       }
+
        /**
         * Adds a file to the index
         *
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-69119-AddABasicSearchToTheFilelistModule.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-69119-AddABasicSearchToTheFilelistModule.rst
new file mode 100644 (file)
index 0000000..8b58925
--- /dev/null
@@ -0,0 +1,18 @@
+===========================================================
+Feature: #69119 - Add a basic search to the filelist module
+===========================================================
+
+Description
+===========
+
+A basic recursive file search by file name has been added to be able to search for files in the file list module like it was possible with EXT:dam.
+
+The search happens recursively from the currently chosen folder in the folder tree. This way it is possible to search whole mount points or just single folders with a lot of files.
+
+The search results will be displayed similar to the regular file list although some features of the regular list view are missing. There is no possibility to order the search results yet. Also the buttons for localization and clipboard commands are missing in this first implementation. Regular file command links like editing, renaming and deleting are already implemented. By default the search results are ordered by the file identifier, i.e. the file path ascending from A-Z.
+
+
+Impact
+======
+
+There is no impact on other parts of the core.
index 4a81e0e..75d0405 100644 (file)
@@ -26,10 +26,12 @@ use TYPO3\CMS\Core\Resource\Exception;
 use TYPO3\CMS\Core\Resource\Folder;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
 use TYPO3\CMS\Core\Resource\Utility\ListUtility;
+use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
 use TYPO3\CMS\Filelist\FileList;
 
 /**
@@ -128,6 +130,18 @@ class FileListController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControl
        protected $moduleName = 'file_list';
 
        /**
+        * @var \TYPO3\CMS\Core\Resource\FileRepository
+        */
+       protected $fileRepository;
+
+       /**
+        * @param \TYPO3\CMS\Core\Resource\FileRepository $fileRepository
+        */
+       public function injectFileRepository(\TYPO3\CMS\Core\Resource\FileRepository $fileRepository) {
+               $this->fileRepository = $fileRepository;
+       }
+
+       /**
         * Initialize variables, file object
         * Incoming GET vars include id, pointer, table, imagemode
         *
@@ -407,6 +421,37 @@ class FileListController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControl
        }
 
        /**
+        * Search for files by name and pass them with a facade to fluid
+        *
+        * @param string $searchWord
+        */
+       public function searchAction($searchWord = '') {
+               if (empty($searchWord)) {
+                       $this->forward('index');
+               }
+
+               $fileFacades = [];
+               $files = $this->fileRepository->searchByName($this->folderObject, $searchWord);
+
+               if (empty($files)) {
+                       $this->controllerContext->getFlashMessageQueue('core.template.flashMessages')->addMessage(
+                               new FlashMessage(LocalizationUtility::translate('flashmessage.no_results', 'filelist'), '', FlashMessage::INFO)
+                       );
+               } else {
+                       foreach ($files as $file) {
+                               $fileFacades[] = new \TYPO3\CMS\Filelist\FileFacade($file);
+                       }
+               }
+
+               $this->view->assign('requireJsModules', ['TYPO3/CMS/Filelist/FileList']);
+               $this->view->assign('searchWord', $searchWord);
+               $this->view->assign('files', $fileFacades);
+               $this->view->assign('settings', [
+                       'jsConfirmationDelete' => $this->getBackendUser()->jsConfirmation(JsConfirmation::DELETE)
+               ]);
+       }
+
+       /**
         * Get main headline based on active folder or storage for backend module
         *
         * Folder names are resolved to their special names like done in the tree view.
diff --git a/typo3/sysext/filelist/Classes/FileFacade.php b/typo3/sysext/filelist/Classes/FileFacade.php
new file mode 100644 (file)
index 0000000..0eb7beb
--- /dev/null
@@ -0,0 +1,280 @@
+<?php
+namespace TYPO3\CMS\Filelist;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Class FileFacade
+ *
+ * This class is meant to be a wrapper for Resource\File objects, which do not
+ * provide necessary methods needed in the views of the filelist extension. It
+ * is a first approach to get rid of the FileList class that mixes up PHP,
+ * HTML and JavaScript.
+ */
+class FileFacade {
+
+       /**
+        * Cache to count the number of references for each file
+        *
+        * @var array
+        */
+       static protected $referenceCounts = [];
+
+       /**
+        * @var \TYPO3\CMS\Core\Resource\FileInterface
+        */
+       protected $resource;
+
+       /**
+        * @param \TYPO3\CMS\Core\Resource\FileInterface $resource
+        * @internal Do not use outside of EXT:filelist!
+        */
+       public function __construct(\TYPO3\CMS\Core\Resource\FileInterface $resource) {
+               $this->resource = $resource;
+       }
+
+       /**
+        * @return string
+        */
+       public function getIcon() {
+               return \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIconForResource(
+                       $this->resource,
+                       array('title' => $this->resource->getName() . ' [' . (int)$this->resource->getProperty('uid') . ']')
+               );
+       }
+
+       /**
+        * @return \TYPO3\CMS\Core\Resource\FileInterface
+        */
+       public function getResource() {
+               return $this->resource;
+       }
+
+       /**
+        * @return bool
+        */
+       public function getIsEditable() {
+               return $this->getIsWritable()
+                       && GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], $this->resource->getExtension());
+       }
+
+       /**
+        * @return bool
+        */
+       public function getIsMetadataEditable() {
+               return $this->resource->isIndexed() && $this->getIsWritable() && $this->getBackendUser()->check('tables_modify', 'sys_file_metadata');
+       }
+
+       /**
+        * @return int
+        */
+       public function getMetadataUid() {
+               $uid = 0;
+               $method = '_getMetadata';
+               if (is_callable([$this->resource, $method])) {
+                       $metadata = call_user_func([$this->resource, $method]);
+
+                       if (isset($metadata['uid'])) {
+                               $uid = (int)$metadata['uid'];
+                       }
+               }
+
+               return $uid;
+       }
+
+       /**
+        * @return string
+        */
+       public function getName() {
+               return $this->resource->getName();
+       }
+
+       /**
+        * @return string
+        */
+       public function getPath() {
+               $method = 'getReadablePath';
+               if (is_callable([$this->resource->getParentFolder(), $method])) {
+                       return call_user_func([$this->resource->getParentFolder(), $method]);
+               }
+
+               return '';
+       }
+
+       /**
+        * @return string
+        */
+       public function getPublicUrl() {
+               return $this->resource->getPublicUrl(TRUE);
+       }
+
+       /**
+        * @return string
+        */
+       public function getExtension() {
+               return strtoupper($this->resource->getExtension());
+       }
+
+       /**
+        * @return string
+        */
+       public function getLastModified() {
+               return BackendUtility::date($this->resource->getModificationTime());
+       }
+
+       /**
+        * @return string
+        */
+       public function getSize() {
+               return GeneralUtility::formatSize($this->resource->getSize(), $this->getLanguageService()->getLL('byteSizeUnits', TRUE));
+       }
+
+       /**
+        * @return bool
+        */
+       public function getIsReadable() {
+               $method = 'checkActionPermission';
+               if (is_callable([$this->resource, $method])) {
+                       return call_user_func_array([$this->resource, $method], ['read']);
+               }
+
+               return FALSE;
+       }
+
+       /**
+        * @return bool
+        */
+       public function getIsWritable() {
+               $method = 'checkActionPermission';
+               if (is_callable([$this->resource, $method])) {
+                       return call_user_func_array([$this->resource, $method], ['write']);
+               }
+
+               return FALSE;
+       }
+
+       /**
+        * @return bool
+        */
+       public function getIsReplaceable() {
+               $method = 'checkActionPermission';
+               if (is_callable([$this->resource, $method])) {
+                       return call_user_func_array([$this->resource, $method], ['replace']);
+               }
+
+               return FALSE;
+       }
+
+       /**
+        * @return bool
+        */
+       public function getIsRenamable() {
+               $method = 'checkActionPermission';
+               if (is_callable([$this->resource, $method])) {
+                       return call_user_func_array([$this->resource, $method], ['rename']);
+               }
+
+               return FALSE;
+       }
+
+       /**
+        * @return bool
+        */
+       public function getIsDeletable() {
+               $method = 'checkActionPermission';
+               if (is_callable([$this->resource, $method])) {
+                       return call_user_func_array([$this->resource, $method], ['delete']);
+               }
+
+               return FALSE;
+       }
+
+       /**
+        * @return bool
+        */
+       public function getIsImage() {
+               return GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], strtolower($this->getExtension()));
+       }
+
+       /**
+        * Fetch, cache and return the number of references of a file
+        *
+        * @return int
+        */
+       public function getReferenceCount() {
+               $uid = (int)$this->resource->getProperty('uid');
+
+               if ($uid <= 0) {
+                       return 0;
+               }
+
+               if (!isset(static::$referenceCounts[$uid])) {
+                       $count = $this->getDatabaseConnection()->exec_SELECTcountRows(
+                               '*',
+                               'sys_refindex',
+                               'ref_table=\'sys_file\''
+                               . ' AND ref_uid=' . (int)$this->resource->getProperty('uid')
+                               . ' AND deleted=0'
+                               . ' AND tablename != \'sys_file_metadata\''
+                       );
+
+                       if (!is_int($count)) {
+                               $count = 0;
+                       }
+
+                       static::$referenceCounts[$uid] = $count;
+               }
+
+               return static::$referenceCounts[$uid];
+       }
+
+       /**
+        * @param string $method
+        * @param array $arguments
+        *
+        * @return mixed
+        */
+       public function __call($method, $arguments) {
+               if (is_callable([$this->resource, $method])) {
+                       return call_user_func_array([$this->resource, $method], $arguments);
+               }
+
+               return NULL;
+       }
+
+       /**
+        * @return \TYPO3\CMS\Core\Database\DatabaseConnection
+        */
+       protected function getDatabaseConnection() {
+               return $GLOBALS['TYPO3_DB'];
+       }
+
+       /**
+        * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+        */
+       protected function getBackendUser() {
+               return $GLOBALS['BE_USER'];
+       }
+
+       /**
+        * @return \TYPO3\CMS\Lang\LanguageService
+        */
+       protected function getLanguageService() {
+               return $GLOBALS['LANG'];
+       }
+
+}
diff --git a/typo3/sysext/filelist/Classes/ViewHelpers/Link/ClickMenuOnIconViewHelper.php b/typo3/sysext/filelist/Classes/ViewHelpers/Link/ClickMenuOnIconViewHelper.php
new file mode 100644 (file)
index 0000000..959692e
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+namespace TYPO3\CMS\Filelist\ViewHelpers\Link;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Class ClickMenuOnIconViewHelper
+ */
+class ClickMenuOnIconViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper {
+
+       /**
+        * @var string
+        */
+       protected $tagName = 'a';
+
+       /**
+        * @return void
+        */
+       public function initializeArguments() {
+               $this->registerUniversalTagAttributes();
+       }
+
+       /**
+        * Renders click menu link (context sensitive menu)
+        *
+        * @param string $table
+        *
+        * @return string
+        * @see \TYPO3\CMS\Backend\Template\DocumentTemplate->wrapClickMenuOnIcon()
+        */
+       public function render($table) {
+               $this->tag->addAttribute('class', 't3-js-clickmenutrigger ' . $this->arguments['class']);
+               $this->tag->addAttribute('data-table', $table);
+               $this->tag->addAttribute('data-listframe', 1);
+               $this->tag->addAttribute('href', '#');
+
+               return $this->tag->render();
+       }
+
+}
diff --git a/typo3/sysext/filelist/Classes/ViewHelpers/Uri/DeleteFileViewHelper.php b/typo3/sysext/filelist/Classes/ViewHelpers/Uri/DeleteFileViewHelper.php
new file mode 100644 (file)
index 0000000..9e309ed
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+namespace TYPO3\CMS\Filelist\ViewHelpers\Uri;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Closure;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
+
+/**
+ * Class DeleteFileViewHelper
+ */
+class DeleteFileViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper implements CompilableInterface {
+
+       /**
+        * Renders a link to delete the file
+        *
+        * @param \TYPO3\CMS\Core\Resource\AbstractFile $file
+        * @param string $returnUrl
+        *
+        * @return string
+        */
+       public function render(\TYPO3\CMS\Core\Resource\AbstractFile $file, $returnUrl = '') {
+               return static::renderStatic(
+                       [
+                               'file' => $file,
+                               'returnUrl' => $returnUrl,
+                       ],
+                       $this->buildRenderChildrenClosure(),
+                       $this->renderingContext
+               );
+       }
+
+       /**
+        * Renders a link to delete the file
+        *
+        * @param array $arguments
+        * @param Closure $renderChildrenClosure
+        * @param RenderingContextInterface $renderingContext
+        *
+        * @return string
+        */
+       static public function renderStatic(array $arguments, Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
+               $veriCode = '&vC=';
+               if ($GLOBALS['BE_USER'] instanceof \TYPO3\CMS\Core\Authentication\BackendUserAuthentication) {
+                       $veriCode .= $GLOBALS['BE_USER']->veriCode() . BackendUtility::getUrlToken('tceAction');
+               }
+
+               if (empty($arguments['returnUrl'])) {
+                       $arguments['returnUrl'] = GeneralUtility::getIndpEnv('REQUEST_URI');
+               }
+
+               /** @var \TYPO3\CMS\Core\Resource\AbstractFile $file */
+               $file = $arguments['file'];
+
+               $params = [
+                       'file' => [
+                               'delete' => [
+                                       0 => [
+                                               'data' => $file->getCombinedIdentifier()
+                                       ]
+                               ]
+                       ],
+                       'redirect' => $arguments['returnUrl']
+               ];
+
+               return BackendUtility::getModuleUrl('tce_file', $params) . $veriCode;
+       }
+
+}
diff --git a/typo3/sysext/filelist/Classes/ViewHelpers/Uri/EditFileContentViewHelper.php b/typo3/sysext/filelist/Classes/ViewHelpers/Uri/EditFileContentViewHelper.php
new file mode 100644 (file)
index 0000000..699ede1
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+namespace TYPO3\CMS\Filelist\ViewHelpers\Uri;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Closure;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
+
+/**
+ * Class EditFileContentViewHelper
+ */
+class EditFileContentViewHelper extends AbstractViewHelper implements CompilableInterface {
+
+       /**
+        * Renders a link to edit the file content
+        *
+        * @param \TYPO3\CMS\Core\Resource\AbstractFile $file
+        * @param string $returnUrl
+        *
+        * @return string
+        */
+       public function render(\TYPO3\CMS\Core\Resource\AbstractFile $file, $returnUrl = '') {
+               return static::renderStatic(
+                       [
+                               'file' => $file,
+                               'returnUrl' => $returnUrl,
+                       ],
+                       $this->buildRenderChildrenClosure(),
+                       $this->renderingContext
+               );
+       }
+
+       /**
+        * Renders a link to edit the file content
+        *
+        * @param array $arguments
+        * @param Closure $renderChildrenClosure
+        * @param RenderingContextInterface $renderingContext
+        *
+        * @return string
+        */
+       static public function renderStatic(array $arguments, Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
+               if (empty($arguments['returnUrl'])) {
+                       $arguments['returnUrl'] = GeneralUtility::getIndpEnv('REQUEST_URI');
+               }
+
+               /** @var \TYPO3\CMS\Core\Resource\AbstractFile $file */
+               $file = $arguments['file'];
+
+               $params = [
+                       'target' => $file->getCombinedIdentifier(),
+                       'returnUrl' => $arguments['returnUrl']
+               ];
+
+               return BackendUtility::getModuleUrl('file_edit', $params);
+       }
+
+}
diff --git a/typo3/sysext/filelist/Classes/ViewHelpers/Uri/EditSysFileMetadataRecordViewHelper.php b/typo3/sysext/filelist/Classes/ViewHelpers/Uri/EditSysFileMetadataRecordViewHelper.php
new file mode 100644 (file)
index 0000000..dc2b40c
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+namespace TYPO3\CMS\Filelist\ViewHelpers\Uri;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Closure;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
+
+/**
+ * Class EditSysFileMetadataRecordViewHelper
+ */
+class EditSysFileMetadataRecordViewHelper extends AbstractViewHelper implements CompilableInterface {
+
+       /**
+        * Renders a link to edit sys_file_metadata
+        *
+        * @param int $uid
+        * @param string $returnUrl
+        *
+        * @return string
+        */
+       public function render($uid, $returnUrl = '') {
+               return static::renderStatic(
+                       [
+                               'uid' => $uid,
+                               'returnUrl' => $returnUrl,
+                       ],
+                       $this->buildRenderChildrenClosure(),
+                       $this->renderingContext
+               );
+       }
+
+       /**
+        * Renders a link to edit sys_file_metadata
+        *
+        * @param array $arguments
+        * @param Closure $renderChildrenClosure
+        * @param RenderingContextInterface $renderingContext
+        *
+        * @return string
+        */
+       static public function renderStatic(array $arguments, Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
+               if (empty($arguments['returnUrl'])) {
+                       $arguments['returnUrl'] = GeneralUtility::getIndpEnv('REQUEST_URI');
+               }
+
+               $params = [
+                       'edit' => ['sys_file_metadata' => [$arguments['uid'] => 'edit']],
+                       'returnUrl' => $arguments['returnUrl']
+               ];
+
+               return BackendUtility::getModuleUrl('record_edit', $params);
+       }
+
+}
diff --git a/typo3/sysext/filelist/Classes/ViewHelpers/Uri/RenameFileViewHelper.php b/typo3/sysext/filelist/Classes/ViewHelpers/Uri/RenameFileViewHelper.php
new file mode 100644 (file)
index 0000000..37341c2
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+namespace TYPO3\CMS\Filelist\ViewHelpers\Uri;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Closure;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
+
+/**
+ * Class RenameFileViewHelper
+ */
+class RenameFileViewHelper extends AbstractViewHelper implements CompilableInterface {
+
+       /**
+        * Renders a link to rename a file
+        *
+        * @param \TYPO3\CMS\Core\Resource\AbstractFile $file
+        * @param string $returnUrl
+        *
+        * @return string
+        */
+       public function render(\TYPO3\CMS\Core\Resource\AbstractFile $file, $returnUrl = '') {
+               return static::renderStatic(
+                       [
+                               'file' => $file,
+                               'returnUrl' => $returnUrl,
+                       ],
+                       $this->buildRenderChildrenClosure(),
+                       $this->renderingContext
+               );
+       }
+
+       /**
+        * Renders a link to rename a file
+        *
+        * @param array $arguments
+        * @param Closure $renderChildrenClosure
+        * @param RenderingContextInterface $renderingContext
+        *
+        * @return string
+        */
+       static public function renderStatic(array $arguments, Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
+               if (empty($arguments['returnUrl'])) {
+                       $arguments['returnUrl'] = GeneralUtility::getIndpEnv('REQUEST_URI');
+               }
+
+               /** @var \TYPO3\CMS\Core\Resource\AbstractFile $file */
+               $file = $arguments['file'];
+
+               $params = [
+                       'target' => $file->getCombinedIdentifier(),
+                       'returnUrl' => $arguments['returnUrl']
+               ];
+
+               return BackendUtility::getModuleUrl('file_rename', $params);
+       }
+
+}
diff --git a/typo3/sysext/filelist/Classes/ViewHelpers/Uri/ReplaceFileViewHelper.php b/typo3/sysext/filelist/Classes/ViewHelpers/Uri/ReplaceFileViewHelper.php
new file mode 100644 (file)
index 0000000..e2d8802
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+namespace TYPO3\CMS\Filelist\ViewHelpers\Uri;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Closure;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
+
+/**
+ * Class ReplaceFileViewHelper
+ */
+class ReplaceFileViewHelper extends AbstractViewHelper implements CompilableInterface {
+
+       /**
+        * Renders a link to replace a file
+        *
+        * @param \TYPO3\CMS\Core\Resource\AbstractFile $file
+        * @param string $returnUrl
+        *
+        * @return string
+        */
+       public function render(\TYPO3\CMS\Core\Resource\AbstractFile $file, $returnUrl = '') {
+               return static::renderStatic(
+                       [
+                               'file' => $file,
+                               'returnUrl' => $returnUrl,
+                       ],
+                       $this->buildRenderChildrenClosure(),
+                       $this->renderingContext
+               );
+       }
+
+       /**
+        * Renders a link to replace a file
+        *
+        * @param array $arguments
+        * @param Closure $renderChildrenClosure
+        * @param RenderingContextInterface $renderingContext
+        *
+        * @return string
+        */
+       static public function renderStatic(array $arguments, Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
+               if (empty($arguments['returnUrl'])) {
+                       $arguments['returnUrl'] = GeneralUtility::getIndpEnv('REQUEST_URI');
+               }
+
+               /** @var \TYPO3\CMS\Core\Resource\AbstractFile $file */
+               $file = $arguments['file'];
+
+               $params = [
+                       'target' => $file->getCombinedIdentifier(),
+                       'uid' => $file->getUid(),
+                       'returnUrl' => $arguments['returnUrl']
+               ];
+
+               return BackendUtility::getModuleUrl('file_replace', $params);
+       }
+
+}
diff --git a/typo3/sysext/filelist/Resources/Private/Language/locallang.xlf b/typo3/sysext/filelist/Resources/Private/Language/locallang.xlf
new file mode 100644 (file)
index 0000000..97a9be4
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
+       <file t3:id="1440157535" source-language="en" datatype="plaintext" original="messages" date="2015-08-21T11:45:35Z" product-name="filelist">
+               <header/>
+               <body>
+                       <trans-unit id="search">
+                               <source>Search</source>
+                       </trans-unit>
+                       <trans-unit id="flashmessage.no_results">
+                               <source>No results found</source>
+                       </trans-unit>
+                       <trans-unit id="flashmessage.no_results">
+                               <source>No results found</source>
+                       </trans-unit>
+               </body>
+       </file>
+</xliff>
diff --git a/typo3/sysext/filelist/Resources/Private/Partials/SearchForm.html b/typo3/sysext/filelist/Resources/Private/Partials/SearchForm.html
new file mode 100644 (file)
index 0000000..b62ed88
--- /dev/null
@@ -0,0 +1,9 @@
+<f:form action="search">
+       <div class="input-group">
+               <input type="hidden" name="cmd" class="form-control" value="search">
+               <f:form.textfield type="text" name="searchWord" class="form-control" value="{searchWord}"/>
+               <span class="input-group-btn">
+                       <button class="btn btn-default" type="submit"><f:translate id="search">Search</f:translate></button>
+               </span>
+       </div>
+</f:form>
index cd4b5a3..d9749e9 100644 (file)
@@ -6,6 +6,8 @@
 
 <f:section name="content">
 
+       <f:render partial="SearchForm" arguments="{searchWord:''}" />
+
        <f:form method="post" name="dblistForm">
                {listHtml -> f:format.raw()}
                <input type="hidden" name="cmd"/>
diff --git a/typo3/sysext/filelist/Resources/Private/Templates/FileList/Search.html b/typo3/sysext/filelist/Resources/Private/Templates/FileList/Search.html
new file mode 100644 (file)
index 0000000..8c25341
--- /dev/null
@@ -0,0 +1,170 @@
+<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
+       xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers"
+       xmlns:fl="http://typo3.org/ns/TYPO3/CMS/Filelist/ViewHelpers">
+<f:layout name="Default"/>
+
+<f:section name="headline">
+       <h1><f:translate id="search">Search</f:translate>: "{searchWord}"</h1>
+</f:section>
+
+<f:section name="content">
+
+       <f:render partial="SearchForm" arguments="{searchWord:searchWord}" />
+
+       <f:if condition="{files->f:count()} > 0">
+               <div class="table-fit">
+                       <table class="table table-striped table-hover" id="typo3-filelist">
+                               <thead>
+                               <tr data-uid="0" data-l10nparent="0">
+                                       <th nowrap="nowrap" class="col-icon"></th>
+                                       <th nowrap="nowrap" class="col-path">{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_mod_file_list.xlf:c_filepath' )}</th>
+                                       <th nowrap="nowrap" class="col-title">{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_mod_file_list.xlf:c_file' )}</th>
+                                       <th nowrap="nowrap" class="col-control"></th>
+                                       <th nowrap="nowrap">{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_mod_file_list.xlf:c_fileext' )}</th>
+                                       <th nowrap="nowrap">{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_mod_file_list.xlf:c_tstamp' )}</th>
+                                       <th nowrap="nowrap">{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_mod_file_list.xlf:c_size' )}</th>
+                                       <th nowrap="nowrap">{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_mod_file_list.xlf:c_rw' )}</th>
+                                       <th nowrap="nowrap">{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_mod_file_list.xlf:c__REF_' )}</th>
+                               </tr>
+                               </thead>
+                               <tbody>
+                               <f:for each="{files}" as="file">
+                                       <tr data-uid="0" data-l10nparent="0">
+                                               <td nowrap="nowrap" class="col-icon">
+                                                       <fl:link.clickMenuOnIcon table="{file.combinedIdentifier}">
+                                                               {file.icon->f:format.raw()}
+                                                       </fl:link.clickMenuOnIcon>
+                                               </td>
+                                               <td nowrap="nowrap" class="col-path">
+                                                       {file.path}
+                                               </td>
+                                               <td nowrap="nowrap" class="col-title">
+                                                       <f:if condition="{file.isMetadataEditable}">
+                                                               <f:then>
+                                                                       <a href="#" class="filelist-file-title"
+                                                                               title="{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_core.xlf:cm.editMetadata' )}"
+                                                                               data-url="{fl:uri.editSysFileMetadataRecord( uid:file.metadataUid, returnUrl:'{f:uri.action( action:\'search\', arguments:{ searchWord:searchWord } )->format.htmlentities()}' )}"
+                                                                       >
+                                                                               {file.name->f:format.crop( maxCharacters:30 )}
+                                                                       </a>
+                                                               </f:then>
+                                                               <f:else>
+                                                                       {file.name->f:format.crop( maxCharacters:30 )}
+                                                               </f:else>
+                                                       </f:if>
+                                                       <f:if condition="{file.isImage}">
+                                                               <br>
+                                                               <f:image image="{file.resource}" maxWidth="64" maxHeight="43" />
+                                                       </f:if>
+                                               </td>
+                                               <td nowrap="nowrap" class="col-control">
+                                                       <div class="btn-group">
+                                                               <f:if condition="{file.isEditable}">
+                                                                       <f:then>
+                                                                               <a href="#" class="btn btn-default filelist-file-edit"
+                                                                                       title="{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_core.xlf:cm.editcontent' )}"
+                                                                                       data-url="{fl:uri.editFileContent( file:file.resource, returnUrl:'{f:uri.action( action:\'search\', arguments:{ searchWord:searchWord } )}' )->format.htmlentities()}"
+                                                                               >
+                                                                                       <core:icon identifier="actions-page-open" />
+                                                                               </a>
+                                                                       </f:then>
+                                                                       <f:else>
+                                                                               <span class="btn btn-default disabled"><core:icon identifier="empty-empty" /></span>
+                                                                       </f:else>
+                                                               </f:if>
+
+                                                               <f:if condition="{file.publicUrl}">
+                                                                       <f:then>
+                                                                               <a href="#" class="btn btn-default filelist-file-view"
+                                                                                       title="{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_core.xlf:cm.view' )}"
+                                                                                       data-url="{file.publicUrl}"
+                                                                               >
+                                                                                       <core:icon identifier="actions-document-view" />
+                                                                               </a>
+                                                                       </f:then>
+                                                                       <f:else>
+                                                                               <span class="btn btn-default disabled"><core:icon identifier="empty-empty" /></span>
+                                                                       </f:else>
+                                                               </f:if>
+
+                                                               <f:if condition="{file.isReplaceable}">
+                                                                       <f:then>
+                                                                               <a href="#" class="btn btn-default filelist-file-replace"
+                                                                                       title="{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_core.xlf:cm.replace' )}"
+                                                                                       data-url="{fl:uri.replaceFile( file:file.resource, returnUrl:'{f:uri.action( action:\'search\', arguments:{ searchWord:searchWord } )}' )->format.htmlentities()}"
+                                                                               >
+                                                                                       <core:icon identifier="actions-edit-replace" />
+                                                                               </a>
+                                                                       </f:then>
+                                                                       <f:else>
+                                                                               <span class="btn btn-default disabled"><core:icon identifier="empty-empty" /></span>
+                                                                       </f:else>
+                                                               </f:if>
+
+                                                               <f:if condition="{file.isRenamable}">
+                                                                       <f:then>
+                                                                               <a href="#" class="btn btn-default filelist-file-rename"
+                                                                                       title="{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_core.xlf:cm.rename' )}"
+                                                                                       data-url="{fl:uri.renameFile( file:file.resource, returnUrl:'{f:uri.action( action:\'search\', arguments:{ searchWord:searchWord } )}' )->format.htmlentities()}"
+                                                                               >
+                                                                                       <core:icon identifier="actions-edit-rename" />
+                                                                               </a>
+                                                                       </f:then>
+                                                                       <f:else>
+                                                                               <span class="btn btn-default disabled"><core:icon identifier="empty-empty" /></span>
+                                                                       </f:else>
+                                                               </f:if>
+
+                                                               <f:if condition="{file.isReadable}">
+                                                                       <f:then>
+                                                                               <a href="#" class="btn btn-default filelist-file-info"
+                                                                                       title="{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_core.xlf:cm.info' )}"
+                                                                                       data-identifier="{file.combinedIdentifier}"
+                                                                               >
+                                                                                       <core:icon identifier="actions-document-info" />
+                                                                               </a>
+                                                                       </f:then>
+                                                                       <f:else>
+                                                                               <span class="btn btn-default disabled"><core:icon identifier="empty-empty" /></span>
+                                                                       </f:else>
+                                                               </f:if>
+                                                               <f:if condition="{file.isDeletable}">
+                                                                       <f:then>
+                                                                               <a href="#" class="btn btn-default filelist-file-delete"
+                                                                                       title="{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_core.xlf:cm.delete' )}"
+                                                                                       data-url="{fl:uri.deleteFile( file:file.resource, returnUrl:'{f:uri.action( action:\'search\', arguments:{ searchWord:searchWord } )}' )->format.htmlentities()}"
+                                                                                       data-confirmation-dialogue="{f:if( condition:settings.jsConfirmationDelete, then:'confirm({f:translate( htmlEscape:\'true\', key:\'LLL:EXT:lang/locallang_core.xlf:mess.delete\', arguments: {0:file.name} )})', else:'1 == 1' )}"
+                                                                               >
+                                                                                       <core:icon identifier="actions-edit-delete" />
+                                                                               </a>
+                                                                       </f:then>
+                                                                       <f:else>
+                                                                               <span class="btn btn-default disabled"><core:icon identifier="empty-empty" /></span>
+                                                                       </f:else>
+                                                               </f:if>
+                                                       </div>
+                                               </td>
+                                               <td nowrap="nowrap">{file.extension}</td>
+                                               <td nowrap="nowrap">{file.lastModified}</td>
+                                               <td nowrap="nowrap">{file.size}</td>
+                                               <td nowrap="nowrap">
+                                                       <f:if condition="{file.isReadable}"><strong class="text-danger">{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_mod_file_list.xlf:read' )}</strong></f:if><f:if condition="{file.isWritable}"><strong class="text-danger">{f:translate( htmlEscape:'true', key:'LLL:EXT:lang/locallang_mod_file_list.xlf:write' )}</strong></f:if>
+                                               </td>
+                                               <td nowrap="nowrap">
+                                                       <f:if condition="{file.referenceCount} > 0">
+                                                               <f:then>
+                                                                       <a href="#" class="filelist-file-references" data-identifier="{file.combinedIdentifier}" title="{f:translate( htmlEscape:'true', key:'LLL:EXT:backend/Resources/Private/Language/locallang.xlf:show_references' )} ({file.referenceCount})">{file.referenceCount}</a>
+                                                               </f:then>
+                                                               <f:else>
+                                                                       -
+                                                               </f:else>
+                                                       </f:if>
+                                               </td>
+                                       </tr>
+                               </f:for>
+                               </tbody>
+                       </table>
+               </div>
+       </f:if>
+</f:section>
+</html>
diff --git a/typo3/sysext/filelist/Resources/Public/JavaScript/FileList.js b/typo3/sysext/filelist/Resources/Public/JavaScript/FileList.js
new file mode 100644 (file)
index 0000000..849ce39
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * JavaScript RequireJS module called "TYPO3/CMS/Filelist/FileList"
+ *
+ */
+define('TYPO3/CMS/Filelist/FileList', ['jquery'], function($) {
+
+       $('a.filelist-file-title').click(function(event) {
+               event.preventDefault();
+
+               var url = $(this).attr('data-url');
+               window.location.href=url;
+       });
+
+       $('a.btn.filelist-file-edit').click(function(event) {
+               event.preventDefault();
+
+               var url = $(this).attr('data-url');
+               top.content.list_frame.location.href=url;
+       });
+
+       $('a.btn.filelist-file-view').click(function(event) {
+               event.preventDefault();
+
+               var url = $(this).attr('data-url');
+               top.openUrlInWindow(url, 'WebFile')
+       });
+
+       $('a.btn.filelist-file-replace').click(function(event) {
+               event.preventDefault();
+
+               var url = $(this).attr('data-url');
+               top.content.list_frame.location.href=url;
+       });
+
+       $('a.btn.filelist-file-rename').click(function(event) {
+               event.preventDefault();
+
+               var url = $(this).attr('data-url');
+               top.content.list_frame.location.href=url;
+       });
+
+       $('a.btn.filelist-file-info').click(function(event) {
+               event.preventDefault();
+
+               var identifier = $(this).attr('data-identifier');
+               openFileInfoPopup(identifier);
+       });
+
+       $('a.btn.filelist-file-delete').click(function(event) {
+               event.preventDefault();
+
+               var url = $(this).attr('data-url');
+               var confirmationDialogue = $(this).attr('data-confirmation-dialogue');
+
+               if (confirmationDialogue) {
+                       top.content.list_frame.location.href=url;
+               }
+       });
+
+       $('a.filelist-file-references').click(function(event) {
+               event.preventDefault();
+
+               var identifier = $(this).attr('data-identifier');
+               openFileInfoPopup(identifier);
+       });
+
+       /**
+        * @param identifier
+        */
+       function openFileInfoPopup(identifier) {
+               top.launchView('_FILE', identifier);
+       }
+
+});
index 15a161f..cdfc9bc 100644 (file)
@@ -8,7 +8,7 @@ if (TYPO3_MODE === 'BE') {
                'list',
                '',
                array(
-                       'FileList' => 'index',
+                       'FileList' => 'index, search',
                ),
                array(
                        'access' => 'user,group',
index 4ffdf53..576815b 100644 (file)
@@ -33,6 +33,9 @@
                        <trans-unit id="c_file">
                                <source>File Name</source>
                        </trans-unit>
+                       <trans-unit id="c_filepath">
+                               <source>File Path</source>
+                       </trans-unit>
                        <trans-unit id="c_size">
                                <source>Size</source>
                        </trans-unit>