diff --git a/api/js/egw_action/EgwDragDropShoelaceTree.ts b/api/js/egw_action/EgwDragDropShoelaceTree.ts index 4a0c5fafa1..dbd390e623 100644 --- a/api/js/egw_action/EgwDragDropShoelaceTree.ts +++ b/api/js/egw_action/EgwDragDropShoelaceTree.ts @@ -25,7 +25,8 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{ // Reference to the widget that's handling actions for us public findActionTargetHandler : FindActionTarget; - private timeout : ReturnType; + // List of timeouts indexed by ID because drag out doesn't always happen before drag in + private timeouts : { [key : string] : ReturnType }; constructor(_tree : Et2Tree) { @@ -33,16 +34,17 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{ super(); this.tree = _tree this.findActionTargetHandler = _tree; + this.timeouts = {}; } public doTriggerEvent(egw_event : number, data : any) { let dom_event = data.event ?? data; const target = this.findActionTargetHandler.findActionTarget(dom_event); - if(egw_event == EGW_AI_DRAG_ENTER) + if(egw_event == EGW_AI_DRAG_ENTER && !target.target.classList.contains("draggedOver")) { target.target.classList.add("draggedOver", "drop-hover"); - this.timeout = setTimeout(() => + this.timeouts[target.target.id] = setTimeout(() => { if(target.target.classList.contains("draggedOver")) { @@ -53,7 +55,7 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{ else if(egw_event == EGW_AI_DRAG_OUT) { target.target.classList.remove("draggedOver", "drop-hover"); - clearTimeout(this.timeout) + clearTimeout(this.timeouts[target.target.id]) } return true } diff --git a/api/js/etemplate/Et2Tree/Et2Tree.ts b/api/js/etemplate/Et2Tree/Et2Tree.ts index d746c4d6c6..c7cefdf0ea 100644 --- a/api/js/etemplate/Et2Tree/Et2Tree.ts +++ b/api/js/etemplate/Et2Tree/Et2Tree.ts @@ -273,6 +273,10 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin background-color: var(--highlight-background-color); } + sl-tree-item.drop-hover > *:not(sl-tree-item) { + pointer-events: none; + } + /*Mail specific style TODO move it out of the component*/ sl-tree-item.unread > .tree-item__label { font-weight: bold; @@ -843,8 +847,29 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin { return; } - let id = option.value ?? (typeof option.id == 'number' ? String(option.id) : option.id); - //console.log(event.type, id); + + // Remove drop hover from any parent nodes + if(event.type == "dragenter") + { + event.stopPropagation(); + let current = option.parentElement; + while(current) + { + current.classList.remove("draggedOver", "drop-hover"); + current = current.parentElement; + } + } + // Ignore/stop events from child nodes, unless it's dragenter and the parent sl-tree-item isn't hovered yet + if(["dragenter", "dragleave"].includes(event.type) && event.target != option && event.composedPath().includes(option)) + { + event.stopPropagation(); + if(event.type != "dragenter" || option.classList.contains("drop-hover")) + { + return; + } + } + //let id = option.value ?? (typeof option.id == 'number' ? String(option.id) : option.id); + //console.log(event.type, id, event.target); const typeMap = { dragenter: EGW_AI_DRAG_ENTER,