Files
cms-dashboard/Resources/Public/JavaScript/dashboard.js
T

14 lines
28 KiB
JavaScript

/*
* 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{LitElement as q,html as h,nothing as D}from"lit";import{state as E,query as H,customElement as M,property as W}from"lit/decorators.js";import{repeat as O}from"lit/directives/repeat.js";import{unsafeHTML as K}from"lit/directives/unsafe-html.js";import{styleMap as B}from"lit/directives/style-map.js";import{Task as G}from"@lit/task";import{fadeOut as Q,fadeIn as V,animate as J}from"@lit-labs/motion";import"@typo3/backend/element/icon-element.js";import p from"@typo3/core/ajax/ajax-request.js";import Y from"@typo3/backend/storage/client.js";import{delay as Z}from"@typo3/core/lit-helper.js";import b from"@typo3/backend/modal.js";import{SeverityEnum as x}from"@typo3/backend/enum/severity.js";import{AjaxResponse as _}from"@typo3/core/ajax/ajax-response.js";import{Categories as tt}from"@typo3/backend/new-record-wizard.js";import{topLevelModuleImport as j}from"@typo3/backend/utility/top-level-module-import.js";import{selector as et}from"@typo3/core/literals.js";import U from"@typo3/backend/utility/dom-helper.js";import w from"@typo3/backend/notification.js";import{SettingsEditorSubmitEvent as it}from"@typo3/backend/settings/editor.js";import r from"~labels/dashboard.messages";var v=function(u,t,e,s){var a=arguments.length,i=a<3?t:s===null?s=Object.getOwnPropertyDescriptor(t,e):s,n;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")i=Reflect.decorate(u,t,e,s);else for(var d=u.length-1;d>=0;d--)(n=u[d])&&(i=(a<3?n(i):a>3?n(t,e,i):n(t,e))||i);return a>3&&i&&Object.defineProperty(t,e,i),i},f;(function(u){u.start="start",u.end="end",u.left="left",u.right="right",u.up="up",u.down="down"})(f||(f={}));const st="typo3:dashboard:widget:add";class S extends Event{static{this.eventName="typo3:dashboard:widget:content:rendered"}constructor(t){super(S.eventName,{bubbles:!0,composed:!0,cancelable:!1}),this.widget=t}}class $ extends Event{static{this.eventName="typo3:dashboard:widget:moveIntend"}constructor(t,e){super($.eventName,{bubbles:!0,composed:!0,cancelable:!1}),this.identifier=t,this.intend=e}}class A extends Event{static{this.eventName="typo3:dashboard:widget:remove"}constructor(t){super(A.eventName,{bubbles:!0,composed:!0,cancelable:!1}),this.identifier=t}}class T extends Event{static{this.eventName="typo3:dashboard:widget:refresh"}constructor(t){super(T.eventName,{bubbles:!0,composed:!0,cancelable:!1}),this.identifier=t}}class L extends Event{static{this.eventName="typo3:dashboard:dashboard:add"}constructor(t,e){super(L.eventName),this.preset=t,this.title=e}}class N extends Event{static{this.eventName="typo3:dashboard:dashboard:edit"}constructor(t,e){super(N.eventName),this.identifier=t,this.title=e}}class P extends Event{static{this.eventName="typo3:dashboard:dashboard:update"}constructor(t,e,s){super(P.eventName),this.identifier=t,this.widgets=e,this.widgetPositions=s}}class z extends Event{static{this.eventName="typo3:dashboard:dashboard:delete"}constructor(t){super(z.eventName),this.identifier=t}}function R(u){const t=new Set;for(let e=0;e<u.height;e++)for(let s=0;s<u.width;s++){const a=`${u.y+e}-${u.x+s}`;t.add(a)}return t}let y=class extends q{constructor(){super(),this.loading=!1,this.dashboards=[],this.currentDashboard=null,this.columns=4,this.dragInformation=null,this.resizeObserver=null,this.clientStorageIdentifier="dashboard/current_dashboard",this.prefersReducedMotion=!1,this.mql=null,this.dragOverTimeout=null,this.activeElementRef=null,this.mqListener=t=>{this.prefersReducedMotion=t.matches},this.addEventListener(T.eventName,t=>{t.preventDefault(),this.getGridItemByIdentifier(t.identifier).querySelector("typo3-dashboard-widget").refresh()}),this.addEventListener(A.eventName,t=>{t.preventDefault();const{identifier:e}=t;new p(TYPO3.settings.ajaxUrls.dashboard_widget_remove).post({dashboard:this.currentDashboard.identifier,identifier:e}).then(async s=>{const a=await s.resolve();if(a.status==="ok"){this.currentDashboard.widgets=this.currentDashboard.widgets.filter(i=>i.identifier!==e);for(const[i,n]of Object.entries(this.currentDashboard.widgetPositions)){const d=Number(i);this.currentDashboard.widgetPositions[d]=n.filter(c=>c.identifier!==e)}this.requestUpdate()}else w.error("",a.message)})}),this.addEventListener($.eventName,t=>{t.preventDefault();const{intend:e,identifier:s}=t,a=this.widgetPositionByIdentifier(s);switch(e){case f.up:a.y=Math.max(0,a.y-1);break;case f.down:a.y++;break;case f.left:a.x=Math.max(0,a.x-1);break;case f.right:a.x=Math.min(this.columns-a.width,a.x+1);break;case f.end:document.activeElement instanceof HTMLElement&&document.activeElement.closest("typo3-dashboard")===this&&(this.activeElementRef=document.activeElement),this.widgetPositionsSort(this.currentDashboard.widgetPositions[this.columns]),this.dispatchEvent(new P(this.currentDashboard.identifier,this.currentDashboard.widgets,this.currentDashboard.widgetPositions));return;default:return}this.widgetPositionChange(this.currentDashboard.widgetPositions[this.columns],a),this.updateComplete.then(()=>{const i=this.getGridItemByIdentifier(s);if(i){const n=e!==f.up;U.scrollIntoViewIfNeeded(i,n)}})}),this.addEventListener(L.eventName,t=>{t.preventDefault();const{preset:e,title:s}=t;new p(TYPO3.settings.ajaxUrls.dashboard_dashboard_add).post({preset:e,title:s}).then(async a=>{const i=await a.resolve();if(i.status==="ok"){const n=i.dashboard;this.dashboards.push(n);const d=this.getDashboardByIdentifier(n.identifier)||this.getDashboardFirst();this.selectDashboard(d),this.requestUpdate()}else w.error("",i.message)})}),this.addEventListener(N.eventName,t=>{t.preventDefault();const{identifier:e,title:s}=t;new p(TYPO3.settings.ajaxUrls.dashboard_dashboard_edit).post({identifier:e,title:s}).then(async a=>{const i=await a.resolve();if(i.status==="ok"){const n=this.dashboards.filter(l=>l.identifier===e)[0],d=this.dashboards.indexOf(n),c=i.dashboard;this.dashboards[d]=c,n.identifier===c.identifier&&this.selectDashboard(c),this.requestUpdate()}else w.error("",i.message)})}),this.addEventListener(P.eventName,t=>{t.preventDefault();const{identifier:e,widgets:s,widgetPositions:a}=t;new p(TYPO3.settings.ajaxUrls.dashboard_dashboard_update).post({identifier:e,widgets:s,widgetPositions:a}).then(async i=>{const n=await i.resolve();if(n.status==="ok"){const d=this.dashboards.filter(o=>o.identifier===e)[0],c=this.dashboards.indexOf(d),l=n.dashboard;this.dashboards[c]=l,d.identifier===l.identifier&&this.selectDashboard(l),this.requestUpdate()}else w.error("",n.message)})}),this.addEventListener(z.eventName,t=>{t.preventDefault();const{identifier:e}=t;new p(TYPO3.settings.ajaxUrls.dashboard_dashboard_delete).post({identifier:e}).then(async s=>{const a=await s.resolve();if(a.status==="ok"){this.dashboards=this.dashboards.filter(n=>n.identifier!==e);const i=this.getDashboardFirst();this.selectDashboard(i),this.requestUpdate()}else w.error("",a.message)})})}connectedCallback(){super.connectedCallback(),this.resizeObserver=new ResizeObserver(t=>{for(const e of t){const{width:s}=e.contentRect;s>950?this.columns=4:s>750?this.columns=2:this.columns=1}}),this.resizeObserver.observe(this),this.mql=window.matchMedia("(prefers-reduced-motion: reduce)"),this.mqListener(this.mql),this.mql.addEventListener("change",this.mqListener)}disconnectedCallback(){super.disconnectedCallback(),this.resizeObserver?.disconnect(),this.resizeObserver=null,this.mql?.removeEventListener("change",this.mqListener),this.mql=null}firstUpdated(){this.load()}updated(){this.activeElementRef&&(this.activeElementRef.focus(),this.activeElementRef=null)}createRenderRoot(){return this}render(){return this.loading?this.renderLoader():h`${this.renderHeader()}<div class=dashboard-container @dragend=${this.handleDragEnd} @dragover=${this.handleDragOver} @dragstart=${this.handleDragStart}>${this.renderContent()}<div class=dashboard-dragging-container></div></div>${this.renderFooter()}`}async load(){this.loading=!0,this.dashboards=await this.fetchDashboards();const t=Y.get(this.clientStorageIdentifier),e=this.getDashboardByIdentifier(t)||this.getDashboardFirst();this.selectDashboard(e),this.loading=!1}async fetchData(t){try{return(await new p(t).get({cache:"no-cache"})).resolve()}catch(e){return console.error(e),[]}}async fetchPresets(){const t=await this.fetchData(TYPO3.settings.ajaxUrls.dashboard_presets_get);return Object.values(t)}async fetchCategories(){const t=await this.fetchData(TYPO3.settings.ajaxUrls.dashboard_categories_get);return tt.fromData(t)}async fetchDashboards(){return await this.fetchData(TYPO3.settings.ajaxUrls.dashboard_dashboards_get)}getDashboardByIdentifier(t){return this.dashboards.find(e=>e.identifier===t)||null}getDashboardFirst(){return this.dashboards.length>0?this.dashboards[0]:null}async createDashboard(){const e=(await this.fetchPresets()).filter(a=>a.showInWizard),s=h`<form><div class=form-group><label class=form-label for=dashboard-form-add-title>${r.get("dashboard.title")}</label> <input class=form-control id=dashboard-form-add-title type=text name=title required></div><div class=dashboard-modal-items>${O(e,a=>a.identifier,(a,i)=>h`<div class=dashboard-modal-item><input type=radio name=preset value=${a.identifier} class=dashboard-modal-item-checkbox id=dashboard-form-add-preset-${a.identifier} ?checked=${i===0}> <label for=dashboard-form-add-preset-${a.identifier} class=dashboard-modal-item-block><span class=dashboard-modal-item-icon> <typo3-backend-icon identifier=${a.icon} size=medium></typo3-backend-icon> </span> <span class=dashboard-modal-item-details><span class=dashboard-modal-item-title>${a.title}</span> <span class=dashboard-modal-item-description>${a.description}</span> </span></label></div>`)}</div></form>`;b.advanced({type:b.types.default,title:r.get("dashboard.add"),size:b.sizes.medium,severity:x.notice,content:s,callback:a=>{a.addEventListener("typo3-modal-shown",()=>{a.querySelector("#dashboard-form-add-title")?.focus()}),a.querySelector("form").addEventListener("submit",i=>{i.preventDefault();const n=i.target,d=new FormData(n);this.dispatchEvent(new L(d.get("preset"),d.get("title"))),a.hideModal()})},buttons:[{text:r.get("dashboard.add.button.close"),btnClass:"btn-default",name:"cancel",trigger:(a,i)=>i.hideModal()},{text:r.get("dashboard.add.button.ok"),btnClass:"btn-primary",name:"save",trigger:(a,i)=>i.querySelector("form").requestSubmit()}]})}editDashboard(t){const e=h`<form><div class=form-group><label class=form-label for=dashboard-form-edit-title>${r.get("dashboard.title")}</label> <input class=form-control id=dashboard-form-edit-title type=text name=title value=${t.title||""} required></div></form>`;b.advanced({type:b.types.default,title:r.get("dashboard.configure"),size:b.sizes.small,severity:x.notice,content:e,callback:s=>{s.addEventListener("typo3-modal-shown",()=>{s.querySelector("#dashboard-form-edit-title")?.focus()}),s.querySelector("form").addEventListener("submit",a=>{a.preventDefault();const i=a.target,n=new FormData(i);this.dispatchEvent(new N(t.identifier,n.get("title"))),s.hideModal()})},buttons:[{text:r.get("dashboard.configure.button.close"),btnClass:"btn-default",name:"cancel",trigger:(s,a)=>a.hideModal()},{text:r.get("dashboard.configure.button.ok"),btnClass:"btn-primary",name:"save",trigger:(s,a)=>a.querySelector("form").requestSubmit()}]})}deleteDashboard(t){const e=b.confirm(r.get("dashboard.delete"),r.get("dashboard.delete.sure"),x.warning,[{text:r.get("dashboard.delete.cancel"),active:!0,btnClass:"btn-default",name:"cancel"},{text:r.get("dashboard.delete.ok"),btnClass:"btn-warning",name:"delete"}]);e.addEventListener("button.clicked",s=>{s.target.getAttribute("name")==="delete"&&this.dispatchEvent(new z(t.identifier)),e.hideModal()})}selectDashboard(t){t!==null&&Y.set(this.clientStorageIdentifier,t.identifier),this.currentDashboard=t}async addWidget(){j("@typo3/backend/new-record-wizard.js");const t=top.document.createElement("typo3-backend-new-record-wizard");t.storeName="dashboard-widgets",t.searchPlaceholder=r.get("widget.addToDashboard.searchLabel"),t.searchNothingFoundLabel=r.get("widget.addToDashboard.searchNotFound"),t.userNotAllowedLabel=r.get("widget.addToDashboard.userNotAllowed"),t.categories=await this.fetchCategories(),t.addEventListener(st,async e=>{const{identifier:s}=e.detail.item,i=await(await new p(TYPO3.settings.ajaxUrls.dashboard_widget_add).post({dashboard:this.currentDashboard.identifier,type:s})).resolve();if(i.status==="ok"){this.currentDashboard.widgets.push(i.widget),this.requestUpdate(),await this.updateComplete;const n=this.getGridItemByIdentifier(i.widget.identifier);n&&(U.scrollIntoViewIfNeeded(n,!0),window.setTimeout(()=>n.querySelector(".widget-actions > button:first-child")?.focus({preventScroll:!0,focusVisible:!1}),50))}else w.error("",i.message)}),b.advanced({type:b.types.default,title:r.get("widget.addToDashboard",[this.currentDashboard.title]),size:b.sizes.medium,severity:x.notice,content:t,callback:e=>{e.addEventListener("button.clicked",()=>{e.hideModal()})},buttons:[{text:r.get("widget.add.button.close"),btnClass:"btn-default",name:"cancel"}]})}renderLoader(){return h`<div class=dashboard-loader><typo3-backend-spinner size=medium></typo3-backend-spinner></div>`}renderHeader(){const t=h`<button class="btn btn-primary btn-sm btn-dashboard-add-tab" title=${r.get("dashboard.add")} @click=${()=>{this.createDashboard()}}><typo3-backend-icon identifier=actions-plus size=small></typo3-backend-icon><span class=visually-hidden>${r.get("dashboard.add")}</span></button>`,e=this.currentDashboard!==null?h`<button class="btn btn-default btn-sm" title=${r.get("dashboard.configure")} @click=${()=>{this.editDashboard(this.currentDashboard)}}><typo3-backend-icon identifier=actions-cog size=small></typo3-backend-icon><span class=visually-hidden>${r.get("dashboard.configure")}</span></button>`:D,s=this.currentDashboard!==null?h`<button class="btn btn-default btn-sm" title=${r.get("dashboard.delete")} @click=${()=>{this.deleteDashboard(this.currentDashboard)}}><typo3-backend-icon identifier=actions-delete size=small></typo3-backend-icon><span class=visually-hidden>${r.get("dashboard.delete")}</span></button>`:D;return h`<div class=dashboard-header><h1 class=visually-hidden>${this.currentDashboard?.title}</h1><div class=dashboard-header-container><div class=dashboard-tabs>${O(this.dashboards,a=>a.identifier,a=>h`<button @click=${()=>{this.selectDashboard(a)}} class=dashboard-tab${a===this.currentDashboard?" dashboard-tab--active":""}>${a.title}</button>`)} ${t}</div>${e||s?h`<div class="dashboard-configuration btn-toolbar" role=toolbar>${e}${s}</div>`:D}</div></div>`}renderContent(){if(this.currentDashboard){if(this.currentDashboard.widgets.length>0){this.initializeCurrentDashboard();const t={keyframeOptions:{duration:250,fill:"both"},in:V,out:Q,skipInitial:!0,disabled:this.prefersReducedMotion};return h`<div class=dashboard-grid style=${B({"--columns":this.columns})}>${O(this.currentDashboard.widgetPositions[this.columns],e=>e.identifier,e=>h`<div class=dashboard-item style=${B({"--col-start":e.x+1,"--col-span":e.width,"--row-start":e.y+1,"--row-span":e.height})} data-widget-hash=${e.identifier} data-widget-key=${this.widgetByIdentifier(e.identifier)?.type} data-widget-identifier=${e.identifier} draggable=true @pointerenter=${s=>s.target.setAttribute("draggable","true")} @widgetRefresh=${()=>this.handleLegacyWidgetRefreshEvent(e)} ${J(t)}><typo3-dashboard-widget .identifier=${e.identifier}></typo3-dashboard-widget></div>`)}</div>`}return h`<div class=dashboard-empty><div class=dashboard-empty-content><h3>${r.get("dashboard.empty.content.title")}</h3><p>${r.get("dashboard.empty.content.description")}</p><button title=${r.get("widget.add")} class="btn btn-primary" @click=${()=>{this.addWidget()}}><typo3-backend-icon identifier=actions-plus size=small></typo3-backend-icon>${r.get("dashboard.empty.content.button")}</button></div></div>`}return D}renderFooter(){return this.currentDashboard===null?D:h`<div class=dashboard-add-item><button class="btn btn-primary btn-dashboard-add-widget" title=${r.get("widget.addToDashboard",[this.currentDashboard.title])} @click=${()=>{this.addWidget()}}><typo3-backend-icon identifier=actions-plus size=small></typo3-backend-icon><span class=visually-hidden>${r.get("widget.addToDashboard",[this.currentDashboard.title])}</span></button></div>`}getGridItemByIdentifier(t){return this.querySelector(et`.dashboard-item[data-widget-identifier="${t}"]`)}handleDragStart(t){const s=t.target.closest(".dashboard-item");if(s===null){t.preventDefault();return}if(document.elementFromPoint(t.clientX,t.clientY).closest(".widget-header")===null){t.preventDefault();return}const i=s.dataset.widgetIdentifier,n=this.widgetPositionByIdentifier(i),d=s.getBoundingClientRect(),c=s.querySelector("typo3-dashboard-widget");c.style.pointerEvents="none",this.dragInformation={identifier:i,itemElement:s,widgetElement:c,height:n.height,width:n.width,offsetY:t.clientY-d.top,offsetX:t.clientX-d.left,currentY:n.y,currentX:n.x,initialPositions:this.currentDashboard.widgetPositions[this.columns].map(o=>({...o}))};const l=new Image;l.src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",t.dataTransfer.setDragImage(l,0,0),t.dataTransfer.setData("text/plain",""),t.dataTransfer.effectAllowed="move",s.classList.add("dashboard-item-dragging"),this.positionDraggingElement(t),this.draggingContainer.appendChild(c)}positionDraggingElement(t){const e=(o,g,m)=>Math.min(m,Math.max(g,o)),{itemElement:s,widgetElement:a}=this.dragInformation,i=s.getBoundingClientRect(),n=this.querySelector(".dashboard-container").getBoundingClientRect(),d=20,c=e(t.clientX-this.dragInformation.offsetX,n.left-d,n.left+n.width-i.width+d),l=Math.max(n.top-d,t.clientY-this.dragInformation.offsetY);a.style.left=`${c}px`,a.style.top=`${l}px`,a.style.width=`${i.width}px`,a.style.height=`${i.height}px`}handleDragEnd(){if(this.dragInformation){const{itemElement:t,widgetElement:e}=this.dragInformation;t.classList.remove("dashboard-item-dragging"),t.appendChild(e),e.removeAttribute("style"),this.dragInformation=null,this.widgetPositionsSort(this.currentDashboard.widgetPositions[this.columns]),this.dispatchEvent(new P(this.currentDashboard.identifier,this.currentDashboard.widgets,this.currentDashboard.widgetPositions))}}handleDragOver(t){if(this.dragInformation){t.preventDefault(),t.dataTransfer.dropEffect="move",this.positionDraggingElement(t);const e=this.querySelector(".dashboard-grid"),s=e.getBoundingClientRect(),a=parseInt(getComputedStyle(e).gap,10),i=parseInt(getComputedStyle(e).gridAutoRows,10)+a,n=(s.width+a)/this.columns,d=Math.max(0,t.clientY-s.top-this.dragInformation.offsetY),c=Math.max(0,t.clientX-s.left-this.dragInformation.offsetX),l=Math.max(0,Math.round(d/i)),o=Math.max(0,Math.min(Math.round(c/n),this.columns-this.dragInformation.width));(this.dragInformation.currentY!==l||this.dragInformation.currentX!==o)&&(this.dragInformation.currentY=l,this.dragInformation.currentX=o,this.dragOverTimeout&&clearTimeout(this.dragOverTimeout),this.dragOverTimeout=window.setTimeout(()=>{if(this.dragInformation){const g=this.widgetPositionByIdentifier(this.dragInformation.identifier);g.y=this.dragInformation.currentY,g.x=this.dragInformation.currentX,this.widgetPositionChange(this.currentDashboard.widgetPositions[this.columns],g)}},100))}}handleLegacyWidgetRefreshEvent(t){this.dispatchEvent(new T(t.identifier))}initializeCurrentDashboard(){this.currentDashboard.widgetPositions=this.currentDashboard.widgetPositions??{};let t=this.currentDashboard.widgetPositions?.[this.columns]??[];const e={small:1,medium:2,large:4},s={small:1,medium:2,large:3};this.currentDashboard.widgets.forEach(a=>{if(t.find(i=>i.identifier===a.identifier)===void 0){const i=s[a.height]??1,n=e[a.width]??1,d={identifier:a.identifier,height:i,width:n<this.columns?n:this.columns,y:0,x:0};t.push(d)}}),t=this.widgetPositionsArrange(t),this.widgetPositionsCollapseRows(t),this.currentDashboard.widgetPositions[this.columns]=t}widgetByIdentifier(t){return this.currentDashboard.widgets.find(e=>e.identifier===t)??null}widgetPositionByIdentifier(t){return this.currentDashboard.widgetPositions[this.columns].find(e=>e.identifier===t)??null}widgetPositionCanPlace(t,e,s,a){return e<0||e>this.columns-t.width||s<0?!1:a.isDisjointFrom(R({...t,x:e,y:s}))}widgetPositionChange(t,e){let s=structuredClone(this.dragInformation?.initialPositions??t);const a=s.findIndex(n=>n.identifier===e.identifier);let i;if(a>-1){const[n]=s.splice(a,1);i={...n},n.y=e.y,n.x=e.x,s.unshift(n)}s=this.widgetPositionsArrange(s,this.dragInformation?.initialPositions??t,i),t.forEach(n=>{const d=s.find(c=>c.identifier===n.identifier);n.y=d.y,n.x=d.x}),this.widgetPositionsCollapseRows(t),this.requestUpdate()}widgetTryPlacementInNeighbourCells(t,e,s){const a=this.columns;for(let i=t.x;i>=Math.max(0,t.x-t.width);i--)if(this.widgetPositionCanPlace(t,i,t.y,e))return{...t,x:i};for(let i=t.y;i>=0;i--)if(this.widgetPositionCanPlace(t,t.x,i,e))return{...t,y:i};for(let i=t.x;i<=Math.min(a,t.x+t.width);i++)if(this.widgetPositionCanPlace(t,i,t.y,e))return{...t,x:i};for(let i=t.y;i<=t.y+(s?.height??3);i++)if(this.widgetPositionCanPlace(t,t.x,i,e))return{...t,y:i};return null}widgetPositionsArrange(t,e,s){let a=new Set;const i=o=>this.widgetPositionCanPlace(o,o.x,o.y,a)?{...o}:null,n=o=>e===void 0?null:this.widgetTryPlacementInNeighbourCells(o,e.reduce((g,m)=>g.union(R(m)),new Set).difference(R(s)).union(a),s),d=o=>this.widgetTryPlacementInNeighbourCells(o,a),c=o=>{const g=Math.max(0,o.y),m=Math.max(0,Math.min(this.columns-o.width,o.x)),F=Math.max(0,m),X=this.columns;for(let C=o.y;C<g+100;C++)for(let I=F;I<X;I++)if(this.widgetPositionCanPlace(o,I,C,a))return{...o,x:I,y:C};throw new Error("Logic error: could not occupy cells")},l=o=>(a=a.union(R(o)),o);return t.map(o=>l(i(o)??n(o)??d(o)??c(o)))}widgetPositionsCollapseRows(t){const e=new Set;t.forEach(i=>{for(let n=0;n<i.height;n++)e.add(i.y+n)});const s={};let a=0;for(let i=0;i<=Math.max(...e);i++)e.has(i)&&(s[i]=a++);t.forEach(i=>{i.y=s[i.y]})}widgetPositionsSort(t){t.sort((e,s)=>e.y!==s.y?e.y-s.y:e.x-s.x)}};v([E()],y.prototype,"loading",void 0),v([E()],y.prototype,"dashboards",void 0),v([E()],y.prototype,"currentDashboard",void 0),v([E()],y.prototype,"columns",void 0),v([E()],y.prototype,"dragInformation",void 0),v([H(".dashboard-dragging-container")],y.prototype,"draggingContainer",void 0),y=v([M("typo3-dashboard")],y);let k=class extends q{constructor(){super(...arguments),this.moving=!1,this.triggerContentRenderedEvent=!1,this.fetchTask=new G(this,{args:()=>[this.identifier],task:async([t],{signal:e})=>{const s=TYPO3.settings.ajaxUrls.dashboard_widget_get,i=await(await new p(s).withQueryArguments({widget:t}).get({signal:e})).resolve();if(i.status!=="ok")throw new Error(i.message);return i.widget},onComplete:async()=>{this.triggerContentRenderedEvent=!0},onError:t=>{console.error(`Error while retrieving widget [${this.identifier}]: ${t instanceof _?`${t.response.status} ${t.response.statusText}`:t.message}`)}})}get widget(){return this.fetchTask.value??null}refresh(){this.handleRefresh()}createRenderRoot(){return this}updated(){if(this.triggerContentRenderedEvent){this.triggerContentRenderedEvent=!1;const{widget:t}=this;this.dispatchEvent(new S(t)),this.dispatchEvent(new CustomEvent("widgetContentRendered",{bubbles:!0,detail:this.widget.eventdata}))}}render(){const t=h`<div class=widget-loader><typo3-backend-spinner size=medium></typo3-backend-spinner></div>`,e=c=>c?.label||"ERROR",s=c=>c?K(c.content):h`<div class=widget-content-main>${r.get("widget.error")}</div>`,a=()=>h`<button type=button title=${r.get("widget.settings")} class="widget-action widget-action-settings" @click=${this.editSettings}><typo3-backend-icon identifier=actions-cog size=small></typo3-backend-icon><span class=visually-hidden>${r.get("widget.settings")}</span></button>`,i=(c=!1)=>h`<button type=button title=${r.get("widget.refresh")} class="widget-action widget-action-refresh" @click=${this.handleRefresh}>${c?h`<typo3-backend-spinner size=small></typo3-backend-spinner>`:h`<typo3-backend-icon identifier=actions-refresh size=small></typo3-backend-icon>`} <span class=visually-hidden>${r.get("widget.refresh")}</span></button>`,n=(c,l=!1)=>h`<div class=widget-header><div class=widget-title>${e(c)}</div><div class=widget-actions>${c?.configurable?a():D} ${c?.refreshable?i(l):D} <button type=button title=${r.get("widget.move")} class="widget-action widget-action-move" @click=${this.handleMoveClick} @focusout=${this.handleMoveFocusOut} @keydown=${this.handleMoveKeyDown}><typo3-backend-icon identifier=${this.moving?"actions-thumbtack":"actions-move"} size=small></typo3-backend-icon><span class=visually-hidden>${r.get("widget.move")}</span></button> <button type=button title=${r.get("widget.remove")} class="widget-action widget-action-remove" @click=${this.handleRemove}><typo3-backend-icon identifier=actions-delete size=small></typo3-backend-icon><span class=visually-hidden>${r.get("widget.remove")}</span></button></div></div><div class=widget-content @pointerenter=${o=>o.target.closest(".dashboard-item").removeAttribute("draggable")} @pointerleave=${o=>o.target.closest(".dashboard-item").setAttribute("draggable","true")}>${s(c)}</div>`,d=this.fetchTask.render({initial:()=>D,error:()=>n(null),pending:()=>this.fetchTask.value?n(this.fetchTask.value,!0):Z(80,()=>t),complete:c=>n(c)});return h`<div class="widget ${this.moving?" widget-selected":""}">${d}</div>`}moveStart(){this.moving===!1&&(this.moving=!0,this.dispatchEvent(new $(this.widget.identifier,f.start)))}moveEnd(){this.moving===!0&&(this.moving=!1,this.dispatchEvent(new $(this.widget.identifier,f.end)))}handleMoveClick(){this.moving?this.moveEnd():this.moveStart()}handleMoveFocusOut(){this.moveEnd()}handleMoveKeyDown(t){if(!this.moving||!["ArrowDown","ArrowUp","ArrowLeft","ArrowRight","Home","End","Enter","Space","Escape","Tab"].includes(t.code)||t.altKey||t.ctrlKey)return;t.preventDefault(),t.stopPropagation();let s=f.end;switch(t.code){case"Escape":case"Enter":case"Space":this.moveEnd();return;case"ArrowUp":s=f.up;break;case"ArrowDown":s=f.down;break;case"ArrowLeft":s=f.left;break;case"ArrowRight":s=f.right;break;default:return}this.dispatchEvent(new $(this.widget.identifier,s))}async editSettings(){j("@typo3/backend/settings/editor.js");const t=`widget_settings_form_${this.identifier}`,s=await(await new p(TYPO3.settings.ajaxUrls.dashboard_widget_settings_get).withQueryArguments({widget:this.widget.identifier}).get({cache:"no-cache"})).resolve();if(s.status!=="ok")throw new Error(s.message);const a=h`<typo3-backend-settings-editor form-name=${t} categories=${s.categories} mode=minimal></typo3-backend-settings-editor>`;b.advanced({type:b.types.default,title:r.get("widget.settings"),size:b.sizes.default,severity:x.notice,content:a,callback:i=>{i.querySelector("typo3-backend-settings-editor").addEventListener(it.eventName,async d=>{const{originalEvent:c,formData:l}=d,{settings:o}=l;c.preventDefault();try{const m=await(await new p(TYPO3.settings.ajaxUrls.dashboard_widget_settings_update).post({widget:this.widget.identifier,settings:o})).resolve();m.status==="ok"?(this.handleRefresh(),i.hideModal()):m.status==="info"?w.info("",m.message):w.error("",m.message)}catch(g){if(g instanceof _)w.error("",g.response.status+" "+g.response.statusText,5),console.error(g);else if(g instanceof Error)w.error("",g.message),console.error(g);else throw g}})},buttons:[{text:r.get("widget.settings.button.close"),btnClass:"btn-default",name:"cancel",trigger:(i,n)=>n.hideModal()},{text:r.get("widget.settings.button.save"),btnClass:"btn-primary",name:"save",form:t}]})}handleRefresh(){this.fetchTask.run()}handleRemove(t){const e=b.confirm(r.get("widget.remove.confirm.title"),r.get("widget.remove.confirm.message"),x.warning,[{text:r.get("widget.remove.button.close"),active:!0,btnClass:"btn-default",name:"cancel"},{text:r.get("widget.remove.button.ok"),btnClass:"btn-warning",name:"delete"}]);e.addEventListener("button.clicked",a=>{a.target.getAttribute("name")==="delete"&&this.dispatchEvent(new A(this.identifier)),e.hideModal()});const s=t.currentTarget;e.addEventListener("typo3-modal-hide",()=>{s?.focus()})}};v([W({type:String,reflect:!0})],k.prototype,"identifier",void 0),v([E()],k.prototype,"moving",void 0),k=v([M("typo3-dashboard-widget")],k);export{y as Dashboard,k as DashboardWidget,S as DashboardWidgetContentRenderedEvent};