Files
cms-backend/Resources/Public/JavaScript/tree/page-tree-element.js
T

14 lines
16 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 M,html as a,nothing as g}from"lit";import{customElement as v,property as b,query as T,state as E}from"lit/decorators.js";import{until as S}from"lit/directives/until.js";import w from"@typo3/core/ajax/ajax-request.js";import P from"@typo3/backend/storage/persistent.js";import{ModuleUtility as $}from"@typo3/backend/module.js";import x from"@typo3/backend/context-menu.js";import{PageTree as F}from"@typo3/backend/tree/page-tree.js";import{TreeNodePositionEnum as u,TreeNodeCommandEnum as d}from"@typo3/backend/tree/tree-node.js";import{TreeToolbar as U}from"@typo3/backend/tree/tree-toolbar.js";import{TreeModuleState as D}from"@typo3/backend/tree/tree-module-state.js";import _ from"@typo3/backend/modal.js";import I from"@typo3/backend/severity.js";import{UrlFactory as z}from"@typo3/core/factory/url-factory.js";import{ModuleStateStorage as C}from"@typo3/backend/storage/module-state-storage.js";import{DataTransferTypes as f}from"@typo3/backend/enum/data-transfer-types.js";import"@typo3/backend/viewport/content-navigation-toggle.js";import"bootstrap";import r from"~labels/core.core";import O from"~labels/core.common";import R from"~labels/core.mod_web_list";import L from"~labels/backend.pages_new";import{openPageWizardModal as A}from"@typo3/backend/page-wizard/helper/wizard-helper.js";var s=function(p,e,t,n){var o=arguments.length,i=o<3?e:n===null?n=Object.getOwnPropertyDescriptor(e,t):n,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")i=Reflect.decorate(p,e,t,n);else for(var m=p.length-1;m>=0;m--)(l=p[m])&&(i=(o<3?l(i):o>3?l(e,t,i):l(e,t))||i);return o>3&&i&&Object.defineProperty(e,t,i),i};const B="typo3-backend-navigation-component-pagetree";let y=class extends F{constructor(){super(...arguments),this.allowNodeEdit=!0,this.allowNodeDrag=!0,this.allowNodeSorting=!0}sendChangeCommand(e){let t="",n="0";if(e.target)if(n=e.target.identifier,e.position===u.BEFORE){const o=this.getPreviousNode(e.target);n=(o.depth===e.target.depth?"-":"")+o.identifier}else e.position===u.AFTER&&(n="-"+n);if(e.command===d.NEW){const o=e;t="&data[pages]["+e.node.identifier+"][pid]="+encodeURIComponent(n)+"&data[pages]["+e.node.identifier+"][title]="+encodeURIComponent(o.title)+"&data[pages]["+e.node.identifier+"][doktype]="+encodeURIComponent(o.doktype)}else if(e.command===d.EDIT)t="&data[pages]["+e.node.identifier+"][title]="+encodeURIComponent(e.title);else if(e.command===d.DELETE){const o=C.current("web");e.node.identifier===o.identifier&&this.selectFirstNode(),t="&cmd[pages]["+e.node.identifier+"][delete]=1"}else t="cmd[pages]["+e.node.identifier+"]["+e.command+"]="+n;this.requestTreeUpdate(t).then(o=>{if(o&&o.hasErrors)this.errorNotification(o.messages);else if(e.command===d.NEW){const i=this.getParentNode(e.node);i.loaded=!1,this.loadChildren(i)}else this.refreshOrFilterTree()})}initializeDragForNode(){throw new Error("unused")}async handleNodeEdit(e,t){if(e.__loading=!0,e.identifier.startsWith("NEW")){const n=this.getPreviousNode(e),o=e.depth===n.depth?u.AFTER:u.INSIDE,i={command:d.NEW,node:e,title:t,position:o,target:n,doktype:e.doktype};await this.sendChangeCommand(i)}else{const n={command:d.EDIT,node:e,title:t};await this.sendChangeCommand(n)}e.__loading=!1}createDataTransferItemsFromNode(e){return[{type:f.treenode,data:this.getNodeTreeIdentifier(e)},{type:f.pages,data:JSON.stringify({records:[{identifier:e.identifier,tablename:"pages"}]})}]}async handleNodeAdd(e,t,n){this.updateComplete.then(()=>{this.editNode(e)})}handleNodeDelete(e){const t={node:e,command:d.DELETE};this.settings.displayDeleteConfirmation?_.confirm(r.get("mess.delete.title"),r.get("mess.delete",[t.node.name]),I.warning,[{text:r.get("labels.cancel"),active:!0,btnClass:"btn-default",name:"cancel"},{text:O.get("delete"),btnClass:"btn-warning",name:"delete"}]).addEventListener("button.clicked",o=>{o.target.name==="delete"&&this.sendChangeCommand(t),_.dismiss()}):this.sendChangeCommand(t)}handleNodeMove(e,t,n){const o={node:e,target:t,position:n,command:d.MOVE};let i="";const l=[e.name,t.name];switch(n){case u.BEFORE:i=r.get("mess.move_before",l);break;case u.AFTER:i=r.get("mess.move_after",l);break;default:i=r.get("mess.move_into",l);break}const m=_.confirm(R.get("move_page"),i,I.warning,[{text:r.get("labels.cancel"),active:!0,btnClass:"btn-default",name:"cancel"},{text:r.get("cm.copy"),btnClass:"btn-warning",name:"copy"},{text:r.get("labels.move"),btnClass:"btn-warning",name:"move"}]);m.addEventListener("button.clicked",N=>{const k=N.target;k.name==="move"?(o.command=d.MOVE,this.sendChangeCommand(o)):k.name==="copy"&&(o.command=d.COPY,this.sendChangeCommand(o)),m.hideModal()})}requestTreeUpdate(e){return new w(top.TYPO3.settings.ajaxUrls.record_process).post(e,{headers:{"Content-Type":"application/x-www-form-urlencoded","X-Requested-With":"XMLHttpRequest"}}).then(t=>t.resolve()).catch(t=>{this.errorNotification(t),this.loadData()})}};y=s([v("typo3-backend-navigation-component-pagetree-tree")],y);let h=class extends D(M){constructor(){super(...arguments),this.mountPointPath=null,this.moduleStateType="web",this.configuration=null,this.refresh=()=>{this.tree.refreshOrFilterTree()},this.setMountPoint=e=>{this.setTemporaryMountPoint(e.detail.pageId)},this.selectFirstNode=()=>{this.tree.selectFirstNode()},this.loadContent=e=>{const t=e.detail.node;if(!t?.checked||(C.updateWithTreeIdentifier("web",t.identifier,t.__treeIdentifier),e.detail.propagate===!1))return;const n=top.TYPO3.ModuleMenu.App,o=z.createUrl($.getFromName(n.getCurrentModule()).link,{id:t.identifier});top.TYPO3.Backend.ContentContainer.setUrl(o)},this.showContextMenu=e=>{const t=e.detail.node;t&&x.show(t.recordType,t.identifier,"tree","","",this.tree.getElementFromNode(t),e.detail.originalEvent)}}connectedCallback(){super.connectedCallback(),document.addEventListener("typo3:pagetree:refresh",this.refresh),document.addEventListener("typo3:pagetree:mountPoint",this.setMountPoint),document.addEventListener("typo3:pagetree:selectFirstNode",this.selectFirstNode)}disconnectedCallback(){document.removeEventListener("typo3:pagetree:refresh",this.refresh),document.removeEventListener("typo3:pagetree:mountPoint",this.setMountPoint),document.removeEventListener("typo3:pagetree:selectFirstNode",this.selectFirstNode),super.disconnectedCallback()}createRenderRoot(){return this}render(){return a`${S(this.renderTree(),"")}`}getConfiguration(){if(this.configuration!==null)return Promise.resolve(this.configuration);const e=top.TYPO3.settings.ajaxUrls.page_tree_configuration;return new w(e).get().then(async t=>{const n=await t.resolve("json");return this.configuration=n,this.mountPointPath=n.temporaryMountPoint||null,n})}async renderTree(){const e=await this.getConfiguration();return a`<typo3-backend-navigation-component-pagetree-toolbar id=typo3-pagetree-toolbar .tree=${this.tree}></typo3-backend-navigation-component-pagetree-toolbar>${this.renderMountPoint()}<typo3-backend-navigation-component-pagetree-tree id=typo3-pagetree-tree .setup=${e} @tree:initialized=${()=>{this.toolbar.tree=this.tree,this.fetchActiveNodeIfMissing()}} @typo3:tree:node-selected=${this.loadContent} @typo3:tree:node-context=${this.showContextMenu} @typo3:tree:nodes-prepared=${this.selectActiveNodeInLoadedNodes}></typo3-backend-navigation-component-pagetree-tree>`}unsetTemporaryMountPoint(){P.unset("pageTree_temporaryMountPoint").then(()=>{this.mountPointPath=null})}renderMountPoint(){return this.mountPointPath===null?g:a`<div class=node-mount-point><div class=node-mount-point__icon><typo3-backend-icon identifier=actions-info-circle size=small></typo3-backend-icon></div><div class=node-mount-point__text>${this.mountPointPath}</div><div class="node-mount-point__icon mountpoint-close" @click=${()=>this.unsetTemporaryMountPoint()} title=${r.get("labels.temporaryPageTreeEntryPoints")}><typo3-backend-icon identifier=actions-close size=small></typo3-backend-icon></div></div>`}setTemporaryMountPoint(e){new w(this.configuration.setTemporaryMountPointUrl).post("pid="+e,{headers:{"Content-Type":"application/x-www-form-urlencoded","X-Requested-With":"XMLHttpRequest"}}).then(t=>t.resolve()).then(t=>{t&&t.hasErrors?(this.tree.errorNotification(t.message),this.tree.loadData()):this.mountPointPath=t.mountPointPath}).catch(t=>{this.tree.errorNotification(t),this.tree.loadData()})}};s([b({type:String})],h.prototype,"mountPointPath",void 0),s([T("typo3-backend-navigation-component-pagetree-tree")],h.prototype,"tree",void 0),s([T("typo3-backend-navigation-component-pagetree-toolbar")],h.prototype,"toolbar",void 0),h=s([v("typo3-backend-navigation-component-pagetree")],h);let c=class extends U{constructor(){super(...arguments),this.tree=null,this.searchInTranslatedPages=!1,this.searchByFrontendUri=!1,this.subMenuItemsExpanded=!1,this.handleResize=this.checkHiddenSubmenuItems.bind(this)}disconnectedCallback(){super.disconnectedCallback(),this.resizeObserver.disconnect(),window.removeEventListener("resize",this.handleResize)}firstUpdated(){super.firstUpdated(),this.resizeObserver=new ResizeObserver(()=>this.checkHiddenSubmenuItems()),this.resizeObserver.observe(this.submenuItemsContainer),window.addEventListener("resize",this.handleResize),this.checkHiddenSubmenuItems()}updated(e){super.updated(e),e.has("tree")&&(this.tree?.settings?.searchInTranslatedPagesEnabled!==void 0&&(this.searchInTranslatedPages=this.tree.settings.searchInTranslatedPagesEnabled),this.tree?.settings?.searchByFrontendUriEnabled!==void 0&&(this.searchByFrontendUri=this.tree.settings.searchByFrontendUriEnabled),this.checkHiddenSubmenuItems())}render(){return a`<div class=tree-toolbar><div class=tree-toolbar__menu><div class=tree-toolbar__search><label for=toolbarSearch class=visually-hidden>${r.get("labels.label.searchString")}</label> <input type=search autocomplete=off id=toolbarSearch class="form-control form-control-sm search-input" placeholder=${r.get("tree.searchPageTree")}></div><div class=dropdown><button type=button class="btn btn-sm btn-icon btn-default btn-borderless dropdown-toggle dropdown-toggle-no-chevron" data-bs-toggle=dropdown data-bs-boundary=window aria-expanded=false aria-label=${r.get("labels.openPageTreeOptionsMenu")}><typo3-backend-icon identifier=actions-menu-alternative size=small></typo3-backend-icon></button><ul class="dropdown-menu dropdown-menu-end"><li><button class=dropdown-item @click=${()=>this.refreshTree()}><span class=dropdown-item-columns> <span class="dropdown-item-column dropdown-item-column-icon" aria-hidden=true><typo3-backend-icon identifier=actions-refresh size=small></typo3-backend-icon> </span> <span class="dropdown-item-column dropdown-item-column-title">${r.get("labels.refresh")} </span> </span></button></li><li><button class=dropdown-item @click=${e=>this.collapseAll(e)}><span class=dropdown-item-columns> <span class="dropdown-item-column dropdown-item-column-icon" aria-hidden=true><typo3-backend-icon identifier=apps-pagetree-category-collapse-all size=small></typo3-backend-icon> </span> <span class="dropdown-item-column dropdown-item-column-title">${r.get("labels.collapse")} </span> </span></button></li>${this.renderSearchOptions()}</ul></div><typo3-backend-content-navigation-toggle class="btn btn-sm btn-icon btn-default btn-borderless" action=collapse></typo3-backend-content-navigation-toggle></div>${this.renderToolbarSubmenu()}</div>`}renderToolbarSubmenu(){const e=[];return this.tree?.settings?.doktypes?.length&&(e.push(a`<button type=button class="btn btn-sm btn-default" @click=${this.launchPageWizard}><typo3-backend-icon identifier=actions-plus size=small></typo3-backend-icon>${L.get("newPage")}</button>`),e.push(this.tree.settings.doktypes.map(t=>a`<div class="tree-toolbar__menuitem tree-toolbar__drag-node" title=${t.title} draggable=true data-tree-icon=${t.icon} data-node-type=${t.nodeType} aria-hidden=true @dragstart=${n=>this.handleDragStart(n,t)}><typo3-backend-icon identifier=${t.icon} size=small></typo3-backend-icon></div>`))),a`<div class=tree-toolbar__submenu><div class="tree-toolbar__submenu-items ${this.subMenuItemsExpanded?"tree-toolbar__submenu-items--expanded":""}">${e}</div>${this.hasHiddenSubMenuItems?a`<button class="btn btn-sm btn-icon btn-default btn-borderless tree-toolbar__submenu-toggle" aria-hidden=true tabindex=-1 @click=${this.toggleSubmenu}><typo3-backend-icon identifier=${this.subMenuItemsExpanded?"actions-chevron-up":"actions-chevron-down"} size=small></typo3-backend-icon></button>`:g}</div>`}renderSearchOptions(){const e=this.tree?.settings?.searchInTranslatedPagesAvailable,t=this.tree?.settings?.searchByFrontendUriAvailable;return!e&&!t?g:a`<li><hr class=dropdown-divider></li>${e?a`<li><button class=dropdown-item @click=${()=>this.toggleTranslationSearch()}><span class=dropdown-item-columns> <span class="dropdown-item-column dropdown-item-column-icon" aria-hidden=true><typo3-backend-icon identifier=${this.searchInTranslatedPages?"actions-check-square":"actions-selection"} size=small></typo3-backend-icon> </span> <span class="dropdown-item-column dropdown-item-column-title">${r.get("tree.search_in_translated_pages")} </span> </span></button></li>`:g} ${t?a`<li><button class=dropdown-item @click=${()=>this.toggleFrontendUriSearch()}><span class=dropdown-item-columns> <span class="dropdown-item-column dropdown-item-column-icon" aria-hidden=true><typo3-backend-icon identifier=${this.searchByFrontendUri?"actions-check-square":"actions-selection"} size=small></typo3-backend-icon> </span> <span class="dropdown-item-column dropdown-item-column-title">${r.get("tree.search_by_frontend_uri")} </span> </span></button></li>`:g}`}async toggleTranslationSearch(){const e=!this.searchInTranslatedPages;try{await P.set("pageTree_searchInTranslatedPages",e?"1":"0"),this.searchInTranslatedPages=e,this.tree?.settings&&(this.tree.settings.searchInTranslatedPagesEnabled=e);const t=this.querySelector(".search-input");t&&t.value.trim()!==""&&this.refreshTree()}catch(t){console.error("Failed to toggle translation search:",t)}}async toggleFrontendUriSearch(){const e=!this.searchByFrontendUri;try{await P.set("pageTree_searchByFrontendUri",e?"1":"0"),this.searchByFrontendUri=e,this.tree?.settings&&(this.tree.settings.searchByFrontendUriEnabled=e);const t=this.querySelector(".search-input");t&&t.value.trim()!==""&&this.refreshTree()}catch(t){console.error("Failed to toggle frontend URI search:",t)}}handleDragStart(e,t){const n={__hidden:!1,__expanded:!1,__indeterminate:!1,__loading:!1,__processed:!1,__treeDragAction:"",__treeIdentifier:"",__treeParents:[""],__parents:[""],__x:0,__y:0,deletable:!1,depth:0,editable:!0,hasChildren:!1,icon:t.icon,overlayIcon:"",identifier:"NEW"+Math.floor(Math.random()*1e9).toString(16),loaded:!1,name:"",note:"",parentIdentifier:"",prefix:"",recordType:"pages",suffix:"",tooltip:"",type:"PageTreeItem",doktype:t.nodeType,statusInformation:[],labels:[]};this.tree.draggingNode=n,this.tree.nodeDragMode=d.NEW,e.dataTransfer.clearData();const o={statusIconIdentifier:this.tree.getNodeDragStatusIcon(),tooltipIconIdentifier:t.icon,tooltipLabel:t.title};e.dataTransfer.setData(f.dragTooltip,JSON.stringify(o)),e.dataTransfer.setData(f.newTreenode,JSON.stringify(n)),e.dataTransfer.effectAllowed="move"}checkHiddenSubmenuItems(){requestAnimationFrame(()=>{const e=this.subMenuItemsExpanded;e&&this.submenuItemsContainer.classList.remove("tree-toolbar__submenu-items--expanded"),this.hasHiddenSubMenuItems=this.submenuItemsContainer.scrollHeight>this.submenuItemsContainer.clientHeight,e&&this.submenuItemsContainer.classList.add("tree-toolbar__submenu-items--expanded")})}toggleSubmenu(e){e.stopPropagation(),this.subMenuItemsExpanded=!this.subMenuItemsExpanded}launchPageWizard(){const e=this.tree.getSelectedNodes();A({positionData:{pageUid:parseInt(e[0]?.identifier,10),insertPosition:"inside"},preventPositionAutoAdvance:!0})}};s([b({type:y})],c.prototype,"tree",void 0),s([b({type:Boolean})],c.prototype,"searchInTranslatedPages",void 0),s([b({type:Boolean})],c.prototype,"searchByFrontendUri",void 0),s([E()],c.prototype,"subMenuItemsExpanded",void 0),s([E()],c.prototype,"hasHiddenSubMenuItems",void 0),s([T(".tree-toolbar__submenu-items")],c.prototype,"submenuItemsContainer",void 0),c=s([v("typo3-backend-navigation-component-pagetree-toolbar")],c);export{y as EditablePageTree,h as PageTreeNavigationComponent,B as navigationComponentName};