Skip to content

Commit cd6da93

Browse files
crisbetovivian-hu-zz
authored andcommitted
fix(drag-drop): prevent mouse wheel scrolling while dragging (#13524)
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 d0f4e7b commit cd6da93

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';
@@ -192,6 +193,15 @@ describe('DragDropRegistry', () => {
192193
expect(event.defaultPrevented).toBe(true);
193194
});
194195

196+
it('should not prevent the default `wheel` actions when nothing is being dragged', () => {
197+
expect(dispatchFakeEvent(document, 'wheel').defaultPrevented).toBe(false);
198+
});
199+
200+
it('should prevent the default `wheel` action when an item is being dragged', () => {
201+
registry.startDragging(testComponent.dragItems.first, createMouseEvent('mousedown'));
202+
expect(dispatchFakeEvent(document, 'wheel').defaultPrevented).toBe(true);
203+
});
204+
195205
});
196206

197207
@Component({

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

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

4545
/** Keeps track of the event listeners that we've bound to the `document`. */
46-
private _globalListeners = new Map<'touchmove' | 'mousemove' | 'touchend' | 'mouseup', {
46+
private _globalListeners = new Map<'touchmove' | 'mousemove' | 'touchend' | 'mouseup' | 'wheel', {
4747
handler: PointerEventHandler,
4848
options?: AddEventListenerOptions | boolean
4949
}>();
@@ -81,10 +81,13 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
8181
registerDragItem(drag: I) {
8282
this._dragInstances.add(drag);
8383

84+
// The `touchmove` event gets bound once, ahead of time, because WebKit
85+
// won't preventDefault on a dynamically-added `touchmove` listener.
86+
// See https://bugs.webkit.org/show_bug.cgi?id=184250.
8487
if (this._dragInstances.size === 1) {
8588
this._ngZone.runOutsideAngular(() => {
86-
// The event handler has to be explicitly active, because
87-
// newer browsers make it passive by default.
89+
// The event handler has to be explicitly active,
90+
// because newer browsers make it passive by default.
8891
this._document.addEventListener('touchmove', this._preventScrollListener,
8992
activeCapturingEventOptions);
9093
});
@@ -135,12 +138,22 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
135138
.set(upEvent, {
136139
handler: e => this.pointerUp.next(e),
137140
options: true
138-
})
139-
.forEach((config, name) => {
140-
this._ngZone.runOutsideAngular(() => {
141-
this._document.addEventListener(name, config.handler, config.options);
142-
});
143141
});
142+
143+
// TODO(crisbeto): prevent mouse wheel scrolling while
144+
// dragging until we've set up proper scroll handling.
145+
if (!isTouchEvent) {
146+
this._globalListeners.set('wheel', {
147+
handler: this._preventScrollListener,
148+
options: activeCapturingEventOptions
149+
});
150+
}
151+
152+
this._ngZone.runOutsideAngular(() => {
153+
this._globalListeners.forEach((config, name) => {
154+
this._document.addEventListener(name, config.handler, config.options);
155+
});
156+
});
144157
}
145158
}
146159

@@ -173,11 +186,9 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
173186
}
174187

175188
/**
176-
* Listener used to prevent `touchmove` events while the element is being dragged.
177-
* This gets bound once, ahead of time, because WebKit won't preventDefault on a
178-
* dynamically-added `touchmove` listener. See https://bugs.webkit.org/show_bug.cgi?id=184250.
189+
* Listener used to prevent `touchmove` and `wheel` events while the element is being dragged.
179190
*/
180-
private _preventScrollListener = (event: TouchEvent) => {
191+
private _preventScrollListener = (event: Event) => {
181192
if (this._activeDragInstances.size) {
182193
event.preventDefault();
183194
}

0 commit comments

Comments
 (0)