/* * 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 F,html as r,nothing as y}from"lit";import{property as T,state as w,customElement as D}from"lit/decorators.js";import{classMap as I}from"lit/directives/class-map.js";import{repeat as x}from"lit/directives/repeat.js";import p,{BookmarkStoreChangedEvent as z,BookmarkGroupType as S}from"@typo3/backend/bookmark/bookmark-store.js";import $ from"@typo3/backend/modal.js";import m from"@typo3/backend/notification.js";import{SeverityEnum as B}from"@typo3/backend/enum/severity.js";import{PseudoButtonLitElement as R}from"@typo3/backend/element/pseudo-button.js";import"@typo3/backend/element/spinner-element.js";import"@typo3/backend/element/icon-element.js";import a from"~labels/core.bookmarks";var g=function(k,e,t,o){var i=arguments.length,s=i<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,t):o,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(k,e,t,o);else for(var d=k.length-1;d>=0;d--)(l=k[d])&&(s=(i<3?l(s):i>3?l(e,t,s):l(e,t))||s);return i>3&&s&&Object.defineProperty(e,t,s),s};class M{constructor(){this.view="list"}}class V{constructor(e){this.bookmark=e,this.view="editBookmark"}}class E{constructor(){this.view="createGroup",this.draft={label:""}}}class L{constructor(e){this.group=e,this.view="editGroup"}}class C{constructor(){this.view="manageGroups"}}let h=class extends F{constructor(){super(...arguments),this.editId=null,this.bookmarks=[],this.groups=[],this.selectedIds=new Set,this.draggedItem=null,this.dropTarget=null,this.groupedBookmarks=new Map,this.viewState=new M,this.handleStoreUpdate=()=>{this.syncFromStore()},this.handleBookmarkBulkDelete=()=>{const e=Array.from(this.selectedIds),t=$.confirm(a.get("confirmDeleteMultiple.title"),a.get("confirmDeleteMultiple.message",[e.length]),B.notice,[{text:a.get("action.cancel"),btnClass:"btn-default",name:"cancel",trigger:()=>t.hideModal()},{text:a.get("action.delete"),btnClass:"btn-primary",name:"delete",trigger:async()=>{await p.deleteMultiple(e)?(m.success(a.get("success.deletedMultiple.title"),a.get("success.deletedMultiple.message",[e.length])),this.selectedIds=new Set):m.error(a.get("error.deleteFailed.title"),a.get("error.deleteFailed.message")),t.hideModal()}}])},this.handleDragOver=e=>{e.preventDefault(),e.dataTransfer&&(e.dataTransfer.dropEffect="move")},this.handleItemDragLeave=e=>{const t=e.relatedTarget;t&&e.currentTarget.contains(t)||(this.dropTarget=null)},this.handleDragEnd=()=>{this.draggedItem=null,this.dropTarget=null}}connectedCallback(){super.connectedCallback(),document.addEventListener(z,this.handleStoreUpdate),this.initFromStore()}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(z,this.handleStoreUpdate)}createRenderRoot(){return this}render(){let e;return this.viewState instanceof V?e=this.renderBookmarkEditView(this.viewState):this.viewState instanceof C?e=this.renderGroupListView():this.viewState instanceof E?e=this.renderGroupCreateView(this.viewState):this.viewState instanceof L?e=this.renderGroupEditView(this.viewState):e=this.renderBookmarkListView(),r`
${e.toolbar}
${e.content}
`}async initFromStore(){if(await this.syncFromStore(),this.editId!==null){const e=this.bookmarks.find(t=>t.id===this.editId);e&&this.navigateToBookmarkEditView(e)}}navigateToBookmarkListView(){this.viewState=new M}navigateToBookmarkEditView(e){this.viewState=new V(e)}navigateToGroupListView(){this.viewState=new C}navigateToGroupCreateView(){this.viewState=new E}navigateToGroupEditView(e){this.viewState=new L(e)}renderBookmarkListView(){const e=this.groupedBookmarks,t=this.selectedIds.size>0,o=this.bookmarks.length>0,i=this.selectedIds.size===this.bookmarks.length&&this.bookmarks.length>0,s=this.helperGetGroupSections(this.getSelectableGroups()),l=r`
{this.selectedIds=n.target.checked?new Set(this.bookmarks.map(b=>b.id)):new Set}}>
${t?r`
`:y}
`,d=r`${o?y:r`
${a.get("empty")}
`} ${x(Array.from(e.entries()),([n])=>n,([n,b])=>{const u=this.groups.find(v=>v.id===n)?.label||a.get("notGrouped"),c=`bookmark-group-${typeof n=="number"?n:n.replace(/-/g,"")}`;return r`
this.handleDrop(v,n)}>
${x(b,v=>v.id,v=>this.renderBookmarkRow(v))}
`})}`;return{toolbar:l,content:d}}renderBookmarkRow(e){const t=this.selectedIds.has(e.id),o=this.draggedItem?.id===e.id,i=this.dropTarget?.item.id===e.id,s=this.dropTarget?.position,l=I({"table-active":t,"opacity-50":o,"row-drop-before":i&&s==="before","row-drop-after":i&&s==="after"}),d=()=>{const c=new Set(this.selectedIds);c.has(e.id)?c.delete(e.id):c.add(e.id),this.selectedIds=c},n=this.groupedBookmarks.get(e.groupId)??[],b=n.findIndex(c=>c.id===e.id),f=b===0,u=b===n.length-1;return r`this.handleDragStart(c,"bookmark",e)} @dragover=${c=>this.handleItemDragOver(c,e)} @dragleave=${this.handleItemDragLeave} @drop=${c=>this.handleDrop(c,e)} @dragend=${this.handleDragEnd}>${e.editable?r` c.stopPropagation()}> `:r``}${e.accessible?r``:r`${e.title}`}${e.editable?r`
${f?r` `:r``} ${u?r` `:r``} ${a.get("manager.dragToReorder")}
`:y}`}renderBookmarkEditView(e){const{bookmark:t}=e,o=r`
`,i=this.helperParseParameters(t.arguments),s=this.helperGetGroupSections(this.getSelectableGroups()),l=r`
this.handleBookmarkUpdate(d,t)}>
{t.title=d.target.value,this.requestUpdate()}} required>
${t.href?r``:y}${i!==null?r``:y}
${a.get("details.url")}${this.helperStripToken(t.href)}
${a.get("details.route")}${t.route}
${a.get("details.parameters")}${i}
`;return{toolbar:o,content:l}}renderGroupListView(){const e=this.groups.filter(i=>i.editable),t=r`
`,o=r`
${e.length>0?r`
${e.map(i=>this.renderGroupRow(i))}
`:r`
${a.get("manager.noGroups")}
`}
`;return{toolbar:t,content:o}}renderGroupRow(e){const t=this.bookmarks.filter(u=>u.groupId===e.id).length,o=this.draggedItem?.id===e.id,i=this.dropTarget?.item.id===e.id,s=this.dropTarget?.position,l=I({"opacity-50":o,"row-drop-before":i&&s==="before","row-drop-after":i&&s==="after"}),d=this.groups.filter(u=>u.editable),n=d.findIndex(u=>u.id===e.id),b=n===0,f=n===d.length-1;return r`this.handleDragStart(u,"group",e)} @dragover=${u=>this.handleItemDragOver(u,e)} @dragleave=${this.handleItemDragLeave} @drop=${u=>this.handleDrop(u,e)} @dragend=${this.handleDragEnd}>
${b?r` `:r``} ${f?r` `:r``} ${a.get("manager.dragToReorder")}
`}renderGroupCreateView(e){const{draft:t}=e,o=r`
`,i=r`
this.handleGroupCreate(s,t)}>
{t.label=s.target.value,this.requestUpdate()}} required autofocus>
`;return{toolbar:o,content:i}}renderGroupEditView(e){const{group:t}=e,o=r`
`,i=r`
this.handleGroupUpdate(s,t)}>
{t.label=s.target.value,this.requestUpdate()}} required>
`;return{toolbar:o,content:i}}async syncFromStore(){this.bookmarks=await p.getBookmarks(),this.groups=await p.getGroups(),this.groupedBookmarks=await p.getGroupedBookmarks()}getSelectableGroups(){return this.groups.filter(e=>e.selectable)}handleBookmarkNavigate(e){this.closest("typo3-backend-modal")?.hideModal(),p.navigate(e)}async handleBookmarkUpdate(e,t){e.preventDefault();const o=await p.update(t.id,t.title,t.groupId);o.success?(m.success(a.get("success.updated.title"),a.get("success.updated.message")),this.navigateToBookmarkListView()):m.error(a.get("error.updateFailed.title"),o.error||a.get("error.unknown.message"))}handleBookmarkDelete(e){const t=$.confirm(a.get("confirmDelete.title"),a.get("confirmDelete.message"),B.notice,[{text:a.get("action.cancel"),btnClass:"btn-default",name:"cancel",trigger:()=>t.hideModal()},{text:a.get("action.delete"),btnClass:"btn-primary",name:"delete",trigger:async()=>{await p.deleteMultiple([e])?(m.success(a.get("success.deleted.title"),a.get("success.deleted.message")),this.navigateToBookmarkListView()):m.error(a.get("error.deleteFailed.title"),a.get("error.deleteFailed.message")),t.hideModal()}}])}async handleBookmarkBulkMove(e){const t=Array.from(this.selectedIds);await p.move(t,e)?(m.success(a.get("success.moved.title"),a.get("success.moved.message",[t.length])),this.selectedIds=new Set):m.error(a.get("error.moveFailed.title"),a.get("error.moveFailed.message"))}async handleBookmarkMoveUp(e){await this.reorderBookmarkRelative(e,-1),await this.restoreFocus("bookmark",e.id,"up")}async handleBookmarkMoveDown(e){await this.reorderBookmarkRelative(e,1),await this.restoreFocus("bookmark",e.id,"down")}async handleGroupMoveUp(e){await this.reorderGroupRelative(e,-1),await this.restoreFocus("group",e.id,"up")}async handleGroupMoveDown(e){await this.reorderGroupRelative(e,1),await this.restoreFocus("group",e.id,"down")}async handleGroupCreate(e,t){if(e.preventDefault(),!t.label.trim())return;const o=await p.createGroup(t.label.trim());o.success?(m.success(a.get("success.groupCreated.title"),a.get("success.groupCreated.message")),this.navigateToGroupListView()):m.error(a.get("error.groupCreateFailed.title"),o.error||a.get("error.groupCreateFailed.message"))}async handleGroupUpdate(e,t){if(e.preventDefault(),!t.label.trim()||!t.editable)return;const o=await p.updateGroup(t.id,t.label.trim());o.success?(m.success(a.get("success.groupUpdated.title"),a.get("success.groupUpdated.message")),this.navigateToGroupListView()):m.error(a.get("error.groupUpdateFailed.title"),o.error||a.get("error.groupUpdateFailed.message"))}handleGroupDelete(e){if(!e.editable)return;const t=$.confirm(a.get("confirmDeleteGroup.title"),a.get("confirmDeleteGroup.message",[e.label]),B.notice,[{text:a.get("action.cancel"),btnClass:"btn-default",name:"cancel",trigger:()=>t.hideModal()},{text:a.get("action.delete"),btnClass:"btn-primary",name:"delete",trigger:async()=>{const o=await p.deleteGroup(e.id);o.success?(m.success(a.get("success.groupDeleted.title"),a.get("success.groupDeleted.message")),this.navigateToGroupListView()):m.error(a.get("error.groupDeleteFailed.title"),o.error||a.get("error.groupDeleteFailed.message")),t.hideModal()}}])}async restoreFocus(e,t,o){await this.updateComplete;const i=e==="bookmark"?`tr[data-bookmark-id="${t}"]`:`tr[data-group-id="${t}"]`,s=this.querySelector(i);if(!s)return;const l=o==="up"?"move-up":"move-down",d=o==="up"?"move-down":"move-up";(s.querySelector(`button[data-action="${l}"]`)??s.querySelector(`button[data-action="${d}"]`))?.focus()}async reorderBookmarkRelative(e,t){const o=[...this.groupedBookmarks.get(e.groupId)??[]],i=o.findIndex(l=>l.id===e.id),s=i+t;i<0||s<0||s>=o.length||([o[i],o[s]]=[o[s],o[i]],await p.reorder(o.map(l=>l.id)),await this.syncFromStore())}async reorderBookmarkToPosition(e,t,o){e.groupId!==t&&await p.update(e.id,e.title,t);const i=[...this.groupedBookmarks.get(t)??[]].filter(s=>s.id!==e.id);i.splice(o,0,e),await p.reorder(i.map(s=>s.id)),await this.syncFromStore()}async reorderGroupRelative(e,t){const o=this.groups.filter(l=>l.editable),i=o.findIndex(l=>l.id===e.id),s=i+t;i<0||s<0||s>=o.length||([o[i],o[s]]=[o[s],o[i]],await p.reorderGroups(o.map(l=>l.id)),await this.syncFromStore())}async reorderGroupToPosition(e,t){const o=this.groups.filter(i=>i.editable&&i.id!==e.id);o.splice(t,0,e),await p.reorderGroups(o.map(i=>i.id)),await this.syncFromStore()}handleDragStart(e,t,o){if(this.draggedItem=o,e.dataTransfer){e.dataTransfer.effectAllowed="move";const i={type:t,id:o.id};e.dataTransfer.setData("application/json",JSON.stringify(i))}}handleItemDragOver(e,t){if(e.preventDefault(),e.stopPropagation(),this.draggedItem===null||this.draggedItem.id===t.id)return;e.dataTransfer&&(e.dataTransfer.dropEffect="move");const o=e.currentTarget.getBoundingClientRect(),i=o.top+o.height/2,s=e.clientYn.id!==e.id).findIndex(n=>n.id===i.id),d=o==="before"?l:l+1;await this.reorderBookmarkToPosition(e,i.groupId,d)}else{const i=t;if(e.groupId!==i){const s=[...this.groupedBookmarks.get(i)??[]];await this.reorderBookmarkToPosition(e,i,s.length)}}}async handleDropGroup(e,t,o){if(e.id===t.id)return;const s=this.groups.filter(d=>d.editable&&d.id!==e.id).findIndex(d=>d.id===t.id),l=o==="before"?s:s+1;await this.reorderGroupToPosition(e,l)}helperGetGroupSections(e){const t=Map.groupBy(e,i=>i.type),o={[S.USER]:a.get("groupType.user"),[S.SYSTEM]:a.get("groupType.system"),[S.GLOBAL]:a.get("groupType.global")};return Array.from(t.entries()).map(([i,s])=>({label:o[i]??i,groups:s}))}helperParseParameters(e){if(!e)return null;try{const t=Object.entries(JSON.parse(e));if(t.length===0)return null;const o=i=>typeof i=="object"&&i!==null?JSON.stringify(i):String(i);return r``}catch{return r`${e}`}}helperStripToken(e){try{const t=new URL(e,window.location.origin);return t.searchParams.delete("token"),decodeURIComponent(t.pathname+t.search)}catch{return e}}};g([T({type:Number})],h.prototype,"editId",void 0),g([w()],h.prototype,"bookmarks",void 0),g([w()],h.prototype,"groups",void 0),g([w()],h.prototype,"selectedIds",void 0),g([w()],h.prototype,"draggedItem",void 0),g([w()],h.prototype,"dropTarget",void 0),g([w()],h.prototype,"groupedBookmarks",void 0),g([w()],h.prototype,"viewState",void 0),h=g([D("typo3-backend-bookmark-manager-content")],h);let G=class extends R{createRenderRoot(){return this}buttonActivated(){const t=(top?.document??document).createElement("typo3-backend-bookmark-manager-content");this.editId!==void 0&&(t.editId=this.editId),$.advanced({type:$.types.default,title:a.get("manage"),size:$.sizes.medium,severity:B.notice,content:t,buttons:[],staticBackdrop:!0})}};g([T({type:Number,attribute:"edit-id"})],G.prototype,"editId",void 0),G=g([D("typo3-backend-bookmark-manager-button")],G);export{G as BookmarkManagerButtonElement,h as BookmarkManagerContentElement};