/* * 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{AjaxResponse as I}from"@typo3/core/ajax/ajax-response.js";import M from"@typo3/core/ajax/ajax-request.js";import N from"@typo3/backend/context-menu-actions.js";import"@typo3/backend/element/spinner-element.js";import{state as m,queryAll as b,customElement as k}from"lit/decorators.js";import{LitElement as C,nothing as x,html as f}from"lit";import{delay as S}from"@typo3/core/lit-helper.js";import{styleMap as v}from"lit/directives/style-map.js";import{unsafeHTML as y}from"lit/directives/unsafe-html.js";import{Task as T,initialState as E}from"@lit/task";import w from"@typo3/backend/notification.js";var d=function(h,t,e,n){var i=arguments.length,o=i<3?t:n===null?n=Object.getOwnPropertyDescriptor(t,e):n,s;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(h,t,e,n);else for(var r=h.length-1;r>=0;r--)(s=h[r])&&(o=(i<3?s(o):i>3?s(t,e,o):s(t,e))||o);return i>3&&o&&Object.defineProperty(t,e,o),o},p;(function(h){h.open="typo3:contextmenu:open",h.close="typo3:contextmenu:close"})(p||(p={}));class F{constructor(){document.addEventListener("click",t=>{this.handleTriggerEvent(t)}),document.addEventListener("contextmenu",t=>{this.handleTriggerEvent(t)})}show(t,e,n,i,o,s=null,r=null){const a=new CustomEvent(p.open,{detail:{table:t,uid:e,context:n,eventSource:s,originalEvent:r},bubbles:!0,composed:!0});top.document.dispatchEvent(a)}handleTriggerEvent(t){if(!(t.target instanceof Element))return;const e=t.target.closest("[data-contextmenu-trigger]");if(e instanceof HTMLElement){this.handleContextMenuEvent(t,e);return}}handleContextMenuEvent(t,e){const n=e.dataset.contextmenuTrigger;if(n==="click"||n===t.type){if(t.preventDefault(),(e.dataset.contextmenuTable??"")==="")throw console.error("Referenced element misses data-contextmenu-table",e),new Error("No data-contextmenu-table attribute provided in contextmenu trigger markup");if((e.dataset.contextmenuUid??"")==="")throw console.error("Referenced element misses data-contextmenu-uid",e),new Error("No data-contextmenu-uid attribute provided in contextmenu trigger markup");this.show(e.dataset.contextmenuTable??"",e.dataset.contextmenuUid??"",e.dataset.contextmenuContext??"","","",e,t)}}}var A=new F;let l=class extends C{constructor(){super(...arguments),this.open=!1,this.table="",this.uid="",this.context="",this.rootPositionY=0,this.rootPositionX=0,this.eventSource=null,this.rootIdentifier="root",this.focusFirstElement=!1,this.fetchTask=new T(this,{autoRun:!1,args:()=>[this.table,this.uid,this.context,this.open],task:async([t,e,n,i],{signal:o})=>{if(!i)return E;const s=new URLSearchParams;if(t!==""&&s.set("table",t),e!==""&&s.set("uid",e.toString()),(n??"")!==""&&s.set("context",n),s.size===0)return E;const r=TYPO3.settings.ajaxUrls.contextmenu,a=await new M(r).withQueryArguments(s).get({signal:o}),c=Object.values(await a.resolve());return c.length===0?E:this.enhanceNodes("root",c)},onComplete:()=>{this.focusFirstElement=!0},onError:t=>{t instanceof I?w.error("",t.response.status+" "+t.response.statusText,5):w.error("",t.message)}}),this.show=t=>{const e=t.detail;if(this.open=!0,this.table=e.table,this.uid=e.uid,this.context=e.context,this.eventSource=e.eventSource,e.originalEvent!==null){const n=this.calculateIframeOffset(e.originalEvent.view,window);let i,o;if(e.originalEvent.pointerId===-1&&e.originalEvent.target){const s=e.originalEvent.target.getBoundingClientRect();o=s.top+s.height/2,i=s.left}else o=e.originalEvent.clientY,i=e.originalEvent.clientX;this.rootPositionY=o+n.y,this.rootPositionX=i+n.x}this.fetchTask.run()},this.hide=async()=>{this.open&&(this.open=!1,this.fetchTask.run(),await this.updateComplete,this.eventSource?.focus())}}get nodes(){return this.fetchTask.value??[]}connectedCallback(){super.connectedCallback(),window.addEventListener("resize",this.hide),document.addEventListener(p.open,this.show),document.addEventListener(p.close,this.hide)}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("resize",this.hide),document.removeEventListener(p.open,this.show),document.removeEventListener(p.close,this.hide)}updated(){this.focusFirstElement&&(this.contextMenuItemElements.length>0&&Array.from(this.contextMenuItemElements).at(0).focus(),this.focusFirstElement=!1),this.updateContextMenuPositions()}createRenderRoot(){return this}render(){return this.fetchTask.render({initial:()=>x,pending:()=>[this.renderOverlay(),S(80,()=>this.renderMenu(null,this.rootIdentifier,this.rootPositionY,this.rootPositionX))],complete:t=>[this.renderOverlay(),this.renderMenu(t,this.rootIdentifier,this.rootPositionY,this.rootPositionX),this.flattenMenuItems(t).filter(e=>e.type==="submenu").map(e=>this.isNodeExpanded(e)?this.renderMenu(e.childItems,this.getNodeIdentifier(e),this.rootPositionY,this.rootPositionX):x)]})}renderOverlay(){return f`
this.handleOverlayClick(t)} @contextmenu=${t=>this.handleOverlayClick(t)}>
`}renderMenu(t,e,n,i){const o={top:n+"px",insetInlineStart:i+"px"};return t===null?f`
`:t.length===0?x:f`
`}renderMenuItem(t){return t.type==="divider"?f`
`:f``}showSubmenu(t){t.__expanded=!0}hideSubmenu(t){t.__expanded=!1}handleNodeClick(t,e){if(e.type==="submenu"){this.isNodeExpanded(e)?this.hideSubmenu(e):this.showSubmenu(e);return}const n=this.extractDataAttributesAndConvertToDataset(e.additionalAttributes),i=e.callbackAction,{callbackModule:o,...s}=n;o?import(o+".js").then(({default:r})=>{r[i](this.table,this.uid,s)}):N&&typeof N[i]=="function"?N[i](this.table,this.uid,s):console.error("action: "+i+" not found"),this.hide()}mapIframeTarget(t,e){if(t.tagName!=="IFRAME")return t;const n=t;let i;try{i=n.contentWindow}catch{return t}const o=n.getBoundingClientRect();return i.document.elementFromPoint(e.clientX-o.x,e.clientY-o.y)??t}async handleOverlayClick(t){t.preventDefault(),t.stopPropagation(),this.eventSource=null,await this.hide();let e=document.elementFromPoint(t.clientX,t.clientY);e&&e!==t.currentTarget&&(e=this.mapIframeTarget(e,t),e.dispatchEvent(new PointerEvent(t.type,t)),(e.tagName==="INPUT"||e.tagName==="TEXTAREA")&&e.focus())}async handleNodeKeyDown(t,e){if(!["ArrowDown","ArrowUp","ArrowLeft","ArrowRight","Home","End","Enter","Space","Escape","Tab"].includes(t.code)||t.altKey||t.ctrlKey)return;t.preventDefault(),t.stopPropagation();const i=this.getParralellNodesForNavigation(e),o=this.getFirstNode(i),s=this.getLastNode(i),r=this.getParentNode(e),a=this.getPreviousNode(e),c=this.getNextNode(e);switch(t.code){case"Enter":case"Space":if(e.type==="submenu"){this.showSubmenu(e),await this.updateComplete;const u=this.getFirstNode(e.childItems);u&&this.getElementFromNode(u)?.focus()}else this.getElementFromNode(e)?.click();break;case"Tab":this.hide();break;case"Escape":r?(this.hideSubmenu(r),await this.updateComplete,this.getElementFromNode(r)?.focus()):this.hide();break;case"ArrowUp":a&&this.getElementFromNode(a)?.focus();break;case"ArrowDown":c&&this.getElementFromNode(c)?.focus();break;case"ArrowRight":if(e.type==="submenu"){this.showSubmenu(e),await this.updateComplete;const u=this.getFirstNode(e.childItems);u&&this.getElementFromNode(u)?.focus()}break;case"ArrowLeft":r&&(this.hideSubmenu(r),await this.updateComplete,this.getElementFromNode(r)?.focus());break;case"Home":this.getElementFromNode(o)?.focus();break;case"End":this.getElementFromNode(s)?.focus();break;default:return}}getNodeIdentifier(t){return t.__contextMenuIdentifier}getNodeParentIdentifier(t){return t.__contextMenuParentIdentifier}getNodePositionInSet(t){return this.getParralellNodesForNavigation(t).indexOf(t)+1}getNodeSetSize(t){return this.getParralellNodesForNavigation(t).length}getParentNode(t){const e=this.getNodeParentIdentifier(t);return this.getNodeByIdentifier(e)}getNodeByIdentifier(t){return this.flattenMenuItems(this.nodes).find(n=>this.getNodeIdentifier(n)===t)??null}getPreviousNode(t){const e=this.getParralellNodesForNavigation(t),i=e.indexOf(t)-1;return e[i]?e[i]:this.getLastNode(e)}getNextNode(t){const e=this.getParralellNodesForNavigation(t),i=e.indexOf(t)+1;return e[i]?e[i]:this.getFirstNode(e)}getFirstNode(t){return t.at(0)??null}getLastNode(t){return t.at(-1)??null}isNodeExpanded(t){return t.__expanded===!0}getElementFromNode(t){return this.querySelector('[data-contextmenu-id="'+this.getNodeIdentifier(t)+'"]')}enhanceNodes(t,e){return e.reduce((i,o)=>{const s=t+"_"+o.identifier,r={...o,__contextMenuIdentifier:s,__contextMenuParentIdentifier:t,__expanded:!1,childItems:this.enhanceNodes(s,Object.values(o.childItems??{}))},a=this;return[...i,new Proxy(r,{set(c,u,g){return c[u]!==g&&(c[u]=g,a.requestUpdate()),!0}})]},[])}calculateIframeOffset(t,e){let n=0,i=0;if(t===e)return{x:n,y:i};const o=this.calculateIframeOffset(t.parent,e);n+=o.x,i+=o.y;const s=t.frameElement;if(s){const r=s.getBoundingClientRect();n+=r.x,i+=r.y}return{x:n,y:i}}extractDataAttributesAndConvertToDataset(t){const e=n=>n.replace(/^data-/,"").replace(/-([a-z])/g,(i,o)=>o.toUpperCase());return Object.fromEntries(Object.entries(t).filter(([n])=>n.startsWith("data-")).map(([n,i])=>[e(n),String(i)]))}updateContextMenuPositions(){if(this.contextMenuElements.length>0){const t=this.contextMenuElements[0];this.updateContextMenuPosition(t,this.rootPositionY,this.rootPositionX);const e=[...this.contextMenuElements].slice(1),n=this.getDocumentDirection();e.forEach(i=>{const o=this.getNodeByIdentifier(i.dataset.contextmenuParent),r=this.getElementFromNode(o).getBoundingClientRect(),a=r.top-7,c=n==="ltr"?r.right:r.left;this.updateContextMenuPosition(i,a,c)})}}updateContextMenuPosition(t,e,n){const s=this.getDocumentDirection(),r={width:t.offsetWidth,height:t.offsetHeight},a={width:document.documentElement.clientWidth,height:document.documentElement.clientHeight};let c=0,u=0;u=e,c=s==="ltr"?n:a.width-n;const g=u+r.height+10+5n.type!=="divider"):this.nodes.filter(n=>n.type!=="divider")}getDocumentDirection(){return document.querySelector("html").dir==="rtl"?"rtl":"ltr"}};d([m()],l.prototype,"open",void 0),d([m()],l.prototype,"table",void 0),d([m()],l.prototype,"uid",void 0),d([m()],l.prototype,"context",void 0),d([m()],l.prototype,"rootPositionY",void 0),d([m()],l.prototype,"rootPositionX",void 0),d([m()],l.prototype,"eventSource",void 0),d([b(".context-menu")],l.prototype,"contextMenuElements",void 0),d([b(".context-menu-item")],l.prototype,"contextMenuItemElements",void 0),l=d([k("typo3-backend-context-menu")],l);export{l as ContextMenuElement,A as default};