mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-07 08:34:29 +01:00
Further fixes on actions
- fixed some duplicate binding causing long delay on tree context menu & general weirdness - remove some unneeded stuff
This commit is contained in:
parent
ad3a7c16a9
commit
557e5bd236
@ -12,7 +12,7 @@ import {Et2Tree} from "../etemplate/Et2Tree/Et2Tree";
|
||||
import {EGW_AI_DRAG_ENTER, EGW_AI_DRAG_OUT, EGW_AO_STATE_FOCUSED, EGW_AO_STATE_SELECTED} from "./egw_action_constants";
|
||||
import {egwBitIsSet} from "./egw_action_common";
|
||||
import {SlTreeItem} from "@shoelace-style/shoelace";
|
||||
import {EgwActionObject} from "./EgwActionObject";
|
||||
import {FindActionTarget} from "../etemplate/FindActionTarget";
|
||||
|
||||
|
||||
export const EXPAND_FOLDER_ON_DRAG_DROP_TIMEOUT = 1000
|
||||
@ -23,7 +23,7 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{
|
||||
tree: Et2Tree;
|
||||
|
||||
// Reference to the widget that's handling actions for us
|
||||
public findActionTargetHandler : EgwActionObject;
|
||||
public findActionTargetHandler : FindActionTarget;
|
||||
|
||||
private timeout : ReturnType<typeof setTimeout>;
|
||||
|
||||
@ -32,12 +32,13 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{
|
||||
|
||||
super();
|
||||
this.tree = _tree
|
||||
this.findActionTargetHandler = _tree.widget_object;
|
||||
this.findActionTargetHandler = _tree;
|
||||
}
|
||||
|
||||
public doTriggerEvent(egw_event : number, dom_event : Event)
|
||||
public doTriggerEvent(egw_event : number, data : any)
|
||||
{
|
||||
const target = this.tree.findActionTarget(dom_event);
|
||||
let dom_event = data.event ?? data;
|
||||
const target = this.findActionTargetHandler.findActionTarget(dom_event);
|
||||
if(egw_event == EGW_AI_DRAG_ENTER)
|
||||
{
|
||||
target.target.classList.add("draggedOver", "drop-hover");
|
||||
@ -54,10 +55,6 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{
|
||||
target.target.classList.remove("draggedOver", "drop-hover");
|
||||
clearTimeout(this.timeout)
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger;
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -71,16 +68,6 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{
|
||||
{
|
||||
const target = this.tree.shadowRoot.querySelector("[id='" + this.stateChangeContext.id + "']");
|
||||
|
||||
// Just set the attribute, we're not changing the tree value
|
||||
// The selected attribute will be reset by the tree next render()
|
||||
if(target && egwBitIsSet(_state, EGW_AO_STATE_SELECTED))
|
||||
{
|
||||
target.setAttribute("selected", "");
|
||||
}
|
||||
else if(target)
|
||||
{
|
||||
target.removeAttribute("selected");
|
||||
}
|
||||
if(target && egwBitIsSet(_state, EGW_AO_STATE_FOCUSED))
|
||||
{
|
||||
target.focus();
|
||||
@ -98,6 +85,11 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{
|
||||
}
|
||||
}
|
||||
|
||||
getWidget()
|
||||
{
|
||||
return this.tree;
|
||||
}
|
||||
|
||||
doGetDOMNode()
|
||||
{
|
||||
return this.tree;
|
||||
|
@ -46,7 +46,10 @@ export class EgwDropActionImplementation implements EgwActionImplementation {
|
||||
{
|
||||
_aoi.handlers = {};
|
||||
}
|
||||
_aoi.handlers[this.type] = [];
|
||||
if(typeof _aoi.handlers[this.type] == "undefined")
|
||||
{
|
||||
_aoi.handlers[this.type] = [];
|
||||
}
|
||||
node.classList.add('et2dropzone');
|
||||
const dragover = (event)=> {
|
||||
if (event.preventDefault) {
|
||||
@ -229,24 +232,7 @@ export class EgwDropActionImplementation implements EgwActionImplementation {
|
||||
event.preventDefault();
|
||||
return false;
|
||||
};
|
||||
|
||||
// Bind events on parent, if provided, instead of individual node
|
||||
if(_aoi.findActionTargetHandler)
|
||||
{
|
||||
// But only bind once
|
||||
if(parentAO && !parentAO.iface.handlers[this.type])
|
||||
{
|
||||
parentAO.iface.handlers[this.type] = parentAO.iface.handlers[this.type] ?? [];
|
||||
// Swap objects, bind down below
|
||||
_aoi = parentAO.iface;
|
||||
node = parentAO.iface.getDOMNode();
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(_aoi.handlers[this.type].length == 0)
|
||||
{
|
||||
// DND Event listeners
|
||||
|
@ -41,20 +41,32 @@ export class EgwPopupActionImplementation implements EgwActionImplementation {
|
||||
_aoi.findActionTargetHandler = parentNode;
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
if(isNew)
|
||||
{
|
||||
//if a parent is available the context menu Event-listener will only be bound once on the parent
|
||||
this._registerDefault(parentNode, _callback, parentAO);
|
||||
this._registerContext(parentNode, _callback, parentAO);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if(node && !parentNode)
|
||||
if(typeof _aoi.handlers == "undefined")
|
||||
{
|
||||
this._registerDefault(node, _callback, _context);
|
||||
this._registerContext(node, _callback, _context);
|
||||
return true;
|
||||
_aoi.handlers = {};
|
||||
}
|
||||
if(typeof _aoi.handlers[this.type] == "undefined")
|
||||
{
|
||||
_aoi.handlers[this.type] = [];
|
||||
}
|
||||
|
||||
if(_aoi.handlers[this.type].length == 0)
|
||||
{
|
||||
_aoi.handlers[this.type].push({type: 'contextmenu', listener: _callback});
|
||||
if(isNew)
|
||||
{
|
||||
//if a parent is available the context menu Event-listener will only be bound once on the parent
|
||||
this._registerDefault(parentNode, _callback, parentAO);
|
||||
this._registerContext(parentNode, _callback, parentAO);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if(node && !parentNode)
|
||||
{
|
||||
this._registerDefault(node, _callback, _context);
|
||||
this._registerContext(node, _callback, _context);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -64,6 +76,13 @@ export class EgwPopupActionImplementation implements EgwActionImplementation {
|
||||
const node = _aoi.getDOMNode();
|
||||
//TODO jQuery replacement
|
||||
jQuery(node).off();
|
||||
|
||||
// Unregister handlers
|
||||
if(_aoi.handlers)
|
||||
{
|
||||
_aoi.handlers[this.type]?.forEach(h => node.removeEventListener(h.type, h.listener));
|
||||
delete _aoi.handlers[this.type];
|
||||
}
|
||||
return true
|
||||
};
|
||||
|
||||
|
@ -133,7 +133,11 @@ export class EgwDragActionImplementation implements EgwActionImplementation {
|
||||
{
|
||||
_aoi.handlers = {};
|
||||
}
|
||||
_aoi.handlers[this.type] = [];
|
||||
if(typeof _aoi.handlers[this.type] == "undefined")
|
||||
{
|
||||
_aoi.handlers[this.type] = [];
|
||||
}
|
||||
|
||||
// Prevent selection
|
||||
node.onselectstart = function () {
|
||||
return false;
|
||||
@ -150,7 +154,13 @@ export class EgwDragActionImplementation implements EgwActionImplementation {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bind mouse handlers
|
||||
if(_aoi.handlers[this.type].length !== 0)
|
||||
{
|
||||
// Already bound
|
||||
return;
|
||||
}
|
||||
|
||||
// Bind mouse handlers
|
||||
//et2_dataview_view_aoi binds mousedown event in et2_dataview_rowAOI to "egwPreventSelect" function from egw_action_common via jQuery.mousedown
|
||||
//jQuery(node).off("mousedown",egwPreventSelect)
|
||||
//et2_dataview_view_aoi binds mousedown event in et2_dataview_rowAOI to "egwPreventSelect" function from egw_action_common via addEventListener
|
||||
@ -291,12 +301,11 @@ export class EgwDragActionImplementation implements EgwActionImplementation {
|
||||
};
|
||||
|
||||
// Drag Event listeners
|
||||
node.addEventListener('dragstart', dragstart, false);
|
||||
node.addEventListener('dragstart', dragstart, false);
|
||||
_aoi.handlers[this.type].push({type: 'dragstart', listener: dragstart});
|
||||
node.addEventListener('dragend', dragend, false);
|
||||
node.addEventListener('dragend', dragend, false);
|
||||
_aoi.handlers[this.type].push({type: 'dragend', listener: dragend});
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -13,7 +13,7 @@ import {EgwActionObject} from "../../egw_action/EgwActionObject";
|
||||
import {EgwAction} from "../../egw_action/EgwAction";
|
||||
import {EgwDragDropShoelaceTree} from "../../egw_action/EgwDragDropShoelaceTree";
|
||||
import {FindActionTarget} from "../FindActionTarget";
|
||||
import {EGW_AI_DRAG_ENTER, EGW_AI_DRAG_OUT} from "../../egw_action/egw_action_constants";
|
||||
import {EGW_AI_DRAG_ENTER, EGW_AI_DRAG_OUT, EGW_AO_FLAG_IS_CONTAINER} from "../../egw_action/egw_action_constants";
|
||||
|
||||
export type TreeItemData = SelectOption & {
|
||||
focused?: boolean;
|
||||
@ -849,9 +849,8 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
||||
const typeMap = {
|
||||
dragenter: EGW_AI_DRAG_ENTER,
|
||||
dragleave: EGW_AI_DRAG_OUT,
|
||||
drop: EGW_AI_DRAG_OUT,
|
||||
}
|
||||
this.widget_object.getObjectById(id).iface.triggerEvent(typeMap[event.type], event);
|
||||
this.widget_object.iface.triggerEvent(typeMap[event.type] ?? event.type, event);
|
||||
}
|
||||
|
||||
protected async finishedLazyLoading()
|
||||
@ -946,7 +945,6 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
||||
this.getDomNode(parentNode.id).loading = false
|
||||
}
|
||||
this.requestUpdate("_selectOptions")
|
||||
this._link_actions(this.actions)
|
||||
})
|
||||
|
||||
}
|
||||
@ -1102,16 +1100,6 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
||||
itemAO.remove();
|
||||
}
|
||||
|
||||
// Need the DOM nodes to actually link the actions
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
this.linkLeafActions(
|
||||
parentAO ?? this.widget_object,
|
||||
_item,
|
||||
this._get_action_links(this.actions)
|
||||
);
|
||||
});
|
||||
|
||||
return results;
|
||||
});
|
||||
}
|
||||
@ -1130,19 +1118,22 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
||||
// Get the top level element for the tree
|
||||
let objectManager = egw_getAppObjectManager(true);
|
||||
this.widget_object = objectManager.getObjectById(this.id);
|
||||
const ao_impl = new et2_action_object_impl(this, this);
|
||||
ao_impl.aoi = new EgwDragDropShoelaceTree(this);
|
||||
if (this.widget_object == null)
|
||||
{
|
||||
// Add a new container to the object manager which will hold the widget
|
||||
// objects
|
||||
this.widget_object = objectManager.insertObject(false, new EgwActionObject(
|
||||
//@ts-ignore
|
||||
this.id, objectManager, (new et2_action_object_impl(this, this)).getAOI(),
|
||||
this._actionManager || objectManager.manager.getActionById(this.id) || objectManager.manager
|
||||
this.id, objectManager, ao_impl.getAOI(),
|
||||
this._actionManager || objectManager.manager.getActionById(this.id) || objectManager.manager,
|
||||
EGW_AO_FLAG_IS_CONTAINER
|
||||
));
|
||||
} else
|
||||
{
|
||||
// @ts-ignore
|
||||
this.widget_object.setAOI((new et2_action_object_impl(this, this)).getAOI());
|
||||
this.widget_object.setAOI(ao_impl.getAOI());
|
||||
}
|
||||
|
||||
// Delete all old objects
|
||||
@ -1153,41 +1144,6 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
||||
// 'allowed' for this widget at this time
|
||||
var action_links = this._get_action_links(actions);
|
||||
this.widget_object.updateActionLinks(action_links);
|
||||
//Drop target enabeling
|
||||
if (typeof this._selectOptions != 'undefined')
|
||||
{
|
||||
let self: Et2Tree = this
|
||||
// Iterate over the options (leaves) and add action to each one
|
||||
for (const selectOption of this._selectOptions)
|
||||
{
|
||||
this.linkLeafActions(this.widget_object, selectOption, action_links)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add actions on a leaf
|
||||
*
|
||||
* @param {EgwActionObject} parentActionObject
|
||||
* @param {TreeItemData} option
|
||||
* @param {string[]} action_links
|
||||
* @protected
|
||||
*/
|
||||
protected linkLeafActions(parentActionObject : EgwActionObject, option : TreeItemData, action_links : string[])
|
||||
{
|
||||
// Add a new action object to the object manager
|
||||
let id = option.value ?? (typeof option.id == 'number' ? String(option.id) : option.id);
|
||||
|
||||
// @ts-ignore
|
||||
let obj : EgwActionObject = parentActionObject.addObject(id, new EgwDragDropShoelaceTree(this, id));
|
||||
obj.findActionTargetHandler = this;
|
||||
obj.updateActionLinks(action_links);
|
||||
|
||||
const children = <TreeItemData[]><unknown>(option.children ?? option.item) ?? [];
|
||||
for(let i = 0; i < children.length; i++)
|
||||
{
|
||||
this.linkLeafActions(obj, children[i], action_links);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1280,7 +1236,7 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the closest SlItem to the click position, and the corresponding EgwActionObject
|
||||
* returns the closest SlTreeItem to the click position, and the corresponding EgwActionObject
|
||||
* @param _event the click event
|
||||
* @returns { target:SlTreeItem, action:EgwActionObject }
|
||||
*/
|
||||
@ -1292,11 +1248,18 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
||||
});
|
||||
let action : EgwActionObject = this.widget_object.getObjectById(target.id);
|
||||
|
||||
// Create on the fly if not there?
|
||||
// Create on the fly if not there? Action handlers might need the EgwActionObject
|
||||
if(!action)
|
||||
{
|
||||
debugger;
|
||||
// NOTE: FLAT object structure under the tree ActionObject to avoid nested selection
|
||||
action = this.widget_object.addObject(target.id, this.widget_object.iface);
|
||||
// Required to get dropped accepted, but also re-binds
|
||||
action.updateActionLinks(this._get_action_links(this.actions));
|
||||
}
|
||||
// This is just the action system, which we override
|
||||
this.widget_object.setAllSelected(false);
|
||||
action.setSelected(true);
|
||||
|
||||
return {target: target, action: action};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user