From b1413c7d03713dfd7fd7e9f316849732547ee9c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Uzna=C5=84ski?= <l.uznanski@macopedia.pl>
Date: Tue, 28 Nov 2017 10:22:28 +0100
Subject: [PATCH] [TASK] Add missing delete button for Documentation

Add a  missing delete button within the Documentation module. Right now,
a user can't delete previously downloaded documentation.

Resolves: #80575
Releases: master, 8.7
Change-Id: I9077270c66ec225f1eb7a26e505da0d98d5f7f0e
Reviewed-on: https://review.typo3.org/54817
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
---
 .../Classes/Controller/DocumentController.php | 27 ++++++
 .../Configuration/Backend/AjaxRoutes.php      | 11 +++
 .../Resources/Private/Language/locallang.xlf  | 14 ++-
 .../Private/Templates/Document/List.html      | 87 ++++++++++---------
 .../Resources/Public/JavaScript/Main.js       | 64 +++++++++++++-
 5 files changed, 158 insertions(+), 45 deletions(-)
 create mode 100644 typo3/sysext/documentation/Configuration/Backend/AjaxRoutes.php

diff --git a/typo3/sysext/documentation/Classes/Controller/DocumentController.php b/typo3/sysext/documentation/Classes/Controller/DocumentController.php
index c3085390dd2e..147bf05edf0c 100644
--- a/typo3/sysext/documentation/Classes/Controller/DocumentController.php
+++ b/typo3/sysext/documentation/Classes/Controller/DocumentController.php
@@ -14,9 +14,12 @@ namespace TYPO3\CMS\Documentation\Controller;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\View\BackendTemplateView;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
+use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Documentation\Domain\Repository\DocumentRepository;
 use TYPO3\CMS\Documentation\Service\DocumentationService;
@@ -164,9 +167,33 @@ class DocumentController extends ActionController
             $documents = array_intersect_key($documents, array_flip($showDocuments));
         }
 
+        $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
+        $pageRenderer->addInlineLanguageLabelFile('EXT:documentation/Resources/Private/Language/locallang.xlf');
+        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Documentation/Main');
+
         $this->view->assign('documents', $documents);
     }
 
+    /**
+     * Delete documentation with given packageKey
+     *
+     * @param ServerRequestInterface $request
+     * @param ResponseInterface $response
+     * @return ResponseInterface
+     */
+    public function deleteAction(ServerRequestInterface $request, ResponseInterface $response)
+    {
+        $basePath = 'typo3conf/Documentation/';
+        $packageKey = $request->getParsedBody();
+        $isDirDeleted = GeneralUtility::rmdir(PATH_site . $basePath . $packageKey['documentationKey'], true);
+        if (!$isDirDeleted) {
+            $this->addFlashMessage(LocalizationUtility::translate('deleteFailed', 'Documentation'), '', FlashMessage::ERROR);
+        }
+
+        $response->getBody()->write(json_encode($isDirDeleted));
+        return $response;
+    }
+
     /**
      * Returns available documents.
      *
diff --git a/typo3/sysext/documentation/Configuration/Backend/AjaxRoutes.php b/typo3/sysext/documentation/Configuration/Backend/AjaxRoutes.php
new file mode 100644
index 000000000000..47f2ab914685
--- /dev/null
+++ b/typo3/sysext/documentation/Configuration/Backend/AjaxRoutes.php
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * Definitions for routes provided by EXT:documentation
+ */
+return [
+    'documentation_remove' => [
+        'path' => '/documentation/remove',
+        'target' => \TYPO3\CMS\Documentation\Controller\DocumentController::class . '::deleteAction'
+    ],
+];
diff --git a/typo3/sysext/documentation/Resources/Private/Language/locallang.xlf b/typo3/sysext/documentation/Resources/Private/Language/locallang.xlf
index a6b0ba968eeb..7782c14c0ad7 100644
--- a/typo3/sysext/documentation/Resources/Private/Language/locallang.xlf
+++ b/typo3/sysext/documentation/Resources/Private/Language/locallang.xlf
@@ -93,11 +93,21 @@
 			<trans-unit id="downloadFailedDetails">
 				<source>The documentation for "%s" could not be downloaded, because of the following error: %s (%d).</source>
 			</trans-unit>
-
+			<trans-unit id="deleteModalDescription">
+				<source>Are you sure you want to delete this record?</source>
+			</trans-unit>
+			<trans-unit id="cancel">
+				<source>Cancel</source>
+			</trans-unit>
+			<trans-unit id="delete">
+				<source>Delete</source>
+			</trans-unit>
+			<trans-unit id="deleteFailed">
+				<source>Deletion of documentation failed.</source>
+			</trans-unit>
 			<trans-unit id="documentationList.search">
 				<source>Search</source>
 			</trans-unit>
-
 		</body>
 	</file>
 </xliff>
diff --git a/typo3/sysext/documentation/Resources/Private/Templates/Document/List.html b/typo3/sysext/documentation/Resources/Private/Templates/Document/List.html
index 6d09fee4608c..fbdeed5b29e3 100644
--- a/typo3/sysext/documentation/Resources/Private/Templates/Document/List.html
+++ b/typo3/sysext/documentation/Resources/Private/Templates/Document/List.html
@@ -3,47 +3,54 @@
 <f:layout name="Default" />
 
 <f:section name="module-headline">
-	<h1><f:translate key="showDocumentation">Show Documentation</f:translate></h1>
+  <h1><f:translate key="showDocumentation">Show Documentation</f:translate></h1>
 </f:section>
 
 <f:section name="Content">
-	<form class="form-inline">
-		<div class="form-group">
-			<f:form.textfield name="typo3-documentation-searchfield" placeholder="{f:translate(key:'documentationList.search')}" id="typo3-documentation-searchfield" value="{search}" class="form-control t3js-documentation-searchfield" />
-		</div>
-	</form>
-	<table id="typo3-documentation-list" class="table table-striped table-hover typo3-documentation-list t3js-documentation-list">
-		<thead>
-			<tr>
-				<th><f:translate key="tx_documentation_domain_model_document.title" /></th>
-				<th><f:translate key="tx_documentation_domain_model_documenttranslation.description" /></th>
-				<th><f:translate key="tx_documentation_domain_model_documenttranslation.actions" /></th>
-			</tr>
-		</thead>
-		<tbody>
-			<f:for each="{documents}" as="document">
-				<f:for each="{document.translations}" as="translation">
-					<tr id="{document.packageKey}" >
-						<td class="col-nowrap">
-							<span class="typo3-app-icon">
-								<span>
-									<span>
-										<img src="../{document.icon}" title="{translation.title}" alt="{translation.title}" />
-									</span>
-								</span>
-							</span>
-							{translation.title}
-							<f:if condition="{document.extensionKey}">({document.extensionKey})</f:if>
-						</td>
-						<td>{translation.description}</td>
-						<td class="col-nowrap">
-							<div class="btn-group">
-								<doc:formats documentTranslation="{translation}" />
-							</div>
-						</td>
-					</tr>
-				</f:for>
-			</f:for>
-		</tbody>
-	</table>
+  <form class="form-inline">
+    <div class="form-group">
+      <f:form.textfield name="typo3-documentation-searchfield" placeholder="{f:translate(key:'documentationList.search')}" id="typo3-documentation-searchfield" value="{search}" class="form-control t3js-documentation-searchfield" />
+    </div>
+  </form>
+  <table id="typo3-documentation-list" class="table table-striped table-hover typo3-documentation-list t3js-documentation-list">
+    <thead>
+      <tr>
+        <th><f:translate key="tx_documentation_domain_model_document.title" /></th>
+        <th><f:translate key="tx_documentation_domain_model_documenttranslation.description" /></th>
+        <th><f:translate key="tx_documentation_domain_model_documenttranslation.actions" /></th>
+      </tr>
+    </thead>
+    <tbody>
+      <f:for each="{documents}" as="document">
+        <f:for each="{document.translations}" as="translation">
+          <tr id="{document.packageKey}" >
+            <td class="col-nowrap">
+              <span class="typo3-app-icon">
+                <span>
+                  <span>
+                    <img src="../{document.icon}" title="{translation.title}" alt="{translation.title}" />
+                  </span>
+                </span>
+              </span>
+              {translation.title}
+              <f:if condition="{document.extensionKey}">({document.extensionKey})</f:if>
+            </td>
+            <td>{translation.description}</td>
+            <td class="col-nowrap">
+              <div class="btn-group">
+                <doc:formats documentTranslation="{translation}" />
+                <f:for each="{document.translations}" as="documentation">
+                  <f:alias map="{documentation-delete-description: '{f:translate(key: \'deleteModalDescription\', extensionName: \'Documentation\')}'}">
+                  <f:link.action action="delete" class="btn btn-default t3js-documentation-delete" additionalAttributes="{data: {documentation-key: '{document.packageKey}', documentation-name: '{documentation.title}', documentation-delete-description: '{documentation-delete-description}'}}" arguments="{packageKey: '{document.packageKey}'}">
+                    <core:icon identifier="actions-edit-delete"/>
+                  </f:link.action>
+                  </f:alias>
+                </f:for>
+              </div>
+            </td>
+          </tr>
+        </f:for>
+      </f:for>
+    </tbody>
+  </table>
 </f:section>
diff --git a/typo3/sysext/documentation/Resources/Public/JavaScript/Main.js b/typo3/sysext/documentation/Resources/Public/JavaScript/Main.js
index eb72d3224730..43a0292d4ae4 100644
--- a/typo3/sysext/documentation/Resources/Public/JavaScript/Main.js
+++ b/typo3/sysext/documentation/Resources/Public/JavaScript/Main.js
@@ -15,12 +15,12 @@
  * Module: TYPO3/CMS/Documentation/Main
  * JavaScript module for ext:documentation
  */
-define(['jquery', 'datatables', 'TYPO3/CMS/Backend/jquery.clearable'], function($) {
+define(['jquery', 'datatables', 'TYPO3/CMS/Backend/Modal', 'TYPO3/CMS/Backend/Notification', 'TYPO3/CMS/Backend/Severity', 'TYPO3/CMS/Backend/jquery.clearable'], function($, DataTable, Modal, Notification, Severity) {
 	'use strict';
 
 	/**
 	 *
-	 * @type {{dataTable: null, searchField: null, identifier: {documentationList: string, searchField: string}}}
+	 * @type {{dataTable: null, searchField: null, identifier: {documentationList: string, searchField: string, deleteButtons: string}}}
 	 * @exports TYPO3/CMS/Documentation/Main
 	 */
 	var Documentation = {
@@ -28,7 +28,8 @@ define(['jquery', 'datatables', 'TYPO3/CMS/Backend/jquery.clearable'], function(
 		searchField: null,
 		identifier: {
 			documentationList: '.t3js-documentation-list',
-			searchField: '.t3js-documentation-searchfield'
+			searchField: '.t3js-documentation-searchfield',
+			deleteButtons: '.t3js-documentation-delete'
 		}
 	};
 
@@ -76,6 +77,58 @@ define(['jquery', 'datatables', 'TYPO3/CMS/Backend/jquery.clearable'], function(
 		return vars;
 	};
 
+	/**
+	 * Delete documentation
+	 *
+	 * @param {Object} $documentationRecord
+	 */
+	Documentation.deleteDocumentation = function($documentationRecord) {
+
+		Modal.confirm($documentationRecord.data('documentationName'), $documentationRecord.data('documentationDeleteDescription'), Severity.warning, [
+			{
+				text: TYPO3.lang['cancel'],
+				active: true,
+				btnClass: 'btn-default',
+				trigger: function() {
+					Modal.dismiss();
+				}
+			}, {
+				text: TYPO3.lang['delete'],
+				btnClass: 'btn-info',
+				trigger: function() {
+					$.ajax({
+						url: TYPO3.settings.ajaxUrls['documentation_remove'],
+						data: {
+							documentationKey: $documentationRecord.data('documentationKey')
+						},
+						type: 'post',
+						cache: false
+					}).done(function(data) {
+						if(data) {
+							$documentationRecord.closest('tr').fadeOut();
+						} else {
+							Documentation.handleErrors(data);
+						}
+					});
+					Modal.dismiss();
+				}
+			}
+		]);
+
+	};
+
+	/**
+	 * handle the errors from result object
+	 *
+	 * @param {Object} result
+	 * @private
+	 */
+	Documentation.handleErrors = function(result) {
+		$.each(result.messages, function(position, message) {
+			Notification.error(message.title, message.message);
+		});
+	};
+
 	$(function() {
 		// Initialize the view
 		Documentation.initializeView();
@@ -86,6 +139,11 @@ define(['jquery', 'datatables', 'TYPO3/CMS/Backend/jquery.clearable'], function(
 				Documentation.dataTable.search('').draw();
 			}
 		});
+		$(Documentation.identifier.deleteButtons).on('click', function(e) {
+			e.preventDefault();
+			e.stopPropagation();
+			Documentation.deleteDocumentation($(this));
+		})
 	});
 
 	return Documentation;
-- 
GitLab