Skip to content

Commit

Permalink
fix(drag-drop): prevent dragging selected text with the mouse (#18103)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
crisbeto authored and jelbourn committed Jan 22, 2020
1 parent 5c9f0d6 commit a949db3
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 1 deletion.
28 changes: 28 additions & 0 deletions src/cdk/drag-drop/directives/drag.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,34 @@ describe('CdkDrag', () => {
subscription.unsubscribe();
}));

it('should prevent the default `mousemove` action even before the drag threshold has ' +
'been reached', fakeAsync(() => {
const fixture = createComponent(StandaloneDraggable, [], 5);
fixture.detectChanges();
const dragElement = fixture.componentInstance.dragElement.nativeElement;

dispatchMouseEvent(dragElement, 'mousedown', 2, 2);
fixture.detectChanges();
const mousemoveEvent = dispatchMouseEvent(document, 'mousemove', 2, 2);
fixture.detectChanges();

expect(mousemoveEvent.defaultPrevented).toBe(true);
}));

it('should prevent the default `touchmove` action even before the drag threshold has ' +
'been reached', fakeAsync(() => {
const fixture = createComponent(StandaloneDraggable, [], 5);
fixture.detectChanges();
const dragElement = fixture.componentInstance.dragElement.nativeElement;

dispatchTouchEvent(dragElement, 'touchstart', 2, 2);
fixture.detectChanges();
const touchmoveEvent = dispatchTouchEvent(document, 'touchmove', 2, 2);
fixture.detectChanges();

expect(touchmoveEvent.defaultPrevented).toBe(true);
}));

});

describe('draggable with a handle', () => {
Expand Down
5 changes: 4 additions & 1 deletion src/cdk/drag-drop/drag-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,10 @@ export class DragRef<T = any> {

/** Handler that is invoked when the user moves their pointer after they've initiated a drag. */
private _pointerMove = (event: MouseEvent | TouchEvent) => {
// Prevent the default action as early as possible in order to block
// native actions like dragging the selected text or images with the mouse.
event.preventDefault();

if (!this._hasStartedDragging) {
const pointerPosition = this._getPointerPositionOnPage(event);
const distanceX = Math.abs(pointerPosition.x - this._pickupPositionOnPage.x);
Expand Down Expand Up @@ -565,7 +569,6 @@ export class DragRef<T = any> {

const constrainedPointerPosition = this._getConstrainedPointerPosition(event);
this._hasMoved = true;
event.preventDefault();
this._updatePointerDirectionDelta(constrainedPointerPosition);

if (this._dropContainer) {
Expand Down

0 comments on commit a949db3

Please sign in to comment.