From c952139da76a12d74f011303f9fc8146fd5f8119 Mon Sep 17 00:00:00 2001
From: Oliver Bartsch <bo@cedev.de>
Date: Wed, 15 Sep 2021 17:50:52 +0200
Subject: [PATCH] [BUGFIX] Streamline clipboard handling

Elements, transferred to the clipboard are no longer
selected after reloading the module. Since introducing
multi record selection, the checkboxes are no longer
bound to clipboard functionality, which makes selecting
elements, just because they were added to a clipboard,
pointless. This did anyway never work for elements in
the "normal" clipboard. Furthermore did selecting
elements always display the corresponding multi
record selection actions. Since those actions overlayed
the module specific actions, e.g. the link to single table
view in the recordlist module, it was no longer possible
to execute the module specific actions, as soon
as one record had been transferred to clipboard.

The old clipboard behaviour allowed to remove items
from clipboard by unchecking them and submitting
this deselection. With the multi record selection
component, this is no longer possible. At least not
all elements can be remove, since the actions are
only shown if at least one element is selected.
To fix this, a new action "Remove from clipboard" is
added to the actions bar, allowing to remove a
dedicated selection of elements from clipboard.
This is anyways more understandable for an editor.

Finally the "paste" action is removed from the
multi record selection actions as it has nothing to
do with the current selection.

Resolves: #95225
Related: #95146
Releases: master
Change-Id: Ibbdadba1c89ac81f9f440fee5d34600663ad6974
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/71091
Tested-by: core-ci <typo3@b13.com>
Tested-by: Jochen <rothjochen@gmail.com>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Jochen <rothjochen@gmail.com>
Reviewed-by: Benni Mack <benni@typo3.org>
---
 .../Resources/Public/TypeScript/FileList.ts   | 11 +++--
 .../Resources/Public/TypeScript/Recordlist.ts | 43 +++---------------
 .../Private/Language/locallang_core.xlf       |  3 ++
 .../FileList/FileClipboardCest.php            |  2 +-
 .../Classes/Controller/FileListController.php | 11 ++---
 typo3/sysext/filelist/Classes/FileList.php    | 14 +-----
 .../Language/locallang_mod_file_list.xlf      |  2 +-
 .../Private/Templates/File/List.html          | 17 ++++---
 .../Resources/Public/JavaScript/FileList.js   |  2 +-
 .../Controller/RecordListController.php       | 10 ++---
 .../Classes/RecordList/DatabaseRecordList.php | 45 ++++++++-----------
 .../Resources/Public/JavaScript/Recordlist.js |  2 +-
 12 files changed, 61 insertions(+), 101 deletions(-)

diff --git a/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileList.ts b/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileList.ts
index 5717a3fb449d..3e4d1056a28c 100644
--- a/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileList.ts
+++ b/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileList.ts
@@ -69,10 +69,10 @@ class Filelist {
       return;
     }
     commandField.value = cmd;
-    // In case we just copy elements to the clipboard, we try to fetch a possible pointer from the query
+    // In case we just change elements on the clipboard, we try to fetch a possible pointer from the query
     // parameters, so after the form submit, we get to the same view as before. This is not done for delete
     // commands, since this may lead to empty sites, in case all elements from the current site are deleted.
-    if (cmd === 'setCB') {
+    if (cmd === 'copyMarked' || cmd === 'removeMarked') {
       const pointerField: HTMLInputElement = fileListForm.querySelector(Selectors.pointerFieldSelector);
       const pointerValue: string = Filelist.parseQueryParameters(document.location).pointer;
       if (pointerField && pointerValue) {
@@ -167,8 +167,11 @@ class Filelist {
     new RegularEvent('multiRecordSelection:action:delete', this.deleteMultiple).bindTo(document);
     new RegularEvent('multiRecordSelection:action:download', this.downloadFilesAndFolders).bindTo(document);
     new RegularEvent('click', this.downloadFolder).delegateTo(document, 'button[data-folder-download]');
-    new RegularEvent('multiRecordSelection:action:setCB', (event: CustomEvent): void => {
-      Filelist.submitClipboardFormWithCommand('setCB', event.target as HTMLButtonElement)
+    new RegularEvent('multiRecordSelection:action:copyMarked', (event: CustomEvent): void => {
+      Filelist.submitClipboardFormWithCommand('copyMarked', event.target as HTMLButtonElement)
+    }).bindTo(document);
+    new RegularEvent('multiRecordSelection:action:removeMarked', (event: CustomEvent): void => {
+      Filelist.submitClipboardFormWithCommand('removeMarked', event.target as HTMLButtonElement)
     }).bindTo(document);
 
     // Respond to browser related clearable event
diff --git a/Build/Sources/TypeScript/recordlist/Resources/Public/TypeScript/Recordlist.ts b/Build/Sources/TypeScript/recordlist/Resources/Public/TypeScript/Recordlist.ts
index ae632bc36300..cf8d48ecaef2 100644
--- a/Build/Sources/TypeScript/recordlist/Resources/Public/TypeScript/Recordlist.ts
+++ b/Build/Sources/TypeScript/recordlist/Resources/Public/TypeScript/Recordlist.ts
@@ -46,12 +46,6 @@ interface EditRecordsConfiguration extends ActionConfiguration {
   tableName: string;
   returnUrl: string;
 }
-interface PasteRecordsConfiguration extends ActionConfiguration {
-  url: string;
-  ok: string;
-  title: string;
-  content: string;
-}
 interface DeleteRecordsConfiguration extends ActionConfiguration {
   ok: string;
   title: string;
@@ -111,10 +105,12 @@ class Recordlist {
 
     // multi record selection events
     new RegularEvent('multiRecordSelection:action:edit', this.onEditMultiple).bindTo(document);
-    new RegularEvent('multiRecordSelection:action:paste', this.pasteInto).bindTo(document);
     new RegularEvent('multiRecordSelection:action:delete', this.deleteMultiple).bindTo(document);
-    new RegularEvent('multiRecordSelection:action:setCB', (event: CustomEvent): void => {
-      Recordlist.submitClipboardFormWithCommand('setCB', event.target as HTMLButtonElement)
+    new RegularEvent('multiRecordSelection:action:copyMarked', (event: CustomEvent): void => {
+      Recordlist.submitClipboardFormWithCommand('copyMarked', event.target as HTMLButtonElement)
+    }).bindTo(document);
+    new RegularEvent('multiRecordSelection:action:removeMarked', (event: CustomEvent): void => {
+      Recordlist.submitClipboardFormWithCommand('removeMarked', event.target as HTMLButtonElement)
     }).bindTo(document);
   }
 
@@ -282,35 +278,6 @@ class Recordlist {
     }
   }
 
-  private pasteInto (event: CustomEvent): void {
-    event.preventDefault();
-    const eventDetails: ActionEventDetails = event.detail as ActionEventDetails;
-    const configuration: PasteRecordsConfiguration = eventDetails.configuration;
-    Modal.advanced({
-      title: configuration.title || 'Paste',
-      content: configuration.content || 'Are you sure you want to paste the current clipboard content?',
-      severity: SeverityEnum.warning,
-      buttons: [
-        {
-          text: TYPO3.lang['button.close'] || 'Close',
-          active: true,
-          btnClass: 'btn-default',
-          trigger: (): JQuery => Modal.currentModal.trigger('modal-dismiss')
-        },
-        {
-          text: configuration.ok || TYPO3.lang['button.ok'] || 'OK',
-          btnClass: 'btn-' + Severity.getCssClass(SeverityEnum.warning),
-          trigger: (): void => {
-            Modal.currentModal.trigger('modal-dismiss');
-            if (configuration.url && configuration.url !== '#') {
-              (event.target as HTMLElement).ownerDocument.location.href = configuration.url;
-            }
-          }
-        }
-      ]
-    });
-  }
-
   private deleteMultiple (event: CustomEvent): void {
     event.preventDefault();
     const eventDetails: ActionEventDetails = event.detail as ActionEventDetails;
diff --git a/typo3/sysext/core/Resources/Private/Language/locallang_core.xlf b/typo3/sysext/core/Resources/Private/Language/locallang_core.xlf
index 84d86825c9b4..0e0f67a76635 100644
--- a/typo3/sysext/core/Resources/Private/Language/locallang_core.xlf
+++ b/typo3/sysext/core/Resources/Private/Language/locallang_core.xlf
@@ -1164,6 +1164,9 @@ Do you want to refresh it now?</source>
 			<trans-unit id="cm.transferToClipboard" resname="cm.transferToClipboard">
 				<source>Transfer to clipboard</source>
 			</trans-unit>
+			<trans-unit id="cm.removeFromClipboard" resname="cm.removeFromClipboard">
+				<source>Remove from clipboard</source>
+			</trans-unit>
 			<trans-unit id="sortable.dragmove" resname="sortable.dragmove">
 				<source>Drag to move</source>
 			</trans-unit>
diff --git a/typo3/sysext/core/Tests/Acceptance/Application/FileList/FileClipboardCest.php b/typo3/sysext/core/Tests/Acceptance/Application/FileList/FileClipboardCest.php
index 48868d093c85..25a829e38da7 100644
--- a/typo3/sysext/core/Tests/Acceptance/Application/FileList/FileClipboardCest.php
+++ b/typo3/sysext/core/Tests/Acceptance/Application/FileList/FileClipboardCest.php
@@ -79,7 +79,7 @@ class FileClipboardCest extends AbstractFileCest
         $I->click('Clipboard #1 (multi-selection mode)');
         $I->click('.dropdown-toggle');
         $I->click('button[data-multi-record-selection-check-action="check-all"]');
-        $I->click('button[data-multi-record-selection-action="setCB"]');
+        $I->click('button[data-multi-record-selection-action="copyMarked"]');
 
         foreach ($expectedFiles as $file) {
             $I->see($file, '#clipboard_form');
diff --git a/typo3/sysext/filelist/Classes/Controller/FileListController.php b/typo3/sysext/filelist/Classes/Controller/FileListController.php
index 2e6628a3c13f..c58963669e88 100644
--- a/typo3/sysext/filelist/Classes/Controller/FileListController.php
+++ b/typo3/sysext/filelist/Classes/Controller/FileListController.php
@@ -323,11 +323,12 @@ class FileListController implements LoggerAwareInterface
 
         // Create clipboard object and initialize it
         $CB = array_replace_recursive($request->getQueryParams()['CB'] ?? [], $request->getParsedBody()['CB'] ?? []);
-        if ($this->cmd === 'setCB') {
-            $CB['el'] = $this->filelist->clipObj->cleanUpCBC(array_merge(
-                (array)($request->getParsedBody()['CBH'] ?? []),
-                (array)($request->getParsedBody()['CBC'] ?? [])
-            ), '_FILE');
+        if (($this->cmd === 'copyMarked' || $this->cmd === 'removeMarked')) {
+            // Get CBC from request, and map the element values, since they must either be the file identifier,
+            // in case the element should be transferred to the clipboard, or false if it should be removed.
+            $CBC = array_map(fn ($item) => $this->cmd === 'copyMarked' ? $item : false, (array)($request->getParsedBody()['CBC'] ?? []));
+            // Cleanup CBC
+            $CB['el'] = $this->filelist->clipObj->cleanUpCBC($CBC, '_FILE');
         }
         if (!($this->MOD_SETTINGS['clipBoard'] ?? false)) {
             $CB['setP'] = 'normal';
diff --git a/typo3/sysext/filelist/Classes/FileList.php b/typo3/sysext/filelist/Classes/FileList.php
index 76997bd18ac1..5991bc8a8d82 100644
--- a/typo3/sysext/filelist/Classes/FileList.php
+++ b/typo3/sysext/filelist/Classes/FileList.php
@@ -511,11 +511,6 @@ class FileList
                 'data-folder-identifier' => $folderObject->getIdentifier(),
                 'data-combined-identifier' => $folderObject->getCombinedIdentifier(),
             ];
-            if ($this->clipObj->current !== 'normal'
-                && $this->clipObj->isSelected('_FILE', md5($folderObject->getCombinedIdentifier()))
-            ) {
-                $attributes['class'] = 'success';
-            }
             if ($isLocked) {
                 foreach ($this->fieldArray as $field) {
                     $theData[$field] = '';
@@ -659,11 +654,6 @@ class FileList
             ) {
                 $attributes['data-metadata-uid'] = (string)$metaDataUid;
             }
-            if ($this->clipObj->current !== 'normal'
-                && $this->clipObj->isSelected('_FILE', md5($fileObject->getCombinedIdentifier()))
-            ) {
-                $attributes['class'] = 'success';
-            }
             foreach ($this->fieldArray as $field) {
                 switch ($field) {
                     case 'size':
@@ -913,13 +903,11 @@ class FileList
         $fullIdentifier = $fileOrFolderObject->getCombinedIdentifier();
         $md5 = md5($fullIdentifier);
         $identifier = '_FILE|' . $md5;
-        $isSelected = $this->clipObj->isSelected('_FILE', $md5) && $this->clipObj->current !== 'normal';
         $this->CBnames[] = $identifier;
 
         return '
             <span class="form-check form-toggle">
-                <input class="form-check-input t3js-multi-record-selection-check" type="checkbox" name="CBC[' . $identifier . ']" value="' . htmlspecialchars($fullIdentifier) . '" ' . ($isSelected ? ' checked="checked"' : '') . ' />
-                <input type="hidden" name="CBH[' . $identifier . ']" value="0" />
+                <input class="form-check-input t3js-multi-record-selection-check" type="checkbox" name="CBC[' . $identifier . ']" value="' . htmlspecialchars($fullIdentifier) . '"/>
             </span>';
     }
 
diff --git a/typo3/sysext/filelist/Resources/Private/Language/locallang_mod_file_list.xlf b/typo3/sysext/filelist/Resources/Private/Language/locallang_mod_file_list.xlf
index 75973249fb62..2765ab2b8ec9 100644
--- a/typo3/sysext/filelist/Resources/Private/Language/locallang_mod_file_list.xlf
+++ b/typo3/sysext/filelist/Resources/Private/Language/locallang_mod_file_list.xlf
@@ -19,7 +19,7 @@
 				<source>Transfer to clipboard</source>
 			</trans-unit>
 			<trans-unit id="clip_deleteMarked" resname="clip_deleteMarked">
-				<source>Delete marked</source>
+				<source>Remove from clipboard</source>
 			</trans-unit>
 			<trans-unit id="clip_deleteMarkedWarning" resname="clip_deleteMarkedWarning">
 				<source>Are you sure you want to delete all marked files from this folder?</source>
diff --git a/typo3/sysext/filelist/Resources/Private/Templates/File/List.html b/typo3/sysext/filelist/Resources/Private/Templates/File/List.html
index 9e2776005c72..ca1715da0528 100644
--- a/typo3/sysext/filelist/Resources/Private/Templates/File/List.html
+++ b/typo3/sysext/filelist/Resources/Private/Templates/File/List.html
@@ -68,11 +68,18 @@
                         </f:if>
                         <f:if condition="{enableClipBoard.enabled}">
                             <div class="col">
-                                <button type="button" class="btn btn-default btn-sm {f:if(condition: '{enableClipBoard.mode} == normal', then: 'disabled')}" data-multi-record-selection-action="setCB">
-                                    <span title="{f:translate(key: 'LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clip_selectMarked')}">
-                                        <core:icon identifier="actions-edit-copy" size="small" /> <f:translate key="LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clip_selectMarked" />
-                                    </span>
-                                </button>
+                                <div class="btn-group">
+                                    <button type="button" class="btn btn-default btn-sm {f:if(condition: '{enableClipBoard.mode} == normal', then: 'disabled')}" data-multi-record-selection-action="copyMarked">
+                                        <span title="{f:translate(key: 'LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clip_selectMarked')}">
+                                            <core:icon identifier="actions-edit-copy" size="small" /> <f:translate key="LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clip_selectMarked" />
+                                        </span>
+                                    </button>
+                                    <button type="button" class="btn btn-default btn-sm {f:if(condition: '{enableClipBoard.mode} == normal', then: 'disabled')}" data-multi-record-selection-action="removeMarked">
+                                        <span title="{f:translate(key: 'LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clip_deleteMarked')}">
+                                            <core:icon identifier="actions-remove" size="small" /> <f:translate key="LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:clip_deleteMarked" />
+                                        </span>
+                                    </button>
+                                </div>
                             </div>
                         </f:if>
                         <div class="col">
diff --git a/typo3/sysext/filelist/Resources/Public/JavaScript/FileList.js b/typo3/sysext/filelist/Resources/Public/JavaScript/FileList.js
index eb8c9bdffee5..c8c88827563d 100644
--- a/typo3/sysext/filelist/Resources/Public/JavaScript/FileList.js
+++ b/typo3/sysext/filelist/Resources/Public/JavaScript/FileList.js
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-define(["require","exports","TYPO3/CMS/Core/lit-helper","TYPO3/CMS/Core/DocumentService","TYPO3/CMS/Backend/Notification","TYPO3/CMS/Backend/InfoWindow","TYPO3/CMS/Backend/BroadcastMessage","TYPO3/CMS/Backend/BroadcastService","TYPO3/CMS/Backend/Tooltip","nprogress","TYPO3/CMS/Backend/Icons","TYPO3/CMS/Core/Ajax/AjaxRequest","TYPO3/CMS/Core/Event/RegularEvent","TYPO3/CMS/Backend/Storage/ModuleStateStorage","TYPO3/CMS/Backend/Modal","TYPO3/CMS/Backend/Enum/Severity","TYPO3/CMS/Backend/Severity"],(function(e,t,o,n,i,l,r,a,d,s,c,u,f,m,p,g,h){"use strict";var w;!function(e){e.fileListFormSelector='form[name="fileListForm"]',e.commandSelector='input[name="cmd"]',e.searchFieldSelector='input[name="searchTerm"]',e.pointerFieldSelector='input[name="pointer"]'}(w||(w={}));class S{constructor(){var e;this.downloadFilesAndFolders=e=>{const t=e.target,n=e.detail,l=n.configuration,r=[];n.checkboxes.forEach(e=>{const t=e.closest("tr");(null==t?void 0:t.dataset[l.folderIdentifier])?r.push(t.dataset[l.folderIdentifier]):(null==t?void 0:t.dataset[l.fileIdentifier])&&r.push(t.dataset[l.fileIdentifier])}),r.length?this.triggerDownload(r,l.downloadUrl,t):i.warning(o.lll("file_download.invalidSelection"))},this.downloadFolder=e=>{const t=e.target,o=t.dataset.folderIdentifier;this.triggerDownload([o],t.dataset.folderDownload,t)},S.processTriggers(),n.ready().then(()=>{d.initialize(".table-fit a[title]"),new f("click",(e,t)=>{e.preventDefault(),S.openInfoPopup(t.dataset.filelistShowItemType,t.dataset.filelistShowItemIdentifier)}).delegateTo(document,"[data-filelist-show-item-identifier][data-filelist-show-item-type]"),new f("click",(e,t)=>{e.preventDefault(),S.openInfoPopup("_FILE",t.dataset.identifier)}).delegateTo(document,"a.filelist-file-info"),new f("click",(e,t)=>{e.preventDefault(),S.openInfoPopup("_FILE",t.dataset.identifier)}).delegateTo(document,"a.filelist-file-references"),new f("click",(e,t)=>{e.preventDefault();const o=t.getAttribute("href");let n=o?encodeURIComponent(o):encodeURIComponent(top.list_frame.document.location.pathname+top.list_frame.document.location.search);top.list_frame.location.href=o+"&redirect="+n}).delegateTo(document,"a.filelist-file-copy")}),new f("multiRecordSelection:action:edit",this.editFileMetadata).bindTo(document),new f("multiRecordSelection:action:delete",this.deleteMultiple).bindTo(document),new f("multiRecordSelection:action:download",this.downloadFilesAndFolders).bindTo(document),new f("click",this.downloadFolder).delegateTo(document,"button[data-folder-download]"),new f("multiRecordSelection:action:setCB",e=>{S.submitClipboardFormWithCommand("setCB",e.target)}).bindTo(document);const t=""!==(null===(e=document.querySelector([w.fileListFormSelector,w.searchFieldSelector].join(" ")))||void 0===e?void 0:e.value);new f("search",e=>{var o;const n=e.target;""===n.value&&t&&(null===(o=n.closest(w.fileListFormSelector))||void 0===o||o.submit())}).delegateTo(document,w.searchFieldSelector)}static submitClipboardFormWithCommand(e,t){const o=t.closest(w.fileListFormSelector);if(!o)return;const n=o.querySelector(w.commandSelector);if(n){if(n.value=e,"setCB"===e){const e=o.querySelector(w.pointerFieldSelector),t=S.parseQueryParameters(document.location).pointer;e&&t&&(e.value=t)}o.submit()}}static openInfoPopup(e,t){l.showItem(e,t)}static processTriggers(){const e=document.querySelector(".filelist-main");if(null===e)return;const t=encodeURIComponent(e.dataset.filelistCurrentIdentifier);m.ModuleStateStorage.update("file",t,!0,void 0),S.emitTreeUpdateRequest(e.dataset.filelistCurrentIdentifier)}static emitTreeUpdateRequest(e){const t=new r.BroadcastMessage("filelist","treeUpdateRequested",{type:"folder",identifier:e});a.post(t)}static parseQueryParameters(e){let t={};if(e&&Object.prototype.hasOwnProperty.call(e,"search")){let o=e.search.substr(1).split("&");for(let e=0;e<o.length;e++){const n=o[e].split("=");t[decodeURIComponent(n[0])]=decodeURIComponent(n[1])}}return t}static getReturnUrl(e){return""===e&&(e=top.list_frame.document.location.pathname+top.list_frame.document.location.search),encodeURIComponent(e)}deleteMultiple(e){e.preventDefault();const t=e.detail.configuration;p.advanced({title:t.title||"Delete",content:t.content||"Are you sure you want to delete those files and folders?",severity:g.SeverityEnum.warning,buttons:[{text:TYPO3.lang["button.close"]||"Close",active:!0,btnClass:"btn-default",trigger:()=>p.currentModal.trigger("modal-dismiss")},{text:t.ok||TYPO3.lang["button.ok"]||"OK",btnClass:"btn-"+h.getCssClass(g.SeverityEnum.warning),trigger:()=>{S.submitClipboardFormWithCommand("delete",e.target),p.currentModal.trigger("modal-dismiss")}}]})}editFileMetadata(e){e.preventDefault();const t=e.detail,o=t.configuration;if(!o||!o.idField||!o.table)return;const n=[];t.checkboxes.forEach(e=>{const t=e.closest("tr");null!==t&&t.dataset[o.idField]&&n.push(t.dataset[o.idField])}),n.length?window.location.href=top.TYPO3.settings.FormEngine.moduleUrl+"&edit["+o.table+"]["+n.join(",")+"]=edit&returnUrl="+S.getReturnUrl(o.returnUrl||""):i.warning("The selected elements can not be edited.")}triggerDownload(e,t,n){i.info(o.lll("file_download.prepare"),"",2);const l=n.innerHTML;n.setAttribute("disabled","disabled"),c.getIcon("spinner-circle-dark",c.sizes.small).then(e=>{n.innerHTML=e}),s.configure({parent:"#typo3-filelist",showSpinner:!1}).start(),new u(t).post({items:e}).then(async e=>{let t=e.response.headers.get("Content-Disposition");if(!t){const t=await e.resolve();return void(!1===t.success&&t.status?i.warning(o.lll("file_download."+t.status),o.lll("file_download."+t.status+".message"),10):i.error(o.lll("file_download.error")))}t=t.substring(t.indexOf(" filename=")+10);const n=await e.raw().arrayBuffer(),l=new Blob([n],{type:e.raw().headers.get("Content-Type")}),r=URL.createObjectURL(l),a=document.createElement("a");a.href=r,a.download=t,document.body.appendChild(a),a.click(),URL.revokeObjectURL(r),document.body.removeChild(a),i.success(o.lll("file_download.success"),"",2)}).catch(()=>{i.error(o.lll("file_download.error"))}).finally(()=>{s.done(),n.removeAttribute("disabled"),n.innerHTML=l})}}return new S}));
\ No newline at end of file
+define(["require","exports","TYPO3/CMS/Core/lit-helper","TYPO3/CMS/Core/DocumentService","TYPO3/CMS/Backend/Notification","TYPO3/CMS/Backend/InfoWindow","TYPO3/CMS/Backend/BroadcastMessage","TYPO3/CMS/Backend/BroadcastService","TYPO3/CMS/Backend/Tooltip","nprogress","TYPO3/CMS/Backend/Icons","TYPO3/CMS/Core/Ajax/AjaxRequest","TYPO3/CMS/Core/Event/RegularEvent","TYPO3/CMS/Backend/Storage/ModuleStateStorage","TYPO3/CMS/Backend/Modal","TYPO3/CMS/Backend/Enum/Severity","TYPO3/CMS/Backend/Severity"],(function(e,t,o,n,i,r,l,a,d,s,c,u,m,f,p,g,h){"use strict";var w;!function(e){e.fileListFormSelector='form[name="fileListForm"]',e.commandSelector='input[name="cmd"]',e.searchFieldSelector='input[name="searchTerm"]',e.pointerFieldSelector='input[name="pointer"]'}(w||(w={}));class S{constructor(){var e;this.downloadFilesAndFolders=e=>{const t=e.target,n=e.detail,r=n.configuration,l=[];n.checkboxes.forEach(e=>{const t=e.closest("tr");(null==t?void 0:t.dataset[r.folderIdentifier])?l.push(t.dataset[r.folderIdentifier]):(null==t?void 0:t.dataset[r.fileIdentifier])&&l.push(t.dataset[r.fileIdentifier])}),l.length?this.triggerDownload(l,r.downloadUrl,t):i.warning(o.lll("file_download.invalidSelection"))},this.downloadFolder=e=>{const t=e.target,o=t.dataset.folderIdentifier;this.triggerDownload([o],t.dataset.folderDownload,t)},S.processTriggers(),n.ready().then(()=>{d.initialize(".table-fit a[title]"),new m("click",(e,t)=>{e.preventDefault(),S.openInfoPopup(t.dataset.filelistShowItemType,t.dataset.filelistShowItemIdentifier)}).delegateTo(document,"[data-filelist-show-item-identifier][data-filelist-show-item-type]"),new m("click",(e,t)=>{e.preventDefault(),S.openInfoPopup("_FILE",t.dataset.identifier)}).delegateTo(document,"a.filelist-file-info"),new m("click",(e,t)=>{e.preventDefault(),S.openInfoPopup("_FILE",t.dataset.identifier)}).delegateTo(document,"a.filelist-file-references"),new m("click",(e,t)=>{e.preventDefault();const o=t.getAttribute("href");let n=o?encodeURIComponent(o):encodeURIComponent(top.list_frame.document.location.pathname+top.list_frame.document.location.search);top.list_frame.location.href=o+"&redirect="+n}).delegateTo(document,"a.filelist-file-copy")}),new m("multiRecordSelection:action:edit",this.editFileMetadata).bindTo(document),new m("multiRecordSelection:action:delete",this.deleteMultiple).bindTo(document),new m("multiRecordSelection:action:download",this.downloadFilesAndFolders).bindTo(document),new m("click",this.downloadFolder).delegateTo(document,"button[data-folder-download]"),new m("multiRecordSelection:action:copyMarked",e=>{S.submitClipboardFormWithCommand("copyMarked",e.target)}).bindTo(document),new m("multiRecordSelection:action:removeMarked",e=>{S.submitClipboardFormWithCommand("removeMarked",e.target)}).bindTo(document);const t=""!==(null===(e=document.querySelector([w.fileListFormSelector,w.searchFieldSelector].join(" ")))||void 0===e?void 0:e.value);new m("search",e=>{var o;const n=e.target;""===n.value&&t&&(null===(o=n.closest(w.fileListFormSelector))||void 0===o||o.submit())}).delegateTo(document,w.searchFieldSelector)}static submitClipboardFormWithCommand(e,t){const o=t.closest(w.fileListFormSelector);if(!o)return;const n=o.querySelector(w.commandSelector);if(n){if(n.value=e,"copyMarked"===e||"removeMarked"===e){const e=o.querySelector(w.pointerFieldSelector),t=S.parseQueryParameters(document.location).pointer;e&&t&&(e.value=t)}o.submit()}}static openInfoPopup(e,t){r.showItem(e,t)}static processTriggers(){const e=document.querySelector(".filelist-main");if(null===e)return;const t=encodeURIComponent(e.dataset.filelistCurrentIdentifier);f.ModuleStateStorage.update("file",t,!0,void 0),S.emitTreeUpdateRequest(e.dataset.filelistCurrentIdentifier)}static emitTreeUpdateRequest(e){const t=new l.BroadcastMessage("filelist","treeUpdateRequested",{type:"folder",identifier:e});a.post(t)}static parseQueryParameters(e){let t={};if(e&&Object.prototype.hasOwnProperty.call(e,"search")){let o=e.search.substr(1).split("&");for(let e=0;e<o.length;e++){const n=o[e].split("=");t[decodeURIComponent(n[0])]=decodeURIComponent(n[1])}}return t}static getReturnUrl(e){return""===e&&(e=top.list_frame.document.location.pathname+top.list_frame.document.location.search),encodeURIComponent(e)}deleteMultiple(e){e.preventDefault();const t=e.detail.configuration;p.advanced({title:t.title||"Delete",content:t.content||"Are you sure you want to delete those files and folders?",severity:g.SeverityEnum.warning,buttons:[{text:TYPO3.lang["button.close"]||"Close",active:!0,btnClass:"btn-default",trigger:()=>p.currentModal.trigger("modal-dismiss")},{text:t.ok||TYPO3.lang["button.ok"]||"OK",btnClass:"btn-"+h.getCssClass(g.SeverityEnum.warning),trigger:()=>{S.submitClipboardFormWithCommand("delete",e.target),p.currentModal.trigger("modal-dismiss")}}]})}editFileMetadata(e){e.preventDefault();const t=e.detail,o=t.configuration;if(!o||!o.idField||!o.table)return;const n=[];t.checkboxes.forEach(e=>{const t=e.closest("tr");null!==t&&t.dataset[o.idField]&&n.push(t.dataset[o.idField])}),n.length?window.location.href=top.TYPO3.settings.FormEngine.moduleUrl+"&edit["+o.table+"]["+n.join(",")+"]=edit&returnUrl="+S.getReturnUrl(o.returnUrl||""):i.warning("The selected elements can not be edited.")}triggerDownload(e,t,n){i.info(o.lll("file_download.prepare"),"",2);const r=n.innerHTML;n.setAttribute("disabled","disabled"),c.getIcon("spinner-circle-dark",c.sizes.small).then(e=>{n.innerHTML=e}),s.configure({parent:"#typo3-filelist",showSpinner:!1}).start(),new u(t).post({items:e}).then(async e=>{let t=e.response.headers.get("Content-Disposition");if(!t){const t=await e.resolve();return void(!1===t.success&&t.status?i.warning(o.lll("file_download."+t.status),o.lll("file_download."+t.status+".message"),10):i.error(o.lll("file_download.error")))}t=t.substring(t.indexOf(" filename=")+10);const n=await e.raw().arrayBuffer(),r=new Blob([n],{type:e.raw().headers.get("Content-Type")}),l=URL.createObjectURL(r),a=document.createElement("a");a.href=l,a.download=t,document.body.appendChild(a),a.click(),URL.revokeObjectURL(l),document.body.removeChild(a),i.success(o.lll("file_download.success"),"",2)}).catch(()=>{i.error(o.lll("file_download.error"))}).finally(()=>{s.done(),n.removeAttribute("disabled"),n.innerHTML=r})}}return new S}));
\ No newline at end of file
diff --git a/typo3/sysext/recordlist/Classes/Controller/RecordListController.php b/typo3/sysext/recordlist/Classes/Controller/RecordListController.php
index 52ac836edc46..83ffb4ad3a9a 100644
--- a/typo3/sysext/recordlist/Classes/Controller/RecordListController.php
+++ b/typo3/sysext/recordlist/Classes/Controller/RecordListController.php
@@ -360,12 +360,12 @@ class RecordListController
         // Clipboard actions are handled:
         // CB is the clipboard command array
         $CB = array_replace_recursive($request->getQueryParams()['CB'] ?? [], $request->getParsedBody()['CB'] ?? []);
-        if ($cmd === 'setCB') {
-            // CBH is all the fields selected for the clipboard, CBC is the checkbox fields which were checked.
-            // By merging we get a full array of checked/unchecked elements
-            // This is set to the 'el' array of the CB after being parsed so only the table in question is registered.
+        if ($cmd === 'copyMarked' || $cmd === 'removeMarked') {
+            // Get CBC from request, and map the element values (true => copy, false => remove)
+            $CBC = array_map(static fn () => ($cmd === 'copyMarked'), (array)($request->getParsedBody()['CBC'] ?? []));
             $cmd_table = (string)($request->getParsedBody()['cmd_table'] ?? $request->getQueryParams()['cmd_table'] ?? '');
-            $CB['el'] = $clipboard->cleanUpCBC(array_merge($request->getParsedBody()['CBH'] ?? [], (array)($request->getParsedBody()['CBC'] ?? [])), $cmd_table);
+            // Cleanup CBC
+            $CB['el'] = $clipboard->cleanUpCBC($CBC, $cmd_table);
         }
         if (!$isClipboardShown) {
             // If the clipboard is NOT shown, set the pad to 'normal'.
diff --git a/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php b/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php
index 1a2a43a803fe..74235e686837 100644
--- a/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php
+++ b/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php
@@ -1967,8 +1967,7 @@ class DatabaseRecordList
         // Setting name of the element in ->CBnames array:
         $identifier = $table . '|' . $row['uid'];
         $this->CBnames[] = $identifier;
-        // Check if the current element is selected
-        $isSelected = $this->clipObj->isSelected($table, $row['uid']);
+        $isSelected = false;
         // If the "duplicateField" value is set then select all elements which are duplicates...
         if ($this->duplicateField && isset($row[$this->duplicateField])) {
             $isSelected = in_array((string)$row[$this->duplicateField], $this->duplicateStack, true);
@@ -1978,7 +1977,6 @@ class DatabaseRecordList
         return '
             <span class="form-check form-toggle">
                 <input class="form-check-input t3js-multi-record-selection-check" type="checkbox" name="CBC[' . $identifier . ']" value="1" ' . ($isSelected ? 'checked="checked" ' : '') . '/>
-                <input type="hidden" name="CBH[' . $identifier . ']" value="0" />
             </span>';
     }
 
@@ -3285,30 +3283,11 @@ class DatabaseRecordList
             ], true);
             $actions['edit'] = '
                 <button type="button" class="btn btn-default btn-sm" data-multi-record-selection-action="edit" data-multi-record-selection-action-config="' . $editActionConfiguration . '">
-                    <span title="' . htmlspecialchars($lang->getLL('clip_editMarked')) . '">
-                        ' . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . ' ' . htmlspecialchars($lang->getLL('clip_editMarked')) . '
+                    <span title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.edit')) . '">
+                        ' . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . ' ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.edit')) . '
                     </span>
                 </button>';
 
-            if ($addClipboardActions) {
-                $elements = $this->clipObj->elFromTable($table);
-                $pasteActionConfiguration = '';
-                if ($elements !== []) {
-                    $pasteActionConfiguration = GeneralUtility::jsonEncodeForHtmlAttribute([
-                        'idField' => 'uid',
-                        'url' => $this->clipObj->pasteUrl($table, $this->id),
-                        'ok' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.pasteinto'),
-                        'title' => $lang->getLL('clip_paste'),
-                        'content' => $this->clipObj->confirmMsgText('pages', $this->pageRow, 'into', $elements)
-                    ], true);
-                }
-                $actions['paste'] = '
-                    <button type="button" class="btn btn-default btn-sm ' . ($elements === [] ? 'disabled': '') . '" data-multi-record-selection-action="paste" data-multi-record-selection-action-config="' . $pasteActionConfiguration . '" aria-haspopup="dialog">
-                        ' . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render() . '
-                        ' . htmlspecialchars($lang->getLL('clip_paste')) . '
-                    </button>';
-            }
-
             if (!(bool)trim(($userTsConfig['options.']['disableDelete.'][$table] ?? $userTsConfig['options.']['disableDelete'] ?? false))) {
                 $deleteActionConfiguration = GeneralUtility::jsonEncodeForHtmlAttribute([
                     'idField' => 'uid',
@@ -3325,20 +3304,26 @@ class DatabaseRecordList
             }
         }
 
-        // Add copy to clipboard in case clipboard actions are enabled and clipboard is not deactivated
+        // Add clipboard actions in case they  are enabled and clipboard is not deactivated
         if ($addClipboardActions && (string)($this->modTSconfig['enableClipBoard'] ?? '') !== 'deactivated') {
             $copyMarked = '
-                <button type="button" class="btn btn-default btn-sm ' . ($this->clipObj->current === 'normal' ? 'disabled' : '') . '" data-multi-record-selection-action="setCB">
+                <button type="button" class="btn btn-default btn-sm ' . ($this->clipObj->current === 'normal' ? 'disabled' : '') . '" data-multi-record-selection-action="copyMarked">
                     <span title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.transferToClipboard')) . '">
                         ' . $this->iconFactory->getIcon('actions-edit-copy', Icon::SIZE_SMALL)->render() . ' ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.transferToClipboard')) . '
                     </span>
                 </button>';
+            $removeMarked = '
+                <button type="button" class="btn btn-default btn-sm ' . ($this->clipObj->current === 'normal' ? 'disabled' : '') . '" data-multi-record-selection-action="removeMarked">
+                    <span title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.removeFromClipboard')) . '">
+                        ' . $this->iconFactory->getIcon('actions-remove', Icon::SIZE_SMALL)->render() . ' ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.removeFromClipboard')) . '
+                    </span>
+                </button>';
             // Add "copy marked" after "edit", or in case "edit" is not set, as first item
             if (!isset($actions['edit'])) {
                 $actions = array_merge(['copyMarked' => $copyMarked], $actions);
             } else {
                 $end = array_splice($actions, (int)(array_search('edit', array_keys($actions), true)) + 1);
-                $actions = array_merge($actions, ['copyMarked' => $copyMarked], $end);
+                $actions = array_merge($actions, ['copyMarked' => $copyMarked, 'removeMarked' => $removeMarked], $end);
             }
         }
 
@@ -3381,6 +3366,12 @@ class DatabaseRecordList
                 </div>';
         }
 
+        // In case both clipboard actions should be rendered, wrap them into a button group
+        if (($actions['copyMarked'] ?? false) && ($actions['removeMarked'] ?? false)) {
+            $actions['copyMarked'] = '<div class="btn-group">' . $actions['copyMarked'] . $actions['removeMarked'] . '</div>';
+            unset($actions['removeMarked']);
+        }
+
         return implode(LF, array_map(static fn (string $action): string => '<div class="col">' . $action . '</div>', $actions));
     }
 
diff --git a/typo3/sysext/recordlist/Resources/Public/JavaScript/Recordlist.js b/typo3/sysext/recordlist/Resources/Public/JavaScript/Recordlist.js
index 0bc56b1f1ff7..45b53f2ca8ab 100644
--- a/typo3/sysext/recordlist/Resources/Public/JavaScript/Recordlist.js
+++ b/typo3/sysext/recordlist/Resources/Public/JavaScript/Recordlist.js
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};define(["require","exports","jquery","TYPO3/CMS/Backend/Icons","TYPO3/CMS/Backend/Storage/Persistent","TYPO3/CMS/Core/Event/RegularEvent","TYPO3/CMS/Backend/Tooltip","TYPO3/CMS/Core/DocumentService","TYPO3/CMS/Backend/Modal","TYPO3/CMS/Backend/Enum/Severity","TYPO3/CMS/Backend/Severity"],(function(t,e,i,a,n,l,o,s,r,d,c){"use strict";i=__importDefault(i);class u{constructor(){this.identifier={entity:".t3js-entity",toggle:".t3js-toggle-recordlist",localize:".t3js-action-localize",searchboxToolbar:"#db_list-searchbox-toolbar",searchboxToggle:".t3js-toggle-search-toolbox",searchField:"#search_field",icons:{collapse:"actions-view-list-collapse",expand:"actions-view-list-expand",editMultiple:".t3js-record-edit-multiple"}},this.toggleClick=t=>{t.preventDefault();const e=i.default(t.currentTarget),l=e.data("table"),o=i.default(e.data("bs-target")),s="expanded"===o.data("state"),r=e.find(".collapseIcon"),d=s?this.identifier.icons.expand:this.identifier.icons.collapse;a.getIcon(d,a.sizes.small).done(t=>{r.html(t)});let c={};n.isset("moduleData.list")&&(c=n.get("moduleData.list"));const u={};u[l]=s?1:0,i.default.extend(c,u),n.set("moduleData.list",c).done(()=>{o.data("state",s?"collapsed":"expanded")})},this.onEditMultiple=t=>{t.preventDefault();let e="",i="",a="",n=[];if("multiRecordSelection:action:edit"===t.type){const a=t.detail,l=a.configuration;if(i=l.returnUrl||"",e=l.tableName||"",""===e)return;a.checkboxes.forEach(t=>{const e=t.closest("tr");null!==e&&e.dataset[l.idField]&&n.push(e.dataset[l.idField])})}else{const l=t.currentTarget,o=l.closest("[data-table]");if(null===o)return;if(e=o.dataset.table||"",""===e)return;i=l.dataset.returnUrl||"",a=l.dataset.columnsOnly||"";const s=o.querySelectorAll(this.identifier.entity+'[data-uid][data-table="'+e+'"] td.col-selector input[type="checkbox"]:checked');if(s.length)s.forEach(t=>{n.push(t.closest(this.identifier.entity+'[data-uid][data-table="'+e+'"]').dataset.uid)});else{const t=o.querySelectorAll(this.identifier.entity+'[data-uid][data-table="'+e+'"]');if(!t.length)return;t.forEach(t=>{n.push(t.dataset.uid)})}}if(!n.length)return;let l=top.TYPO3.settings.FormEngine.moduleUrl+"&edit["+e+"]["+n.join(",")+"]=edit&returnUrl="+u.getReturnUrl(i);""!==a&&(l+="&columnsOnly="+a),window.location.href=l},this.disableButton=t=>{i.default(t.currentTarget).prop("disable",!0).addClass("disabled")},this.toggleSearchbox=()=>{const t=i.default(this.identifier.searchboxToolbar);t.toggle(),t.is(":visible")&&i.default(this.identifier.searchField).focus()},this.deleteRow=t=>{const e=i.default(`table[data-table="${t.table}"]`),a=e.find(`tr[data-uid="${t.uid}"]`),n=e.closest(".panel"),l=n.find(".panel-heading"),o=e.find(`[data-l10nparent="${t.uid}"]`),s=i.default().add(a).add(o);if(s.fadeTo("slow",.4,()=>{s.slideUp("slow",()=>{s.remove(),0===e.find("tbody tr").length&&n.slideUp("slow")})}),"0"===a.data("l10nparent")||""===a.data("l10nparent")){const t=Number(l.find(".t3js-table-total-items").html());l.find(".t3js-table-total-items").text(t-1)}"pages"===t.table&&top.document.dispatchEvent(new CustomEvent("typo3:pagetree:refresh"))},this.registerPaginationEvents=()=>{document.querySelectorAll(".t3js-recordlist-paging").forEach(t=>{t.addEventListener("keyup",e=>{e.preventDefault();let i=parseInt(t.value,10);i<parseInt(t.min,10)&&(i=parseInt(t.min,10)),i>parseInt(t.max,10)&&(i=parseInt(t.max,10)),"Enter"===e.key&&i!==parseInt(t.dataset.currentpage,10)&&(window.location.href=t.dataset.currenturl+i.toString())})})},i.default(document).on("click",this.identifier.toggle,this.toggleClick),i.default(document).on("click",this.identifier.icons.editMultiple,this.onEditMultiple),i.default(document).on("click",this.identifier.localize,this.disableButton),i.default(document).on("click",this.identifier.searchboxToggle,this.toggleSearchbox),s.ready().then(()=>{o.initialize(".table-fit a[title]"),this.registerPaginationEvents()}),new l("typo3:datahandler:process",this.handleDataHandlerResult.bind(this)).bindTo(document),new l("multiRecordSelection:action:edit",this.onEditMultiple).bindTo(document),new l("multiRecordSelection:action:paste",this.pasteInto).bindTo(document),new l("multiRecordSelection:action:delete",this.deleteMultiple).bindTo(document),new l("multiRecordSelection:action:setCB",t=>{u.submitClipboardFormWithCommand("setCB",t.target)}).bindTo(document)}static submitClipboardFormWithCommand(t,e){const i=e.closest("form");if(!i)return;const a=i.querySelector('input[name="cmd"]');a&&(a.value=t,i.submit())}static getReturnUrl(t){return""===t&&(t=top.list_frame.document.location.pathname+top.list_frame.document.location.search),encodeURIComponent(t)}handleDataHandlerResult(t){const e=t.detail.payload;e.hasErrors||"datahandler"!==e.component&&"delete"===e.action&&this.deleteRow(e)}pasteInto(t){t.preventDefault();const e=t.detail.configuration;r.advanced({title:e.title||"Paste",content:e.content||"Are you sure you want to paste the current clipboard content?",severity:d.SeverityEnum.warning,buttons:[{text:TYPO3.lang["button.close"]||"Close",active:!0,btnClass:"btn-default",trigger:()=>r.currentModal.trigger("modal-dismiss")},{text:e.ok||TYPO3.lang["button.ok"]||"OK",btnClass:"btn-"+c.getCssClass(d.SeverityEnum.warning),trigger:()=>{r.currentModal.trigger("modal-dismiss"),e.url&&"#"!==e.url&&(t.target.ownerDocument.location.href=e.url)}}]})}deleteMultiple(t){t.preventDefault();const e=t.detail.configuration;r.advanced({title:e.title||"Delete",content:e.content||"Are you sure you want to delete those records?",severity:d.SeverityEnum.warning,buttons:[{text:TYPO3.lang["button.close"]||"Close",active:!0,btnClass:"btn-default",trigger:()=>r.currentModal.trigger("modal-dismiss")},{text:e.ok||TYPO3.lang["button.ok"]||"OK",btnClass:"btn-"+c.getCssClass(d.SeverityEnum.warning),trigger:()=>{r.currentModal.trigger("modal-dismiss"),u.submitClipboardFormWithCommand("delete",t.target)}}]})}}return new u}));
\ No newline at end of file
+var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};define(["require","exports","jquery","TYPO3/CMS/Backend/Icons","TYPO3/CMS/Backend/Storage/Persistent","TYPO3/CMS/Core/Event/RegularEvent","TYPO3/CMS/Backend/Tooltip","TYPO3/CMS/Core/DocumentService","TYPO3/CMS/Backend/Modal","TYPO3/CMS/Backend/Enum/Severity","TYPO3/CMS/Backend/Severity"],(function(t,e,i,a,n,l,o,d,r,s,c){"use strict";i=__importDefault(i);class u{constructor(){this.identifier={entity:".t3js-entity",toggle:".t3js-toggle-recordlist",localize:".t3js-action-localize",searchboxToolbar:"#db_list-searchbox-toolbar",searchboxToggle:".t3js-toggle-search-toolbox",searchField:"#search_field",icons:{collapse:"actions-view-list-collapse",expand:"actions-view-list-expand",editMultiple:".t3js-record-edit-multiple"}},this.toggleClick=t=>{t.preventDefault();const e=i.default(t.currentTarget),l=e.data("table"),o=i.default(e.data("bs-target")),d="expanded"===o.data("state"),r=e.find(".collapseIcon"),s=d?this.identifier.icons.expand:this.identifier.icons.collapse;a.getIcon(s,a.sizes.small).done(t=>{r.html(t)});let c={};n.isset("moduleData.list")&&(c=n.get("moduleData.list"));const u={};u[l]=d?1:0,i.default.extend(c,u),n.set("moduleData.list",c).done(()=>{o.data("state",d?"collapsed":"expanded")})},this.onEditMultiple=t=>{t.preventDefault();let e="",i="",a="",n=[];if("multiRecordSelection:action:edit"===t.type){const a=t.detail,l=a.configuration;if(i=l.returnUrl||"",e=l.tableName||"",""===e)return;a.checkboxes.forEach(t=>{const e=t.closest("tr");null!==e&&e.dataset[l.idField]&&n.push(e.dataset[l.idField])})}else{const l=t.currentTarget,o=l.closest("[data-table]");if(null===o)return;if(e=o.dataset.table||"",""===e)return;i=l.dataset.returnUrl||"",a=l.dataset.columnsOnly||"";const d=o.querySelectorAll(this.identifier.entity+'[data-uid][data-table="'+e+'"] td.col-selector input[type="checkbox"]:checked');if(d.length)d.forEach(t=>{n.push(t.closest(this.identifier.entity+'[data-uid][data-table="'+e+'"]').dataset.uid)});else{const t=o.querySelectorAll(this.identifier.entity+'[data-uid][data-table="'+e+'"]');if(!t.length)return;t.forEach(t=>{n.push(t.dataset.uid)})}}if(!n.length)return;let l=top.TYPO3.settings.FormEngine.moduleUrl+"&edit["+e+"]["+n.join(",")+"]=edit&returnUrl="+u.getReturnUrl(i);""!==a&&(l+="&columnsOnly="+a),window.location.href=l},this.disableButton=t=>{i.default(t.currentTarget).prop("disable",!0).addClass("disabled")},this.toggleSearchbox=()=>{const t=i.default(this.identifier.searchboxToolbar);t.toggle(),t.is(":visible")&&i.default(this.identifier.searchField).focus()},this.deleteRow=t=>{const e=i.default(`table[data-table="${t.table}"]`),a=e.find(`tr[data-uid="${t.uid}"]`),n=e.closest(".panel"),l=n.find(".panel-heading"),o=e.find(`[data-l10nparent="${t.uid}"]`),d=i.default().add(a).add(o);if(d.fadeTo("slow",.4,()=>{d.slideUp("slow",()=>{d.remove(),0===e.find("tbody tr").length&&n.slideUp("slow")})}),"0"===a.data("l10nparent")||""===a.data("l10nparent")){const t=Number(l.find(".t3js-table-total-items").html());l.find(".t3js-table-total-items").text(t-1)}"pages"===t.table&&top.document.dispatchEvent(new CustomEvent("typo3:pagetree:refresh"))},this.registerPaginationEvents=()=>{document.querySelectorAll(".t3js-recordlist-paging").forEach(t=>{t.addEventListener("keyup",e=>{e.preventDefault();let i=parseInt(t.value,10);i<parseInt(t.min,10)&&(i=parseInt(t.min,10)),i>parseInt(t.max,10)&&(i=parseInt(t.max,10)),"Enter"===e.key&&i!==parseInt(t.dataset.currentpage,10)&&(window.location.href=t.dataset.currenturl+i.toString())})})},i.default(document).on("click",this.identifier.toggle,this.toggleClick),i.default(document).on("click",this.identifier.icons.editMultiple,this.onEditMultiple),i.default(document).on("click",this.identifier.localize,this.disableButton),i.default(document).on("click",this.identifier.searchboxToggle,this.toggleSearchbox),d.ready().then(()=>{o.initialize(".table-fit a[title]"),this.registerPaginationEvents()}),new l("typo3:datahandler:process",this.handleDataHandlerResult.bind(this)).bindTo(document),new l("multiRecordSelection:action:edit",this.onEditMultiple).bindTo(document),new l("multiRecordSelection:action:delete",this.deleteMultiple).bindTo(document),new l("multiRecordSelection:action:copyMarked",t=>{u.submitClipboardFormWithCommand("copyMarked",t.target)}).bindTo(document),new l("multiRecordSelection:action:removeMarked",t=>{u.submitClipboardFormWithCommand("removeMarked",t.target)}).bindTo(document)}static submitClipboardFormWithCommand(t,e){const i=e.closest("form");if(!i)return;const a=i.querySelector('input[name="cmd"]');a&&(a.value=t,i.submit())}static getReturnUrl(t){return""===t&&(t=top.list_frame.document.location.pathname+top.list_frame.document.location.search),encodeURIComponent(t)}handleDataHandlerResult(t){const e=t.detail.payload;e.hasErrors||"datahandler"!==e.component&&"delete"===e.action&&this.deleteRow(e)}deleteMultiple(t){t.preventDefault();const e=t.detail.configuration;r.advanced({title:e.title||"Delete",content:e.content||"Are you sure you want to delete those records?",severity:s.SeverityEnum.warning,buttons:[{text:TYPO3.lang["button.close"]||"Close",active:!0,btnClass:"btn-default",trigger:()=>r.currentModal.trigger("modal-dismiss")},{text:e.ok||TYPO3.lang["button.ok"]||"OK",btnClass:"btn-"+c.getCssClass(s.SeverityEnum.warning),trigger:()=>{r.currentModal.trigger("modal-dismiss"),u.submitClipboardFormWithCommand("delete",t.target)}}]})}}return new u}));
\ No newline at end of file
-- 
GitLab