Skip to content

Commit a949db3

Browse files
crisbetojelbourn
authored andcommitted
fix(drag-drop): prevent dragging selected text with the mouse (#18103)
When a drag item has some text inside it and the user starts dragging after a small delay, they'll pause our dragging sequence mid-way and start the native browser text dragging. Once they've stopped dragging the text, our dragging takes over which ends up looking glitchy. The problem comes from the fact that for mouse events we were calling `preventDefault` only after the delay and the drag threshold had been reached, whereas for touch events we were doing it all the time. These changes move the `preventDefault` call up so we call it for all mouse events as well.
1 parent 5c9f0d6 commit a949db3

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

src/cdk/drag-drop/directives/drag.spec.ts

+28
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,34 @@ describe('CdkDrag', () => {
11321132
subscription.unsubscribe();
11331133
}));
11341134

1135+
it('should prevent the default `mousemove` action even before the drag threshold has ' +
1136+
'been reached', fakeAsync(() => {
1137+
const fixture = createComponent(StandaloneDraggable, [], 5);
1138+
fixture.detectChanges();
1139+
const dragElement = fixture.componentInstance.dragElement.nativeElement;
1140+
1141+
dispatchMouseEvent(dragElement, 'mousedown', 2, 2);
1142+
fixture.detectChanges();
1143+
const mousemoveEvent = dispatchMouseEvent(document, 'mousemove', 2, 2);
1144+
fixture.detectChanges();
1145+
1146+
expect(mousemoveEvent.defaultPrevented).toBe(true);
1147+
}));
1148+
1149+
it('should prevent the default `touchmove` action even before the drag threshold has ' +
1150+
'been reached', fakeAsync(() => {
1151+
const fixture = createComponent(StandaloneDraggable, [], 5);
1152+
fixture.detectChanges();
1153+
const dragElement = fixture.componentInstance.dragElement.nativeElement;
1154+
1155+
dispatchTouchEvent(dragElement, 'touchstart', 2, 2);
1156+
fixture.detectChanges();
1157+
const touchmoveEvent = dispatchTouchEvent(document, 'touchmove', 2, 2);
1158+
fixture.detectChanges();
1159+
1160+
expect(touchmoveEvent.defaultPrevented).toBe(true);
1161+
}));
1162+
11351163
});
11361164

11371165
describe('draggable with a handle', () => {

src/cdk/drag-drop/drag-ref.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,10 @@ export class DragRef<T = any> {
525525

526526
/** Handler that is invoked when the user moves their pointer after they've initiated a drag. */
527527
private _pointerMove = (event: MouseEvent | TouchEvent) => {
528+
// Prevent the default action as early as possible in order to block
529+
// native actions like dragging the selected text or images with the mouse.
530+
event.preventDefault();
531+
528532
if (!this._hasStartedDragging) {
529533
const pointerPosition = this._getPointerPositionOnPage(event);
530534
const distanceX = Math.abs(pointerPosition.x - this._pickupPositionOnPage.x);
@@ -565,7 +569,6 @@ export class DragRef<T = any> {
565569

566570
const constrainedPointerPosition = this._getConstrainedPointerPosition(event);
567571
this._hasMoved = true;
568-
event.preventDefault();
569572
this._updatePointerDirectionDelta(constrainedPointerPosition);
570573

571574
if (this._dropContainer) {

0 commit comments

Comments
 (0)