Skip to content

Commit

Permalink
[INTERNAL] core.dnd: leaving the browser context while dragging
Browse files Browse the repository at this point in the history
 - Private isDragAllowed hook added for controls to determine whether
control should not be draggable even though they are made draggable with
DragDropInfo configutations.

BCP: 2280200014
Fixes: #3669
Change-Id: I12735641ce303ac959a16cc43ec43d2cb927adc5
  • Loading branch information
aborjinik committed Jan 19, 2023
1 parent f5c5732 commit 1ffc033
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 27 deletions.
41 changes: 26 additions & 15 deletions src/sap.ui.core/src/sap/ui/core/dnd/DragAndDrop.js
Expand Up @@ -24,18 +24,20 @@ function(lib, Device, Element, UIArea, jQuery, Configuration) {
*/

var DnD = {},
oDragControl = null, // the control being dragged
oDropControl = null, // the current drop target control
oValidDropControl = null, // the control which the dragged control can be dropped on based on the valid drop info
aValidDragInfos = [], // valid DragInfos configured for the currently dragged source
aValidDropInfos = [], // valid DropInfos configured for the current drop target
oDragSession = null, // stores active drag session throughout a drag activity
$DropIndicator, // drop position indicator
$GhostContainer, // container to place custom ghosts
sCalculatedDropPosition, // calculated position of the drop action relative to the valid dropped control.
iTargetEnteringTime, // timestamp of drag enter
mLastIndicatorStyle = {}, // holds the last style settings of the indicator
oDraggableAncestorNode; // reference to ancestor node that has draggable=true attribute
oDragControl = null, // the control being dragged
oDropControl = null, // the current drop target control
oValidDropControl = null, // the control which the dragged control can be dropped on based on the valid drop info
aValidDragInfos = [], // valid DragInfos configured for the currently dragged source
aValidDropInfos = [], // valid DropInfos configured for the current drop target
oDragSession = null, // stores active drag session throughout a drag activity
$DropIndicator, // drop position indicator
$GhostContainer, // container to place custom ghosts
sCalculatedDropPosition, // calculated position of the drop action relative to the valid dropped control.
iTargetEnteringTime, // timestamp of drag enter
mLastIndicatorStyle = {}, // holds the last style settings of the indicator
oDraggableAncestorNode, // reference to ancestor node that has draggable=true attribute
iDragEndTimer, // timer for the dragend event to ensure it is dispatched after the drop event
bDraggedOutOfBrowser; // determines whether something dragged out of the browser context e.g. for file upload


function addStyleClass(oElement, sStyleClass) {
Expand Down Expand Up @@ -280,6 +282,7 @@ function(lib, Device, Element, UIArea, jQuery, Configuration) {
function closeDragSession(oEvent) {
oDragControl = oDropControl = oValidDropControl = oDragSession = null;
sCalculatedDropPosition = "";
bDraggedOutOfBrowser = false;
aValidDragInfos = [];
aValidDropInfos = [];
}
Expand Down Expand Up @@ -623,7 +626,7 @@ function(lib, Device, Element, UIArea, jQuery, Configuration) {
if (!aValidDropInfos.length) {
oValidDropControl = null;
} else if (!oDragSession) {
// something is dragged from outside the browser
bDraggedOutOfBrowser = true;
oEvent.dragSession = oDragSession = createDragSession(oEvent);
}
};
Expand Down Expand Up @@ -684,6 +687,14 @@ function(lib, Device, Element, UIArea, jQuery, Configuration) {
sCalculatedDropPosition = showDropPosition(oEvent, oValidDropInfo, oValidDropControl);
};

DnD.onafterdragleave = function(oEvent) {
// clean up the drop indicator if the user left the browser window while dragging
if (bDraggedOutOfBrowser && !oEvent.relatedTarget) {
hideDropIndicator();
closeDragSession();
}
};

DnD.onbeforedrop = function(oEvent) {
// prevent default action
if (aValidDropInfos.length) {
Expand All @@ -698,12 +709,12 @@ function(lib, Device, Element, UIArea, jQuery, Configuration) {
});

// dragend event is not dispatched if the dragged element is removed
this.iDragEndTimer = window.requestAnimationFrame(this.onafterdragend.bind(this, oEvent));
iDragEndTimer = requestAnimationFrame(this.onafterdragend.bind(this, oEvent));
};

DnD.onafterdragend = function(oEvent) {
// cleanup the timer if there is a waiting job on the queue
this.iDragEndTimer = window.cancelAnimationFrame(this.iDragEndTimer);
iDragEndTimer = cancelAnimationFrame(iDragEndTimer);

// fire dragend event of valid DragInfos
aValidDragInfos.forEach(function(oDragInfo) {
Expand Down
11 changes: 4 additions & 7 deletions src/sap.ui.core/src/sap/ui/core/dnd/DragInfo.js
Expand Up @@ -101,14 +101,11 @@ sap.ui.define(["./DragDropBase"],
return false;
}

// control itself is the drag source
if (oDragSource === oControl && !sSourceAggregation) {
return true;
}

// control itself is the drag source or
// control is in the aggregation of the drag source
if (oControl.getParent() === oDragSource && sSourceAggregation === oControl.sParentAggregationName) {
return true;
if ((oDragSource === oControl && !sSourceAggregation) ||
(oControl.getParent() === oDragSource && sSourceAggregation === oControl.sParentAggregationName)) {
return oControl.isDragAllowed && !oControl.isDragAllowed(this) ? false : true;
}

return false;
Expand Down
13 changes: 12 additions & 1 deletion src/sap.ui.core/test/sap/ui/core/qunit/dnd/DragAndDrop.qunit.js
Expand Up @@ -726,11 +726,22 @@ sap.ui.define([
});

QUnit.test("dragged from outside the browser", function(assert) {
var oSession;
this.oTargetDomRef.focus();
this.oDropInfo.attachDragEnter(function(oEvent) {
assert.ok(oEvent.getParameter("dragSession"), "drag session exists");
oSession = oEvent.getParameter("dragSession");
assert.ok(oSession, "drag session exists");
});

this.oTargetDomRef.dispatchEvent(createNativeDragEventDummy("dragenter"));
assert.equal(oSession.getDropControl(), this.oTargetControl, "drop control accessible from the session");
assert.equal(document.querySelector(".sapUiDnDIndicator").style.width, this.oTargetDomRef.style.width, "drop indicator width set correctly");
assert.equal(document.querySelector(".sapUiDnDIndicator").style.height, this.oTargetDomRef.style.height, "drop indicator height set correctly");
assert.notEqual(document.querySelector(".sapUiDnDIndicator").style.display, "none", "drop indicator is visible");

this.oTargetDomRef.dispatchEvent(createNativeDragEventDummy("dragleave"));
assert.equal(document.querySelector(".sapUiDnDIndicator").style.display, "none", "drop indicator is not visible anylonger");
assert.notOk(oSession.getDropControl(), "there is no more drop control");
});

QUnit.test("setDropControl", function(assert) {
Expand Down
10 changes: 10 additions & 0 deletions src/sap.ui.core/test/sap/ui/core/qunit/dnd/DragInfo.qunit.js
Expand Up @@ -63,6 +63,10 @@ sap.ui.define([

assert.ok(oDragInfo.isDraggable(oControl), "Draggable: The drag source is the control itself");

oControl.isDragAllowed = function() { assert.equal(arguments[0], oDragInfo); return false; };
assert.notOk(oDragInfo.isDraggable(oControl), "Not Draggable: oControl.isDragAllowed method did not permit");
delete oControl.isDragAllowed;

oDragInfo.setSourceAggregation("children");
assert.notOk(oDragInfo.isDraggable(oControl), "Not Draggable: sourceAggregation is defined");

Expand All @@ -85,6 +89,12 @@ sap.ui.define([
assert.ok(oDragInfo.isDraggable(oControl), "Draggable: Child control is in the defined sourceAggregation");
assert.ok(oControl.getDomRef().draggable, "Dom Draggable: Child control is in the defined sourceAggregation");

oControl.isDragAllowed = function() { assert.equal(arguments[0], oDragInfo); return false; };
assert.notOk(oDragInfo.isDraggable(oControl), "Not Draggable: oControl.isDragAllowed method did not permit");
oControl.rerender();
assert.notOk(oControl.getDomRef().draggable, "Dom Not Draggable: oControl.isDragAllowed method did not permit");
delete oControl.isDragAllowed;

oDragInfo.setSourceAggregation("thereIsNoSuchAnAggregationName");
sap.ui.getCore().applyChanges();

Expand Down
Expand Up @@ -130,10 +130,8 @@
}
},
drop: function(oEvent) {
jQuery.sap.require("sap.ui.core.format.FileSizeFormat");
var oBrowserEvent = oEvent.getParameter("browserEvent");
var oFileSizeFormater = sap.ui.core.format.FileSizeFormat.getInstance();
var aFiles = [].slice.call(oBrowserEvent.dataTransfer.files);
var aFiles = Array.from(oBrowserEvent.dataTransfer.files);
var mFileTypes = {
"text/plain": "attachment-text-file",
"text/html": "attachment-text-file",
Expand All @@ -146,7 +144,7 @@
oFileList.addItem(new sap.m.StandardListItem({
title: oFile.name,
icon : "sap-icon://" + (mFileTypes[oFile.type] || "document"),
info: oFileSizeFormater.format(oFile.size)
info: new Date(oFile.lastModified).toLocaleString()
}));
});
}
Expand Down

0 comments on commit 1ffc033

Please sign in to comment.