From 75b9be60c3d308d415900a2fc43ede9cf4cda053 Mon Sep 17 00:00:00 2001 From: Andreas Fernandez <a.fernandez@scripting-base.de> Date: Fri, 20 Mar 2020 12:34:24 +0100 Subject: [PATCH] [BUGFIX] React on delete actions via context menu If a record gets deleted via context menu no further handling could be added as the promise returned by AjaxDataHandler is available in an encapsulated scope only. To bypass this issue, the AjaxDataHandler now optionally emits events to listen on. This patch implements event listeners for the record list and the information module of "Template tools". Resolves: #90791 Releases: master Change-Id: I0b659e695f31b2f3ab40adc17421f8b036d5aab6 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/63811 Tested-by: Susanne Moog <look@susi.dev> Tested-by: TYPO3com <noreply@typo3.com> Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de> Reviewed-by: Susanne Moog <look@susi.dev> Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de> --- .../Public/TypeScript/AjaxDataHandler.ts | 37 +++++++++++++---- .../Public/TypeScript/ContextMenuActions.ts | 3 +- .../Resources/Public/TypeScript/Recordlist.ts | 41 ++++++++++++++++++- .../Public/TypeScript/InformationModule.ts | 28 +++++++++++++ .../Public/JavaScript/AjaxDataHandler.js | 2 +- .../Public/JavaScript/ContextMenuActions.js | 2 +- .../Resources/Public/JavaScript/Recordlist.js | 2 +- .../Private/Templates/InformationModule.html | 1 + .../Public/JavaScript/InformationModule.js | 13 ++++++ 9 files changed, 115 insertions(+), 14 deletions(-) create mode 100644 Build/Sources/TypeScript/tstemplate/Resources/Public/TypeScript/InformationModule.ts create mode 100644 typo3/sysext/tstemplate/Resources/Public/JavaScript/InformationModule.js diff --git a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/AjaxDataHandler.ts b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/AjaxDataHandler.ts index 695cfe8ba835..ce94494a93d7 100644 --- a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/AjaxDataHandler.ts +++ b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/AjaxDataHandler.ts @@ -28,6 +28,14 @@ enum Identifiers { icon = '.t3js-icon', } +interface AfterProcessEventDict { + component: string; + action: string; + trigger?: Node; + table: string; + uid: number; +} + /** * Module: TYPO3/CMS/Backend/AjaxDataHandler * Javascript functions to work with AJAX and interacting with Datahandler @@ -65,20 +73,29 @@ class AjaxDataHandler { /** * Generic function to call from the outside the script and validate directly showing errors * - * @param {Object} parameters - * @returns {JQueryPromise<any>} + * @param {string | object} parameters + * @param {AfterProcessEventDict} eventDict Dictionary used as event detail. This is private API yet. + * @returns {Promise<any>} */ - public process(parameters: string | object): Promise<any> { + public process(parameters: string | object, eventDict?: AfterProcessEventDict): Promise<any> { const promise = AjaxDataHandler.call(parameters); return promise.then((result: ResponseInterface): ResponseInterface => { if (result.hasErrors) { this.handleErrors(result); } + if (eventDict) { + const event = new CustomEvent(`datahandler:process:${eventDict.action}`,{ + detail: {...eventDict, hasErrors: result.hasErrors} + }); + document.dispatchEvent(event); + } + return result; }); } + // TODO: Many extensions rely on this behavior but it's misplaced in AjaxDataHandler. Move into Recordlist.ts and deprecate in v11. private initialize(): void { // HIDE/UNHIDE: click events for all action icons to hide/unhide $(document).on('click', Identifiers.hide, (e: JQueryEventObject): void => { @@ -92,7 +109,7 @@ class AjaxDataHandler { this._showSpinnerIcon($iconElement); // make the AJAX call to toggle the visibility - AjaxDataHandler.call(params).then((result: ResponseInterface): void => { + this.process(params).then((result: ResponseInterface): void => { // print messages on errors if (result.hasErrors) { this.handleErrors(result); @@ -201,8 +218,14 @@ class AjaxDataHandler { // add a spinner this._showSpinnerIcon($iconElement); + const $table = $anchorElement.closest('table[data-table]'); + const table = $table.data('table'); + let $rowElements = $anchorElement.closest('tr[data-uid]'); + const uid = $rowElements.data('uid'); + // make the AJAX call to toggle the visibility - AjaxDataHandler.call(params).then((result: ResponseInterface): void => { + const eventData = {component: 'datahandler', trigger: $anchorElement.get(0), action: 'delete', table, uid}; + this.process(params, eventData).then((result: ResponseInterface): void => { // revert to the old class Icons.getIcon('actions-edit-delete', Icons.sizes.small).then((icon: string): void => { $iconElement = $anchorElement.find(Identifiers.icon); @@ -212,12 +235,8 @@ class AjaxDataHandler { if (result.hasErrors) { this.handleErrors(result); } else { - const $table = $anchorElement.closest('table[data-table]'); const $panel = $anchorElement.closest('.panel'); const $panelHeading = $panel.find('.panel-heading'); - const table = $table.data('table'); - let $rowElements = $anchorElement.closest('tr[data-uid]'); - const uid = $rowElements.data('uid'); const $translatedRowElements = $table.find('[data-l10nparent=' + uid + ']').closest('tr[data-uid]'); $rowElements = $rowElements.add($translatedRowElements); diff --git a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/ContextMenuActions.ts b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/ContextMenuActions.ts index 9462be89d19c..bfaf7a1850ed 100644 --- a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/ContextMenuActions.ts +++ b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/ContextMenuActions.ts @@ -231,7 +231,8 @@ class ContextMenuActions { $modal.on('button.clicked', (e: JQueryEventObject): void => { if (e.target.getAttribute('name') === 'delete') { - AjaxDataHandler.process('cmd[' + table + '][' + uid + '][delete]=1').then((): void => { + const eventData = {component: 'contextmenu', trigger: $anchorElement.get(0), action: 'delete', table, uid}; + AjaxDataHandler.process('cmd[' + table + '][' + uid + '][delete]=1', eventData).then((): void => { if (table === 'pages' && Viewport.NavigationContainer.PageTree) { if (uid === top.fsMod.recentIds.web) { let node = Viewport.NavigationContainer.PageTree.getFirstNode(); diff --git a/Build/Sources/TypeScript/recordlist/Resources/Public/TypeScript/Recordlist.ts b/Build/Sources/TypeScript/recordlist/Resources/Public/TypeScript/Recordlist.ts index 8b8feb5d915b..d01175aace66 100644 --- a/Build/Sources/TypeScript/recordlist/Resources/Public/TypeScript/Recordlist.ts +++ b/Build/Sources/TypeScript/recordlist/Resources/Public/TypeScript/Recordlist.ts @@ -12,8 +12,10 @@ */ import * as $ from 'jquery'; -import PersistentStorage = require('TYPO3/CMS/Backend/Storage/Persistent'); import Icons = require('TYPO3/CMS/Backend/Icons'); +import PersistentStorage = require('TYPO3/CMS/Backend/Storage/Persistent'); +import RegularEvent = require('TYPO3/CMS/Core/Event/RegularEvent'); +import Viewport = require('TYPO3/CMS/Backend/Viewport'); declare global { const T3_THIS_LOCATION: string; @@ -52,6 +54,7 @@ class Recordlist { $(document).on('click', this.identifier.toggle, this.toggleClick); $(document).on('click', this.identifier.icons.editMultiple, this.onEditMultiple); $(document).on('click', this.identifier.localize, this.disableButton); + new RegularEvent('datahandler:process:delete', this.deleteRow).bindTo(document); } public toggleClick = (e: JQueryEventObject): void => { @@ -166,6 +169,42 @@ class Recordlist { $me.prop('disable', true).addClass('disabled'); } + private deleteRow = (e: CustomEvent): void => { + if (e.detail.hasErrors) { + return; + } + + if (e.detail.component === 'datahandler') { + // In this case the delete action was triggered by AjaxDataHandler itself, which currently has its own handling. + // Visual handling is about to get decoupled from data handling itself, thus the logic is duplicated for now. + return; + } + + const $tableElement = $(`table[data-table="${e.detail.table}"]`); + const $rowElement = $tableElement.find(`tr[data-uid="${e.detail.uid}"]`); + const $panel = $tableElement.closest('.panel'); + const $panelHeading = $panel.find('.panel-heading'); + const $translatedRowElements = $tableElement.find(`[data-l10nparent="${e.detail.uid}"]`); + + const $rowElements = $().add($rowElement).add($translatedRowElements); + $rowElements.fadeTo('slow', 0.4, (): void => { + $rowElements.slideUp('slow', (): void => { + $rowElements.remove(); + if ($tableElement.find('tbody tr').length === 0) { + $panel.slideUp('slow'); + } + }); + }); + if ($rowElement.data('l10nparent') === '0' || $rowElement.data('l10nparent') === '') { + const count = Number($panelHeading.find('.t3js-table-total-items').html()); + $panelHeading.find('.t3js-table-total-items').text(count - 1); + } + + if (e.detail.table === 'pages') { + Viewport.NavigationContainer.PageTree.refreshTree(); + } + } + private getCheckboxState(CBname: string): boolean { const fullName = 'CBC[' + CBname + ']'; const checkbox: HTMLInputElement = document.querySelector('form[name="dblistForm"] [name="' + fullName + '"]'); diff --git a/Build/Sources/TypeScript/tstemplate/Resources/Public/TypeScript/InformationModule.ts b/Build/Sources/TypeScript/tstemplate/Resources/Public/TypeScript/InformationModule.ts new file mode 100644 index 000000000000..7e382bfcd231 --- /dev/null +++ b/Build/Sources/TypeScript/tstemplate/Resources/Public/TypeScript/InformationModule.ts @@ -0,0 +1,28 @@ +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +import RegularEvent = require('TYPO3/CMS/Core/Event/RegularEvent'); + +class InformationModule { + constructor() { + this.registerEventListeners(); + } + + private registerEventListeners(): void { + new RegularEvent('datahandler:process:delete', (e: CustomEvent): void => { + document.location.reload(); + }).bindTo(document); + } +} + +export = new InformationModule(); diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/AjaxDataHandler.js b/typo3/sysext/backend/Resources/Public/JavaScript/AjaxDataHandler.js index 21efa05f5099..e2a737156665 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/AjaxDataHandler.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/AjaxDataHandler.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -define(["require","exports","TYPO3/CMS/Core/Ajax/AjaxRequest","./Enum/Severity","jquery","./Icons","./Modal","./Notification","./Viewport"],(function(e,t,a,n,i,s,r,o,l){"use strict";var d;!function(e){e.hide=".t3js-record-hide",e.delete=".t3js-record-delete",e.icon=".t3js-icon"}(d||(d={}));class c{static refreshPageTree(){l.NavigationContainer&&l.NavigationContainer.PageTree&&l.NavigationContainer.PageTree.refreshTree()}static call(e){return new a(TYPO3.settings.ajaxUrls.record_process).withQueryArguments(e).get().then(async e=>await e.resolve())}constructor(){i(()=>{this.initialize()})}process(e){return c.call(e).then(e=>(e.hasErrors&&this.handleErrors(e),e))}initialize(){i(document).on("click",d.hide,e=>{e.preventDefault();const t=i(e.currentTarget),a=t.find(d.icon),n=t.closest("tr[data-uid]"),s=t.data("params");this._showSpinnerIcon(a),c.call(s).then(e=>{e.hasErrors?this.handleErrors(e):this.toggleRow(n)})}),i(document).on("click",d.delete,e=>{e.preventDefault();const t=i(e.currentTarget);t.tooltip("hide"),r.confirm(t.data("title"),t.data("message"),n.SeverityEnum.warning,[{text:t.data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",name:"cancel"},{text:t.data("button-ok-text")||TYPO3.lang["button.delete"]||"Delete",btnClass:"btn-warning",name:"delete"}]).on("button.clicked",e=>{"cancel"===e.target.getAttribute("name")?r.dismiss():"delete"===e.target.getAttribute("name")&&(r.dismiss(),this.deleteRecord(t))})})}toggleRow(e){const t=e.find(d.hide),a=t.closest("table[data-table]").data("table"),n=t.data("params");let r,o,l;"hidden"===t.data("state")?(o="visible",r=n.replace("=0","=1"),l="actions-edit-hide"):(o="hidden",r=n.replace("=1","=0"),l="actions-edit-unhide"),t.data("state",o).data("params",r),t.tooltip("hide").one("hidden.bs.tooltip",()=>{const e=t.data("toggleTitle");t.data("toggleTitle",t.attr("data-original-title")).attr("data-original-title",e)});const h=t.find(d.icon);s.getIcon(l,s.sizes.small).then(e=>{h.replaceWith(e)});const g=e.find(".col-icon "+d.icon);"hidden"===o?s.getIcon("miscellaneous-placeholder",s.sizes.small,"overlay-hidden").then(e=>{g.append(i(e).find(".icon-overlay"))}):g.find(".icon-overlay").remove(),e.fadeTo("fast",.4,()=>{e.fadeTo("fast",1)}),"pages"===a&&c.refreshPageTree()}deleteRecord(e){const t=e.data("params");let a=e.find(d.icon);this._showSpinnerIcon(a),c.call(t).then(t=>{if(s.getIcon("actions-edit-delete",s.sizes.small).then(t=>{a=e.find(d.icon),a.replaceWith(t)}),t.hasErrors)this.handleErrors(t);else{const t=e.closest("table[data-table]"),a=e.closest(".panel"),n=a.find(".panel-heading"),i=t.data("table");let s=e.closest("tr[data-uid]");const r=s.data("uid"),o=t.find("[data-l10nparent="+r+"]").closest("tr[data-uid]");if(s=s.add(o),s.fadeTo("slow",.4,()=>{s.slideUp("slow",()=>{s.remove(),0===t.find("tbody tr").length&&a.slideUp("slow")})}),"0"===e.data("l10parent")||""===e.data("l10parent")){const e=Number(n.find(".t3js-table-total-items").html());n.find(".t3js-table-total-items").text(e-1)}"pages"===i&&c.refreshPageTree()}})}handleErrors(e){i.each(e.messages,(e,t)=>{o.error(t.title,t.message)})}_showSpinnerIcon(e){s.getIcon("spinner-circle-dark",s.sizes.small).then(t=>{e.replaceWith(t)})}}return new c})); \ No newline at end of file +define(["require","exports","TYPO3/CMS/Core/Ajax/AjaxRequest","./Enum/Severity","jquery","./Icons","./Modal","./Notification","./Viewport"],(function(e,t,a,n,s,i,r,o,l){"use strict";var d;!function(e){e.hide=".t3js-record-hide",e.delete=".t3js-record-delete",e.icon=".t3js-icon"}(d||(d={}));class c{static refreshPageTree(){l.NavigationContainer&&l.NavigationContainer.PageTree&&l.NavigationContainer.PageTree.refreshTree()}static call(e){return new a(TYPO3.settings.ajaxUrls.record_process).withQueryArguments(e).get().then(async e=>await e.resolve())}constructor(){s(()=>{this.initialize()})}process(e,t){return c.call(e).then(e=>{if(e.hasErrors&&this.handleErrors(e),t){const a=new CustomEvent(`datahandler:process:${t.action}`,{detail:Object.assign(Object.assign({},t),{hasErrors:e.hasErrors})});document.dispatchEvent(a)}return e})}initialize(){s(document).on("click",d.hide,e=>{e.preventDefault();const t=s(e.currentTarget),a=t.find(d.icon),n=t.closest("tr[data-uid]"),i=t.data("params");this._showSpinnerIcon(a),this.process(i).then(e=>{e.hasErrors?this.handleErrors(e):this.toggleRow(n)})}),s(document).on("click",d.delete,e=>{e.preventDefault();const t=s(e.currentTarget);t.tooltip("hide"),r.confirm(t.data("title"),t.data("message"),n.SeverityEnum.warning,[{text:t.data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",name:"cancel"},{text:t.data("button-ok-text")||TYPO3.lang["button.delete"]||"Delete",btnClass:"btn-warning",name:"delete"}]).on("button.clicked",e=>{"cancel"===e.target.getAttribute("name")?r.dismiss():"delete"===e.target.getAttribute("name")&&(r.dismiss(),this.deleteRecord(t))})})}toggleRow(e){const t=e.find(d.hide),a=t.closest("table[data-table]").data("table"),n=t.data("params");let r,o,l;"hidden"===t.data("state")?(o="visible",r=n.replace("=0","=1"),l="actions-edit-hide"):(o="hidden",r=n.replace("=1","=0"),l="actions-edit-unhide"),t.data("state",o).data("params",r),t.tooltip("hide").one("hidden.bs.tooltip",()=>{const e=t.data("toggleTitle");t.data("toggleTitle",t.attr("data-original-title")).attr("data-original-title",e)});const h=t.find(d.icon);i.getIcon(l,i.sizes.small).then(e=>{h.replaceWith(e)});const g=e.find(".col-icon "+d.icon);"hidden"===o?i.getIcon("miscellaneous-placeholder",i.sizes.small,"overlay-hidden").then(e=>{g.append(s(e).find(".icon-overlay"))}):g.find(".icon-overlay").remove(),e.fadeTo("fast",.4,()=>{e.fadeTo("fast",1)}),"pages"===a&&c.refreshPageTree()}deleteRecord(e){const t=e.data("params");let a=e.find(d.icon);this._showSpinnerIcon(a);const n=e.closest("table[data-table]"),s=n.data("table");let r=e.closest("tr[data-uid]");const o=r.data("uid"),l={component:"datahandler",trigger:e.get(0),action:"delete",table:s,uid:o};this.process(t,l).then(t=>{if(i.getIcon("actions-edit-delete",i.sizes.small).then(t=>{a=e.find(d.icon),a.replaceWith(t)}),t.hasErrors)this.handleErrors(t);else{const t=e.closest(".panel"),a=t.find(".panel-heading"),i=n.find("[data-l10nparent="+o+"]").closest("tr[data-uid]");if(r=r.add(i),r.fadeTo("slow",.4,()=>{r.slideUp("slow",()=>{r.remove(),0===n.find("tbody tr").length&&t.slideUp("slow")})}),"0"===e.data("l10parent")||""===e.data("l10parent")){const e=Number(a.find(".t3js-table-total-items").html());a.find(".t3js-table-total-items").text(e-1)}"pages"===s&&c.refreshPageTree()}})}handleErrors(e){s.each(e.messages,(e,t)=>{o.error(t.title,t.message)})}_showSpinnerIcon(e){i.getIcon("spinner-circle-dark",i.sizes.small).then(t=>{e.replaceWith(t)})}}return new c})); \ No newline at end of file diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/ContextMenuActions.js b/typo3/sysext/backend/Resources/Public/JavaScript/ContextMenuActions.js index 5ce6619f2ae2..aabf8335c0c4 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/ContextMenuActions.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/ContextMenuActions.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -define(["require","exports","./Enum/Severity","jquery","./AjaxDataHandler","TYPO3/CMS/Core/Ajax/AjaxRequest","./InfoWindow","./Modal","./ModuleMenu","TYPO3/CMS/Backend/Notification","./Viewport"],(function(e,t,n,a,r,i,o,s,l,c,d){"use strict";class g{static getReturnUrl(){return encodeURIComponent(top.list_frame.document.location.pathname+top.list_frame.document.location.search)}static editRecord(e,t){let n="",r=a(this).data("pages-language-uid");r&&(n="&overrideVals[pages][sys_language_uid]="+r),d.ContentContainer.setUrl(top.TYPO3.settings.FormEngine.moduleUrl+"&edit["+e+"]["+t+"]=edit"+n+"&returnUrl="+g.getReturnUrl())}static viewRecord(){const e=a(this).data("preview-url");if(e){window.open(e,"newTYPO3frontendWindow").focus()}}static openInfoPopUp(e,t){o.showItem(e,t)}static mountAsTreeRoot(e,t){"pages"===e&&d.NavigationContainer.PageTree.setTemporaryMountPoint(t)}static newPageWizard(e,t){d.ContentContainer.setUrl(top.TYPO3.settings.NewRecord.moduleUrl+"&id="+t+"&pagesOnly=1&returnUrl="+g.getReturnUrl())}static newContentWizard(){const e=a(this);let t=e.data("new-wizard-url");t&&(t+="&returnUrl="+g.getReturnUrl(),s.advanced({title:e.data("title"),type:s.types.ajax,size:s.sizes.medium,content:t,severity:n.SeverityEnum.notice}))}static newRecord(e,t){d.ContentContainer.setUrl(top.TYPO3.settings.FormEngine.moduleUrl+"&edit["+e+"][-"+t+"]=new&returnUrl="+g.getReturnUrl())}static openHistoryPopUp(e,t){d.ContentContainer.setUrl(top.TYPO3.settings.RecordHistory.moduleUrl+"&element="+e+":"+t+"&returnUrl="+g.getReturnUrl())}static openListModule(e,t){const n="pages"===e?t:a(this).data("page-uid");l.App.showModule("web_list","id="+n)}static pagesSort(){const e=a(this).data("pages-sort-url");e&&d.ContentContainer.setUrl(e)}static pagesNewMultiple(){const e=a(this).data("pages-new-multiple-url");e&&d.ContentContainer.setUrl(e)}static disableRecord(e,t){const n=a(this).data("disable-field")||"hidden";d.ContentContainer.setUrl(top.TYPO3.settings.RecordCommit.moduleUrl+"&data["+e+"]["+t+"]["+n+"]=1&redirect="+g.getReturnUrl()).done(()=>{d.NavigationContainer.PageTree.refreshTree()})}static enableRecord(e,t){const n=a(this).data("disable-field")||"hidden";d.ContentContainer.setUrl(top.TYPO3.settings.RecordCommit.moduleUrl+"&data["+e+"]["+t+"]["+n+"]=0&redirect="+g.getReturnUrl()).done(()=>{d.NavigationContainer.PageTree.refreshTree()})}static showInMenus(e,t){d.ContentContainer.setUrl(top.TYPO3.settings.RecordCommit.moduleUrl+"&data["+e+"]["+t+"][nav_hide]=0&redirect="+g.getReturnUrl()).done(()=>{d.NavigationContainer.PageTree.refreshTree()})}static hideInMenus(e,t){d.ContentContainer.setUrl(top.TYPO3.settings.RecordCommit.moduleUrl+"&data["+e+"]["+t+"][nav_hide]=1&redirect="+g.getReturnUrl()).done(()=>{d.NavigationContainer.PageTree.refreshTree()})}static deleteRecord(e,t){const i=a(this);s.confirm(i.data("title"),i.data("message"),n.SeverityEnum.warning,[{text:a(this).data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",name:"cancel"},{text:a(this).data("button-ok-text")||TYPO3.lang["button.delete"]||"Delete",btnClass:"btn-warning",name:"delete"}]).on("button.clicked",n=>{"delete"===n.target.getAttribute("name")&&r.process("cmd["+e+"]["+t+"][delete]=1").then(()=>{if("pages"===e&&d.NavigationContainer.PageTree){if(t===top.fsMod.recentIds.web){let e=d.NavigationContainer.PageTree.getFirstNode();d.NavigationContainer.PageTree.selectNode(e)}d.NavigationContainer.PageTree.refreshTree()}}),s.dismiss()})}static copy(e,t){const n=TYPO3.settings.ajaxUrls.contextmenu_clipboard+"&CB[el]["+e+"%7C"+t+"]=1&CB[setCopyMode]=1";new i(n).get().finally(()=>{g.triggerRefresh(d.ContentContainer.get().location.href)})}static clipboardRelease(e,t){const n=TYPO3.settings.ajaxUrls.contextmenu_clipboard+"&CB[el]["+e+"%7C"+t+"]=0";new i(n).get().finally(()=>{g.triggerRefresh(d.ContentContainer.get().location.href)})}static cut(e,t){const n=TYPO3.settings.ajaxUrls.contextmenu_clipboard+"&CB[el]["+e+"%7C"+t+"]=1&CB[setCopyMode]=0";new i(n).get().finally(()=>{g.triggerRefresh(d.ContentContainer.get().location.href)})}static triggerRefresh(e){e.includes("record%2Fedit")||d.ContentContainer.refresh()}static clearCache(e,t){new i(TYPO3.settings.ajaxUrls.web_list_clearpagecache).withQueryArguments({id:t}).get({cache:"no-cache"}).then(async e=>{const t=await e.resolve();!0===t.success?c.success(t.title,t.message,1):c.error(t.title,t.message,1)},()=>{c.error("Clearing page caches went wrong on the server side.")})}static pasteAfter(e,t){g.pasteInto.bind(a(this))(e,-t)}static pasteInto(e,t){const r=a(this),i=()=>{const n="&CB[paste]="+e+"%7C"+t+"&CB[pad]=normal&redirect="+g.getReturnUrl();d.ContentContainer.setUrl(top.TYPO3.settings.RecordCommit.moduleUrl+n).done(()=>{"pages"===e&&d.NavigationContainer.PageTree&&d.NavigationContainer.PageTree.refreshTree()})};r.data("title")?s.confirm(r.data("title"),r.data("message"),n.SeverityEnum.warning,[{text:a(this).data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",name:"cancel"},{text:a(this).data("button-ok-text")||TYPO3.lang["button.ok"]||"OK",btnClass:"btn-warning",name:"ok"}]).on("button.clicked",e=>{"ok"===e.target.getAttribute("name")&&i(),s.dismiss()}):i()}}return g})); \ No newline at end of file +define(["require","exports","./Enum/Severity","jquery","./AjaxDataHandler","TYPO3/CMS/Core/Ajax/AjaxRequest","./InfoWindow","./Modal","./ModuleMenu","TYPO3/CMS/Backend/Notification","./Viewport"],(function(e,t,n,a,r,i,o,s,l,c,d){"use strict";class g{static getReturnUrl(){return encodeURIComponent(top.list_frame.document.location.pathname+top.list_frame.document.location.search)}static editRecord(e,t){let n="",r=a(this).data("pages-language-uid");r&&(n="&overrideVals[pages][sys_language_uid]="+r),d.ContentContainer.setUrl(top.TYPO3.settings.FormEngine.moduleUrl+"&edit["+e+"]["+t+"]=edit"+n+"&returnUrl="+g.getReturnUrl())}static viewRecord(){const e=a(this).data("preview-url");if(e){window.open(e,"newTYPO3frontendWindow").focus()}}static openInfoPopUp(e,t){o.showItem(e,t)}static mountAsTreeRoot(e,t){"pages"===e&&d.NavigationContainer.PageTree.setTemporaryMountPoint(t)}static newPageWizard(e,t){d.ContentContainer.setUrl(top.TYPO3.settings.NewRecord.moduleUrl+"&id="+t+"&pagesOnly=1&returnUrl="+g.getReturnUrl())}static newContentWizard(){const e=a(this);let t=e.data("new-wizard-url");t&&(t+="&returnUrl="+g.getReturnUrl(),s.advanced({title:e.data("title"),type:s.types.ajax,size:s.sizes.medium,content:t,severity:n.SeverityEnum.notice}))}static newRecord(e,t){d.ContentContainer.setUrl(top.TYPO3.settings.FormEngine.moduleUrl+"&edit["+e+"][-"+t+"]=new&returnUrl="+g.getReturnUrl())}static openHistoryPopUp(e,t){d.ContentContainer.setUrl(top.TYPO3.settings.RecordHistory.moduleUrl+"&element="+e+":"+t+"&returnUrl="+g.getReturnUrl())}static openListModule(e,t){const n="pages"===e?t:a(this).data("page-uid");l.App.showModule("web_list","id="+n)}static pagesSort(){const e=a(this).data("pages-sort-url");e&&d.ContentContainer.setUrl(e)}static pagesNewMultiple(){const e=a(this).data("pages-new-multiple-url");e&&d.ContentContainer.setUrl(e)}static disableRecord(e,t){const n=a(this).data("disable-field")||"hidden";d.ContentContainer.setUrl(top.TYPO3.settings.RecordCommit.moduleUrl+"&data["+e+"]["+t+"]["+n+"]=1&redirect="+g.getReturnUrl()).done(()=>{d.NavigationContainer.PageTree.refreshTree()})}static enableRecord(e,t){const n=a(this).data("disable-field")||"hidden";d.ContentContainer.setUrl(top.TYPO3.settings.RecordCommit.moduleUrl+"&data["+e+"]["+t+"]["+n+"]=0&redirect="+g.getReturnUrl()).done(()=>{d.NavigationContainer.PageTree.refreshTree()})}static showInMenus(e,t){d.ContentContainer.setUrl(top.TYPO3.settings.RecordCommit.moduleUrl+"&data["+e+"]["+t+"][nav_hide]=0&redirect="+g.getReturnUrl()).done(()=>{d.NavigationContainer.PageTree.refreshTree()})}static hideInMenus(e,t){d.ContentContainer.setUrl(top.TYPO3.settings.RecordCommit.moduleUrl+"&data["+e+"]["+t+"][nav_hide]=1&redirect="+g.getReturnUrl()).done(()=>{d.NavigationContainer.PageTree.refreshTree()})}static deleteRecord(e,t){const i=a(this);s.confirm(i.data("title"),i.data("message"),n.SeverityEnum.warning,[{text:a(this).data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",name:"cancel"},{text:a(this).data("button-ok-text")||TYPO3.lang["button.delete"]||"Delete",btnClass:"btn-warning",name:"delete"}]).on("button.clicked",n=>{if("delete"===n.target.getAttribute("name")){const n={component:"contextmenu",trigger:i.get(0),action:"delete",table:e,uid:t};r.process("cmd["+e+"]["+t+"][delete]=1",n).then(()=>{if("pages"===e&&d.NavigationContainer.PageTree){if(t===top.fsMod.recentIds.web){let e=d.NavigationContainer.PageTree.getFirstNode();d.NavigationContainer.PageTree.selectNode(e)}d.NavigationContainer.PageTree.refreshTree()}})}s.dismiss()})}static copy(e,t){const n=TYPO3.settings.ajaxUrls.contextmenu_clipboard+"&CB[el]["+e+"%7C"+t+"]=1&CB[setCopyMode]=1";new i(n).get().finally(()=>{g.triggerRefresh(d.ContentContainer.get().location.href)})}static clipboardRelease(e,t){const n=TYPO3.settings.ajaxUrls.contextmenu_clipboard+"&CB[el]["+e+"%7C"+t+"]=0";new i(n).get().finally(()=>{g.triggerRefresh(d.ContentContainer.get().location.href)})}static cut(e,t){const n=TYPO3.settings.ajaxUrls.contextmenu_clipboard+"&CB[el]["+e+"%7C"+t+"]=1&CB[setCopyMode]=0";new i(n).get().finally(()=>{g.triggerRefresh(d.ContentContainer.get().location.href)})}static triggerRefresh(e){e.includes("record%2Fedit")||d.ContentContainer.refresh()}static clearCache(e,t){new i(TYPO3.settings.ajaxUrls.web_list_clearpagecache).withQueryArguments({id:t}).get({cache:"no-cache"}).then(async e=>{const t=await e.resolve();!0===t.success?c.success(t.title,t.message,1):c.error(t.title,t.message,1)},()=>{c.error("Clearing page caches went wrong on the server side.")})}static pasteAfter(e,t){g.pasteInto.bind(a(this))(e,-t)}static pasteInto(e,t){const r=a(this),i=()=>{const n="&CB[paste]="+e+"%7C"+t+"&CB[pad]=normal&redirect="+g.getReturnUrl();d.ContentContainer.setUrl(top.TYPO3.settings.RecordCommit.moduleUrl+n).done(()=>{"pages"===e&&d.NavigationContainer.PageTree&&d.NavigationContainer.PageTree.refreshTree()})};r.data("title")?s.confirm(r.data("title"),r.data("message"),n.SeverityEnum.warning,[{text:a(this).data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",name:"cancel"},{text:a(this).data("button-ok-text")||TYPO3.lang["button.ok"]||"OK",btnClass:"btn-warning",name:"ok"}]).on("button.clicked",e=>{"ok"===e.target.getAttribute("name")&&i(),s.dismiss()}):i()}}return g})); \ No newline at end of file diff --git a/typo3/sysext/recordlist/Resources/Public/JavaScript/Recordlist.js b/typo3/sysext/recordlist/Resources/Public/JavaScript/Recordlist.js index e32744f9c827..bab0e1a5165b 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! */ -define(["require","exports","jquery","TYPO3/CMS/Backend/Storage/Persistent","TYPO3/CMS/Backend/Icons"],(function(t,e,i,s,a){"use strict";return new class{constructor(){this.identifier={entity:".t3js-entity",toggle:".t3js-toggle-recordlist",localize:".t3js-action-localize",icons:{collapse:"actions-view-list-collapse",expand:"actions-view-list-expand",editMultiple:".t3js-record-edit-multiple"}},this.toggleClick=t=>{t.preventDefault();const e=i(t.currentTarget),n=e.data("table"),l=i(e.data("target")),d="expanded"===l.data("state"),o=e.find(".collapseIcon"),c=d?this.identifier.icons.expand:this.identifier.icons.collapse;a.getIcon(c,a.sizes.small).done(t=>{o.html(t)});let r={};s.isset("moduleData.list")&&(r=s.get("moduleData.list"));const u={};u[n]=d?1:0,i.extend(!0,r,u),s.set("moduleData.list",r).done(()=>{l.data("state",d?"collapsed":"expanded")})},this.onEditMultiple=t=>{let e,s,a,n,l;t.preventDefault(),e=i(t.currentTarget).closest("[data-table]"),0!==e.length&&(n=i(t.currentTarget).data("uri"),s=e.data("table"),a=e.find(this.identifier.entity+'[data-uid][data-table="'+s+'"]').map((t,e)=>i(e).data("uid")).toArray().join(","),l=n.match(/{[^}]+}/g),i.each(l,(t,e)=>{const l=e.substr(1,e.length-2).split(":");let d;switch(l.shift()){case"entityIdentifiers":d=a;break;case"T3_THIS_LOCATION":d=T3_THIS_LOCATION;break;default:return}i.each(l,(t,e)=>{"editList"===e&&(d=this.editList(s,d))}),n=n.replace(e,d)}),window.location.href=n)},this.disableButton=t=>{i(t.currentTarget).prop("disable",!0).addClass("disabled")},i(document).on("click",this.identifier.toggle,this.toggleClick),i(document).on("click",this.identifier.icons.editMultiple,this.onEditMultiple),i(document).on("click",this.identifier.localize,this.disableButton)}editList(t,e){const i=[];let s=0,a=e.indexOf(",");for(;-1!==a;)this.getCheckboxState(t+"|"+e.substr(s,a-s))&&i.push(e.substr(s,a-s)),s=a+1,a=e.indexOf(",",s);return this.getCheckboxState(t+"|"+e.substr(s))&&i.push(e.substr(s)),i.length>0?i.join(","):e}getCheckboxState(t){const e="CBC["+t+"]";return document.querySelector('form[name="dblistForm"] [name="'+e+'"]').checked}}})); \ No newline at end of file +define(["require","exports","jquery","TYPO3/CMS/Backend/Icons","TYPO3/CMS/Backend/Storage/Persistent","TYPO3/CMS/Core/Event/RegularEvent","TYPO3/CMS/Backend/Viewport"],(function(t,e,i,a,n,s,l){"use strict";return new class{constructor(){this.identifier={entity:".t3js-entity",toggle:".t3js-toggle-recordlist",localize:".t3js-action-localize",icons:{collapse:"actions-view-list-collapse",expand:"actions-view-list-expand",editMultiple:".t3js-record-edit-multiple"}},this.toggleClick=t=>{t.preventDefault();const e=i(t.currentTarget),s=e.data("table"),l=i(e.data("target")),d="expanded"===l.data("state"),o=e.find(".collapseIcon"),r=d?this.identifier.icons.expand:this.identifier.icons.collapse;a.getIcon(r,a.sizes.small).done(t=>{o.html(t)});let c={};n.isset("moduleData.list")&&(c=n.get("moduleData.list"));const u={};u[s]=d?1:0,i.extend(!0,c,u),n.set("moduleData.list",c).done(()=>{l.data("state",d?"collapsed":"expanded")})},this.onEditMultiple=t=>{let e,a,n,s,l;t.preventDefault(),e=i(t.currentTarget).closest("[data-table]"),0!==e.length&&(s=i(t.currentTarget).data("uri"),a=e.data("table"),n=e.find(this.identifier.entity+'[data-uid][data-table="'+a+'"]').map((t,e)=>i(e).data("uid")).toArray().join(","),l=s.match(/{[^}]+}/g),i.each(l,(t,e)=>{const l=e.substr(1,e.length-2).split(":");let d;switch(l.shift()){case"entityIdentifiers":d=n;break;case"T3_THIS_LOCATION":d=T3_THIS_LOCATION;break;default:return}i.each(l,(t,e)=>{"editList"===e&&(d=this.editList(a,d))}),s=s.replace(e,d)}),window.location.href=s)},this.disableButton=t=>{i(t.currentTarget).prop("disable",!0).addClass("disabled")},this.deleteRow=t=>{if(t.detail.hasErrors)return;if("datahandler"===t.detail.component)return;const e=i(`table[data-table="${t.detail.table}"]`),a=e.find(`tr[data-uid="${t.detail.uid}"]`),n=e.closest(".panel"),s=n.find(".panel-heading"),d=e.find(`[data-l10nparent="${t.detail.uid}"]`),o=i().add(a).add(d);if(o.fadeTo("slow",.4,()=>{o.slideUp("slow",()=>{o.remove(),0===e.find("tbody tr").length&&n.slideUp("slow")})}),"0"===a.data("l10nparent")||""===a.data("l10nparent")){const t=Number(s.find(".t3js-table-total-items").html());s.find(".t3js-table-total-items").text(t-1)}"pages"===t.detail.table&&l.NavigationContainer.PageTree.refreshTree()},i(document).on("click",this.identifier.toggle,this.toggleClick),i(document).on("click",this.identifier.icons.editMultiple,this.onEditMultiple),i(document).on("click",this.identifier.localize,this.disableButton),new s("datahandler:process:delete",this.deleteRow).bindTo(document)}editList(t,e){const i=[];let a=0,n=e.indexOf(",");for(;-1!==n;)this.getCheckboxState(t+"|"+e.substr(a,n-a))&&i.push(e.substr(a,n-a)),a=n+1,n=e.indexOf(",",a);return this.getCheckboxState(t+"|"+e.substr(a))&&i.push(e.substr(a)),i.length>0?i.join(","):e}getCheckboxState(t){const e="CBC["+t+"]";return document.querySelector('form[name="dblistForm"] [name="'+e+'"]').checked}}})); \ No newline at end of file diff --git a/typo3/sysext/tstemplate/Resources/Private/Templates/InformationModule.html b/typo3/sysext/tstemplate/Resources/Private/Templates/InformationModule.html index 207123e48e5f..2a6dd3a71a51 100644 --- a/typo3/sysext/tstemplate/Resources/Private/Templates/InformationModule.html +++ b/typo3/sysext/tstemplate/Resources/Private/Templates/InformationModule.html @@ -1,3 +1,4 @@ +<f:be.pageRenderer includeRequireJsModules="{0: 'TYPO3/CMS/Tstemplate/InformationModule'}" /> <h3><f:translate key="{LLPrefix}templateInformation"/></h3> <div> <f:if condition="{siteTitle}">({siteTitle})</f:if> diff --git a/typo3/sysext/tstemplate/Resources/Public/JavaScript/InformationModule.js b/typo3/sysext/tstemplate/Resources/Public/JavaScript/InformationModule.js new file mode 100644 index 000000000000..61a49c747624 --- /dev/null +++ b/typo3/sysext/tstemplate/Resources/Public/JavaScript/InformationModule.js @@ -0,0 +1,13 @@ +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ +define(["require","exports","TYPO3/CMS/Core/Event/RegularEvent"],(function(e,t,r){"use strict";return new class{constructor(){this.registerEventListeners()}registerEventListeners(){new r("datahandler:process:delete",e=>{document.location.reload()}).bindTo(document)}}})); \ No newline at end of file -- GitLab