diff --git a/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileList.ts b/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileList.ts index 5717a3fb449de41f0821e96c074a0bf99e08e171..3e4d1056a28cbae269d57855f117062e1c646224 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 ae632bc36300892d3e4b8e0c6ded0a2d5192d856..cf8d48ecaef2389d35850c90ce818b32a6bde9f2 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 84d86825c9b407691e944955288ae4aa2768f482..0e0f67a76635d3ffadc4a2f2bbe552eacdb81538 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 48868d093c8554713a1334ba0b54960273ab193b..25a829e38da7452a2a3bd052a70d415770f6406f 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 2e6628a3c13f5b5120f3e3b31eb3a3a2843af828..c58963669e882d340df25e2a3daf36cafd85c325 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 76997bd18ac14cf1ba845d2a1316db0c42ab6b87..5991bc8a8d823f8ce1b0529752d3e01f5d263eea 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 75973249fb62b212137c28c6418c22d37e4ee2c9..2765ab2b8ec90b7b9a4bbf79fa537a0712aedccb 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 9e2776005c72e2163478869ddda2a0a23a2a322c..ca1715da0528ebcdb515478714851d65fdb18bcb 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 eb8c9bdffee559448223081da4cac78700caba67..c8c88827563d3f8f410a595476520f28aec64b78 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 52ac836edc4685f000db1e91c171ea35cd3bfb35..83ffb4ad3a9ae35bd73390e5d33d8d19ab2edb5f 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 1a2a43a803fe0f2b8ccdfb4247aeec1dc7ec4e8f..74235e68683770e558fc9d1164ae561ae6ba0b0c 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 0bc56b1f1ff74ecebff86341beb727c251e7564d..45b53f2ca8abaebe6a855c2b62a555cdc8f0eb21 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