[!!!][TASK] Migrate file edit form to FormEngine 29/53129/12
authorAndreas Fernandez <a.fernandez@scripting-base.de>
Mon, 5 Jun 2017 19:09:34 +0000 (21:09 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Mon, 3 Jul 2017 13:23:57 +0000 (15:23 +0200)
To simplify the overhaul of EXT:t3editor, the form to change a file's
content is based on FormEngine now.

Additionally, the file rename form has been streamlined to the overall
backend visual appearance.

Resolves: #81763
Releases: master
Change-Id: Ifb9bc5513bff923a6d4cdbcb6046e87f4dcf3626
Reviewed-on: https://review.typo3.org/53129
Tested-by: TYPO3com <no-reply@typo3.com>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
20 files changed:
typo3/sysext/backend/Classes/Controller/File/EditFileController.php
typo3/sysext/backend/Classes/Controller/File/FileController.php
typo3/sysext/backend/Classes/Controller/File/FileUploadController.php
typo3/sysext/backend/Classes/Controller/File/RenameFileController.php
typo3/sysext/backend/Resources/Private/Templates/File/CreateFolder.html
typo3/sysext/backend/Resources/Private/Templates/File/EditFile.html
typo3/sysext/backend/Resources/Private/Templates/File/RenameFile.html
typo3/sysext/backend/Resources/Private/TypeScript/RenameFile.ts
typo3/sysext/backend/Resources/Public/JavaScript/DragUploader.js
typo3/sysext/backend/Resources/Public/JavaScript/RenameFile.js
typo3/sysext/core/Documentation/Changelog/master/Breaking-81763-HookParametersOfTypo3file_editphppreOutputProcessingHookChanged.rst [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Deprecation-81763-DeprecatedLanguageLabelForFileRename.rst [new file with mode: 0644]
typo3/sysext/filelist/Resources/Public/JavaScript/ContextMenuActions.js
typo3/sysext/filelist/Resources/Public/JavaScript/FileDelete.js
typo3/sysext/impexp/Resources/Private/Partials/Import/Upload.html
typo3/sysext/lang/Resources/Private/Language/locallang_core.xlf
typo3/sysext/recordlist/Classes/View/FolderUtilityRenderer.php
typo3/sysext/t3editor/Classes/Hook/FileEditHook.php
typo3/sysext/t3editor/Resources/Public/JavaScript/FileEdit.js [deleted file]
typo3/sysext/t3editor/ext_localconf.php

index 6ca34b4..09d151a 100644 (file)
@@ -16,14 +16,19 @@ namespace TYPO3\CMS\Backend\Controller\File;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Backend\Form\FormResultCompiler;
+use TYPO3\CMS\Backend\Form\NodeFactory;
 use TYPO3\CMS\Backend\Module\AbstractModule;
 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Imaging\Icon;
+use TYPO3\CMS\Core\Messaging\FlashMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessageService;
 use TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\HttpUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
 
 /**
@@ -138,10 +143,21 @@ class EditFileController extends AbstractModule
     }
 
     /**
-     * Main function, redering the actual content of the editing page
+     * Main function, rendering the actual content of the editing page
      */
     public function main()
     {
+        $dataColumnDefinition = [
+            'label' => htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_common.xlf:file'))
+                . ' ' . htmlspecialchars($this->target),
+            'config' => [
+                'type' => 'text',
+                'cols' => 48,
+                'wrap' => 'OFF',
+            ],
+            'defaultExtras' => 'fixed-font: enable-tab'
+        ];
+
         $this->getButtons();
         // Hook: before compiling the output
         if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['preOutputProcessingHook'])) {
@@ -149,7 +165,8 @@ class EditFileController extends AbstractModule
             if (is_array($preOutputProcessingHook)) {
                 $hookParameters = [
                     'content' => &$this->content,
-                    'target' => &$this->target
+                    'target' => &$this->target,
+                    'dataColumnDefinition' => &$dataColumnDefinition,
                 ];
                 foreach ($preOutputProcessingHook as $hookFunction) {
                     GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
@@ -164,22 +181,67 @@ class EditFileController extends AbstractModule
         $extList = $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'];
         try {
             if (!$extList || !GeneralUtility::inList($extList, $this->fileObject->getExtension())) {
-                throw new \Exception('Files with that extension are not editable.', 1476050135);
+                throw new \Exception('Files with that extension are not editable. Allowed extensions are: ' . $extList, 1476050135);
             }
 
-            // Read file content to edit:
-            $fileContent = $this->fileObject->getContents();
-
             // Making the formfields
             $hValue = BackendUtility::getModuleUrl('file_edit', [
                 'target' => $this->origTarget,
                 'returnUrl' => $this->returnUrl
             ]);
-            $assigns['uid'] = $this->fileObject->getUid();
-            $assigns['fileContent'] = $fileContent;
-            $assigns['hValue'] = $hValue;
+
+            $formData = [
+                'databaseRow' => [
+                    'uid' => 0,
+                    'data' => $this->fileObject->getContents(),
+                    'target' => $this->fileObject->getUid(),
+                    'redirect' => $hValue,
+                ],
+                'tableName' => 'editfile',
+                'processedTca' => [
+                    'columns' => [
+                        'data' => $dataColumnDefinition,
+                        'target' => [
+                            'config' => [
+                                'type' => 'input',
+                                'renderType' => 'hidden',
+                            ],
+                        ],
+                        'redirect' => [
+                            'config' => [
+                                'type' => 'input',
+                                'renderType' => 'hidden',
+                            ],
+                        ],
+                    ],
+                    'types' => [
+                        1 => [
+                            'showitem' => 'data,target,redirect',
+                        ],
+                    ],
+                ],
+                'recordTypeValue' => 1,
+                'inlineStructure' => [],
+                'renderType' => 'fullRecordContainer',
+            ];
+
+            $resultArray = GeneralUtility::makeInstance(NodeFactory::class)->create($formData)->render();
+            $formResultCompiler = GeneralUtility::makeInstance(FormResultCompiler::class);
+            $formResultCompiler->mergeResult($resultArray);
+
+            $form = $formResultCompiler->addCssFiles()
+                . $resultArray['html']
+                . $formResultCompiler->printNeededJSFunctions();
+
+            $assigns['form'] = $form;
         } catch (\Exception $e) {
-            $assigns['extList'] = $extList;
+            $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $e->getMessage(), '', FlashMessage::ERROR, true);
+
+            $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
+            $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
+            $defaultFlashMessageQueue->enqueue($flashMessage);
+
+            HttpUtility::redirect($this->returnUrl, HttpUtility::HTTP_STATUS_500);
         }
 
         // Rendering of the output via fluid
@@ -227,8 +289,6 @@ class EditFileController extends AbstractModule
 
     /**
      * Builds the buttons for the docheader and returns them as an array
-     *
-     * @return array
      */
     public function getButtons()
     {
@@ -246,6 +306,7 @@ class EditFileController extends AbstractModule
             ->setName('_save')
             ->setValue('1')
             ->setOnClick('document.editform.submit();')
+            ->setForm('EditFileController')
             ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_edit.php.submit'))
             ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL));
 
@@ -253,6 +314,7 @@ class EditFileController extends AbstractModule
         $saveAndCloseButton = $buttonBar->makeInputButton()
             ->setName('_saveandclose')
             ->setValue('1')
+            ->setForm('EditFileController')
             ->setOnClick(
                 'document.editform.redirect.value='
                 . GeneralUtility::quoteJSvalue($this->returnUrl)
index 49be98c..e61d290 100644 (file)
@@ -92,8 +92,16 @@ class FileController
     protected function init()
     {
         // Set the GPvars from outside
-        $this->file = GeneralUtility::_GP('file');
+        $this->file = GeneralUtility::_GP('data');
+        if ($this->file === null) {
+            // This happens in clipboard mode only
+            $this->redirect = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('redirect'));
+        } else {
+            $mode = key($this->file);
+            $this->redirect = GeneralUtility::sanitizeLocalUrl($this->file[$mode][0]['redirect']);
+        }
         $this->CB = GeneralUtility::_GP('CB');
+
         if (isset($this->file['rename'][0]['conflictMode'])) {
             $conflictMode = $this->file['rename'][0]['conflictMode'];
             unset($this->file['rename'][0]['conflictMode']);
@@ -101,7 +109,6 @@ class FileController
         } else {
             $this->overwriteExistingFiles = DuplicationBehavior::cast(GeneralUtility::_GP('overwriteExistingFiles'));
         }
-        $this->redirect = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('redirect'));
         $this->initClipboard();
         $this->fileProcessor = GeneralUtility::makeInstance(ExtendedFileUtility::class);
     }
index c7ef406..a1788bd 100644 (file)
@@ -180,8 +180,8 @@ class FileUploadController extends AbstractModule
         // Adding 'size="50" ' for the sake of Mozilla!
         $content .= '
                                <input type="file" multiple="multiple" name="upload_1[]" />
-                               <input type="hidden" name="file[upload][1][target]" value="' . htmlspecialchars($this->folderObject->getCombinedIdentifier()) . '" />
-                               <input type="hidden" name="file[upload][1][data]" value="1" /><br />
+                               <input type="hidden" name="data[upload][1][target]" value="' . htmlspecialchars($this->folderObject->getCombinedIdentifier()) . '" />
+                               <input type="hidden" name="data[upload][1][data]" value="1" /><br />
                        ';
         $content .= '
                        </div>
index 3a1d718..2026258 100644 (file)
@@ -17,9 +17,12 @@ namespace TYPO3\CMS\Backend\Controller\File;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Module\AbstractModule;
+use TYPO3\CMS\Backend\Template\Components\ButtonBar;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Resource\DuplicationBehavior;
+use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Core\Resource\Folder;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
 
@@ -46,7 +49,7 @@ class RenameFileController extends AbstractModule
     /**
      * The file or folder object that should be renamed
      *
-     * @var \TYPO3\CMS\Core\Resource\File|\TYPO3\CMS\Core\Resource\Folder $fileOrFolderObject
+     * @var File|Folder $fileOrFolderObject
      */
     protected $fileOrFolderObject;
 
@@ -102,7 +105,7 @@ class RenameFileController extends AbstractModule
         // so the redirect will NOT end in an error message
         // this case only happens if you select the folder itself in the foldertree and then use the clickmenu to
         // rename the folder
-        if ($this->fileOrFolderObject instanceof \TYPO3\CMS\Core\Resource\Folder) {
+        if ($this->fileOrFolderObject instanceof Folder) {
             $parsedUrl = parse_url($this->returnUrl);
             $queryParts = GeneralUtility::explodeUrl2Array(urldecode($parsedUrl['query']));
             if ($queryParts['id'] === $this->fileOrFolderObject->getCombinedIdentifier()) {
@@ -138,16 +141,19 @@ class RenameFileController extends AbstractModule
         $assigns['moduleUrlTceFile'] = BackendUtility::getModuleUrl('tce_file');
         $assigns['returnUrl'] = $this->returnUrl;
 
-        if ($this->fileOrFolderObject instanceof \TYPO3\CMS\Core\Resource\Folder) {
+        if ($this->fileOrFolderObject instanceof Folder) {
             $fileIdentifier = $this->fileOrFolderObject->getCombinedIdentifier();
+            $targetLabel = 'file_rename.php.label.target.folder';
         } else {
             $fileIdentifier = $this->fileOrFolderObject->getUid();
+            $targetLabel = 'file_rename.php.label.target.file';
             $assigns['conflictMode'] = DuplicationBehavior::cast(DuplicationBehavior::RENAME);
             $assigns['destination'] = substr($this->fileOrFolderObject->getCombinedIdentifier(), 0, -strlen($this->fileOrFolderObject->getName()));
         }
 
         $assigns['fileName'] = $this->fileOrFolderObject->getName();
         $assigns['fileIdentifier'] = $fileIdentifier;
+        $assigns['fieldLabel'] = $targetLabel;
 
         // Create buttons
         $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
@@ -163,10 +169,22 @@ class RenameFileController extends AbstractModule
             $backButton = $buttonBar->makeLinkButton()
                 ->setHref($this->returnUrl)
                 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
-                ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
+                ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-close', Icon::SIZE_SMALL));
             $buttonBar->addButton($backButton);
         }
 
+        // Save and Close button
+        $saveAndCloseButton = $buttonBar->makeInputButton()
+            ->setName('_saveandclose')
+            ->setValue('1')
+            ->setShowLabelText(true)
+            ->setClasses('t3js-submit-file-rename')
+            ->setForm('RenameFileController')
+            ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_edit.php.saveAndClose'))
+            ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save-close', Icon::SIZE_SMALL));
+
+        $buttonBar->addButton($saveAndCloseButton, ButtonBar::BUTTON_POSITION_LEFT, 20);
+
         $this->moduleTemplate->getPageRenderer()->addInlineLanguageLabelArray([
             'file_rename.actions.cancel' => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_rename.actions.cancel'),
             'file_rename.actions.rename' => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_rename.actions.rename'),
index a0ee00c..b4045c5 100644 (file)
@@ -24,8 +24,8 @@
                             <div class="form-group">
                                 <label for="folder_new_{folder.this}"><f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_newfolder.php.label_newfolder" /> {folder.next}:</label>
                                 <div class="form-control-wrap">
-                                    <input type="text" class="form-control" id="folder_new_{folder.this}" name="file[newfolder][{folder.this}][data]" onchange="changed=true;" />
-                                    <input type="hidden" name="file[newfolder][{folder.this}][target]" value="{target}" />
+                                    <input type="text" class="form-control" id="folder_new_{folder.this}" name="data[newfolder][{folder.this}][data]" onchange="changed=true;" />
+                                    <input type="hidden" name="data[newfolder][{folder.this}][target]" value="{target}" />
                                 </div>
                             </div>
                         </div>
@@ -33,7 +33,7 @@
                 </div>
                 <div class="form-group">
                     <input class="btn btn-default" type="submit" value="{f:translate(key: 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_newfolder.php.submit')}" />
-                    <input type="hidden" name="redirect" value="{returnUrl}" />
+                    <input type="hidden" name="data[newfolder][0][redirect]" value="{returnUrl}" />
                 </div>
             </form>
         </div>
@@ -47,9 +47,9 @@
                         <div class="form-group">
                             <label for="newMedia"><f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:online_media.new_media.label" /></label> {cshFileNewMedia -> f:format.raw()}
                             <div class="form-control-wrap">
-                                <input class="form-control" type="text" id="newMedia" name="file[newMedia][0][url]"
+                                <input class="form-control" type="text" id="newMedia" name="data[newMedia][0][url]"
                                        placeholder="{f:translate(key: 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:online_media.new_media.placeholder')}" />
-                                <input type="hidden" name="file[newMedia][0][target]" value="{target}" />
+                                <input type="hidden" name="data[newMedia][0][target]" value="{target}" />
                             </div>
                             <div class="help-block">
                                 <f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:online_media.new_media.allowedProviders" /><br>
@@ -62,7 +62,7 @@
                 </div>
                 <div class="form-group">
                     <input class="btn btn-default" type="submit" value="{f:translate(key: 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:online_media.new_media.submit')}" />
-                    <input type="hidden" name="redirect" value="{returnUrl}" />
+                    <input type="hidden" name="data[newMedia][0][redirect]" value="{returnUrl}" />
                 </div>
             </div>
         </form>
@@ -74,8 +74,8 @@
                         <div class="form-group">
                             <label for="newfile"><f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_newfolder.php.label_newfile" /></label> {cshFileNewFile -> f:format.raw()}
                             <div class="form-control-wrap">
-                                <input class="form-control" type="text" id="newfile" name="file[newfile][0][data]" onchange="changed=true;" />
-                                <input type="hidden" name="file[newfile][0][target]" value="{target}" />
+                                <input class="form-control" type="text" id="newfile" name="data[newfile][0][data]" onchange="changed=true;" />
+                                <input type="hidden" name="data[newfile][0][target]" value="{target}" />
                             </div>
                             <div class="help-block">
                                 <f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:cm.allowedFileExtensions" /><br>
@@ -88,7 +88,7 @@
                 </div>
                 <div class="form-group">
                     <button class="btn btn-default" name="edit" type="submit" value="1"><f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_newfolder.php.newfile_submit" /></button>
-                    <input type="hidden" name="redirect" value="{returnUrl}" />
+                    <input type="hidden" name="data[newfile][0][redirect]" value="{returnUrl}" />
                 </div>
             </div>
         </form>
index d763dee..544fd00 100644 (file)
@@ -1,14 +1,4 @@
 <form action="{moduleUrlTceFile}" method="post" id="EditFileController" name="editform">
     <h1><f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_edit.php.pagetitle" /> {fileName}</h1>
-    <div id="c-edit">
-        <textarea rows="30" name="file[editfile][0][data]" wrap="off" class="form-control text-monospace t3js-enable-tab">{fileContent}</textarea>
-        <input type="hidden" name="file[editfile][0][target]" value="{uid}" />
-        <input type="hidden" name="redirect" value="{hValue}" />
-    </div>
-    <br />
-    <f:if condition="{extList}">
-        <f:format.raw>
-            <f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_edit.php.coundNot" arguments="{0: extList}" />
-        </f:format.raw>
-    </f:if>
+    <f:format.raw>{form}</f:format.raw>
 </form>
index 531a156..e0e321c 100644 (file)
@@ -1,24 +1,27 @@
-<h1>
-    <f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_rename.php.pagetitle"/>
-</h1>
-<div>
-    <form action="{moduleUrlTceFile}" method="post" name="editform" role="form">
-        <div class="form-group">
-            <input class="form-control" type="text" name="file[rename][0][target]" value="{fileName}"
-                   data-original="{fileName}" style="width:384px;"/>
-            <input type="hidden" name="file[rename][0][data]" value="{fileIdentifier}"/>
-            <f:if condition="{destination}">
-                <input type="hidden" name="file[rename][0][destination]" value="{destination}"/>
-                <input type="hidden" name="file[rename][0][conflictMode]" value="{conflictMode}"/>
-            </f:if>
+<form action="{moduleUrlTceFile}" method="post" name="editform" role="form" id="RenameFileController">
+    <fieldset class="form-section">
+        <div class="row">
+            <div class="form-group col-md-12">
+                <label class="t3js-formengine-label" for="rename_target">
+                    <f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:{fieldLabel}" />
+                </label>
+                <div class="formengine-field-item">
+                    <div class="form-control-wrap">
+                        <div class="form-wizards-wrap">
+                            <div class="form-wizards-element">
+                                <input id="rename_target" class="form-control" type="text" name="data[rename][0][target]" value="{fileName}" data-original="{fileName}" />
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
         </div>
-        <div class="form-group">
-            <input class="btn btn-primary t3js-submit-file-rename" type="submit"
-                   value="{f:translate(key: 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_rename.php.submit')}"/>
-            <input class="btn btn-danger" type="submit"
-                   value="{f:translate(key: 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.cancel')}"
-                   onclick="backToList(); return false;"/>
-            <input type="hidden" name="redirect" value="{returnUrl}"/>
-        </div>
-    </form>
-</div>
+    </fieldset>
+
+    <f:if condition="{destination}">
+        <input type="hidden" name="data[rename][0][destination]" value="{destination}"/>
+        <input type="hidden" name="data[rename][0][conflictMode]" value="{conflictMode}"/>
+    </f:if>
+    <input type="hidden" name="data[rename][0][data]" value="{fileIdentifier}"/>
+    <input type="hidden" name="data[rename][0][redirect]" value="{returnUrl}"/>
+</form>
\ No newline at end of file
index ac9bb01..d05ac01 100644 (file)
@@ -33,16 +33,16 @@ class RenameFile {
   private checkForDuplicate(e: any): void {
     e.preventDefault();
 
-    const form: any = $(e.currentTarget).closest('form');
-    const fileNameField: any = form.find('input[name="file[rename][0][target]"]');
-    const conflictModeField: any = form.find('input[name="file[rename][0][conflictMode]"]');
+    const form: any = $('#' + $(e.currentTarget).attr('form'));
+    const fileNameField: any = form.find('input[name="data[rename][0][target]"]');
+    const conflictModeField: any = form.find('input[name="data[rename][0][conflictMode]"]');
     const ajaxUrl: string = TYPO3.settings.ajaxUrls.file_exists;
 
     $.ajax({
       cache: false,
       data: {
         fileName: fileNameField.val(),
-        fileTarget: form.find('input[name="file[rename][0][destination]"]').val(),
+        fileTarget: form.find('input[name="data[rename][0][destination]"]').val(),
       },
       success: (response: any): void => {
         const fileExists: boolean = response !== false;
index 9e575dd..e2dc9dd 100644 (file)
@@ -562,8 +562,8 @@ define(['jquery',
                        me.updateMessage('- ' + DragUploader.fileSizeAsString(me.file.size));
 
                        var formData = new FormData();
-                       formData.append('file[upload][1][target]', me.dragUploader.target);
-                       formData.append('file[upload][1][data]', '1');
+                       formData.append('data[upload][1][target]', me.dragUploader.target);
+                       formData.append('data[upload][1][data]', '1');
                        formData.append('overwriteExistingFiles', me.override);
                        formData.append('redirect', '');
                        formData.append('upload_1', me.file);
index 59b38b9..5350e22 100644 (file)
@@ -26,15 +26,15 @@ define(["require", "exports", "jquery", "TYPO3/CMS/Backend/Modal", "TYPO3/CMS/Ba
         };
         RenameFile.prototype.checkForDuplicate = function (e) {
             e.preventDefault();
-            var form = $(e.currentTarget).closest('form');
-            var fileNameField = form.find('input[name="file[rename][0][target]"]');
-            var conflictModeField = form.find('input[name="file[rename][0][conflictMode]"]');
+            var form = $('#' + $(e.currentTarget).attr('form'));
+            var fileNameField = form.find('input[name="data[rename][0][target]"]');
+            var conflictModeField = form.find('input[name="data[rename][0][conflictMode]"]');
             var ajaxUrl = TYPO3.settings.ajaxUrls.file_exists;
             $.ajax({
                 cache: false,
                 data: {
                     fileName: fileNameField.val(),
-                    fileTarget: form.find('input[name="file[rename][0][destination]"]').val(),
+                    fileTarget: form.find('input[name="data[rename][0][destination]"]').val(),
                 },
                 success: function (response) {
                     var fileExists = response !== false;
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-81763-HookParametersOfTypo3file_editphppreOutputProcessingHookChanged.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-81763-HookParametersOfTypo3file_editphppreOutputProcessingHookChanged.rst
new file mode 100644 (file)
index 0000000..8223fdd
--- /dev/null
@@ -0,0 +1,35 @@
+.. include:: ../../Includes.txt
+
+================================================================================================
+Breaking: #81763 - Hook parameters of ['typo3/file_edit.php']['preOutputProcessingHook'] changed
+================================================================================================
+
+See :issue:`81763`
+
+Description
+===========
+
+The hook parameters passed into :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['preOutputProcessingHook']`
+have been changed due to rewriting the edit file form to use FormEngine.
+
+
+Impact
+======
+
+Any information added to modify the output may have no effect anymore.
+
+
+Affected Installations
+======================
+
+Every installation using an extension that hooks into :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['preOutputProcessingHook']`
+to modify the form's output is affected.
+
+
+Migration
+=========
+
+As the form is based on FormEngine now, you may want to adjust the newly introduced hook parameter :php:`$dataColumnDefinition`,
+representing the definition of the `data` field which contains the file content. An example can be found in EXT:t3editor.
+
+.. index:: Backend
\ No newline at end of file
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-81763-DeprecatedLanguageLabelForFileRename.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-81763-DeprecatedLanguageLabelForFileRename.rst
new file mode 100644 (file)
index 0000000..491a514
--- /dev/null
@@ -0,0 +1,26 @@
+.. include:: ../../Includes.txt
+
+===============================================================
+Deprecation: #81763 - Deprecated language label for file rename
+===============================================================
+
+See :issue:`81763`
+
+Description
+===========
+
+The language label `file_rename.php.submit` in `EXT:lang/Resources/Private/Language/locallang_core.xlf` has been marked as deprecated.
+
+
+Affected Installations
+======================
+
+Any TYPO3 extension using the deprecated label is affected.
+
+
+Migration
+=========
+
+Add the label to the `locallang.xlf` of your extension and adjust the usage of the label.
+
+.. index:: Backend
\ No newline at end of file
index 799bb66..def7f5f 100644 (file)
@@ -71,7 +71,7 @@ define(['jquery', 'TYPO3/CMS/Backend/Modal', 'TYPO3/CMS/Backend/Severity'], func
         var $anchorElement = $(this);
         var performDelete = function () {
             top.TYPO3.Backend.ContentContainer.setUrl(
-                top.TYPO3.settings.FileCommit.moduleUrl + '&file[delete][0][data]=' + top.rawurlencode(uid) + '&redirect=' + ContextMenuActions.getReturnUrl()
+                top.TYPO3.settings.FileCommit.moduleUrl + '&data[delete][0][data]=' + top.rawurlencode(uid) + '&data[delete][0][redirect]=' + ContextMenuActions.getReturnUrl()
             );
         };
         if (!$anchorElement.data('title')) {
index 41facd9..0dd2ec4 100644 (file)
@@ -28,7 +28,7 @@ define(['jquery', 'TYPO3/CMS/Backend/Modal', 'TYPO3/CMS/Backend/Severity'], func
                }
                var identifier = $anchorElement.data('identifier');
                var deleteType = $anchorElement.data('deleteType');
-               var deleteUrl = $anchorElement.data('deleteUrl') + '&file[delete][0][data]=' + encodeURIComponent(identifier);
+               var deleteUrl = $anchorElement.data('deleteUrl') + '&data[delete][0][data]=' + encodeURIComponent(identifier);
                if ($anchorElement.data('check')) {
                        var $modal = Modal.confirm($anchorElement.data('title'), $anchorElement.data('content'), Severity.warning, [
                                {
@@ -48,11 +48,11 @@ define(['jquery', 'TYPO3/CMS/Backend/Modal', 'TYPO3/CMS/Backend/Severity'], func
                                        Modal.dismiss();
                                } else if (e.target.name === 'yes') {
                                        Modal.dismiss();
-                                       top.list_frame.location.href = deleteUrl + '&redirect=' + redirectUrl;
+                                       top.list_frame.location.href = deleteUrl + '&data[delete][0][redirect]=' + redirectUrl;
                                }
                        });
                } else {
-                       top.list_frame.location.href = deleteUrl + '&redirect=' + redirectUrl;
+                       top.list_frame.location.href = deleteUrl + '&data[delete][0][redirect]=' + redirectUrl;
                }
        });
 
index b69b578..06b41dd 100644 (file)
@@ -6,8 +6,8 @@
 </h4>
 <div class="form-group">
        <f:form.upload name="upload_1" />
-       <f:form.hidden name="file[upload][1][target]" value="{tempFolder}" />
-       <f:form.hidden name="file[upload][1][data]" value="1" />
+       <f:form.hidden name="data[upload][1][target]" value="{tempFolder}" />
+       <f:form.hidden name="data[upload][1][data]" value="1" />
 </div>
 <div class="form-group">
        <f:form.submit class="btn btn-default" name="_upload" value="{f:translate(key: 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:file_upload.php.submit')}" />
index 333ecb8..19e5727 100644 (file)
@@ -633,6 +633,13 @@ Do you want to continue WITHOUT saving?</source>
                        </trans-unit>
                        <trans-unit id="file_rename.php.submit">
                                <source>Rename</source>
+                               <note from="developer">This label is not used since TYPO3 v9.</note>
+                       </trans-unit>
+                       <trans-unit id="file_rename.php.label.target.file">
+                               <source>New file name</source>
+                       </trans-unit>
+                       <trans-unit id="file_rename.php.label.target.folder">
+                               <source>New folder name</source>
                        </trans-unit>
                        <trans-unit id="file_replace.php.pagetitle">
                                <source>Replace</source>
index 79fe7a6..232765e 100644 (file)
@@ -144,9 +144,9 @@ class FolderUtilityRenderer
             $markup[] = '<input type="file" multiple="multiple" name="upload_' . $a . '[]" size="50" />';
             $markup[] = '</span>';
             $markup[] = '</div>';
-            $markup[] = '<input type="hidden" name="file[upload][' . $a . '][target]" value="'
+            $markup[] = '<input type="hidden" name="data[upload][' . $a . '][target]" value="'
                 . htmlspecialchars($combinedIdentifier) . '" />';
-            $markup[] = '<input type="hidden" name="file[upload][' . $a . '][data]" value="' . $a . '" />';
+            $markup[] = '<input type="hidden" name="data[upload][' . $a . '][data]" value="' . $a . '" />';
         }
         $redirectValue = $this->parameterProvider->getScriptUrl() . GeneralUtility::implodeArrayForUrl(
             '',
index 939ea39..5640373 100644 (file)
@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 namespace TYPO3\CMS\T3editor\Hook;
 
 /*
@@ -14,8 +15,9 @@ namespace TYPO3\CMS\T3editor\Hook;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Core\Page\PageRenderer;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Backend\Controller\File\EditFileController;
+use TYPO3\CMS\Core\Resource\ResourceFactory;
+use TYPO3\CMS\T3editor\Form\Element\T3editorElement;
 
 /**
  * File edit hook for t3editor
@@ -23,106 +25,55 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 class FileEditHook
 {
     /**
-     * @var \TYPO3\CMS\T3editor\T3editor
-     */
-    protected $t3editor = null;
-
-    /**
-     * @var string
-     */
-    protected $ajaxSaveType = 'TypoScriptTemplateInformationModuleFunctionController';
-
-    /**
-     * @return \TYPO3\CMS\T3editor\T3editor
+     * Editor mode to file extension mapping. This is just temporarily in place and will be removed after refactoring
+     * EXT:t3editor.
+     *
+     * @var array
      */
-    protected function getT3editor()
-    {
-        if ($this->t3editor === null) {
-            $this->t3editor = GeneralUtility::makeInstance(\TYPO3\CMS\T3editor\T3editor::class)->setAjaxSaveType($this->ajaxSaveType);
-        }
-        return $this->t3editor;
-    }
+    protected $fileExtensions = [
+        T3editorElement::MODE_CSS => ['css'],
+        T3editorElement::MODE_HTML => ['htm', 'html'],
+        T3editorElement::MODE_JAVASCRIPT => ['js'],
+        T3editorElement::MODE_PHP => ['php', 'php5', 'php7', 'phps'],
+        T3editorElement::MODE_SPARQL => ['rq'],
+        T3editorElement::MODE_TYPOSCRIPT => ['ts', 'typoscript', 'txt'],
+        T3editorElement::MODE_XML => ['xml'],
+    ];
 
     /**
      * Hook-function: inject t3editor JavaScript code before the page is compiled
      * called in file_edit module
      *
      * @param array $parameters
-     * @param \TYPO3\CMS\Backend\Controller\File\EditFileController $pObj
+     * @param EditFileController $pObj
      */
-    public function preOutputProcessingHook($parameters, $pObj)
+    public function preOutputProcessingHook(array $parameters, EditFileController $pObj)
     {
-        $t3editor = $this->getT3editor();
-        $t3editor->setModeByFile($parameters['target']);
-        if (!$t3editor->getMode()) {
-            return;
+        $target = '';
+        if (isset($parameters['target']) && is_string($parameters['target'])) {
+            $target = $parameters['target'];
         }
-        $t3editor->getJavascriptCode();
-        $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/T3editor/FileEdit');
+        $parameters['dataColumnDefinition']['config']['renderType'] = 't3editor';
+        $parameters['dataColumnDefinition']['config']['format'] = $this->determineFormatByExtension($target);
     }
 
     /**
-     * Hook-function: inject t3editor JavaScript code before the page is compiled
-     * called in \TYPO3\CMS\Backend\Template\DocumentTemplate:startPage
-     *
-     * @see \TYPO3\CMS\Backend\Template\DocumentTemplate::startPage
+     * @param string $fileIdentifier
+     * @return string
      */
-    public function preStartPageHook()
+    protected function determineFormatByExtension(string $fileIdentifier): string
     {
-        // @todo: this is a workaround. Ideally the document template holds the current request so we can match the route
-        // against the name of the route and not the GET parameter
-        if (GeneralUtility::_GET('route') === '/file/editcontent') {
-            $t3editor = $this->getT3editor();
-            $t3editor->getJavascriptCode();
-            $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/T3editor/FileEdit');
+        $fileExtension = ResourceFactory::getInstance()->retrieveFileOrFolderObject($fileIdentifier)->getExtension();
+        if (empty($fileExtension)) {
+            return T3editorElement::MODE_MIXED;
         }
-    }
 
-    /**
-     * Hook-function:
-     * called in file_edit module
-     *
-     * @param array $parameters
-     * @param \TYPO3\CMS\Backend\Controller\File\EditFileController $pObj
-     */
-    public function postOutputProcessingHook($parameters, $pObj)
-    {
-        $t3editor = $this->getT3editor();
-        if (!$t3editor->getMode()) {
-            return;
+        foreach ($this->fileExtensions as $format => $extensions) {
+            if (in_array($fileExtension, $extensions, true)) {
+                return $format;
+            }
         }
-        $attributes = 'rows="30" wrap="off" style="width:98%;height:60%"';
-        $title = $GLOBALS['LANG']->getLL('file') . ' ' . htmlspecialchars($pObj->target);
-        $outCode = $t3editor->getCodeEditor('file[editfile][0][data]', 'text-monospace enable-tab', '$1', $attributes, $title, [
-            'target' => (int)$pObj->target
-        ]);
-        $parameters['pageContent'] = preg_replace('/\\<textarea .*name="file\\[editfile\\]\\[0\\]\\[data\\]".*\\>([^\\<]*)\\<\\/textarea\\>/mi', $outCode, $parameters['pageContent']);
-    }
 
-    /**
-     * @param array $parameters
-     * @param mixed $pObj
-     *
-     * @return bool TRUE if successful
-     */
-    public function save($parameters, $pObj)
-    {
-        $savingsuccess = false;
-        if ($parameters['type'] === $this->ajaxSaveType) {
-            /** @var \TYPO3\CMS\Backend\Controller\File\FileController $tceFile */
-            $tceFile = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Controller\File\FileController::class);
-            $response = $tceFile->processAjaxRequest($parameters['request'], $parameters['response']);
-            $result = json_decode((string)$response->getBody(), true);
-            $savingsuccess = is_array($result) && $result['editfile'][0];
-        }
-        return $savingsuccess;
-    }
-
-    /**
-     * @return PageRenderer
-     */
-    protected function getPageRenderer()
-    {
-        return GeneralUtility::makeInstance(PageRenderer::class);
+        return T3editorElement::MODE_MIXED;
     }
 }
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/FileEdit.js b/typo3/sysext/t3editor/Resources/Public/JavaScript/FileEdit.js
deleted file mode 100644 (file)
index 7ef510a..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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!
- */
-
-/**
- * Module: TYPO3/CMS/T3editor/FileEdit
- * File edit for ext:t3editor
- * @exports TYPO3/CMS/T3editor/FileEdit
- */
-define(['jquery', 'TYPO3/CMS/T3editor/T3editor'], function ($, T3editor) {
-       'use strict';
-
-       $(function() {
-
-               // Remove document.editform.submit from save and close onclick
-               // Form will be submitted by the new on click handler
-               var $saveAndCloseButton = $('[data-name="_saveandclose"], [name="_saveandclose"]'),
-                       $saveButton = $('[data-name="_save"], [name="_save"]');
-
-               var onClick = $saveAndCloseButton.attr('onclick');
-               $saveAndCloseButton.attr('onclick', onClick.replace('document.editform.submit();', ''));
-
-               // Remove onclick for save icon, saving is done by an AJAX-call
-               $saveButton.removeAttr('onclick');
-
-               $saveButton.on('click', function(e) {
-                       e.preventDefault();
-
-                       if (!T3editor || !T3editor.instances[0]) {
-                               document.editform.submit();
-                               return false;
-                       }
-
-                       T3editor.saveFunction(T3editor.instances[0]);
-                       return false;
-               });
-
-               $saveAndCloseButton.on('click', function(e) {
-                       e.preventDefault();
-
-                       if (!T3editor || !T3editor.instances[0]) {
-                               document.editform.submit();
-                               return false;
-                       }
-                       T3editor.updateTextarea(T3editor.instances[0]);
-                       document.editform.submit();
-                       return false;
-               });
-
-       });
-});
index 52b5279..be60459 100644 (file)
@@ -2,11 +2,7 @@
 defined('TYPO3_MODE') or die();
 
 if (TYPO3_MODE === 'BE') {
-    // Register hooks for tstemplate module
-    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3editor/classes/class.tx_t3editor.php']['ajaxSaveCode']['file_edit'] = \TYPO3\CMS\T3editor\Hook\FileEditHook::class . '->save';
-    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'][] = \TYPO3\CMS\T3editor\Hook\FileEditHook::class . '->preStartPageHook';
     $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['preOutputProcessingHook'][] = \TYPO3\CMS\T3editor\Hook\FileEditHook::class . '->preOutputProcessingHook';
-    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/file_edit.php']['postOutputProcessingHook'][] = \TYPO3\CMS\T3editor\Hook\FileEditHook::class . '->postOutputProcessingHook';
 }
 
 $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1433089350] = [