From 9199f2540db48dab3ddd2d0fa9434baf58744c1a Mon Sep 17 00:00:00 2001 From: Oliver Hader <oliver@typo3.org> Date: Mon, 13 Apr 2020 19:27:49 +0200 Subject: [PATCH] [TASK] Reduce inline JavaScript in ext:filelist This change aims to reduce the amount of inline JavaScript by removing `onchange` or `onclick` events and dynamically created JavaScript code/settings. There are still a couple of aspects that need to be solved in a general way - e.g. assigning global language labels (`TYPO3.lang`) or settings (`TYPO3.settings`). * allows `Modal` confirmation to emit `ModalResponseEvent` * extracts inline JavaScript from controllers & templates * introduces `BroadcastChannel` in `nav_frame` (folder tree) * uses plain links (`<a href="..."`) where applicable * updates folder tree when navigating in browser history Resolves: #91016 Releases: master Change-Id: Ied6a626e09df07bd1a240b9b6b4250cd6fff4c8a Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/64154 Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de> Tested-by: TYPO3com <noreply@typo3.com> Tested-by: Benni Mack <benni@typo3.org> Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de> Reviewed-by: Benni Mack <benni@typo3.org> --- .../Resources/Public/TypeScript/Modal.ts | 24 +++++- .../Public/TypeScript/ModalInterface.ts | 19 +++++ .../Public/TypeScript/CreateFolder.ts | 73 +++++++++++++++++ .../Resources/Public/TypeScript/FileList.ts | 80 +++++++++++++++--- .../Public/TypeScript/FileReplace.ts | 34 ++++++++ .../FileSystemNavigationFrameController.php | 1 + .../Resources/Public/JavaScript/LegacyTree.js | 11 ++- .../Resources/Public/JavaScript/Modal.js | 2 +- .../Public/JavaScript/ModalInterface.js | 13 +++ .../File/CreateFolderController.php | 66 ++++++--------- .../Controller/File/EditFileController.php | 42 ++++------ .../Controller/File/RenameFileController.php | 6 -- .../Controller/File/ReplaceFileController.php | 5 +- .../Classes/Controller/FileListController.php | 34 +++----- typo3/sysext/filelist/Classes/FileList.php | 82 +++++++++++-------- .../Resources/Private/Layouts/Default.html | 7 +- .../Private/Templates/File/CreateFolder.html | 8 +- .../Private/Templates/File/ReplaceFile.html | 19 ++--- .../Public/JavaScript/CreateFolder.js | 13 +++ .../Resources/Public/JavaScript/FileList.js | 2 +- .../Public/JavaScript/FileReplace.js | 13 +++ 21 files changed, 388 insertions(+), 166 deletions(-) create mode 100644 Build/Sources/TypeScript/backend/Resources/Public/TypeScript/ModalInterface.ts create mode 100644 Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/CreateFolder.ts create mode 100644 Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileReplace.ts create mode 100644 typo3/sysext/backend/Resources/Public/JavaScript/ModalInterface.js create mode 100644 typo3/sysext/filelist/Resources/Public/JavaScript/CreateFolder.js create mode 100644 typo3/sysext/filelist/Resources/Public/JavaScript/FileReplace.js diff --git a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/Modal.ts b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/Modal.ts index e706f36ae226..61ebe1125962 100644 --- a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/Modal.ts +++ b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/Modal.ts @@ -15,6 +15,7 @@ import 'bootstrap'; import * as $ from 'jquery'; import {AjaxResponse} from 'TYPO3/CMS/Core/Ajax/AjaxResponse'; import {AbstractAction} from './ActionButton/AbstractAction'; +import {ModalResponseEvent} from 'TYPO3/CMS/Backend/ModalInterface'; import {SeverityEnum} from './Enum/Severity'; import AjaxRequest = require('TYPO3/CMS/Core/Ajax/AjaxRequest'); import SecurityUtility = require('TYPO3/CMS/Core/SecurityUtility'); @@ -123,6 +124,16 @@ class Modal { private readonly securityUtility: SecurityUtility; + private static createModalResponseEventFromElement(element: HTMLElement, result: boolean): ModalResponseEvent | null { + if (!element.dataset.eventName) { + return null; + } + return new CustomEvent( + element.dataset.eventName, { + detail: { result, payload: element.dataset.eventPayload || null } + }); + } + constructor(securityUtility: SecurityUtility) { this.securityUtility = securityUtility; $(document).on('modal-dismiss', this.dismiss); @@ -377,6 +388,10 @@ class Modal { btnClass: 'btn-default', trigger: (): void => { this.currentModal.trigger('modal-dismiss'); + const event = Modal.createModalResponseEventFromElement(evt.currentTarget as HTMLElement, false); + if (event !== null) { + evt.currentTarget.dispatchEvent(event); + } }, }, { @@ -384,7 +399,14 @@ class Modal { btnClass: 'btn-' + Severity.getCssClass(severity), trigger: (): void => { this.currentModal.trigger('modal-dismiss'); - evt.target.ownerDocument.location.href = $element.data('href') || $element.attr('href'); + const event = Modal.createModalResponseEventFromElement(evt.currentTarget as HTMLElement, true); + if (event !== null) { + evt.currentTarget.dispatchEvent(event); + } + const href = $element.data('href') || $element.attr('href'); + if (href && href !== '#') { + evt.target.ownerDocument.location.href = href; + } }, }, ], diff --git a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/ModalInterface.ts b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/ModalInterface.ts new file mode 100644 index 000000000000..9a123380fe22 --- /dev/null +++ b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/ModalInterface.ts @@ -0,0 +1,19 @@ +/* + * 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! + */ + +export interface ModalResponseEvent extends CustomEvent { + readonly detail: { + result: boolean, + payload: any + }; +} diff --git a/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/CreateFolder.ts b/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/CreateFolder.ts new file mode 100644 index 000000000000..15b5f53710d3 --- /dev/null +++ b/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/CreateFolder.ts @@ -0,0 +1,73 @@ +/* + * 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 * as $ from 'jquery'; +import Modal = require('TYPO3/CMS/Backend/Modal'); +import RegularEvent = require('TYPO3/CMS/Core/Event/RegularEvent'); + +/** + * Module: TYPO3/CMS/Filelist/CreateFolder + * @exports TYPO3/CMS/Filelist/CreateFolder + */ +class CreateFolder { + private selfUrl: string; + private confirmTitle: string; + private confirmText: string; + private changed: boolean = false; + + constructor() { + $((): void => { + const mainElement: HTMLElement = document.querySelector('.filelist-create-folder-main'); + if (!(mainElement instanceof HTMLElement)) { + throw new Error('Main element not found'); + } + this.selfUrl = mainElement.dataset.selfUrl; + this.confirmTitle = mainElement.dataset.confirmTitle; + this.confirmText = mainElement.dataset.confirmText; + this.registerEvents(); + }); + } + + public reload(amount: number): void { + const url = this.selfUrl.replace(/AMOUNT/, amount.toString()); + if (!this.changed) { + window.location.href = url; + } else { + const modal = Modal.confirm(this.confirmTitle, this.confirmText); + modal.on('confirm.button.cancel', (): void => { + modal.trigger('modal-dismiss'); + }); + modal.on('confirm.button.ok', (): void => { + modal.trigger('modal-dismiss'); + window.location.href = url; + }); + } + } + + private registerEvents(): void { + const inputElementSelectors = [ + 'input[type="text"][name^="data[newfolder]"]', + 'input[type="text"][name^="data[newfile]"]', + 'input[type="text"][name^="data[newMedia]"]' + ]; + new RegularEvent('change', (): void => { + this.changed = true; + }).delegateTo(document, inputElementSelectors.join(',')); + new RegularEvent('change', (e: Event): void => { + const amount = parseInt((e.target as HTMLSelectElement).value, 10); + this.reload(amount); + }).bindTo(document.getElementById('number-of-new-folders')); + } +} + +export = new CreateFolder(); diff --git a/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileList.ts b/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileList.ts index 4cb94e4c4dd0..df34f205079f 100644 --- a/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileList.ts +++ b/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileList.ts @@ -13,31 +13,81 @@ import * as $ from 'jquery'; import InfoWindow = require('TYPO3/CMS/Backend/InfoWindow'); +import {BroadcastMessage} from 'TYPO3/CMS/Backend/BroadcastMessage'; +import {ModalResponseEvent} from 'TYPO3/CMS/Backend/ModalInterface'; +import broadcastService = require('TYPO3/CMS/Backend/BroadcastService'); +import RegularEvent = require('TYPO3/CMS/Core/Event/RegularEvent'); /** * Module: TYPO3/CMS/Filelist/Filelist * @exports TYPO3/CMS/Filelist/Filelist */ class Filelist { - /** - * @param identifier - */ - private static openFileInfoPopup(identifier: string): void { - InfoWindow.showItem('_FILE', identifier); + protected static openInfoPopup(type: string, identifier: string): void { + InfoWindow.showItem(type, identifier); + } + + private static processTriggers(): void { + const mainElement: HTMLElement = document.querySelector('.filelist-main'); + if (mainElement === null) { + return + } + // emit event for currently shown folder + Filelist.emitTreeUpdateRequest( + mainElement.dataset.filelistCurrentFolderHash + ); + // update recentIds (for whatever reason) + if (top.fsMod && top.fsMod.recentIds instanceof Object) { + top.fsMod.recentIds.file = encodeURIComponent(mainElement.dataset.filelistCurrentIdentifier); + } + } + + private static registerTreeUpdateEvents(): void { + // listen potential change of folder + new RegularEvent('click', function (this: HTMLElement): void { + Filelist.emitTreeUpdateRequest( + this.dataset.treeUpdateRequest + ); + }).delegateTo(document.body, '[data-tree-update-request]'); + } + + private static emitTreeUpdateRequest(identifier: string): void { + const message = new BroadcastMessage( + 'filelist', + 'treeUpdateRequested', + {type: 'folder', identifier: identifier} + ); + broadcastService.post(message); + } + + private static submitClipboardFormWithCommand(cmd: string): void { + const $form = $('form[name="dblistForm"]'); + $form.find('input[name="cmd"]').val(cmd); + $form.submit(); } constructor() { + Filelist.processTriggers(); $((): void => { + Filelist.registerTreeUpdateEvents(); + // file index events + $('[data-filelist-show-item-identifier][data-filelist-show-item-type]').click((evt: JQueryEventObject): void => { + const $element = $(evt.currentTarget); + evt.preventDefault(); + Filelist.openInfoPopup( + $element.data('filelistShowItemType'), + $element.data('filelistShowItemIdentifier') + ); + }); + // file search events $('a.btn.filelist-file-info').click((event: JQueryEventObject): void => { event.preventDefault(); - Filelist.openFileInfoPopup($(event.currentTarget).attr('data-identifier')); + Filelist.openInfoPopup('_FILE', $(event.currentTarget).attr('data-identifier')); }); - $('a.filelist-file-references').click((event: JQueryEventObject): void => { event.preventDefault(); - Filelist.openFileInfoPopup($(event.currentTarget).attr('data-identifier')); + Filelist.openInfoPopup('_FILE', $(event.currentTarget).attr('data-identifier')); }); - $('a.btn.filelist-file-copy').click((event: JQueryEventObject): void => { event.preventDefault(); const $element = $(event.currentTarget); @@ -45,9 +95,19 @@ class Filelist { let redirectUrl = (url) ? encodeURIComponent(url) : encodeURIComponent(top.list_frame.document.location.pathname + top.list_frame.document.location.search); - top.list_frame.location.href = url + '&redirect=' + redirectUrl; }); + // clipboard events + $('[data-event-name="filelist:clipboard:cmd"]').on('filelist:clipboard:cmd', (evt: JQueryEventObject) => { + const originalEvent = evt.originalEvent as ModalResponseEvent; + if (originalEvent.detail.result) { + Filelist.submitClipboardFormWithCommand(originalEvent.detail.payload); + } + }); + $('[data-filelist-clipboard-cmd]:not([data-filelist-clipboard-cmd=""])').click((evt: JQueryEventObject): void => { + const cmd = $(evt.currentTarget).data('filelistClipboardCmd'); + Filelist.submitClipboardFormWithCommand(cmd); + }); }); } } diff --git a/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileReplace.ts b/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileReplace.ts new file mode 100644 index 000000000000..13612df28c3a --- /dev/null +++ b/Build/Sources/TypeScript/filelist/Resources/Public/TypeScript/FileReplace.ts @@ -0,0 +1,34 @@ +/* + * 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 FileReplace { + constructor() { + this.registerEvents(); + } + + private registerEvents(): void { + new RegularEvent('click', function (this: HTMLElement): void { + const targetSelector = this.dataset.filelistClickTarget; + (document.querySelector(targetSelector) as HTMLElement).click(); + }).delegateTo(document.body, '[data-filelist-click-target]:not([data-filelist-click-target=""]'); + + new RegularEvent('change', function (this: HTMLInputElement): void { + const targetSelector = this.dataset.filelistChangeTarget; + (document.querySelector(targetSelector) as HTMLInputElement).value = this.value; + }).delegateTo(document.body, '[data-filelist-change-target]:not([data-filelist-change-target=""])'); + } +} + +export = new FileReplace(); diff --git a/typo3/sysext/backend/Classes/Controller/FileSystemNavigationFrameController.php b/typo3/sysext/backend/Classes/Controller/FileSystemNavigationFrameController.php index 17911be79543..611a2ad317e2 100644 --- a/typo3/sysext/backend/Classes/Controller/FileSystemNavigationFrameController.php +++ b/typo3/sysext/backend/Classes/Controller/FileSystemNavigationFrameController.php @@ -161,6 +161,7 @@ class FileSystemNavigationFrameController // Adding javascript for drag & drop activation and highlighting $pageRenderer = $this->moduleTemplate->getPageRenderer(); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu'); + $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/BroadcastService', 'function(service) { service.listen(); }'); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyTree', 'function() { DragDrop.table = "folders"; Tree.registerDragDropHandlers(); diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/LegacyTree.js b/typo3/sysext/backend/Resources/Public/JavaScript/LegacyTree.js index 389e535dbbd8..5c904b4ddb50 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/LegacyTree.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/LegacyTree.js @@ -23,7 +23,6 @@ var Tree, DragDrop; * @exports TYPO3/CMS/Backend/LegacyTree */ define(['jquery'], function($) { - DragDrop = { dragID: null, table: null // can be "pages" or "folders", needed for doing the changes when dropping @@ -214,5 +213,15 @@ define(['jquery'], function($) { } }; + // event listener updating current tree state + document.addEventListener('typo3:filelist:treeUpdateRequested', (evt) => { + var identifier = evt.detail.payload.identifier; + // @todo currentBank is not defined unless item was clicked in tree + if (top.fsMod && top.fsMod.currentBank) { + identifier += '_' + top.fsMod.currentBank; + } + Tree.highlightActiveItem('file', identifier); + }); + return Tree; }); diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/Modal.js b/typo3/sysext/backend/Resources/Public/JavaScript/Modal.js index 9b50004fc5c7..755df6112dcd 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/Modal.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/Modal.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -define(["require","exports","jquery","./Enum/Severity","TYPO3/CMS/Core/Ajax/AjaxRequest","TYPO3/CMS/Core/SecurityUtility","./Icons","./Severity","bootstrap"],(function(t,e,a,n,i,s,l,o){"use strict";var d,r,c,u;!function(t){t.modal=".t3js-modal",t.content=".t3js-modal-content",t.title=".t3js-modal-title",t.close=".t3js-modal-close",t.body=".t3js-modal-body",t.footer=".t3js-modal-footer",t.iframe=".t3js-modal-iframe",t.iconPlaceholder=".t3js-modal-icon-placeholder"}(d||(d={})),function(t){t.small="small",t.default="default",t.medium="medium",t.large="large",t.full="full"}(r||(r={})),function(t){t.default="default",t.light="light",t.dark="dark"}(c||(c={})),function(t){t.default="default",t.ajax="ajax",t.iframe="iframe"}(u||(u={}));class f{constructor(t){this.sizes=r,this.styles=c,this.types=u,this.currentModal=null,this.instances=[],this.$template=a('<div class="t3js-modal modal fade"><div class="modal-dialog"><div class="t3js-modal-content modal-content"><div class="modal-header"><button class="t3js-modal-close close"><span aria-hidden="true"><span class="t3js-modal-icon-placeholder" data-icon="actions-close"></span></span><span class="sr-only"></span></button><h4 class="t3js-modal-title modal-title"></h4></div><div class="t3js-modal-body modal-body"></div><div class="t3js-modal-footer modal-footer"></div></div></div></div>'),this.defaultConfiguration={type:u.default,title:"Information",content:"No content provided, please check your <code>Modal</code> configuration.",severity:n.SeverityEnum.notice,buttons:[],style:c.default,size:r.default,additionalCssClasses:[],callback:a.noop(),ajaxCallback:a.noop(),ajaxTarget:null},this.securityUtility=t,a(document).on("modal-dismiss",this.dismiss),this.initializeMarkupTrigger(document)}dismiss(){this.currentModal&&this.currentModal.modal("hide")}confirm(t,e,i=n.SeverityEnum.warning,s=[],l){return 0===s.length&&s.push({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-"+o.getCssClass(i),name:"ok"}),this.advanced({title:t,content:e,severity:i,buttons:s,additionalCssClasses:l,callback:t=>{t.on("button.clicked",t=>{"cancel"===t.target.getAttribute("name")?a(t.currentTarget).trigger("confirm.button.cancel"):"ok"===t.target.getAttribute("name")&&a(t.currentTarget).trigger("confirm.button.ok")})}})}loadUrl(t,e=n.SeverityEnum.info,a,i,s,l){return this.advanced({type:u.ajax,title:t,severity:e,buttons:a,ajaxCallback:s,ajaxTarget:l,content:i})}show(t,e,a=n.SeverityEnum.info,i,s){return this.advanced({type:u.default,title:t,content:e,severity:a,buttons:i,additionalCssClasses:s})}advanced(t){return t.type="string"==typeof t.type&&t.type in u?t.type:this.defaultConfiguration.type,t.title="string"==typeof t.title?t.title:this.defaultConfiguration.title,t.content="string"==typeof t.content||"object"==typeof t.content?t.content:this.defaultConfiguration.content,t.severity=void 0!==t.severity?t.severity:this.defaultConfiguration.severity,t.buttons=t.buttons||this.defaultConfiguration.buttons,t.size="string"==typeof t.size&&t.size in r?t.size:this.defaultConfiguration.size,t.style="string"==typeof t.style&&t.style in c?t.style:this.defaultConfiguration.style,t.additionalCssClasses=t.additionalCssClasses||this.defaultConfiguration.additionalCssClasses,t.callback="function"==typeof t.callback?t.callback:this.defaultConfiguration.callback,t.ajaxCallback="function"==typeof t.ajaxCallback?t.ajaxCallback:this.defaultConfiguration.ajaxCallback,t.ajaxTarget="string"==typeof t.ajaxTarget?t.ajaxTarget:this.defaultConfiguration.ajaxTarget,this.generate(t)}setButtons(t){const e=this.currentModal.find(d.footer);if(t.length>0){e.empty();for(let n=0;n<t.length;n++){const i=t[n],s=a("<button />",{class:"btn"});s.html("<span>"+this.securityUtility.encodeHtml(i.text,!1)+"</span>"),i.active&&s.addClass("t3js-active"),""!==i.btnClass&&s.addClass(i.btnClass),""!==i.name&&s.attr("name",i.name),i.action?s.on("click",()=>{e.find("button").not(s).addClass("disabled"),i.action.execute(s.get(0)).then(()=>{this.currentModal.modal("hide")})}):i.trigger&&s.on("click",i.trigger),i.dataAttributes&&Object.keys(i.dataAttributes).length>0&&Object.keys(i.dataAttributes).map(t=>{s.attr("data-"+t,i.dataAttributes[t])}),i.icon&&s.prepend('<span class="t3js-modal-icon-placeholder" data-icon="'+i.icon+'"></span>'),e.append(s)}e.show(),e.find("button").on("click",t=>{a(t.currentTarget).trigger("button.clicked")})}else e.hide();return this.currentModal}initializeMarkupTrigger(t){a(t).on("click",".t3js-modal-trigger",t=>{t.preventDefault();const e=a(t.currentTarget),i=e.data("content")||"Are you sure?",s=void 0!==n.SeverityEnum[e.data("severity")]?n.SeverityEnum[e.data("severity")]:n.SeverityEnum.info;let l=e.data("url")||null;if(null!==l){const t=l.includes("?")?"&":"?";l=l+t+a.param({data:e.data()})}this.advanced({type:null!==l?u.ajax:u.default,title:e.data("title")||"Alert",content:null!==l?l:i,severity:s,buttons:[{text:e.data("button-close-text")||TYPO3.lang["button.close"]||"Close",active:!0,btnClass:"btn-default",trigger:()=>{this.currentModal.trigger("modal-dismiss")}},{text:e.data("button-ok-text")||TYPO3.lang["button.ok"]||"OK",btnClass:"btn-"+o.getCssClass(s),trigger:()=>{this.currentModal.trigger("modal-dismiss"),t.target.ownerDocument.location.href=e.data("href")||e.attr("href")}}]})})}generate(t){const e=this.$template.clone();if(t.additionalCssClasses.length>0)for(let a of t.additionalCssClasses)e.addClass(a);if(e.addClass("modal-type-"+t.type),e.addClass("modal-severity-"+o.getCssClass(t.severity)),e.addClass("modal-style-"+t.style),e.addClass("modal-size-"+t.size),e.attr("tabindex","-1"),e.find(d.title).text(t.title),e.find(d.close).on("click",()=>{e.modal("hide")}),"ajax"===t.type){const a=t.ajaxTarget?t.ajaxTarget:d.body,n=e.find(a);l.getIcon("spinner-circle",l.sizes.default,null,null,l.markupIdentifiers.inline).then(e=>{n.html('<div class="modal-loading">'+e+"</div>"),new i(t.content).get().then(async e=>{this.currentModal.find(a).empty().append(await e.raw().text()),t.ajaxCallback&&t.ajaxCallback(),this.currentModal.trigger("modal-loaded")})})}else"iframe"===t.type?(e.find(d.body).append(a("<iframe />",{src:t.content,name:"modal_frame",class:"modal-iframe t3js-modal-iframe"})),e.find(d.iframe).on("load",()=>{e.find(d.title).text(e.find(d.iframe).get(0).contentDocument.title)})):("string"==typeof t.content&&(t.content=a("<p />").html(this.securityUtility.encodeHtml(t.content))),e.find(d.body).append(t.content));return e.on("shown.bs.modal",t=>{const e=a(t.currentTarget);e.find(d.footer).find(".t3js-active").first().focus(),e.find(d.iconPlaceholder).each((t,e)=>{l.getIcon(a(e).data("icon"),l.sizes.small,null,null,l.markupIdentifiers.inline).then(t=>{this.currentModal.find(d.iconPlaceholder+"[data-icon="+a(t).data("identifier")+"]").replaceWith(t)})})}),e.on("hidden.bs.modal",t=>{if(this.instances.length>0){const t=this.instances.length-1;this.instances.splice(t,1),this.currentModal=this.instances[t-1]}e.trigger("modal-destroyed"),a(t.currentTarget).remove(),this.instances.length>0&&a("body").addClass("modal-open")}),e.on("show.bs.modal",e=>{this.currentModal=a(e.currentTarget),this.setButtons(t.buttons),this.instances.push(this.currentModal)}),e.on("modal-dismiss",t=>{a(t.currentTarget).modal("hide")}),t.callback&&t.callback(e),e.modal()}}let m=null;try{parent&&parent.window.TYPO3&&parent.window.TYPO3.Modal?(parent.window.TYPO3.Modal.initializeMarkupTrigger(document),m=parent.window.TYPO3.Modal):top&&top.TYPO3.Modal&&(top.TYPO3.Modal.initializeMarkupTrigger(document),m=top.TYPO3.Modal)}catch(t){}return m||(m=new f(new s),TYPO3.Modal=m),m})); \ No newline at end of file +define(["require","exports","jquery","./Enum/Severity","TYPO3/CMS/Core/Ajax/AjaxRequest","TYPO3/CMS/Core/SecurityUtility","./Icons","./Severity","bootstrap"],(function(t,e,a,n,s,i,l,o){"use strict";var d,r,c,u;!function(t){t.modal=".t3js-modal",t.content=".t3js-modal-content",t.title=".t3js-modal-title",t.close=".t3js-modal-close",t.body=".t3js-modal-body",t.footer=".t3js-modal-footer",t.iframe=".t3js-modal-iframe",t.iconPlaceholder=".t3js-modal-icon-placeholder"}(d||(d={})),function(t){t.small="small",t.default="default",t.medium="medium",t.large="large",t.full="full"}(r||(r={})),function(t){t.default="default",t.light="light",t.dark="dark"}(c||(c={})),function(t){t.default="default",t.ajax="ajax",t.iframe="iframe"}(u||(u={}));class m{constructor(t){this.sizes=r,this.styles=c,this.types=u,this.currentModal=null,this.instances=[],this.$template=a('<div class="t3js-modal modal fade"><div class="modal-dialog"><div class="t3js-modal-content modal-content"><div class="modal-header"><button class="t3js-modal-close close"><span aria-hidden="true"><span class="t3js-modal-icon-placeholder" data-icon="actions-close"></span></span><span class="sr-only"></span></button><h4 class="t3js-modal-title modal-title"></h4></div><div class="t3js-modal-body modal-body"></div><div class="t3js-modal-footer modal-footer"></div></div></div></div>'),this.defaultConfiguration={type:u.default,title:"Information",content:"No content provided, please check your <code>Modal</code> configuration.",severity:n.SeverityEnum.notice,buttons:[],style:c.default,size:r.default,additionalCssClasses:[],callback:a.noop(),ajaxCallback:a.noop(),ajaxTarget:null},this.securityUtility=t,a(document).on("modal-dismiss",this.dismiss),this.initializeMarkupTrigger(document)}static createModalResponseEventFromElement(t,e){return t.dataset.eventName?new CustomEvent(t.dataset.eventName,{detail:{result:e,payload:t.dataset.eventPayload||null}}):null}dismiss(){this.currentModal&&this.currentModal.modal("hide")}confirm(t,e,s=n.SeverityEnum.warning,i=[],l){return 0===i.length&&i.push({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-"+o.getCssClass(s),name:"ok"}),this.advanced({title:t,content:e,severity:s,buttons:i,additionalCssClasses:l,callback:t=>{t.on("button.clicked",t=>{"cancel"===t.target.getAttribute("name")?a(t.currentTarget).trigger("confirm.button.cancel"):"ok"===t.target.getAttribute("name")&&a(t.currentTarget).trigger("confirm.button.ok")})}})}loadUrl(t,e=n.SeverityEnum.info,a,s,i,l){return this.advanced({type:u.ajax,title:t,severity:e,buttons:a,ajaxCallback:i,ajaxTarget:l,content:s})}show(t,e,a=n.SeverityEnum.info,s,i){return this.advanced({type:u.default,title:t,content:e,severity:a,buttons:s,additionalCssClasses:i})}advanced(t){return t.type="string"==typeof t.type&&t.type in u?t.type:this.defaultConfiguration.type,t.title="string"==typeof t.title?t.title:this.defaultConfiguration.title,t.content="string"==typeof t.content||"object"==typeof t.content?t.content:this.defaultConfiguration.content,t.severity=void 0!==t.severity?t.severity:this.defaultConfiguration.severity,t.buttons=t.buttons||this.defaultConfiguration.buttons,t.size="string"==typeof t.size&&t.size in r?t.size:this.defaultConfiguration.size,t.style="string"==typeof t.style&&t.style in c?t.style:this.defaultConfiguration.style,t.additionalCssClasses=t.additionalCssClasses||this.defaultConfiguration.additionalCssClasses,t.callback="function"==typeof t.callback?t.callback:this.defaultConfiguration.callback,t.ajaxCallback="function"==typeof t.ajaxCallback?t.ajaxCallback:this.defaultConfiguration.ajaxCallback,t.ajaxTarget="string"==typeof t.ajaxTarget?t.ajaxTarget:this.defaultConfiguration.ajaxTarget,this.generate(t)}setButtons(t){const e=this.currentModal.find(d.footer);if(t.length>0){e.empty();for(let n=0;n<t.length;n++){const s=t[n],i=a("<button />",{class:"btn"});i.html("<span>"+this.securityUtility.encodeHtml(s.text,!1)+"</span>"),s.active&&i.addClass("t3js-active"),""!==s.btnClass&&i.addClass(s.btnClass),""!==s.name&&i.attr("name",s.name),s.action?i.on("click",()=>{e.find("button").not(i).addClass("disabled"),s.action.execute(i.get(0)).then(()=>{this.currentModal.modal("hide")})}):s.trigger&&i.on("click",s.trigger),s.dataAttributes&&Object.keys(s.dataAttributes).length>0&&Object.keys(s.dataAttributes).map(t=>{i.attr("data-"+t,s.dataAttributes[t])}),s.icon&&i.prepend('<span class="t3js-modal-icon-placeholder" data-icon="'+s.icon+'"></span>'),e.append(i)}e.show(),e.find("button").on("click",t=>{a(t.currentTarget).trigger("button.clicked")})}else e.hide();return this.currentModal}initializeMarkupTrigger(t){a(t).on("click",".t3js-modal-trigger",t=>{t.preventDefault();const e=a(t.currentTarget),s=e.data("content")||"Are you sure?",i=void 0!==n.SeverityEnum[e.data("severity")]?n.SeverityEnum[e.data("severity")]:n.SeverityEnum.info;let l=e.data("url")||null;if(null!==l){const t=l.includes("?")?"&":"?";l=l+t+a.param({data:e.data()})}this.advanced({type:null!==l?u.ajax:u.default,title:e.data("title")||"Alert",content:null!==l?l:s,severity:i,buttons:[{text:e.data("button-close-text")||TYPO3.lang["button.close"]||"Close",active:!0,btnClass:"btn-default",trigger:()=>{this.currentModal.trigger("modal-dismiss");const e=m.createModalResponseEventFromElement(t.currentTarget,!1);null!==e&&t.currentTarget.dispatchEvent(e)}},{text:e.data("button-ok-text")||TYPO3.lang["button.ok"]||"OK",btnClass:"btn-"+o.getCssClass(i),trigger:()=>{this.currentModal.trigger("modal-dismiss");const a=m.createModalResponseEventFromElement(t.currentTarget,!0);null!==a&&t.currentTarget.dispatchEvent(a);const n=e.data("href")||e.attr("href");n&&"#"!==n&&(t.target.ownerDocument.location.href=n)}}]})})}generate(t){const e=this.$template.clone();if(t.additionalCssClasses.length>0)for(let a of t.additionalCssClasses)e.addClass(a);if(e.addClass("modal-type-"+t.type),e.addClass("modal-severity-"+o.getCssClass(t.severity)),e.addClass("modal-style-"+t.style),e.addClass("modal-size-"+t.size),e.attr("tabindex","-1"),e.find(d.title).text(t.title),e.find(d.close).on("click",()=>{e.modal("hide")}),"ajax"===t.type){const a=t.ajaxTarget?t.ajaxTarget:d.body,n=e.find(a);l.getIcon("spinner-circle",l.sizes.default,null,null,l.markupIdentifiers.inline).then(e=>{n.html('<div class="modal-loading">'+e+"</div>"),new s(t.content).get().then(async e=>{this.currentModal.find(a).empty().append(await e.raw().text()),t.ajaxCallback&&t.ajaxCallback(),this.currentModal.trigger("modal-loaded")})})}else"iframe"===t.type?(e.find(d.body).append(a("<iframe />",{src:t.content,name:"modal_frame",class:"modal-iframe t3js-modal-iframe"})),e.find(d.iframe).on("load",()=>{e.find(d.title).text(e.find(d.iframe).get(0).contentDocument.title)})):("string"==typeof t.content&&(t.content=a("<p />").html(this.securityUtility.encodeHtml(t.content))),e.find(d.body).append(t.content));return e.on("shown.bs.modal",t=>{const e=a(t.currentTarget);e.find(d.footer).find(".t3js-active").first().focus(),e.find(d.iconPlaceholder).each((t,e)=>{l.getIcon(a(e).data("icon"),l.sizes.small,null,null,l.markupIdentifiers.inline).then(t=>{this.currentModal.find(d.iconPlaceholder+"[data-icon="+a(t).data("identifier")+"]").replaceWith(t)})})}),e.on("hidden.bs.modal",t=>{if(this.instances.length>0){const t=this.instances.length-1;this.instances.splice(t,1),this.currentModal=this.instances[t-1]}e.trigger("modal-destroyed"),a(t.currentTarget).remove(),this.instances.length>0&&a("body").addClass("modal-open")}),e.on("show.bs.modal",e=>{this.currentModal=a(e.currentTarget),this.setButtons(t.buttons),this.instances.push(this.currentModal)}),e.on("modal-dismiss",t=>{a(t.currentTarget).modal("hide")}),t.callback&&t.callback(e),e.modal()}}let f=null;try{parent&&parent.window.TYPO3&&parent.window.TYPO3.Modal?(parent.window.TYPO3.Modal.initializeMarkupTrigger(document),f=parent.window.TYPO3.Modal):top&&top.TYPO3.Modal&&(top.TYPO3.Modal.initializeMarkupTrigger(document),f=top.TYPO3.Modal)}catch(t){}return f||(f=new m(new i),TYPO3.Modal=f),f})); \ No newline at end of file diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/ModalInterface.js b/typo3/sysext/backend/Resources/Public/JavaScript/ModalInterface.js new file mode 100644 index 000000000000..d3632d54e8aa --- /dev/null +++ b/typo3/sysext/backend/Resources/Public/JavaScript/ModalInterface.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"],(function(e,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0})})); \ No newline at end of file diff --git a/typo3/sysext/filelist/Classes/Controller/File/CreateFolderController.php b/typo3/sysext/filelist/Classes/Controller/File/CreateFolderController.php index f6e55da2f8d7..b2697aeea2bf 100644 --- a/typo3/sysext/filelist/Classes/Controller/File/CreateFolderController.php +++ b/typo3/sysext/filelist/Classes/Controller/File/CreateFolderController.php @@ -84,6 +84,16 @@ class CreateFolderController */ protected $moduleTemplate; + /** + * @var UriBuilder + */ + protected $uriBuilder; + + public function __construct() + { + $this->uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); + } + /** * Processes the request, currently everything is handled and put together via "main()" * @@ -133,44 +143,10 @@ class CreateFolderController $pathInfo = [ 'combined_identifier' => $this->folderObject->getCombinedIdentifier(), ]; - $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($pathInfo); $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu'); - $this->moduleTemplate->addJavaScriptCode( - 'CreateFolderInlineJavaScript', - 'var path = "' . $this->target . '"; - var confirmTitle = ' - . GeneralUtility::quoteJSvalue( - $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:pleaseConfirm') - ) - . '; - var confirmText = ' - . GeneralUtility::quoteJSvalue( - $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:mess.redraw') - ) - . '; - function reload(a) { - var params = "&target="+encodeURIComponent(path)+"&number="+a+"&returnUrl=' . rawurlencode($this->returnUrl) . '"; - var url = \'' . (string)$uriBuilder->buildUriFromRoute('file_newfolder') . '\'; - if (!changed) { - window.location.href = url + params; - } else { - var modal = top.TYPO3.Modal.confirm(confirmTitle, confirmText); - modal.on(\'confirm.button.cancel\', function(e) { - top.TYPO3.Modal.currentModal.trigger(\'modal-dismiss\'); - }); - modal.on(\'confirm.button.ok\', function(e) { - top.TYPO3.Modal.currentModal.trigger(\'modal-dismiss\'); - window.location.href = url + params; - }); - } - } - function backToList() { - top.goToModule("file_FilelistList"); - } - var changed = 0;' - ); + $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Filelist/CreateFolder'); } /** @@ -179,11 +155,18 @@ class CreateFolderController protected function main() { $lang = $this->getLanguageService(); - $assigns = []; - $assigns['target'] = $this->target; + $assigns = [ + 'target' => $this->target, + 'confirmTitle' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:pleaseConfirm'), + 'confirmText' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:mess.redraw'), + 'selfUrl' => (string)$this->uriBuilder->buildUriFromRoute('file_newfolder', [ + 'target' => $this->target, + 'returnUrl' => $this->returnUrl, + 'number' => 'AMOUNT', + ]), + ]; if ($this->folderObject->checkActionPermission('add')) { - $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - $assigns['moduleUrlTceFile'] = (string)$uriBuilder->buildUriFromRoute('tce_file'); + $assigns['moduleUrlTceFile'] = (string)$this->uriBuilder->buildUriFromRoute('tce_file'); $assigns['cshFileNewFolder'] = BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfolder'); // Making the selector box for the number of concurrent folder-creations $this->number = MathUtility::forceIntegerInRange($this->number, 1, 10); @@ -205,8 +188,7 @@ class CreateFolderController } if ($this->folderObject->getStorage()->checkUserActionPermission('add', 'File')) { - $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - $assigns['moduleUrlOnlineMedia'] = (string)$uriBuilder->buildUriFromRoute('online_media'); + $assigns['moduleUrlOnlineMedia'] = (string)$this->uriBuilder->buildUriFromRoute('online_media'); $assigns['cshFileNewMedia'] = BackendUtility::cshItem('xMOD_csh_corebe', 'file_newMedia'); // Create a list of allowed file extensions with the readable format "youtube, vimeo" etc. $fileExtList = []; @@ -219,7 +201,7 @@ class CreateFolderController } $assigns['fileExtList'] = $fileExtList; - $assigns['moduleUrlTceFile'] = (string)$uriBuilder->buildUriFromRoute('tce_file'); + $assigns['moduleUrlTceFile'] = (string)$this->uriBuilder->buildUriFromRoute('tce_file'); $assigns['cshFileNewFile'] = BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfile'); // Create a list of allowed file extensions with a text format "*.txt, *.css" etc. $fileExtList = []; diff --git a/typo3/sysext/filelist/Classes/Controller/File/EditFileController.php b/typo3/sysext/filelist/Classes/Controller/File/EditFileController.php index 52d040b16b2c..62427c82a4d7 100644 --- a/typo3/sysext/filelist/Classes/Controller/File/EditFileController.php +++ b/typo3/sysext/filelist/Classes/Controller/File/EditFileController.php @@ -32,6 +32,7 @@ use TYPO3\CMS\Core\Localization\LanguageService; use TYPO3\CMS\Core\Messaging\FlashMessage; use TYPO3\CMS\Core\Messaging\FlashMessageService; use TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException; +use TYPO3\CMS\Core\Resource\File; use TYPO3\CMS\Core\Resource\ResourceFactory; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Fluid\View\StandaloneView; @@ -73,7 +74,7 @@ class EditFileController /** * the file that is being edited on * - * @var \TYPO3\CMS\Core\Resource\AbstractFile + * @var File */ protected $fileObject; @@ -84,12 +85,18 @@ class EditFileController */ protected $moduleTemplate; + /** + * @var UriBuilder + */ + protected $uriBuilder; + /** * Constructor */ public function __construct() { $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class); + $this->uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); } /** @@ -122,7 +129,6 @@ class EditFileController // Setting target, which must be a file reference to a file within the mounts. $this->target = $this->origTarget = $parsedBody['target'] ?? $queryParams['target'] ?? ''; - $this->returnUrl = GeneralUtility::sanitizeLocalUrl($parsedBody['returnUrl'] ?? $queryParams['returnUrl'] ?? ''); // create the file object if ($this->target) { $this->fileObject = GeneralUtility::makeInstance(ResourceFactory::class) @@ -140,13 +146,12 @@ class EditFileController 1375889832 ); } - - // Setting template object - $this->moduleTemplate->addJavaScriptCode( - 'FileEditBackToList', - 'function backToList() { - top.goToModule("file_FilelistList"); - }' + $this->returnUrl = GeneralUtility::sanitizeLocalUrl( + $parsedBody['returnUrl'] + ?? $queryParams['returnUrl'] + ?? (string)$this->uriBuilder->buildUriFromRoute('file_FilelistList', [ + 'id' => $this->fileObject->getParentFolder()->getCombinedIdentifier() + ]) ); } @@ -180,8 +185,7 @@ class EditFileController } $assigns = []; - $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - $assigns['moduleUrlTceFile'] = (string)$uriBuilder->buildUriFromRoute('tce_file'); + $assigns['moduleUrlTceFile'] = (string)$this->uriBuilder->buildUriFromRoute('tce_file'); $assigns['fileName'] = $this->fileObject->getName(); try { @@ -192,17 +196,12 @@ class EditFileController } // Making the formfields - $hValue = (string)$uriBuilder->buildUriFromRoute('file_edit', [ - 'target' => $this->origTarget, - 'returnUrl' => $this->returnUrl - ]); - $formData = [ 'databaseRow' => [ 'uid' => 0, 'data' => $this->fileObject->getContents(), 'target' => $this->fileObject->getUid(), - 'redirect' => $hValue, + 'redirect' => $this->returnUrl, ], 'tableName' => 'editfile', 'processedTca' => [ @@ -303,11 +302,6 @@ class EditFileController ->setName('_saveandclosedok') ->setValue('1') ->setForm('EditFileController') - ->setOnClick( - 'document.editform.elements.namedItem("data[editfile][0][redirect]").value=' - . GeneralUtility::quoteJSvalue($this->returnUrl) - . ';' - ) ->setTitle($lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:file_edit.php.saveAndClose')) ->setIcon($this->moduleTemplate->getIconFactory()->getIcon( 'actions-document-save-close', @@ -321,8 +315,8 @@ class EditFileController // Cancel button $closeButton = $buttonBar->makeLinkButton() - ->setHref('#') - ->setOnClick('backToList(); return false;') + ->setShowLabelText(true) + ->setHref($this->returnUrl) ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.cancel')) ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-close', Icon::SIZE_SMALL)); $buttonBar->addButton($closeButton, ButtonBar::BUTTON_POSITION_LEFT, 10); diff --git a/typo3/sysext/filelist/Classes/Controller/File/RenameFileController.php b/typo3/sysext/filelist/Classes/Controller/File/RenameFileController.php index 125b46c1bcef..8eda2232144f 100644 --- a/typo3/sysext/filelist/Classes/Controller/File/RenameFileController.php +++ b/typo3/sysext/filelist/Classes/Controller/File/RenameFileController.php @@ -133,12 +133,6 @@ class RenameFileController // Setting up the context sensitive menu $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu'); $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Filelist/RenameFile'); - - // Add javaScript - $this->moduleTemplate->addJavaScriptCode( - 'RenameFileInlineJavaScript', - 'function backToList() {top.goToModule("file_FilelistList");}' - ); } /** diff --git a/typo3/sysext/filelist/Classes/Controller/File/ReplaceFileController.php b/typo3/sysext/filelist/Classes/Controller/File/ReplaceFileController.php index e3d2ba7fdf22..847ff3b55941 100644 --- a/typo3/sysext/filelist/Classes/Controller/File/ReplaceFileController.php +++ b/typo3/sysext/filelist/Classes/Controller/File/ReplaceFileController.php @@ -133,10 +133,7 @@ class ReplaceFileController ]; $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($pathInfo); $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu'); - $this->moduleTemplate->addJavaScriptCode( - 'ReplaceFileOnlineJavaScript', - 'function backToList() {top.goToModule("file_FilelistList");}' - ); + $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Filelist/FileReplace'); } /** diff --git a/typo3/sysext/filelist/Classes/Controller/FileListController.php b/typo3/sysext/filelist/Classes/Controller/FileListController.php index e4b84381b13f..00aa380c2d61 100644 --- a/typo3/sysext/filelist/Classes/Controller/FileListController.php +++ b/typo3/sysext/filelist/Classes/Controller/FileListController.php @@ -292,9 +292,17 @@ class FileListController extends ActionController implements LoggerAwareInterfac parent::initializeView($view); $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer(); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileListLocalisation'); + $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileList'); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileSearch'); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu'); $this->registerDocHeaderButtons(); + if ($this->folderObject instanceof Folder) { + $view->assign( + 'currentFolderHash', + 'folder' . GeneralUtility::md5int($this->folderObject->getCombinedIdentifier()) + ); + } + $view->assign('currentIdentifier', $this->id); } protected function initializeIndexAction() @@ -399,8 +407,6 @@ class FileListController extends ActionController implements LoggerAwareInterfac ); } - // Set top JavaScript: - $this->addJumpToUrl(); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ClipboardComponent'); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileDelete'); $pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf', 'buttons'); @@ -539,10 +545,6 @@ class FileListController extends ActionController implements LoggerAwareInterfac $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer(); - $pageRenderer->addInlineSetting('ShowItem', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('show_item')); - $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileList'); - $thumbnailConfiguration = GeneralUtility::makeInstance(ThumbnailConfiguration::class); $this->view->assign('thumbnail', [ 'width' => $thumbnailConfiguration->getWidth(), @@ -557,12 +559,12 @@ class FileListController extends ActionController implements LoggerAwareInterfac ]); $this->view->assign('moduleSettings', $this->MOD_SETTINGS); + $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer(); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileDelete'); $pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf', 'buttons'); $this->initClipboard(); $this->buildListOptionCheckboxes($searchWord); - $this->addJumpToUrl(); } /** @@ -641,11 +643,11 @@ class FileListController extends ActionController implements LoggerAwareInterfac if ($parentFolder->getIdentifier() !== $this->folderObject->getIdentifier() && $currentStorage->isWithinFileMountBoundaries($parentFolder) ) { - $levelUpClick = 'top.document.getElementsByName("nav_frame")[0].contentWindow.Tree.highlightActiveItem("file","folder' - . GeneralUtility::md5int($parentFolder->getCombinedIdentifier()) . '_"+top.fsMod.currentBank)'; $levelUpButton = $buttonBar->makeLinkButton() + ->setDataAttributes([ + 'tree-update-request' => htmlspecialchars('folder' . GeneralUtility::md5int($parentFolder->getCombinedIdentifier())), + ]) ->setHref((string)$uriBuilder->buildUriFromRoute('file_FilelistList', ['id' => $parentFolder->getCombinedIdentifier()])) - ->setOnClick($levelUpClick) ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.upOneLevel')) ->setIcon($iconFactory->getIcon('actions-view-go-up', Icon::SIZE_SMALL)); $buttonBar->addButton($levelUpButton, ButtonBar::BUTTON_POSITION_LEFT, 1); @@ -840,16 +842,4 @@ class FileListController extends ActionController implements LoggerAwareInterfac $this->view->assign('showClipBoard', (bool)$this->MOD_SETTINGS['clipBoard']); $this->view->assign('clipBoardHtml', $this->filelist->clipObj->printClipboard()); } - - /** - * add javascript jumpToUrl function - */ - protected function addJumpToUrl(): void - { - $this->view->getModuleTemplate()->addJavaScriptCode( - 'FileListIndex', - 'if (top.fsMod) top.fsMod.recentIds["file"] = "' . rawurlencode($this->id) . '"; - ' - ); - } } diff --git a/typo3/sysext/filelist/Classes/FileList.php b/typo3/sysext/filelist/Classes/FileList.php index ef8a62c36fe0..0e4627969398 100644 --- a/typo3/sysext/filelist/Classes/FileList.php +++ b/typo3/sysext/filelist/Classes/FileList.php @@ -38,7 +38,8 @@ use TYPO3\CMS\Core\Utility\MathUtility; use TYPO3\CMS\Filelist\Configuration\ThumbnailConfiguration; /** - * Class for rendering of File>Filelist + * Class for rendering of File>Filelist (basically used in FileListController) + * @see \TYPO3\CMS\Filelist\Controller\FileListController * @internal this is a concrete TYPO3 controller implementation and solely used for EXT:filelist and not part of TYPO3's Core API. */ class FileList @@ -240,18 +241,15 @@ class FileList */ public function linkClipboardHeaderIcon($string, $cmd, $warning = '') { - $jsCode = 'document.dblistForm.cmd.value=' . GeneralUtility::quoteJSvalue($cmd) - . ';document.dblistForm.submit();'; - - $attributes = []; if ($warning) { $attributes['class'] = 'btn btn-default t3js-modal-trigger'; - $attributes['data-href'] = 'javascript:' . $jsCode; $attributes['data-severity'] = 'warning'; $attributes['data-content'] = $warning; + $attributes['data-event-name'] = 'filelist:clipboard:cmd'; + $attributes['data-event-payload'] = $cmd; } else { $attributes['class'] = 'btn btn-default'; - $attributes['onclick'] = $jsCode . 'return false;'; + $attributes['data-filelist-clipboard-cmd'] = $cmd; } return '<a href="#" ' . GeneralUtility::implodeAttributes($attributes, true) . '>' . $string . '</a>'; @@ -630,12 +628,15 @@ class FileList public function linkWrapDir($title, Folder $folderObject) { $href = (string)$this->uriBuilder->buildUriFromRoute('file_FilelistList', ['id' => $folderObject->getCombinedIdentifier()]); - $onclick = ' onclick="' . htmlspecialchars('top.document.getElementsByName("nav_frame")[0].contentWindow.Tree.highlightActiveItem("file","folder' . GeneralUtility::md5int($folderObject->getCombinedIdentifier()) . '_"+top.fsMod.currentBank)') . '"'; + $triggerTreeUpdateAttribute = sprintf( + ' data-tree-update-request="%s"', + htmlspecialchars('folder' . GeneralUtility::md5int($folderObject->getCombinedIdentifier())) + ); // Sometimes $code contains plain HTML tags. In such a case the string should not be modified! if ((string)$title === strip_tags($title)) { - return '<a href="' . htmlspecialchars($href) . '"' . $onclick . ' title="' . htmlspecialchars($title) . '">' . $title . '</a>'; + return '<a href="' . htmlspecialchars($href) . '"' . $triggerTreeUpdateAttribute . ' title="' . htmlspecialchars($title) . '">' . $title . '</a>'; } - return '<a href="' . htmlspecialchars($href) . '"' . $onclick . '>' . $title . '</a>'; + return '<a href="' . htmlspecialchars($href) . '"' . $triggerTreeUpdateAttribute . '>' . $title . '</a>'; } /** @@ -997,9 +998,11 @@ class FileList // Edit file content (if editable) if ($fileOrFolderObject instanceof File && $fileOrFolderObject->checkActionPermission('write') && $fileOrFolderObject->isTextFile()) { - $url = (string)$this->uriBuilder->buildUriFromRoute('file_edit', ['target' => $fullIdentifier]); - $editOnClick = 'top.list_frame.location.href=' . GeneralUtility::quoteJSvalue($url) . '+\'&returnUrl=\'+encodeURIComponent(top.list_frame.document.location.pathname+top.list_frame.document.location.search);return false;'; - $cells['edit'] = '<a href="#" class="btn btn-default" onclick="' . htmlspecialchars($editOnClick) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.editcontent') . '">' + $attributes = [ + 'href' => (string)$this->uriBuilder->buildUriFromRoute('file_edit', ['target' => $fullIdentifier, 'returnUrl' => $this->listURL()]), + 'title' => $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.editcontent'), + ]; + $cells['edit'] = '<a class="btn btn-default" ' . GeneralUtility::implodeAttributes($attributes, true) . '>' . $this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render() . '</a>'; } else { @@ -1036,16 +1039,20 @@ class FileList // replace file if ($fileOrFolderObject instanceof File && $fileOrFolderObject->checkActionPermission('replace')) { - $url = (string)$this->uriBuilder->buildUriFromRoute('file_replace', ['target' => $fullIdentifier, 'uid' => $fileOrFolderObject->getUid()]); - $replaceOnClick = 'top.list_frame.location.href = ' . GeneralUtility::quoteJSvalue($url) . '+\'&returnUrl=\'+encodeURIComponent(top.list_frame.document.location.pathname+top.list_frame.document.location.search);return false;'; - $cells['replace'] = '<a href="#" class="btn btn-default" onclick="' . $replaceOnClick . '" title="' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.replace') . '">' . $this->iconFactory->getIcon('actions-edit-replace', Icon::SIZE_SMALL)->render() . '</a>'; + $attributes = [ + 'href' => $url = (string)$this->uriBuilder->buildUriFromRoute('file_replace', ['target' => $fullIdentifier, 'uid' => $fileOrFolderObject->getUid(), 'returnUrl' => $this->listURL()]), + 'title' => $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.replace'), + ]; + $cells['replace'] = '<a class="btn btn-default" ' . GeneralUtility::implodeAttributes($attributes, true) . '>' . $this->iconFactory->getIcon('actions-edit-replace', Icon::SIZE_SMALL)->render() . '</a>'; } // rename the file if ($fileOrFolderObject->checkActionPermission('rename')) { - $url = (string)$this->uriBuilder->buildUriFromRoute('file_rename', ['target' => $fullIdentifier]); - $renameOnClick = 'top.list_frame.location.href = ' . GeneralUtility::quoteJSvalue($url) . '+\'&returnUrl=\'+encodeURIComponent(top.list_frame.document.location.pathname+top.list_frame.document.location.search);return false;'; - $cells['rename'] = '<a href="#" class="btn btn-default" onclick="' . htmlspecialchars($renameOnClick) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.rename') . '">' . $this->iconFactory->getIcon('actions-edit-rename', Icon::SIZE_SMALL)->render() . '</a>'; + $attributes = [ + 'href' => (string)$this->uriBuilder->buildUriFromRoute('file_rename', ['target' => $fullIdentifier]), + 'title' => $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.rename'), + ]; + $cells['rename'] = '<a class="btn btn-default" ' . GeneralUtility::implodeAttributes($attributes, true) . '>' . $this->iconFactory->getIcon('actions-edit-rename', Icon::SIZE_SMALL)->render() . '</a>'; } else { $cells['rename'] = $this->spaceIcon; } @@ -1053,20 +1060,24 @@ class FileList // upload files if ($fileOrFolderObject->getStorage()->checkUserActionPermission('add', 'File') && $fileOrFolderObject->checkActionPermission('write')) { if ($fileOrFolderObject instanceof Folder) { - $url = (string)$this->uriBuilder->buildUriFromRoute('file_upload', ['target' => $fullIdentifier]); - $uploadOnClick = 'top.list_frame.location.href = ' . GeneralUtility::quoteJSvalue($url) . '+\'&returnUrl=\'+encodeURIComponent(top.list_frame.document.location.pathname+top.list_frame.document.location.search);return false;'; - $cells['upload'] = '<a href="#" class="btn btn-default" onclick="' . htmlspecialchars($uploadOnClick) . '" title="' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.upload')) . '">' . $this->iconFactory->getIcon('actions-edit-upload', Icon::SIZE_SMALL)->render() . '</a>'; + $attributes = [ + 'href' => (string)$this->uriBuilder->buildUriFromRoute('file_upload', ['target' => $fullIdentifier]), + 'title' => $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.upload'), + ]; + $cells['upload'] = '<a class="btn btn-default" ' . GeneralUtility::implodeAttributes($attributes, true) . '>' . $this->iconFactory->getIcon('actions-edit-upload', Icon::SIZE_SMALL)->render() . '</a>'; } } if ($fileOrFolderObject->checkActionPermission('read')) { - $infoOnClick = ''; - if ($fileOrFolderObject instanceof Folder) { - $infoOnClick = 'top.TYPO3.InfoWindow.showItem(\'_FOLDER\', ' . GeneralUtility::quoteJSvalue($fullIdentifier) . ');return false;'; - } elseif ($fileOrFolderObject instanceof File) { - $infoOnClick = 'top.TYPO3.InfoWindow.showItem(\'_FILE\', ' . GeneralUtility::quoteJSvalue($fullIdentifier) . ');return false;'; + $attributes = [ + 'title' => $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.info'), + ]; + if ($fileOrFolderObject instanceof Folder || $fileOrFolderObject instanceof File) { + $attributes['data-filelist-show-item-type'] = $fileOrFolderObject instanceof File ? '_FILE' : '_FOLDER'; + $attributes['data-filelist-show-item-identifier'] = $fullIdentifier; } - $cells['info'] = '<a href="#" class="btn btn-default" onclick="' . htmlspecialchars($infoOnClick) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.info') . '">' . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render() . '</a>'; + $cells['info'] = '<a href="#" class="btn btn-default" ' . GeneralUtility::implodeAttributes($attributes, true) . '>' + . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render() . '</a>'; } else { $cells['info'] = $this->spaceIcon; } @@ -1190,13 +1201,14 @@ class FileList if (!$references) { return '-'; } - $htmlCode = '<a href="#" onclick="' . htmlspecialchars( - 'top.TYPO3.InfoWindow.showItem(\'_FILE\', ' . GeneralUtility::quoteJSvalue($fileObject->getCombinedIdentifier()) . '); return false;' - ) . '" title="' . htmlspecialchars( - $this->getLanguageService()->sL( - 'LLL:EXT:backend/Resources/Private/Language/locallang.xlf:show_references' - ) . ' (' . $references . ')' - ) . '">'; + $attributes = [ + 'data-filelist-show-item-type' => '_FILE', + 'data-filelist-show-item-identifier' => $fileObject->getCombinedIdentifier(), + 'title' => $this->getLanguageService() + ->sL('LLL:EXT:backend/Resources/Private/Language/locallang.xlf:show_references') + . ' (' . $references . ')' + ]; + $htmlCode = '<a href="#" ' . GeneralUtility::implodeAttributes($attributes, true) . '">'; $htmlCode .= $references; $htmlCode .= '</a>'; return $htmlCode; diff --git a/typo3/sysext/filelist/Resources/Private/Layouts/Default.html b/typo3/sysext/filelist/Resources/Private/Layouts/Default.html index 56866620e711..94c3e27950ad 100644 --- a/typo3/sysext/filelist/Resources/Private/Layouts/Default.html +++ b/typo3/sysext/filelist/Resources/Private/Layouts/Default.html @@ -1,5 +1,8 @@ -<f:render section="headline" /> -<f:render section="content" /> +<f:comment><!-- identifier initializes tree state --></f:comment> +<div class="filelist-main" data-filelist-current-folder-hash="{currentFolderHash}" data-filelist-current-identifier="{currentIdentifier}"> + <f:render section="headline" /> + <f:render section="content" /> +</div> <div class="t3js-drag-uploader" data-target-folder="{folderIdentifier}" data-progress-container="#typo3-filelist" data-dropzone-trigger=".t3js-drag-uploader-trigger" data-dropzone-target=".t3js-module-body h1:first" diff --git a/typo3/sysext/filelist/Resources/Private/Templates/File/CreateFolder.html b/typo3/sysext/filelist/Resources/Private/Templates/File/CreateFolder.html index b6aaf95fab5c..389d97818320 100644 --- a/typo3/sysext/filelist/Resources/Private/Templates/File/CreateFolder.html +++ b/typo3/sysext/filelist/Resources/Private/Templates/File/CreateFolder.html @@ -1,4 +1,4 @@ -<div> +<div class="filelist-create-folder-main" data-self-url="{selfUrl}" data-confirm-title="{confirmTitle}" data-confirm-text="{confirmText}"> <h1><f:translate key="LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:file_newfolder.php.pagetitle" /></h1> <f:if condition="{moduleUrlTceFile}"> <h3><f:translate key="LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:file_newfolder.php.newfolders" /></h3> @@ -10,7 +10,7 @@ <label for="number-of-new-folders"><f:translate key="LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:file_newfolder.php.number_of_folders" /></label> {cshFileNewFolder -> f:format.raw()} <div class="form-control-wrap"> <div class="input-group"> - <select class="form-control form-control-adapt" name="number" id="number-of-new-folders" onchange="reload(this.options[this.selectedIndex].value);">'; + <select class="form-control form-control-adapt" name="number" id="number-of-new-folders">'; <f:for each="{options}" as="option"> <option value="{option.value}"{option.selected}>{option.value}</option> </f:for> @@ -24,7 +24,7 @@ <div class="form-group"> <label for="folder_new_{folder.this}"><f:translate key="LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:file_newfolder.php.label_newfolder" /> {folder.next}:</label> <div class="form-control-wrap"> - <input type="text" class="form-control" id="folder_new_{folder.this}" name="data[newfolder][{folder.this}][data]" onchange="changed=true;" /> + <input type="text" class="form-control" id="folder_new_{folder.this}" name="data[newfolder][{folder.this}][data]" /> <input type="hidden" name="data[newfolder][{folder.this}][target]" value="{target}" /> </div> </div> @@ -77,7 +77,7 @@ <div class="form-group"> <label for="newfile"><f:translate key="LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:file_newfolder.php.label_newfile" /></label> {cshFileNewFile -> f:format.raw()} <div class="form-control-wrap"> - <input class="form-control" type="text" id="newfile" name="data[newfile][0][data]" onchange="changed=true;" /> + <input class="form-control" type="text" id="newfile" name="data[newfile][0][data]" /> <input type="hidden" name="data[newfile][0][target]" value="{target}" /> </div> <div class="help-block"> diff --git a/typo3/sysext/filelist/Resources/Private/Templates/File/ReplaceFile.html b/typo3/sysext/filelist/Resources/Private/Templates/File/ReplaceFile.html index 13b7f96b9e19..b33349285709 100644 --- a/typo3/sysext/filelist/Resources/Private/Templates/File/ReplaceFile.html +++ b/typo3/sysext/filelist/Resources/Private/Templates/File/ReplaceFile.html @@ -10,30 +10,23 @@ <label for="file_replace"><f:translate key="LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:file_replace.php.selectfile" /></label> <div class="input-group col-xs-6"> <input type="text" name="fakefile" id="fakefile" class="form-control input-xlarge" readonly> - <a class="input-group-addon btn btn-primary" onclick="$('#file_replace').click();"> + <a class="input-group-addon btn btn-primary" data-filelist-click-target="#file_replace"> <f:translate key="LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:file_replace.php.browse" /> </a> </div> - <input class="form-control" type="file" id="file_replace" name="replace_1" style="visibility: hidden;" /> + <input class="form-control" type="file" id="file_replace" data-filelist-change-target="#fakefile" name="replace_1" style="visibility: hidden;" /> </div> - <script> - require(['jquery'], function($) { - $('#file_replace').change(function() { - $('#fakefile').val($(this).val()); - }); - }); - </script> - <input type="hidden" name="overwriteExistingFiles" value="replace" /> <input type="hidden" name="data[replace][1][data]" value="1" /> <input type="hidden" name="data[replace][1][uid]" value="{uid}" /> <div class="form-group"> - <input class="btn btn-primary" type="submit" value="{f:translate(key: 'LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:file_replace.php.submit')}" /> - <input class="btn btn-danger" type="submit" value="{f:translate(key: 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.cancel')}" - onclick="backToList(); return false;" /> <input type="hidden" name="data[replace][1][redirect]" value="{returnUrl}" /> + <input class="btn btn-primary" type="submit" value="{f:translate(key: 'LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:file_replace.php.submit')}" /> + <a href="{returnUrl}" class="btn btn-danger"> + <f:translate key="LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.cancel" /> + </a> </div> </form> </div> diff --git a/typo3/sysext/filelist/Resources/Public/JavaScript/CreateFolder.js b/typo3/sysext/filelist/Resources/Public/JavaScript/CreateFolder.js new file mode 100644 index 000000000000..34d9f24b3754 --- /dev/null +++ b/typo3/sysext/filelist/Resources/Public/JavaScript/CreateFolder.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","jquery","TYPO3/CMS/Backend/Modal","TYPO3/CMS/Core/Event/RegularEvent"],(function(e,t,n,i,o){"use strict";return new class{constructor(){this.changed=!1,n(()=>{const e=document.querySelector(".filelist-create-folder-main");if(!(e instanceof HTMLElement))throw new Error("Main element not found");this.selfUrl=e.dataset.selfUrl,this.confirmTitle=e.dataset.confirmTitle,this.confirmText=e.dataset.confirmText,this.registerEvents()})}reload(e){const t=this.selfUrl.replace(/AMOUNT/,e.toString());if(this.changed){const e=i.confirm(this.confirmTitle,this.confirmText);e.on("confirm.button.cancel",()=>{e.trigger("modal-dismiss")}),e.on("confirm.button.ok",()=>{e.trigger("modal-dismiss"),window.location.href=t})}else window.location.href=t}registerEvents(){new o("change",()=>{this.changed=!0}).delegateTo(document,['input[type="text"][name^="data[newfolder]"]','input[type="text"][name^="data[newfile]"]','input[type="text"][name^="data[newMedia]"]'].join(",")),new o("change",e=>{const t=parseInt(e.target.value,10);this.reload(t)}).bindTo(document.getElementById("number-of-new-folders"))}}})); \ No newline at end of file diff --git a/typo3/sysext/filelist/Resources/Public/JavaScript/FileList.js b/typo3/sysext/filelist/Resources/Public/JavaScript/FileList.js index f9c4f4667a55..e7ff4500cb04 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","jquery","TYPO3/CMS/Backend/InfoWindow"],(function(e,t,n,o){"use strict";class r{static openFileInfoPopup(e){o.showItem("_FILE",e)}constructor(){n(()=>{n("a.btn.filelist-file-info").click(e=>{e.preventDefault(),r.openFileInfoPopup(n(e.currentTarget).attr("data-identifier"))}),n("a.filelist-file-references").click(e=>{e.preventDefault(),r.openFileInfoPopup(n(e.currentTarget).attr("data-identifier"))}),n("a.btn.filelist-file-copy").click(e=>{e.preventDefault();const t=n(e.currentTarget).attr("href");let o=t?encodeURIComponent(t):encodeURIComponent(top.list_frame.document.location.pathname+top.list_frame.document.location.search);top.list_frame.location.href=t+"&redirect="+o})})}}return new r})); \ No newline at end of file +define(["require","exports","jquery","TYPO3/CMS/Backend/InfoWindow","TYPO3/CMS/Backend/BroadcastMessage","TYPO3/CMS/Backend/BroadcastService","TYPO3/CMS/Core/Event/RegularEvent"],(function(e,t,i,a,r,o,n){"use strict";class s{static openInfoPopup(e,t){a.showItem(e,t)}static processTriggers(){const e=document.querySelector(".filelist-main");null!==e&&(s.emitTreeUpdateRequest(e.dataset.filelistCurrentFolderHash),top.fsMod&&top.fsMod.recentIds instanceof Object&&(top.fsMod.recentIds.file=encodeURIComponent(e.dataset.filelistCurrentIdentifier)))}static registerTreeUpdateEvents(){new n("click",(function(){s.emitTreeUpdateRequest(this.dataset.treeUpdateRequest)})).delegateTo(document.body,"[data-tree-update-request]")}static emitTreeUpdateRequest(e){const t=new r.BroadcastMessage("filelist","treeUpdateRequested",{type:"folder",identifier:e});o.post(t)}static submitClipboardFormWithCommand(e){const t=i('form[name="dblistForm"]');t.find('input[name="cmd"]').val(e),t.submit()}constructor(){s.processTriggers(),i(()=>{s.registerTreeUpdateEvents(),i("[data-filelist-show-item-identifier][data-filelist-show-item-type]").click(e=>{const t=i(e.currentTarget);e.preventDefault(),s.openInfoPopup(t.data("filelistShowItemType"),t.data("filelistShowItemIdentifier"))}),i("a.btn.filelist-file-info").click(e=>{e.preventDefault(),s.openInfoPopup("_FILE",i(e.currentTarget).attr("data-identifier"))}),i("a.filelist-file-references").click(e=>{e.preventDefault(),s.openInfoPopup("_FILE",i(e.currentTarget).attr("data-identifier"))}),i("a.btn.filelist-file-copy").click(e=>{e.preventDefault();const t=i(e.currentTarget).attr("href");let a=t?encodeURIComponent(t):encodeURIComponent(top.list_frame.document.location.pathname+top.list_frame.document.location.search);top.list_frame.location.href=t+"&redirect="+a}),i('[data-event-name="filelist:clipboard:cmd"]').on("filelist:clipboard:cmd",e=>{const t=e.originalEvent;t.detail.result&&s.submitClipboardFormWithCommand(t.detail.payload)}),i('[data-filelist-clipboard-cmd]:not([data-filelist-clipboard-cmd=""])').click(e=>{const t=i(e.currentTarget).data("filelistClipboardCmd");s.submitClipboardFormWithCommand(t)})})}}return new s})); \ No newline at end of file diff --git a/typo3/sysext/filelist/Resources/Public/JavaScript/FileReplace.js b/typo3/sysext/filelist/Resources/Public/JavaScript/FileReplace.js new file mode 100644 index 000000000000..d61e2366e8ec --- /dev/null +++ b/typo3/sysext/filelist/Resources/Public/JavaScript/FileReplace.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,i){"use strict";return new class{constructor(){this.registerEvents()}registerEvents(){new i("click",(function(){const e=this.dataset.filelistClickTarget;document.querySelector(e).click()})).delegateTo(document.body,'[data-filelist-click-target]:not([data-filelist-click-target=""]'),new i("change",(function(){const e=this.dataset.filelistChangeTarget;document.querySelector(e).value=this.value})).delegateTo(document.body,'[data-filelist-change-target]:not([data-filelist-change-target=""])')}}})); \ No newline at end of file -- GitLab