- fix drag-hover not working smoothly
- fix drop zone events being triggered by other draggable items (none et2action draggable)
This commit is contained in:
Hadi Nategh 2022-05-20 16:02:20 +02:00
parent d7beb18470
commit ef6cf29ce1
4 changed files with 124 additions and 39 deletions

View File

@ -617,7 +617,7 @@ egwAction.prototype.execute = function(_senders, _target)
if(!this._check_confirm_mass_selections(_senders, _target)) if(!this._check_confirm_mass_selections(_senders, _target))
{ {
this._check_confirm(_senders, _target); return this._check_confirm(_senders, _target);
} }
}; };

View File

@ -214,7 +214,8 @@ export function egwDragActionImplementation()
} }
node.setAttribute('draggable', true); node.setAttribute('draggable', true);
node.addEventListener('dragstart', function(event) { const dragstart = function(event) {
event.stopImmediatePropagation();
if (action) { if (action) {
if (_context.isSelection(event)) return; if (_context.isSelection(event)) return;
@ -245,11 +246,15 @@ export function egwDragActionImplementation()
} }
} }
} }
event.dataTransfer.effectAllowed = 'copy';
if (event.dataTransfer.types.length == 0) { if (event.dataTransfer.types.length == 0) {
// No file data? Abort: drag does nothing // No file data? Abort: drag does nothing
event.preventDefault(); event.preventDefault();
return; return;
} }
} else {
event.dataTransfer.effectAllowed = 'linkMove';
} }
// The helper function is called before the start function // The helper function is called before the start function
// is evoked. Call the given callback function. The callback // is evoked. Call the given callback function. The callback
@ -267,19 +272,30 @@ export function egwDragActionImplementation()
}) })
}; };
if (!ai.helper) if (!ai.helper) {
{
ai.helper = ai.defaultDDHelper(ai.selected); ai.helper = ai.defaultDDHelper(ai.selected);
} }
// Add a basic class to the helper in order to standardize the background layout // Add a basic class to the helper in order to standardize the background layout
ai.helper[0].classList.add('et2_egw_action_ddHelper', 'ui-draggable-dragging'); ai.helper[0].classList.add('et2_egw_action_ddHelper', 'ui-draggable-dragging');
document.body.append(ai.helper[0]); document.body.append(ai.helper[0]);
this.classList.add('drag--moving'); this.classList.add('drag--moving');
event.dataTransfer.setData('application/json', JSON.stringify(data)) event.dataTransfer.setData('application/json', JSON.stringify(data))
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.setDragImage(ai.helper[0], 12, 12); event.dataTransfer.setDragImage(ai.helper[0], 12, 12);
} , false);
this.setAttribute('data-egwActionObjID', JSON.stringify(data.selected));
};
const dragend = function(event){
const helper = document.querySelector('.et2_egw_action_ddHelper');
if (helper) helper.remove();
};
// Drag Event listeners
node.addEventListener('dragstart', dragstart , false);
node.addEventListener('dragend', dragend, false);
return true; return true;
} }
@ -425,53 +441,73 @@ export function egwDropActionImplementation()
{ {
var ai = new egwActionImplementation(); var ai = new egwActionImplementation();
//keeps track of current drop element where dragged item's entered.
// it's necessary for dragenter/dragleave issue correction.
var currentDropEl = null;
ai.type = "drop"; ai.type = "drop";
ai.doRegisterAction = function(_aoi, _callback, _context) ai.doRegisterAction = function(_aoi, _callback, _context)
{ {
var node = _aoi.getDOMNode()[0] ? _aoi.getDOMNode()[0] : _aoi.getDOMNode(); var node = _aoi.getDOMNode()[0] ? _aoi.getDOMNode()[0] : _aoi.getDOMNode();
var self = this; var self = this;
if (node) if (node)
{ {
node.classList.add('et2dropzone'); node.classList.add('et2dropzone');
node.addEventListener('dragover', function (event) { const dragover = function (event) {
if (event.preventDefault) { if (event.preventDefault) {
event.preventDefault(); event.preventDefault();
} }
event.dataTransfer.dropEffect = 'move'; if (!self.getTheDraggedDOM()) return ;
_aoi.triggerEvent(EGW_AI_DRAG_OVER, {event: event});//TODO: check this event
return false;
}, false);
node.addEventListener('dragenter', function (event) { const data = {
// stop the event from being fired for its children event: event,
event.stopPropagation(); ui: self.getTheDraggedData()
};
_aoi.triggerEvent(EGW_AI_DRAG_OVER, data);
return true;
};
const dragenter = function (event) {
event.stopImmediatePropagation();
// don't trigger dragenter if we are entering the drag element // don't trigger dragenter if we are entering the drag element
if (event.dataTransfer.getData('application/json') != '' || self.isTheDraggedDOM(this)) return; // don't go further if the dragged element is no there (happens when a none et2 dragged element is being dragged)
if (!self.getTheDraggedDOM() || self.isTheDraggedDOM(this) || this == currentDropEl) return;
currentDropEl = event.currentTarget;
event.dataTransfer.dropEffect = 'link';
this.classList.add('drop-hover'); this.classList.add('drop-hover');
}, false);
node.addEventListener('drop', function (event) { // stop the event from being fired for its children
event.preventDefault(); event.preventDefault();
return false;
};
const drop = function (event) {
event.preventDefault();
// don't go further if the dragged element is no there (happens when a none et2 dragged element is being dragged)
if (!self.getTheDraggedDOM()) return ;
// remove the hover class // remove the hover class
this.classList.remove('drop-hover'); this.classList.remove('drop-hover');
// clean up the helper dom const helper = self.getHelperDOM();
const helper = document.querySelector('.et2_egw_action_ddHelper'); let ui = self.getTheDraggedData();
const ui = { ui.position = {top: event.clientY, left: event.clientX};
position: {top: event.clientY, left: event.clientX}, ui.offset = {top: event.offsetY, left: event.offsetX};
offset: {top: event.offsetY, left: event.offsetX}
}
if (helper) helper.remove();
let data = JSON.parse(event.dataTransfer.getData('application/json')); let data = JSON.parse(event.dataTransfer.getData('application/json'));
if (!self.isAccepted(data, _context, _callback) || self.isTheDraggedDOM(this)) return; if (!self.isAccepted(data, _context, _callback) || self.isTheDraggedDOM(this))
{
// clean up the helper dom
if (helper) helper.remove();
return;
}
let selected = data.selected.map((item) => { let selected = data.selected.map((item) => {
return egw_getObjectManager(item.id, false) return egw_getObjectManager(item.id, false)
@ -545,20 +581,41 @@ export function egwDropActionImplementation()
// Set cursor back to auto. Seems FF can't handle cursor reversion // Set cursor back to auto. Seems FF can't handle cursor reversion
jQuery('body').css({cursor: 'auto'}); jQuery('body').css({cursor: 'auto'});
_aoi.triggerEvent(EGW_AI_DRAG_OUT, {event: event});//TODO: check this event _aoi.triggerEvent(EGW_AI_DRAG_OUT, {event: event, ui: self.getTheDraggedData()});
}, false);
node.addEventListener('dragleave', function (event) { // clean up the helper dom
// stop the event from being fired for its children if (helper) helper.remove();
event.stopPropagation();
};
const dragleave = function (event) {
event.stopImmediatePropagation();
// don't trigger dragleave if we are leaving the drag element // don't trigger dragleave if we are leaving the drag element
if (event.dataTransfer.getData('application/json') != '') return; // don't go further if the dragged element is no there (happens when a none et2 dragged element is being dragged)
if (!self.getTheDraggedDOM() || self.isTheDraggedDOM(this) || this == currentDropEl) return;
_aoi.triggerEvent(EGW_AI_DRAG_OUT, {event: event});//TODO: check this event const data = {
event: event,
ui: self.getTheDraggedData()
};
_aoi.triggerEvent(EGW_AI_DRAG_OUT, data);
this.classList.remove('drop-hover'); this.classList.remove('drop-hover');
}, false);
event.preventDefault();
return false;
};
// DND Event listeners
node.addEventListener('dragover', dragover, false);
node.addEventListener('dragenter', dragenter, false);
node.addEventListener('drop', drop, false);
node.addEventListener('dragleave', dragleave, false);
return true; return true;
} }
@ -570,6 +627,33 @@ export function egwDropActionImplementation()
return _dom.classList.contains('drag--moving'); return _dom.classList.contains('drag--moving');
} }
ai.getTheDraggedDOM = function ()
{
return document.querySelector('.drag--moving');
}
ai.getHelperDOM = function ()
{
return document.querySelector('.et2_egw_action_ddHelper');
}
ai.getTheDraggedData = function()
{
let data = this.getTheDraggedDOM().dataset.egwactionobjid;
let selected = [];
if (data)
{
data = JSON.parse(data);
selected = data.map((item)=>{return egw_getObjectManager(item.id, false)});
}
return {
draggable: this.getTheDraggedDOM(),
helper: this.getHelperDOM(),
selected: selected
}
}
// check if given draggable is accepted for drop // check if given draggable is accepted for drop
ai.isAccepted = function(_data, _context, _callback, _node) ai.isAccepted = function(_data, _context, _callback, _node)
{ {

View File

@ -114,7 +114,7 @@ export function et2_dataview_rowAOI(_node)
}; };
if (egwIsMobile()) { if (egwIsMobile()) {
jQuery(_node).swipe({ /*jQuery(_node).swipe({
allowPageScroll: "vertical", allowPageScroll: "vertical",
longTapThreshold: 10, longTapThreshold: 10,
swipe: function (event, direction, distance) swipe: function (event, direction, distance)
@ -131,7 +131,7 @@ export function et2_dataview_rowAOI(_node)
return; return;
} }
}); });*/
} else { } else {
jQuery(_node).click(selectHandler); jQuery(_node).click(selectHandler);
} }

View File

@ -19,7 +19,7 @@ import "../jquery/jquery.noconflict.js";
import "../jquery/mousewheel/mousewheel.js"; import "../jquery/mousewheel/mousewheel.js";
import '../jsapi/egw_inheritance.js'; import '../jsapi/egw_inheritance.js';
import {EGW_KEY_ENTER, EGW_KEY_SPACE} from '../egw_action/egw_action_constants.js'; import {EGW_KEY_ENTER, EGW_KEY_SPACE} from '../egw_action/egw_action_constants.js';
import interact from "@interactjs/interactjs";
/** /**
* ui siemenu entry class * ui siemenu entry class
* Basic sidebar menu implementation * Basic sidebar menu implementation
@ -359,6 +359,7 @@ window.egw_fw_ui_tab = function(_parent, _contHeaderDiv, _contDiv, _icon, _callb
// If dragging something over the tab, activate that app // If dragging something over the tab, activate that app
var tab = this.headerDiv; var tab = this.headerDiv;
this.headerDiv.addEventListener('dragenter', (event) => { this.headerDiv.addEventListener('dragenter', (event) => {
event.stopPropagation();
tab._callbackObject.call(tab); tab._callbackObject.call(tab);
}); });