diff --git a/src/sap.ui.core/src/sap/ui/core/dnd/DragAndDrop.js b/src/sap.ui.core/src/sap/ui/core/dnd/DragAndDrop.js index 08fdab1790ed..d982d2aa5632 100644 --- a/src/sap.ui.core/src/sap/ui/core/dnd/DragAndDrop.js +++ b/src/sap.ui.core/src/sap/ui/core/dnd/DragAndDrop.js @@ -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) { @@ -280,6 +282,7 @@ function(lib, Device, Element, UIArea, jQuery, Configuration) { function closeDragSession(oEvent) { oDragControl = oDropControl = oValidDropControl = oDragSession = null; sCalculatedDropPosition = ""; + bDraggedOutOfBrowser = false; aValidDragInfos = []; aValidDropInfos = []; } @@ -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); } }; @@ -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) { @@ -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) { diff --git a/src/sap.ui.core/src/sap/ui/core/dnd/DragInfo.js b/src/sap.ui.core/src/sap/ui/core/dnd/DragInfo.js index c6e5bda44b89..c445e765af1f 100644 --- a/src/sap.ui.core/src/sap/ui/core/dnd/DragInfo.js +++ b/src/sap.ui.core/src/sap/ui/core/dnd/DragInfo.js @@ -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; diff --git a/src/sap.ui.core/test/sap/ui/core/qunit/dnd/DragAndDrop.qunit.js b/src/sap.ui.core/test/sap/ui/core/qunit/dnd/DragAndDrop.qunit.js index f6370d335bb0..e8671a0516ac 100644 --- a/src/sap.ui.core/test/sap/ui/core/qunit/dnd/DragAndDrop.qunit.js +++ b/src/sap.ui.core/test/sap/ui/core/qunit/dnd/DragAndDrop.qunit.js @@ -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) { diff --git a/src/sap.ui.core/test/sap/ui/core/qunit/dnd/DragInfo.qunit.js b/src/sap.ui.core/test/sap/ui/core/qunit/dnd/DragInfo.qunit.js index e58954742ecf..199d25451e1b 100644 --- a/src/sap.ui.core/test/sap/ui/core/qunit/dnd/DragInfo.qunit.js +++ b/src/sap.ui.core/test/sap/ui/core/qunit/dnd/DragInfo.qunit.js @@ -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"); @@ -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(); diff --git a/src/sap.ui.core/test/sap/ui/core/samples/draganddrop/DragAndDrop.html b/src/sap.ui.core/test/sap/ui/core/samples/draganddrop/DragAndDrop.html index 8b06a33a4f16..e61dc36d5b89 100644 --- a/src/sap.ui.core/test/sap/ui/core/samples/draganddrop/DragAndDrop.html +++ b/src/sap.ui.core/test/sap/ui/core/samples/draganddrop/DragAndDrop.html @@ -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", @@ -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() })); }); }