Skip to content

Commit 11da288

Browse files
committed
fix(drag-drop): prevent mouse wheel scrolling while dragging
Prevents users from scrolling using the mouse wheel while an item is being dragged. This is a temporary measure until we have a solution to auto-scrolling while dragging, as well as to avoid having to measure the page for every pixel that the user has dragged. Fixes #13508.
1 parent 2e4a511 commit 11da288

File tree

2 files changed

+33
-12
lines changed

2 files changed

+33
-12
lines changed

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

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
dispatchMouseEvent,
66
createTouchEvent,
77
dispatchTouchEvent,
8+
dispatchFakeEvent,
89
} from '@angular/cdk/testing';
910
import {DragDropRegistry} from './drag-drop-registry';
1011
import {DragDropModule} from './drag-drop-module';
@@ -155,6 +156,15 @@ describe('DragDropRegistry', () => {
155156
expect(dispatchTouchEvent(document, 'touchmove').defaultPrevented).toBe(true);
156157
});
157158

159+
it('should not prevent the default `wheel` actions when nothing is being dragged', () => {
160+
expect(dispatchFakeEvent(document, 'wheel').defaultPrevented).toBe(false);
161+
});
162+
163+
it('should prevent the default `wheel` action when an item is being dragged', () => {
164+
registry.startDragging(testComponent.dragItems.first, createMouseEvent('mousedown'));
165+
expect(dispatchFakeEvent(document, 'wheel').defaultPrevented).toBe(true);
166+
});
167+
158168
});
159169

160170
@Component({

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

+23-12
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
4040
private _activeDragInstances = new Set<I>();
4141

4242
/** Keeps track of the event listeners that we've bound to the `document`. */
43-
private _globalListeners = new Map<'touchmove' | 'mousemove' | 'touchend' | 'mouseup', {
43+
private _globalListeners = new Map<'touchmove' | 'mousemove' | 'touchend' | 'mouseup' | 'wheel', {
4444
handler: PointerEventHandler,
4545
options?: any
4646
}>();
@@ -78,10 +78,13 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
7878
registerDragItem(drag: I) {
7979
this._dragInstances.add(drag);
8080

81+
// The `touchmove` event gets bound once, ahead of time, because WebKit
82+
// won't preventDefault on a dynamically-added `touchmove` listener.
83+
// See https://bugs.webkit.org/show_bug.cgi?id=184250.
8184
if (this._dragInstances.size === 1) {
8285
this._ngZone.runOutsideAngular(() => {
83-
// The event handler has to be explicitly active, because
84-
// newer browsers make it passive by default.
86+
// The event handler has to be explicitly active,
87+
// because newer browsers make it passive by default.
8588
this._document.addEventListener('touchmove', this._preventScrollListener,
8689
activeEventOptions);
8790
});
@@ -126,12 +129,22 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
126129
// use `preventDefault` to prevent the page from scrolling while the user is dragging.
127130
this._globalListeners
128131
.set(moveEvent, {handler: e => this.pointerMove.next(e), options: activeEventOptions})
129-
.set(upEvent, {handler: e => this.pointerUp.next(e)})
130-
.forEach((config, name) => {
131-
this._ngZone.runOutsideAngular(() => {
132-
this._document.addEventListener(name, config.handler, config.options);
133-
});
132+
.set(upEvent, {handler: e => this.pointerUp.next(e)});
133+
134+
// TODO(crisbeto): prevent mouse wheel scrolling while
135+
// dragging until we've set up proper scroll handling.
136+
if (!isTouchEvent) {
137+
this._globalListeners.set('wheel', {
138+
handler: this._preventScrollListener,
139+
options: activeEventOptions
134140
});
141+
}
142+
143+
this._ngZone.runOutsideAngular(() => {
144+
this._globalListeners.forEach((config, name) => {
145+
this._document.addEventListener(name, config.handler, config.options);
146+
});
147+
});
135148
}
136149
}
137150

@@ -164,11 +177,9 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
164177
}
165178

166179
/**
167-
* Listener used to prevent `touchmove` events while the element is being dragged.
168-
* This gets bound once, ahead of time, because WebKit won't preventDefault on a
169-
* dynamically-added `touchmove` listener. See https://bugs.webkit.org/show_bug.cgi?id=184250.
180+
* Listener used to prevent `touchmove` and `wheel` events while the element is being dragged.
170181
*/
171-
private _preventScrollListener = (event: TouchEvent) => {
182+
private _preventScrollListener = (event: Event) => {
172183
if (this._activeDragInstances.size) {
173184
event.preventDefault();
174185
}

0 commit comments

Comments
 (0)