Skip to content

Commit

Permalink
Add enter/leave tracking for dragging files or links out of window
Browse files Browse the repository at this point in the history
  • Loading branch information
gaearon committed Mar 18, 2015
1 parent c27c1e2 commit 60cffe9
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 1 deletion.
15 changes: 14 additions & 1 deletion modules/backends/HTML5.js
@@ -1,5 +1,6 @@
import { DragSource } from 'dnd-core';
import NativeTypes from '../NativeTypes';
import EnterLeaveCounter from '../utils/EnterLeaveCounter';
import warning from 'react/lib/warning';

function isUrlDataTransfer(dataTransfer) {
Expand Down Expand Up @@ -62,6 +63,8 @@ export default class HTML5Backend {
this.registry = registry;

this.nodeHandlers = {};
this.enterLeaveCounter = new EnterLeaveCounter();

this.handleTopDragStart = this.handleTopDragStart.bind(this);
this.handleTopDragStartCapture = this.handleTopDragStartCapture.bind(this);
this.handleTopDragEnd = this.handleTopDragEnd.bind(this);
Expand Down Expand Up @@ -223,7 +226,8 @@ export default class HTML5Backend {
handleTopDragEnterCapture(e) {
this.dragEnterTargetHandles = [];

if (this.monitor.isDragging()) {
const isFirstEnter = this.enterLeaveCounter.enter(e.target);
if (!isFirstEnter || this.monitor.isDragging()) {
return;
}

Expand Down Expand Up @@ -261,6 +265,13 @@ export default class HTML5Backend {
if (this.isDraggingNativeItem()) {
e.preventDefault();
}

const isLastLeave = this.enterLeaveCounter.leave(e.target);
if (!isLastLeave || !this.isDraggingNativeItem()) {
return;
}

this.actions.endDrag();
}

handleTopDragLeave() {
Expand All @@ -276,6 +287,8 @@ export default class HTML5Backend {
const source = this.registry.getSource(sourceHandle);
source.mutateItemByReadingDataTransfer(e.dataTransfer);
}

this.enterLeaveCounter.reset();
}

handleDrop(e, targetHandle) {
Expand Down
35 changes: 35 additions & 0 deletions modules/utils/EnterLeaveCounter.js
@@ -0,0 +1,35 @@
import union from 'lodash/array/union';
import without from 'lodash/array/without';

export default class EnterLeaveCounter {
constructor() {
this.entered = [];
}

enter(enteringNode) {
this.entered = union(
this.entered.filter(node =>
document.body.contains(node) &&
(!node.contains || node.contains(enteringNode))
),
[enteringNode]
);

return this.entered.length === 1;
}

leave(leavingNode) {
this.entered = without(
this.entered.filter(node =>
document.body.contains(node)
),
leavingNode
);

return this.entered.length === 0;
}

reset() {
this.entered = [];
}
}

0 comments on commit 60cffe9

Please sign in to comment.