Skip to content

Commit ad81954

Browse files
authored
Merge pull request #375 from randym/fix/rm_delay_distance
fix(delay_distance): fix drag start concurrency
2 parents c533811 + d3e5e23 commit ad81954

File tree

14 files changed

+557
-296
lines changed

14 files changed

+557
-296
lines changed

.prettierrc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
{
2+
"trailingComma": "all",
23
"printWidth": 120,
3-
"singleQuote": true
4+
"singleQuote": true,
5+
"bracketSpacing": false,
6+
"arrowParens": "always"
47
}

scripts/test/helpers/constants.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ export const defaultMouseEventOptions = {
1111
button: 0,
1212
clientX: 0,
1313
clientY: 0,
14+
pageX: 0,
15+
pageY: 0,
1416
};
1517

16-
export const DRAG_DELAY = 0;
18+
export const DRAG_DELAY = 100;

scripts/test/helpers/sensor.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ import {DRAG_DELAY, defaultTouchEventOptions, defaultMouseEventOptions} from './
22
import {triggerEvent} from './event';
33

44
export function waitForDragDelay(dragDelay = DRAG_DELAY) {
5+
const next = Date.now() + dragDelay + 1;
6+
const dateMock = jest.spyOn(Date, 'now').mockImplementation(() => {
7+
return next;
8+
});
59
jest.runTimersToTime(dragDelay + 1);
10+
dateMock.mockRestore();
611
}
712

813
export function clickMouse(element, options = {}) {

scripts/test/matchers/sensor.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
1-
function toHaveTriggeredSensorEvent(received, expectedEventName) {
1+
function toHaveTriggeredSensorEvent(received, expectedEventName, count) {
22
let triggered = false;
3-
3+
let callCount = 0;
44
function callback() {
5+
count !== undefined && (callCount = callCount + 1);
56
triggered = true;
67
}
78

89
document.addEventListener(expectedEventName, callback);
910
received();
1011
document.removeEventListener(expectedEventName, callback);
1112

12-
const pass = Boolean(triggered);
13+
const pass = Boolean(triggered) && Boolean(count === undefined || callCount === count);
1314

1415
return {
1516
pass,
1617
message: () => {
1718
const expectation = pass ? 'not to have been' : 'to have been';
19+
const defaultMessage = `Expected sensor event '${expectedEventName}' ${expectation} to be triggered`;
1820

19-
return `Expected sensor event '${expectedEventName}' ${expectation} triggered`;
21+
return count ? `${defaultMessage} ${count} time(s)` : defaultMessage;
2022
},
2123
};
2224
}

src/Draggable/Sensors/DragSensor/DragSensor.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ export default class DragSensor extends Sensor {
161161
this.trigger(container, dragStopEvent);
162162

163163
this.dragging = false;
164-
this.delayOver = false;
165164
this.startEvent = null;
166165

167166
this[reset]();
@@ -210,7 +209,6 @@ export default class DragSensor extends Sensor {
210209
this.startEvent = event;
211210

212211
this.mouseDownTimeout = setTimeout(() => {
213-
this.delayOver = true;
214212
target.draggable = true;
215213
this.draggableElement = target;
216214
}, this.options.delay);

src/Draggable/Sensors/MouseSensor/MouseSensor.js

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {closest, distance} from 'shared/utils';
1+
import {closest, distance as euclideanDistance} from 'shared/utils';
22
import Sensor from '../Sensor';
33
import {DragStartSensorEvent, DragMoveSensorEvent, DragStopSensorEvent} from '../SensorEvent';
44

@@ -63,28 +63,27 @@ export default class MouseSensor extends Sensor {
6363
if (event.button !== 0 || event.ctrlKey || event.metaKey) {
6464
return;
6565
}
66-
67-
this.startEvent = event;
68-
69-
document.addEventListener('mouseup', this[onMouseUp]);
70-
document.addEventListener('mousemove', this[onDistanceChange]);
71-
7266
const container = closest(event.target, this.containers);
7367

7468
if (!container) {
7569
return;
7670
}
7771

78-
document.addEventListener('dragstart', preventNativeDragStart);
72+
const {delay = 0} = this.options;
73+
const {pageX, pageY} = event;
74+
75+
Object.assign(this, {pageX, pageY});
76+
this.onMouseDownAt = Date.now();
77+
this.startEvent = event;
7978

8079
this.currentContainer = container;
81-
this.mouseDownTimeout = setTimeout(() => {
82-
this.delayOver = true;
83-
if (this.distance < this.options.distance) {
84-
return;
85-
}
86-
this[startDrag]();
87-
}, this.options.delay);
80+
document.addEventListener('mouseup', this[onMouseUp]);
81+
document.addEventListener('dragstart', preventNativeDragStart);
82+
document.addEventListener('mousemove', this[onDistanceChange]);
83+
84+
this.mouseDownTimeout = window.setTimeout(() => {
85+
this[onDistanceChange]({pageX: this.pageX, pageY: this.pageY});
86+
}, delay);
8887
}
8988

9089
/**
@@ -114,15 +113,28 @@ export default class MouseSensor extends Sensor {
114113
}
115114

116115
/**
117-
* Detect change in distance
116+
* Detect change in distance, starting drag when both
117+
* delay and distance requirements are met
118118
* @private
119119
* @param {Event} event - Mouse move event
120120
*/
121121
[onDistanceChange](event) {
122-
if (this.dragging) return;
123-
this.distance = distance(this.startEvent.pageX, this.startEvent.pageY, event.pageX, event.pageY);
122+
const {pageX, pageY} = event;
123+
const {delay, distance} = this.options;
124+
const {startEvent} = this;
125+
126+
Object.assign(this, {pageX, pageY});
127+
128+
if (!this.currentContainer) {
129+
return;
130+
}
131+
132+
const timeElapsed = Date.now() - this.onMouseDownAt;
133+
const distanceTravelled = euclideanDistance(startEvent.pageX, startEvent.pageY, pageX, pageY) || 0;
124134

125-
if (this.delayOver && this.distance >= this.options.distance) {
135+
if (timeElapsed >= delay && distanceTravelled >= distance) {
136+
window.clearTimeout(this.mouseDownTimeout);
137+
document.removeEventListener('mousemove', this[onDistanceChange]);
126138
this[startDrag]();
127139
}
128140
}
@@ -187,8 +199,6 @@ export default class MouseSensor extends Sensor {
187199

188200
this.currentContainer = null;
189201
this.dragging = false;
190-
this.distance = 0;
191-
this.delayOver = false;
192202
this.startEvent = null;
193203
}
194204

0 commit comments

Comments
 (0)