mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-21 23:43:17 +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 {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 {egwBitIsSet} from "./egw_action_common";
|
||||||
import {SlTreeItem} from "@shoelace-style/shoelace";
|
import {SlTreeItem} from "@shoelace-style/shoelace";
|
||||||
import {EgwActionObject} from "./EgwActionObject";
|
import {FindActionTarget} from "../etemplate/FindActionTarget";
|
||||||
|
|
||||||
|
|
||||||
export const EXPAND_FOLDER_ON_DRAG_DROP_TIMEOUT = 1000
|
export const EXPAND_FOLDER_ON_DRAG_DROP_TIMEOUT = 1000
|
||||||
@ -23,7 +23,7 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{
|
|||||||
tree: Et2Tree;
|
tree: Et2Tree;
|
||||||
|
|
||||||
// Reference to the widget that's handling actions for us
|
// Reference to the widget that's handling actions for us
|
||||||
public findActionTargetHandler : EgwActionObject;
|
public findActionTargetHandler : FindActionTarget;
|
||||||
|
|
||||||
private timeout : ReturnType<typeof setTimeout>;
|
private timeout : ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
@ -32,12 +32,13 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{
|
|||||||
|
|
||||||
super();
|
super();
|
||||||
this.tree = _tree
|
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)
|
if(egw_event == EGW_AI_DRAG_ENTER)
|
||||||
{
|
{
|
||||||
target.target.classList.add("draggedOver", "drop-hover");
|
target.target.classList.add("draggedOver", "drop-hover");
|
||||||
@ -54,10 +55,6 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{
|
|||||||
target.target.classList.remove("draggedOver", "drop-hover");
|
target.target.classList.remove("draggedOver", "drop-hover");
|
||||||
clearTimeout(this.timeout)
|
clearTimeout(this.timeout)
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
debugger;
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,16 +68,6 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{
|
|||||||
{
|
{
|
||||||
const target = this.tree.shadowRoot.querySelector("[id='" + this.stateChangeContext.id + "']");
|
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))
|
if(target && egwBitIsSet(_state, EGW_AO_STATE_FOCUSED))
|
||||||
{
|
{
|
||||||
target.focus();
|
target.focus();
|
||||||
@ -98,6 +85,11 @@ export class EgwDragDropShoelaceTree extends egwActionObjectInterface{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getWidget()
|
||||||
|
{
|
||||||
|
return this.tree;
|
||||||
|
}
|
||||||
|
|
||||||
doGetDOMNode()
|
doGetDOMNode()
|
||||||
{
|
{
|
||||||
return this.tree;
|
return this.tree;
|
||||||
|
@ -46,7 +46,10 @@ export class EgwDropActionImplementation implements EgwActionImplementation {
|
|||||||
{
|
{
|
||||||
_aoi.handlers = {};
|
_aoi.handlers = {};
|
||||||
}
|
}
|
||||||
_aoi.handlers[this.type] = [];
|
if(typeof _aoi.handlers[this.type] == "undefined")
|
||||||
|
{
|
||||||
|
_aoi.handlers[this.type] = [];
|
||||||
|
}
|
||||||
node.classList.add('et2dropzone');
|
node.classList.add('et2dropzone');
|
||||||
const dragover = (event)=> {
|
const dragover = (event)=> {
|
||||||
if (event.preventDefault) {
|
if (event.preventDefault) {
|
||||||
@ -229,24 +232,7 @@ export class EgwDropActionImplementation implements EgwActionImplementation {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return false;
|
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)
|
if(_aoi.handlers[this.type].length == 0)
|
||||||
{
|
{
|
||||||
// DND Event listeners
|
// DND Event listeners
|
||||||
|
@ -41,20 +41,32 @@ export class EgwPopupActionImplementation implements EgwActionImplementation {
|
|||||||
_aoi.findActionTargetHandler = parentNode;
|
_aoi.findActionTargetHandler = parentNode;
|
||||||
isNew = true;
|
isNew = true;
|
||||||
}
|
}
|
||||||
|
if(typeof _aoi.handlers == "undefined")
|
||||||
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);
|
_aoi.handlers = {};
|
||||||
this._registerContext(node, _callback, _context);
|
}
|
||||||
return true;
|
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;
|
return false;
|
||||||
|
|
||||||
@ -64,6 +76,13 @@ export class EgwPopupActionImplementation implements EgwActionImplementation {
|
|||||||
const node = _aoi.getDOMNode();
|
const node = _aoi.getDOMNode();
|
||||||
//TODO jQuery replacement
|
//TODO jQuery replacement
|
||||||
jQuery(node).off();
|
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
|
return true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -133,7 +133,11 @@ export class EgwDragActionImplementation implements EgwActionImplementation {
|
|||||||
{
|
{
|
||||||
_aoi.handlers = {};
|
_aoi.handlers = {};
|
||||||
}
|
}
|
||||||
_aoi.handlers[this.type] = [];
|
if(typeof _aoi.handlers[this.type] == "undefined")
|
||||||
|
{
|
||||||
|
_aoi.handlers[this.type] = [];
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent selection
|
// Prevent selection
|
||||||
node.onselectstart = function () {
|
node.onselectstart = function () {
|
||||||
return false;
|
return false;
|
||||||
@ -150,7 +154,13 @@ export class EgwDragActionImplementation implements EgwActionImplementation {
|
|||||||
return;
|
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
|
//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)
|
//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
|
//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
|
// Drag Event listeners
|
||||||
node.addEventListener('dragstart', dragstart, false);
|
node.addEventListener('dragstart', dragstart, false);
|
||||||
_aoi.handlers[this.type].push({type: 'dragstart', listener: dragstart});
|
_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});
|
_aoi.handlers[this.type].push({type: 'dragend', listener: dragend});
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -13,7 +13,7 @@ import {EgwActionObject} from "../../egw_action/EgwActionObject";
|
|||||||
import {EgwAction} from "../../egw_action/EgwAction";
|
import {EgwAction} from "../../egw_action/EgwAction";
|
||||||
import {EgwDragDropShoelaceTree} from "../../egw_action/EgwDragDropShoelaceTree";
|
import {EgwDragDropShoelaceTree} from "../../egw_action/EgwDragDropShoelaceTree";
|
||||||
import {FindActionTarget} from "../FindActionTarget";
|
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 & {
|
export type TreeItemData = SelectOption & {
|
||||||
focused?: boolean;
|
focused?: boolean;
|
||||||
@ -849,9 +849,8 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
|||||||
const typeMap = {
|
const typeMap = {
|
||||||
dragenter: EGW_AI_DRAG_ENTER,
|
dragenter: EGW_AI_DRAG_ENTER,
|
||||||
dragleave: EGW_AI_DRAG_OUT,
|
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()
|
protected async finishedLazyLoading()
|
||||||
@ -946,7 +945,6 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
|||||||
this.getDomNode(parentNode.id).loading = false
|
this.getDomNode(parentNode.id).loading = false
|
||||||
}
|
}
|
||||||
this.requestUpdate("_selectOptions")
|
this.requestUpdate("_selectOptions")
|
||||||
this._link_actions(this.actions)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1102,16 +1100,6 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
|||||||
itemAO.remove();
|
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;
|
return results;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1130,19 +1118,22 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
|||||||
// Get the top level element for the tree
|
// Get the top level element for the tree
|
||||||
let objectManager = egw_getAppObjectManager(true);
|
let objectManager = egw_getAppObjectManager(true);
|
||||||
this.widget_object = objectManager.getObjectById(this.id);
|
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)
|
if (this.widget_object == null)
|
||||||
{
|
{
|
||||||
// Add a new container to the object manager which will hold the widget
|
// Add a new container to the object manager which will hold the widget
|
||||||
// objects
|
// objects
|
||||||
this.widget_object = objectManager.insertObject(false, new EgwActionObject(
|
this.widget_object = objectManager.insertObject(false, new EgwActionObject(
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
this.id, objectManager, (new et2_action_object_impl(this, this)).getAOI(),
|
this.id, objectManager, ao_impl.getAOI(),
|
||||||
this._actionManager || objectManager.manager.getActionById(this.id) || objectManager.manager
|
this._actionManager || objectManager.manager.getActionById(this.id) || objectManager.manager,
|
||||||
|
EGW_AO_FLAG_IS_CONTAINER
|
||||||
));
|
));
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
// @ts-ignore
|
// @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
|
// Delete all old objects
|
||||||
@ -1153,41 +1144,6 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
|||||||
// 'allowed' for this widget at this time
|
// 'allowed' for this widget at this time
|
||||||
var action_links = this._get_action_links(actions);
|
var action_links = this._get_action_links(actions);
|
||||||
this.widget_object.updateActionLinks(action_links);
|
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
|
* @param _event the click event
|
||||||
* @returns { target:SlTreeItem, action:EgwActionObject }
|
* @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);
|
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)
|
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};
|
return {target: target, action: action};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user