diff --git a/Build/Sources/TypeScript/backend/context-menu.ts b/Build/Sources/TypeScript/backend/context-menu.ts
index 65dd7108ad0cd5b6c8bda757ed768f5a4fe21e7e..a80b2d8ca4a9287f4c9825d6250bead155821134 100644
--- a/Build/Sources/TypeScript/backend/context-menu.ts
+++ b/Build/Sources/TypeScript/backend/context-menu.ts
@@ -17,6 +17,7 @@ import ContextMenuActions from './context-menu-actions';
 import DebounceEvent from '@typo3/core/event/debounce-event';
 import RegularEvent from '@typo3/core/event/regular-event';
 import { selector } from '@typo3/core/literals';
+import '@typo3/backend/element/spinner-element';
 
 interface MousePosition {
   X: number;
@@ -122,6 +123,7 @@ class ContextMenu {
     originalEvent: PointerEvent = null
   ): void {
     this.hideAll();
+    this.initializeContextMenuContainer();
 
     this.record = { table: table, uid: uid };
     const focusableSource = eventSource.matches('a, button, [tabindex]:not([tabindex="-1"])')
@@ -154,48 +156,49 @@ class ContextMenu {
    * Manipulates the DOM to add the divs needed for context menu at the bottom of the <body>-tag
    */
   private initializeContextMenuContainer(): void {
-    if (document.querySelector('#contentMenu0') === null) {
-      const contextMenu1 = document.createElement('div');
-      contextMenu1.classList.add('context-menu');
-      contextMenu1.id = 'contentMenu0';
-      contextMenu1.style.display = 'none';
-      document.querySelector('body').append(contextMenu1);
-
-      const contextMenu2 = document.createElement('div');
-      contextMenu2.classList.add('context-menu');
-      contextMenu2.id = 'contentMenu1';
-      contextMenu2.style.display = 'none';
-      contextMenu2.dataset.parent = '#contentMenu0'
-      document.querySelector('body').append(contextMenu2);
-
-      document.querySelectorAll('.context-menu').forEach((contextMenu: Element): void => {
-        // Explicitly update cursor position if element is entered to avoid timing issues
-        new RegularEvent('mouseenter', (event: MouseEvent): void => {
-          this.storeMousePosition(event);
-        }).bindTo(contextMenu);
-
-        new DebounceEvent('mouseleave', (event: MouseEvent) => {
-          const target: HTMLElement = event.target as HTMLElement;
-          const childMenu: HTMLElement | null = document.querySelector(selector`[data-parent="#${target.id}"]`);
-
-          const hideThisMenu =
-            !ContextMenu.within(target, this.mousePos.X, this.mousePos.Y) // cursor it outside triggered context menu
-            && (childMenu === null || childMenu.offsetParent === null); // child menu, if any, is not visible
-
-          if (hideThisMenu) {
-            this.hide(target);
-
-            // close parent menu (if any) if cursor is outside its boundaries
-            let parent: HTMLElement | null;
-            if (typeof target.dataset.parent !== 'undefined' && (parent = document.querySelector(target.dataset.parent)) !== null) {
-              if (!ContextMenu.within(parent, this.mousePos.X, this.mousePos.Y)) {
-                this.hide(document.querySelector(target.dataset.parent));
-              }
+    if (document.querySelector('#contentMenu0') !== null) {
+      return;
+    }
+    const contextMenu1 = document.createElement('div');
+    contextMenu1.classList.add('context-menu');
+    contextMenu1.id = 'contentMenu0';
+    contextMenu1.style.display = 'none';
+    document.querySelector('body').append(contextMenu1);
+
+    const contextMenu2 = document.createElement('div');
+    contextMenu2.classList.add('context-menu');
+    contextMenu2.id = 'contentMenu1';
+    contextMenu2.style.display = 'none';
+    contextMenu2.dataset.parent = '#contentMenu0'
+    document.querySelector('body').append(contextMenu2);
+
+    document.querySelectorAll('.context-menu').forEach((contextMenu: Element): void => {
+      // Explicitly update cursor position if element is entered to avoid timing issues
+      new RegularEvent('mouseenter', (event: MouseEvent): void => {
+        this.storeMousePosition(event);
+      }).bindTo(contextMenu);
+
+      new DebounceEvent('mouseleave', (event: MouseEvent) => {
+        const target: HTMLElement = event.target as HTMLElement;
+        const childMenu: HTMLElement | null = document.querySelector(selector`[data-parent="#${target.id}"]`);
+
+        const hideThisMenu =
+          !ContextMenu.within(target, this.mousePos.X, this.mousePos.Y) // cursor it outside triggered context menu
+          && (childMenu === null || childMenu.offsetParent === null); // child menu, if any, is not visible
+
+        if (hideThisMenu) {
+          this.hide(target);
+
+          // close parent menu (if any), if cursor is outside its boundaries
+          let parent: HTMLElement | null;
+          if (typeof target.dataset.parent !== 'undefined' && (parent = document.querySelector(target.dataset.parent)) !== null) {
+            if (!ContextMenu.within(parent, this.mousePos.X, this.mousePos.Y)) {
+              this.hide(document.querySelector(target.dataset.parent));
             }
           }
-        }, 500).bindTo(contextMenu);
-      });
-    }
+        }
+      }, 500).bindTo(contextMenu);
+    });
   }
 
   private handleTriggerEvent(event: PointerEvent): void
@@ -237,28 +240,44 @@ class ContextMenu {
    * Make the AJAX request
    *
    * @param {string} parameters Parameters sent to the server
+   * @param {MousePosition} position
    */
   private fetch(parameters: string, position: MousePosition): void {
+    const stubMenu = this.renderStubMenu(0, position);
     const url = TYPO3.settings.ajaxUrls.contextmenu;
     (new AjaxRequest(url)).withQueryArguments(parameters).get().then(async (response: AjaxResponse): Promise<void> => {
       const data: MenuItems = await response.resolve();
       if (typeof response !== 'undefined' && Object.keys(response).length > 0) {
-        this.populateData(data, 0, position);
+        this.populateData(data, 0);
       }
+    }).catch((): void => {
+      this.hide(stubMenu);
     });
   }
 
+  private renderStubMenu(level: number, position: MousePosition): HTMLElement|null {
+    const contentMenuCurrent = document.querySelector('#contentMenu' + level) as HTMLElement;
+    if (contentMenuCurrent !== null) {
+      contentMenuCurrent.replaceChildren(document.createRange().createContextualFragment('<typo3-backend-spinner size="medium"></typo3-backend-spinner>'));
+      contentMenuCurrent.style.display = null;
+      position ??= this.getPosition(contentMenuCurrent);
+      const coordinates = this.toPixel(position);
+
+      contentMenuCurrent.style.top = coordinates.top;
+      contentMenuCurrent.style.insetInlineStart = coordinates.start;
+    }
+
+    return contentMenuCurrent;
+  }
+
   /**
    * Fills the context menu with content and displays it correctly
    * depending on the mouse position
    *
    * @param {MenuItems} items The data that will be put in the menu
    * @param {number} level The depth of the context menu
-   * @param {MousPosition}
    */
-  private populateData(items: MenuItems, level: number, position: MousePosition): void {
-    this.initializeContextMenuContainer();
-
+  private populateData(items: MenuItems, level: number): void {
     const contentMenuCurrent = document.querySelector('#contentMenu' + level) as HTMLElement;
     const contentMenuParent = document.querySelector('#contentMenu' + (level - 1)) as HTMLElement;
     if (contentMenuCurrent !== null && contentMenuParent?.offsetParent !== null) {
@@ -272,11 +291,6 @@ class ContextMenu {
       contentMenuCurrent.innerHTML = '';
       contentMenuCurrent.appendChild(menuGroup);
       contentMenuCurrent.style.display = null;
-      position ??= this.getPosition(contentMenuCurrent);
-      const coordinates = this.toPixel(position);
-
-      contentMenuCurrent.style.top = coordinates.top;
-      contentMenuCurrent.style.insetInlineStart = coordinates.start;
       (contentMenuCurrent.querySelector('.context-menu-item[tabindex="-1"]') as HTMLElement).focus();
       this.initializeEvents(contentMenuCurrent, level);
     }
diff --git a/Build/Sources/TypeScript/filelist/file-list-actions.ts b/Build/Sources/TypeScript/filelist/file-list-actions.ts
index ef4c74720d97c0cd2932aaff477acff107cff34a..5f005c01bbb2f84a67e635a9777a40502a8cef38 100644
--- a/Build/Sources/TypeScript/filelist/file-list-actions.ts
+++ b/Build/Sources/TypeScript/filelist/file-list-actions.ts
@@ -70,6 +70,8 @@ class FileListActions {
   constructor() {
     new RegularEvent('contextmenu', (event: Event, target: HTMLElement): void => {
       event.preventDefault();
+      event.stopImmediatePropagation();
+
       const detail: FileListActionDetail = this.getActionDetail(event, target);
       switch (detail.action) {
         case 'primary':
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/context-menu.js b/typo3/sysext/backend/Resources/Public/JavaScript/context-menu.js
index 33f13dbce778a49a22161e355ffd815fbb8fb1bd..cc569ab645a8ce487d35cc58fc4aece7cdde92a3 100644
--- a/typo3/sysext/backend/Resources/Public/JavaScript/context-menu.js
+++ b/typo3/sysext/backend/Resources/Public/JavaScript/context-menu.js
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import ContextMenuActions from"@typo3/backend/context-menu-actions.js";import DebounceEvent from"@typo3/core/event/debounce-event.js";import RegularEvent from"@typo3/core/event/regular-event.js";import{selector}from"@typo3/core/literals.js";class ContextMenu{constructor(){this.mousePos={X:null,Y:null},this.record={uid:null,table:null},this.eventSources=[],document.addEventListener("click",(e=>{this.handleTriggerEvent(e)})),document.addEventListener("contextmenu",(e=>{this.handleTriggerEvent(e)}))}static drawActionItem(e){const t=document.createElement("li");t.role="menuitem",t.classList.add("context-menu-item"),t.dataset.callbackAction=e.callbackAction,t.tabIndex=-1;const n=e.additionalAttributes||{};for(const e of Object.entries(n)){const[n,o]=e;t.setAttribute(n,o)}const o=document.createElement("span");o.classList.add("context-menu-item-icon"),o.innerHTML=e.icon;const s=document.createElement("span");return s.classList.add("context-menu-item-label"),s.innerHTML=e.label,t.append(o),t.append(s),t}static within(e,t,n){const o=e.getBoundingClientRect(),s=window.pageXOffset||document.documentElement.scrollLeft,i=window.pageYOffset||document.documentElement.scrollTop,c=t>=o.left+s&&t<=o.left+s+o.width,a=n>=o.top+i&&n<=o.top+i+o.height;return c&&a}show(e,t,n,o,s,i=null,c=null){this.hideAll(),this.record={table:e,uid:t};const a=i.matches('a, button, [tabindex]:not([tabindex="-1"])')?i:i.closest('a, button, [tabindex]:not([tabindex="-1"])');!1===this.eventSources.includes(a)&&this.eventSources.push(a);const r=new URLSearchParams;void 0!==e&&r.set("table",e),void 0!==t&&r.set("uid",t.toString()),void 0!==n&&r.set("context",n);let l=null;null!==c&&(this.storeMousePosition(c),l=this.mousePos),this.fetch(r.toString(),l)}initializeContextMenuContainer(){if(null===document.querySelector("#contentMenu0")){const e=document.createElement("div");e.classList.add("context-menu"),e.id="contentMenu0",e.style.display="none",document.querySelector("body").append(e);const t=document.createElement("div");t.classList.add("context-menu"),t.id="contentMenu1",t.style.display="none",t.dataset.parent="#contentMenu0",document.querySelector("body").append(t),document.querySelectorAll(".context-menu").forEach((e=>{new RegularEvent("mouseenter",(e=>{this.storeMousePosition(e)})).bindTo(e),new DebounceEvent("mouseleave",(e=>{const t=e.target,n=document.querySelector(selector`[data-parent="#${t.id}"]`);if(!ContextMenu.within(t,this.mousePos.X,this.mousePos.Y)&&(null===n||null===n.offsetParent)){let e;this.hide(t),void 0!==t.dataset.parent&&null!==(e=document.querySelector(t.dataset.parent))&&(ContextMenu.within(e,this.mousePos.X,this.mousePos.Y)||this.hide(document.querySelector(t.dataset.parent)))}}),500).bindTo(e)}))}}handleTriggerEvent(e){if(!(e.target instanceof Element))return;const t=e.target.closest("[data-contextmenu-trigger]");if(t instanceof HTMLElement)return void this.handleContextMenuEvent(e,t);e.target.closest(".context-menu")||this.hideAll()}handleContextMenuEvent(e,t){const n=t.dataset.contextmenuTrigger;"click"!==n&&n!==e.type||(e.preventDefault(),this.show(t.dataset.contextmenuTable??"",t.dataset.contextmenuUid??"",t.dataset.contextmenuContext??"","","",t,e))}fetch(e,t){const n=TYPO3.settings.ajaxUrls.contextmenu;new AjaxRequest(n).withQueryArguments(e).get().then((async e=>{const n=await e.resolve();void 0!==e&&Object.keys(e).length>0&&this.populateData(n,0,t)}))}populateData(e,t,n){this.initializeContextMenuContainer();const o=document.querySelector("#contentMenu"+t),s=document.querySelector("#contentMenu"+(t-1));if(null!==o&&null!==s?.offsetParent){const s=document.createElement("ul");s.classList.add("context-menu-group"),s.role="menu",this.drawMenu(e,t).forEach((e=>{s.appendChild(e)})),o.innerHTML="",o.appendChild(s),o.style.display=null,n??(n=this.getPosition(o));const i=this.toPixel(n);o.style.top=i.top,o.style.insetInlineStart=i.start,o.querySelector('.context-menu-item[tabindex="-1"]').focus(),this.initializeEvents(o,t)}}initializeEvents(e,t){e.querySelectorAll("li.context-menu-item").forEach((e=>{e.addEventListener("click",(e=>{e.preventDefault();const n=e.currentTarget;if(n.classList.contains("context-menu-item-submenu"))return void this.openSubmenu(t,n);const{callbackAction:o,callbackModule:s,...i}=n.dataset;n.dataset.callbackModule?import(s+".js").then((({default:e})=>{e[o](this.record.table,this.record.uid,i)})):ContextMenuActions&&"function"==typeof ContextMenuActions[o]?ContextMenuActions[o](this.record.table,this.record.uid,i):console.error("action: "+o+" not found"),this.hideAll()})),e.addEventListener("keydown",(e=>{e.preventDefault();const n=e.target;switch(e.key){case"Down":case"ArrowDown":this.setFocusToNextItem(n);break;case"Up":case"ArrowUp":this.setFocusToPreviousItem(n);break;case"Right":case"ArrowRight":if(!n.classList.contains("context-menu-item-submenu"))return;this.openSubmenu(t,n);break;case"Home":this.setFocusToFirstItem(n);break;case"End":this.setFocusToLastItem(n);break;case"Enter":case"Space":n.click();break;case"Esc":case"Escape":case"Left":case"ArrowLeft":this.hide(n.closest(".context-menu"));break;case"Tab":this.hideAll();break;default:return}}))}))}setFocusToPreviousItem(e){let t=this.getItemBackward(e.previousElementSibling);t||(t=this.getLastItem(e)),t.focus()}setFocusToNextItem(e){let t=this.getItemForward(e.nextElementSibling);t||(t=this.getFirstItem(e)),t.focus()}setFocusToFirstItem(e){const t=this.getFirstItem(e);t&&t.focus()}setFocusToLastItem(e){const t=this.getLastItem(e);t&&t.focus()}getItemBackward(e){for(;e&&(!e.classList.contains("context-menu-item")||"-1"!==e.getAttribute("tabindex"));)e=e.previousElementSibling;return e}getItemForward(e){for(;e&&(!e.classList.contains("context-menu-item")||"-1"!==e.getAttribute("tabindex"));)e=e.nextElementSibling;return e}getFirstItem(e){return this.getItemForward(e.parentElement.firstElementChild)}getLastItem(e){return this.getItemBackward(e.parentElement.lastElementChild)}openSubmenu(e,t){!1===this.eventSources.includes(t)&&this.eventSources.push(t);const n=document.querySelector("#contentMenu"+(e+1));n.innerHTML="",n.appendChild(t.nextElementSibling.querySelector(".context-menu-group").cloneNode(!0)),n.style.display=null;const o=this.toPixel(this.getPosition(n));n.style.top=o.top,n.style.insetInlineStart=o.start,n.querySelector('.context-menu-item[tabindex="-1"]').focus(),this.initializeEvents(n,e)}toPixel(e){return{start:Math.round(e.X)+"px",top:Math.round(e.Y)+"px"}}getPosition(e){const t="rtl"===document.querySelector("html").dir?"rtl":"ltr",n=this.eventSources?.[this.eventSources.length-1],o=e.offsetWidth,s=e.offsetHeight,i=window.innerWidth,c=window.innerHeight;let a=0,r=0;if(null!=n){const e=n.getBoundingClientRect();r=e.y,a="ltr"===t?e.x+e.width:i-e.x,n.classList.contains("context-menu-item-submenu")&&(r-=8)}else r=this.mousePos.Y,a="ltr"===t?this.mousePos.X:i-this.mousePos.X;return r+s+10+5<c?r+=5:r=c-s-10,a+o+10+5<i?a+=5:a=i-o-10,{X:a,Y:r}}drawMenu(e,t){const n=[];for(const o of Object.values(e))if("item"===o.type)n.push(ContextMenu.drawActionItem(o));else if("divider"===o.type){const e=document.createElement("li");e.role="separator",e.classList.add("context-menu-divider"),n.push(e)}else if("submenu"===o.type||o.childItems){const e=document.createElement("li");e.role="menuitem",e.ariaHasPopup="true",e.classList.add("context-menu-item","context-menu-item-submenu"),e.tabIndex=-1;const s=document.createElement("span");s.classList.add("context-menu-item-icon"),s.innerHTML=o.icon,e.appendChild(s);const i=document.createElement("span");i.classList.add("context-menu-item-label"),i.innerHTML=o.label,e.appendChild(i);const c=document.createElement("span");c.classList.add("context-menu-item-indicator"),c.innerHTML='<typo3-backend-icon identifier="actions-chevron-'+("rtl"===document.querySelector("html").dir?"left":"right")+'" size="small"></typo3-backend-icon>',e.appendChild(c),n.push(e);const a=document.createElement("div");a.classList.add("context-menu","contentMenu"+(t+1)),a.style.display="none";const r=document.createElement("ul");r.role="menu",r.classList.add("context-menu-group"),this.drawMenu(o.childItems,1).forEach((e=>{r.appendChild(e)})),a.appendChild(r),n.push(a)}return n}storeMousePosition(e){this.mousePos={X:e.pageX,Y:e.pageY}}hide(e){if(null===e)return;e.style.top=null,e.style.insetInlineStart=null,e.style.display="none";const t=this.eventSources.pop();t&&t.focus()}hideAll(){this.hide(document.querySelector("#contentMenu0")),this.hide(document.querySelector("#contentMenu1"))}}export default new ContextMenu;
\ No newline at end of file
+import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import ContextMenuActions from"@typo3/backend/context-menu-actions.js";import DebounceEvent from"@typo3/core/event/debounce-event.js";import RegularEvent from"@typo3/core/event/regular-event.js";import{selector}from"@typo3/core/literals.js";import"@typo3/backend/element/spinner-element.js";class ContextMenu{constructor(){this.mousePos={X:null,Y:null},this.record={uid:null,table:null},this.eventSources=[],document.addEventListener("click",(e=>{this.handleTriggerEvent(e)})),document.addEventListener("contextmenu",(e=>{this.handleTriggerEvent(e)}))}static drawActionItem(e){const t=document.createElement("li");t.role="menuitem",t.classList.add("context-menu-item"),t.dataset.callbackAction=e.callbackAction,t.tabIndex=-1;const n=e.additionalAttributes||{};for(const e of Object.entries(n)){const[n,o]=e;t.setAttribute(n,o)}const o=document.createElement("span");o.classList.add("context-menu-item-icon"),o.innerHTML=e.icon;const s=document.createElement("span");return s.classList.add("context-menu-item-label"),s.innerHTML=e.label,t.append(o),t.append(s),t}static within(e,t,n){const o=e.getBoundingClientRect(),s=window.pageXOffset||document.documentElement.scrollLeft,i=window.pageYOffset||document.documentElement.scrollTop,c=t>=o.left+s&&t<=o.left+s+o.width,r=n>=o.top+i&&n<=o.top+i+o.height;return c&&r}show(e,t,n,o,s,i=null,c=null){this.hideAll(),this.initializeContextMenuContainer(),this.record={table:e,uid:t};const r=i.matches('a, button, [tabindex]:not([tabindex="-1"])')?i:i.closest('a, button, [tabindex]:not([tabindex="-1"])');!1===this.eventSources.includes(r)&&this.eventSources.push(r);const a=new URLSearchParams;void 0!==e&&a.set("table",e),void 0!==t&&a.set("uid",t.toString()),void 0!==n&&a.set("context",n);let l=null;null!==c&&(this.storeMousePosition(c),l=this.mousePos),this.fetch(a.toString(),l)}initializeContextMenuContainer(){if(null!==document.querySelector("#contentMenu0"))return;const e=document.createElement("div");e.classList.add("context-menu"),e.id="contentMenu0",e.style.display="none",document.querySelector("body").append(e);const t=document.createElement("div");t.classList.add("context-menu"),t.id="contentMenu1",t.style.display="none",t.dataset.parent="#contentMenu0",document.querySelector("body").append(t),document.querySelectorAll(".context-menu").forEach((e=>{new RegularEvent("mouseenter",(e=>{this.storeMousePosition(e)})).bindTo(e),new DebounceEvent("mouseleave",(e=>{const t=e.target,n=document.querySelector(selector`[data-parent="#${t.id}"]`);if(!ContextMenu.within(t,this.mousePos.X,this.mousePos.Y)&&(null===n||null===n.offsetParent)){let e;this.hide(t),void 0!==t.dataset.parent&&null!==(e=document.querySelector(t.dataset.parent))&&(ContextMenu.within(e,this.mousePos.X,this.mousePos.Y)||this.hide(document.querySelector(t.dataset.parent)))}}),500).bindTo(e)}))}handleTriggerEvent(e){if(!(e.target instanceof Element))return;const t=e.target.closest("[data-contextmenu-trigger]");if(t instanceof HTMLElement)return void this.handleContextMenuEvent(e,t);e.target.closest(".context-menu")||this.hideAll()}handleContextMenuEvent(e,t){const n=t.dataset.contextmenuTrigger;"click"!==n&&n!==e.type||(e.preventDefault(),this.show(t.dataset.contextmenuTable??"",t.dataset.contextmenuUid??"",t.dataset.contextmenuContext??"","","",t,e))}fetch(e,t){const n=this.renderStubMenu(0,t),o=TYPO3.settings.ajaxUrls.contextmenu;new AjaxRequest(o).withQueryArguments(e).get().then((async e=>{const t=await e.resolve();void 0!==e&&Object.keys(e).length>0&&this.populateData(t,0)})).catch((()=>{this.hide(n)}))}renderStubMenu(e,t){const n=document.querySelector("#contentMenu"+e);if(null!==n){n.replaceChildren(document.createRange().createContextualFragment('<typo3-backend-spinner size="medium"></typo3-backend-spinner>')),n.style.display=null,t??(t=this.getPosition(n));const e=this.toPixel(t);n.style.top=e.top,n.style.insetInlineStart=e.start}return n}populateData(e,t){const n=document.querySelector("#contentMenu"+t),o=document.querySelector("#contentMenu"+(t-1));if(null!==n&&null!==o?.offsetParent){const o=document.createElement("ul");o.classList.add("context-menu-group"),o.role="menu",this.drawMenu(e,t).forEach((e=>{o.appendChild(e)})),n.innerHTML="",n.appendChild(o),n.style.display=null,n.querySelector('.context-menu-item[tabindex="-1"]').focus(),this.initializeEvents(n,t)}}initializeEvents(e,t){e.querySelectorAll("li.context-menu-item").forEach((e=>{e.addEventListener("click",(e=>{e.preventDefault();const n=e.currentTarget;if(n.classList.contains("context-menu-item-submenu"))return void this.openSubmenu(t,n);const{callbackAction:o,callbackModule:s,...i}=n.dataset;n.dataset.callbackModule?import(s+".js").then((({default:e})=>{e[o](this.record.table,this.record.uid,i)})):ContextMenuActions&&"function"==typeof ContextMenuActions[o]?ContextMenuActions[o](this.record.table,this.record.uid,i):console.error("action: "+o+" not found"),this.hideAll()})),e.addEventListener("keydown",(e=>{e.preventDefault();const n=e.target;switch(e.key){case"Down":case"ArrowDown":this.setFocusToNextItem(n);break;case"Up":case"ArrowUp":this.setFocusToPreviousItem(n);break;case"Right":case"ArrowRight":if(!n.classList.contains("context-menu-item-submenu"))return;this.openSubmenu(t,n);break;case"Home":this.setFocusToFirstItem(n);break;case"End":this.setFocusToLastItem(n);break;case"Enter":case"Space":n.click();break;case"Esc":case"Escape":case"Left":case"ArrowLeft":this.hide(n.closest(".context-menu"));break;case"Tab":this.hideAll();break;default:return}}))}))}setFocusToPreviousItem(e){let t=this.getItemBackward(e.previousElementSibling);t||(t=this.getLastItem(e)),t.focus()}setFocusToNextItem(e){let t=this.getItemForward(e.nextElementSibling);t||(t=this.getFirstItem(e)),t.focus()}setFocusToFirstItem(e){const t=this.getFirstItem(e);t&&t.focus()}setFocusToLastItem(e){const t=this.getLastItem(e);t&&t.focus()}getItemBackward(e){for(;e&&(!e.classList.contains("context-menu-item")||"-1"!==e.getAttribute("tabindex"));)e=e.previousElementSibling;return e}getItemForward(e){for(;e&&(!e.classList.contains("context-menu-item")||"-1"!==e.getAttribute("tabindex"));)e=e.nextElementSibling;return e}getFirstItem(e){return this.getItemForward(e.parentElement.firstElementChild)}getLastItem(e){return this.getItemBackward(e.parentElement.lastElementChild)}openSubmenu(e,t){!1===this.eventSources.includes(t)&&this.eventSources.push(t);const n=document.querySelector("#contentMenu"+(e+1));n.innerHTML="",n.appendChild(t.nextElementSibling.querySelector(".context-menu-group").cloneNode(!0)),n.style.display=null;const o=this.toPixel(this.getPosition(n));n.style.top=o.top,n.style.insetInlineStart=o.start,n.querySelector('.context-menu-item[tabindex="-1"]').focus(),this.initializeEvents(n,e)}toPixel(e){return{start:Math.round(e.X)+"px",top:Math.round(e.Y)+"px"}}getPosition(e){const t="rtl"===document.querySelector("html").dir?"rtl":"ltr",n=this.eventSources?.[this.eventSources.length-1],o=e.offsetWidth,s=e.offsetHeight,i=window.innerWidth,c=window.innerHeight;let r=0,a=0;if(null!=n){const e=n.getBoundingClientRect();a=e.y,r="ltr"===t?e.x+e.width:i-e.x,n.classList.contains("context-menu-item-submenu")&&(a-=8)}else a=this.mousePos.Y,r="ltr"===t?this.mousePos.X:i-this.mousePos.X;return a+s+10+5<c?a+=5:a=c-s-10,r+o+10+5<i?r+=5:r=i-o-10,{X:r,Y:a}}drawMenu(e,t){const n=[];for(const o of Object.values(e))if("item"===o.type)n.push(ContextMenu.drawActionItem(o));else if("divider"===o.type){const e=document.createElement("li");e.role="separator",e.classList.add("context-menu-divider"),n.push(e)}else if("submenu"===o.type||o.childItems){const e=document.createElement("li");e.role="menuitem",e.ariaHasPopup="true",e.classList.add("context-menu-item","context-menu-item-submenu"),e.tabIndex=-1;const s=document.createElement("span");s.classList.add("context-menu-item-icon"),s.innerHTML=o.icon,e.appendChild(s);const i=document.createElement("span");i.classList.add("context-menu-item-label"),i.innerHTML=o.label,e.appendChild(i);const c=document.createElement("span");c.classList.add("context-menu-item-indicator"),c.innerHTML='<typo3-backend-icon identifier="actions-chevron-'+("rtl"===document.querySelector("html").dir?"left":"right")+'" size="small"></typo3-backend-icon>',e.appendChild(c),n.push(e);const r=document.createElement("div");r.classList.add("context-menu","contentMenu"+(t+1)),r.style.display="none";const a=document.createElement("ul");a.role="menu",a.classList.add("context-menu-group"),this.drawMenu(o.childItems,1).forEach((e=>{a.appendChild(e)})),r.appendChild(a),n.push(r)}return n}storeMousePosition(e){this.mousePos={X:e.pageX,Y:e.pageY}}hide(e){if(null===e)return;e.style.top=null,e.style.insetInlineStart=null,e.style.display="none";const t=this.eventSources.pop();t&&t.focus()}hideAll(){this.hide(document.querySelector("#contentMenu0")),this.hide(document.querySelector("#contentMenu1"))}}export default new ContextMenu;
\ No newline at end of file
diff --git a/typo3/sysext/filelist/Resources/Public/JavaScript/file-list-actions.js b/typo3/sysext/filelist/Resources/Public/JavaScript/file-list-actions.js
index 32ffbc347d29cd0eab6ea8704dc7ec53eaa27972..ff9aa17bb2e55bc80b13dd6c079ca88c89d08406 100644
--- a/typo3/sysext/filelist/Resources/Public/JavaScript/file-list-actions.js
+++ b/typo3/sysext/filelist/Resources/Public/JavaScript/file-list-actions.js
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-import RegularEvent from"@typo3/core/event/regular-event.js";export var FileListActionEvent;!function(e){e.primary="typo3:filelist:resource:action:primary",e.primaryContextmenu="typo3:filelist:resource:action:primaryContextmenu",e.show="typo3:filelist:resource:action:show",e.rename="typo3:filelist:resource:action:rename",e.select="typo3:filelist:resource:action:select",e.download="typo3:filelist:resource:action:download",e.updateOnlineMedia="typo3:filelist:resource:action:updateOnlineMedia"}(FileListActionEvent||(FileListActionEvent={}));export var FileListActionSelector;!function(e){e.elementSelector="[data-filelist-element]",e.actionSelector="[data-filelist-action]"}(FileListActionSelector||(FileListActionSelector={}));export class FileListActionUtility{static createResourceFromContextDataset(e){return{type:e.filecontextType,identifier:e.filecontextIdentifier,name:e.filecontextName,thumbnail:null,uid:e.filecontextUid?parseInt(e.filecontextUid,10):null,metaUid:e.filecontextMetaUid?parseInt(e.filecontextMetaUid,10):null}}static getResourceForElement(e){return{type:e.dataset.filelistType,identifier:e.dataset.filelistIdentifier,name:e.dataset.filelistName,thumbnail:"filelistThumbnail"in e.dataset&&""!==e.dataset.filelistThumbnail.trim()?e.dataset.filelistThumbnail:null,uid:e.dataset.filelistUid?parseInt(e.dataset.filelistUid,10):null,metaUid:e.dataset.filelistMetaUid?parseInt(e.dataset.filelistMetaUid,10):null}}}class FileListActions{constructor(){new RegularEvent("contextmenu",((e,t)=>{e.preventDefault();const i=this.getActionDetail(e,t);if("primary"===i.action)document.dispatchEvent(new CustomEvent(FileListActionEvent.primaryContextmenu,{detail:i}))})).delegateTo(document,FileListActionSelector.actionSelector),new RegularEvent("click",((e,t)=>{e.preventDefault();const i=this.getActionDetail(e,t);switch(i.action){case"primary":document.dispatchEvent(new CustomEvent(FileListActionEvent.primary,{detail:i}));break;case"show":document.dispatchEvent(new CustomEvent(FileListActionEvent.show,{detail:i}));break;case"select":document.dispatchEvent(new CustomEvent(FileListActionEvent.select,{detail:i}));break;case"rename":document.dispatchEvent(new CustomEvent(FileListActionEvent.rename,{detail:i}));break;case"download":document.dispatchEvent(new CustomEvent(FileListActionEvent.download,{detail:i}));break;case"updateOnlineMedia":document.dispatchEvent(new CustomEvent(FileListActionEvent.updateOnlineMedia,{detail:i}))}})).delegateTo(document,FileListActionSelector.actionSelector)}getActionDetail(e,t){const i=t.dataset.filelistAction,n=t.closest(FileListActionSelector.elementSelector);return{event:e,trigger:t,action:i,resources:[FileListActionUtility.getResourceForElement(n)],url:t.dataset.filelistActionUrl??null}}}export default new FileListActions;
\ No newline at end of file
+import RegularEvent from"@typo3/core/event/regular-event.js";export var FileListActionEvent;!function(e){e.primary="typo3:filelist:resource:action:primary",e.primaryContextmenu="typo3:filelist:resource:action:primaryContextmenu",e.show="typo3:filelist:resource:action:show",e.rename="typo3:filelist:resource:action:rename",e.select="typo3:filelist:resource:action:select",e.download="typo3:filelist:resource:action:download",e.updateOnlineMedia="typo3:filelist:resource:action:updateOnlineMedia"}(FileListActionEvent||(FileListActionEvent={}));export var FileListActionSelector;!function(e){e.elementSelector="[data-filelist-element]",e.actionSelector="[data-filelist-action]"}(FileListActionSelector||(FileListActionSelector={}));export class FileListActionUtility{static createResourceFromContextDataset(e){return{type:e.filecontextType,identifier:e.filecontextIdentifier,name:e.filecontextName,thumbnail:null,uid:e.filecontextUid?parseInt(e.filecontextUid,10):null,metaUid:e.filecontextMetaUid?parseInt(e.filecontextMetaUid,10):null}}static getResourceForElement(e){return{type:e.dataset.filelistType,identifier:e.dataset.filelistIdentifier,name:e.dataset.filelistName,thumbnail:"filelistThumbnail"in e.dataset&&""!==e.dataset.filelistThumbnail.trim()?e.dataset.filelistThumbnail:null,uid:e.dataset.filelistUid?parseInt(e.dataset.filelistUid,10):null,metaUid:e.dataset.filelistMetaUid?parseInt(e.dataset.filelistMetaUid,10):null}}}class FileListActions{constructor(){new RegularEvent("contextmenu",((e,t)=>{e.preventDefault(),e.stopImmediatePropagation();const i=this.getActionDetail(e,t);if("primary"===i.action)document.dispatchEvent(new CustomEvent(FileListActionEvent.primaryContextmenu,{detail:i}))})).delegateTo(document,FileListActionSelector.actionSelector),new RegularEvent("click",((e,t)=>{e.preventDefault();const i=this.getActionDetail(e,t);switch(i.action){case"primary":document.dispatchEvent(new CustomEvent(FileListActionEvent.primary,{detail:i}));break;case"show":document.dispatchEvent(new CustomEvent(FileListActionEvent.show,{detail:i}));break;case"select":document.dispatchEvent(new CustomEvent(FileListActionEvent.select,{detail:i}));break;case"rename":document.dispatchEvent(new CustomEvent(FileListActionEvent.rename,{detail:i}));break;case"download":document.dispatchEvent(new CustomEvent(FileListActionEvent.download,{detail:i}));break;case"updateOnlineMedia":document.dispatchEvent(new CustomEvent(FileListActionEvent.updateOnlineMedia,{detail:i}))}})).delegateTo(document,FileListActionSelector.actionSelector)}getActionDetail(e,t){const i=t.dataset.filelistAction,n=t.closest(FileListActionSelector.elementSelector);return{event:e,trigger:t,action:i,resources:[FileListActionUtility.getResourceForElement(n)],url:t.dataset.filelistActionUrl??null}}}export default new FileListActions;
\ No newline at end of file