From e1f4d209c5cf05be24f9f31d1bc5fec60a6a827c Mon Sep 17 00:00:00 2001 From: Benjamin Franzke <ben@bnf.dev> Date: Fri, 7 Jul 2023 15:01:48 +0200 Subject: [PATCH] [TASK] Update URL bar in nested backend installtool Map backend URLs like /typo3/install.php?install%5Bcontroller%5D=settings to /typo3/module/tools/settings for display in the browsers URL bar. Resolves: #101287 Releases: main, 12.4 Change-Id: I5177146e28b01011f946c578804a8141fe9a371f Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/79920 Reviewed-by: Benjamin Franzke <ben@bnf.dev> Tested-by: core-ci <typo3@b13.com> Tested-by: Benjamin Franzke <ben@bnf.dev> --- .../TypeScript/backend/module/router.ts | 18 +++++++++++++++--- .../Public/JavaScript/module/router.js | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Build/Sources/TypeScript/backend/module/router.ts b/Build/Sources/TypeScript/backend/module/router.ts index 3edb7c50321f..9d31c90fd052 100644 --- a/Build/Sources/TypeScript/backend/module/router.ts +++ b/Build/Sources/TypeScript/backend/module/router.ts @@ -196,9 +196,21 @@ export class ModuleRouter extends LitElement { } if (!params.has('token')) { - // non token-urls (e.g. backend install tool) cannot be mapped by - // the main backend controller right now - return; + // InstallTool doesn't use a backend-route with a token, + // but has backend-routes that act as wrappers. + // Rewrite the URL for display in the browser URL bar. + // @todo: rewrite installtool as webcomponent backend + // module in order to advertise a proper module URL on it's own + if (params.has('install[controller]')) { + const controller = params.get('install[controller]'); + params.delete('install[controller]'); + params.delete('install[context]'); + url.pathname = url.pathname.replace('/typo3/install.php', '/typo3/module/tools/' + controller); + } else { + // non token-urls cannot be mapped by + // the main backend controller right now + return; + } } params.delete('token'); diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/module/router.js b/typo3/sysext/backend/Resources/Public/JavaScript/module/router.js index da53c49fa399..319e33843072 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/module/router.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/module/router.js @@ -10,7 +10,7 @@ * * The TYPO3 project - inspiring people to share! */ -var __decorate=function(t,e,o,r){var i,l=arguments.length,n=l<3?e:null===r?r=Object.getOwnPropertyDescriptor(e,o):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(t,e,o,r);else for(var a=t.length-1;a>=0;a--)(i=t[a])&&(n=(l<3?i(n):l>3?i(e,o,n):i(e,o))||n);return l>3&&n&&Object.defineProperty(e,o,n),n};import{html,css,LitElement}from"lit";import{customElement,property,query}from"lit/decorators.js";import{ModuleUtility}from"@typo3/backend/module.js";const IFRAME_COMPONENT="@typo3/backend/module/iframe",alwaysUpdate=()=>!0;let ModuleRouter=class extends LitElement{constructor(){super(),this.module="",this.endpoint="",this.addEventListener("typo3-module-load",(({target:t,detail:e})=>{const o=t.getAttribute("slot");this.pushState({slotName:o,detail:e})})),this.addEventListener("typo3-module-loaded",(({detail:t})=>{this.updateBrowserState(t)})),this.addEventListener("typo3-iframe-load",(({detail:t})=>{let e={slotName:IFRAME_COMPONENT,detail:t};if(e.detail.url.includes(this.stateTrackerUrl+"?state=")){const t=e.detail.url.split("?state=");e=JSON.parse(decodeURIComponent(t[1]||"{}"))}this.slotElement.getAttribute("name")!==e.slotName&&this.slotElement.setAttribute("name",e.slotName),this.markActive(e.slotName,this.slotElement.getAttribute("name")===IFRAME_COMPONENT?null:e.detail.url,!1),this.updateBrowserState(e.detail),this.parentElement.dispatchEvent(new CustomEvent("typo3-module-load",{bubbles:!0,composed:!0,detail:e.detail}))})),this.addEventListener("typo3-iframe-loaded",(({detail:t})=>{this.updateBrowserState(t),this.parentElement.dispatchEvent(new CustomEvent("typo3-module-loaded",{bubbles:!0,composed:!0,detail:t}))}))}render(){const t=ModuleUtility.getFromName(this.module).component||IFRAME_COMPONENT;return html`<slot name="${t}"></slot>`}updated(){const t=ModuleUtility.getFromName(this.module).component||IFRAME_COMPONENT;this.markActive(t,this.endpoint)}async markActive(t,e,o=!0){const r=await this.getModuleElement(t);e&&(o||r.getAttribute("endpoint")!==e)&&r.setAttribute("endpoint",e),r.hasAttribute("active")||r.setAttribute("active","");for(let t=r.previousElementSibling;null!==t;t=t.previousElementSibling)t.removeAttribute("active");for(let t=r.nextElementSibling;null!==t;t=t.nextElementSibling)t.removeAttribute("active")}async getModuleElement(t){let e=this.querySelector(`*[slot="${t}"]`);if(null!==e)return e;try{const o=await import(t+".js");e=document.createElement(o.componentName)}catch(e){throw console.error({msg:`Error importing ${t} as backend module`,err:e}),e}return e.setAttribute("slot",t),this.appendChild(e),e}async pushState(t){const e=this.stateTrackerUrl+"?state="+encodeURIComponent(JSON.stringify(t));(await this.getModuleElement(IFRAME_COMPONENT)).setAttribute("endpoint",e)}updateBrowserState(t){const e=new URL(t.url||"",window.location.origin),o=new URLSearchParams(e.search),r="title"in t?t.title:"";if(null!==r){const t=[this.sitename];""!==r&&t.unshift(r),this.sitenameFirst&&t.reverse(),document.title=t.join(" · ")}if(!o.has("token"))return;o.delete("token"),e.search=o.toString();const i=e.toString();window.history.replaceState(t,"",i)}};ModuleRouter.styles=css` +var __decorate=function(t,e,o,r){var i,l=arguments.length,n=l<3?e:null===r?r=Object.getOwnPropertyDescriptor(e,o):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(t,e,o,r);else for(var a=t.length-1;a>=0;a--)(i=t[a])&&(n=(l<3?i(n):l>3?i(e,o,n):i(e,o))||n);return l>3&&n&&Object.defineProperty(e,o,n),n};import{html,css,LitElement}from"lit";import{customElement,property,query}from"lit/decorators.js";import{ModuleUtility}from"@typo3/backend/module.js";const IFRAME_COMPONENT="@typo3/backend/module/iframe",alwaysUpdate=()=>!0;let ModuleRouter=class extends LitElement{constructor(){super(),this.module="",this.endpoint="",this.addEventListener("typo3-module-load",(({target:t,detail:e})=>{const o=t.getAttribute("slot");this.pushState({slotName:o,detail:e})})),this.addEventListener("typo3-module-loaded",(({detail:t})=>{this.updateBrowserState(t)})),this.addEventListener("typo3-iframe-load",(({detail:t})=>{let e={slotName:IFRAME_COMPONENT,detail:t};if(e.detail.url.includes(this.stateTrackerUrl+"?state=")){const t=e.detail.url.split("?state=");e=JSON.parse(decodeURIComponent(t[1]||"{}"))}this.slotElement.getAttribute("name")!==e.slotName&&this.slotElement.setAttribute("name",e.slotName),this.markActive(e.slotName,this.slotElement.getAttribute("name")===IFRAME_COMPONENT?null:e.detail.url,!1),this.updateBrowserState(e.detail),this.parentElement.dispatchEvent(new CustomEvent("typo3-module-load",{bubbles:!0,composed:!0,detail:e.detail}))})),this.addEventListener("typo3-iframe-loaded",(({detail:t})=>{this.updateBrowserState(t),this.parentElement.dispatchEvent(new CustomEvent("typo3-module-loaded",{bubbles:!0,composed:!0,detail:t}))}))}render(){const t=ModuleUtility.getFromName(this.module).component||IFRAME_COMPONENT;return html`<slot name="${t}"></slot>`}updated(){const t=ModuleUtility.getFromName(this.module).component||IFRAME_COMPONENT;this.markActive(t,this.endpoint)}async markActive(t,e,o=!0){const r=await this.getModuleElement(t);e&&(o||r.getAttribute("endpoint")!==e)&&r.setAttribute("endpoint",e),r.hasAttribute("active")||r.setAttribute("active","");for(let t=r.previousElementSibling;null!==t;t=t.previousElementSibling)t.removeAttribute("active");for(let t=r.nextElementSibling;null!==t;t=t.nextElementSibling)t.removeAttribute("active")}async getModuleElement(t){let e=this.querySelector(`*[slot="${t}"]`);if(null!==e)return e;try{const o=await import(t+".js");e=document.createElement(o.componentName)}catch(e){throw console.error({msg:`Error importing ${t} as backend module`,err:e}),e}return e.setAttribute("slot",t),this.appendChild(e),e}async pushState(t){const e=this.stateTrackerUrl+"?state="+encodeURIComponent(JSON.stringify(t));(await this.getModuleElement(IFRAME_COMPONENT)).setAttribute("endpoint",e)}updateBrowserState(t){const e=new URL(t.url||"",window.location.origin),o=new URLSearchParams(e.search),r="title"in t?t.title:"";if(null!==r){const t=[this.sitename];""!==r&&t.unshift(r),this.sitenameFirst&&t.reverse(),document.title=t.join(" · ")}if(!o.has("token")){if(!o.has("install[controller]"))return;{const t=o.get("install[controller]");o.delete("install[controller]"),o.delete("install[context]"),e.pathname=e.pathname.replace("/typo3/install.php","/typo3/module/tools/"+t)}}o.delete("token"),e.search=o.toString();const i=e.toString();window.history.replaceState(t,"",i)}};ModuleRouter.styles=css` :host { width: 100%; min-height: 100%; -- GitLab