@@ -54,6 +54,14 @@ import {CDK_DROP_CONTAINER, CdkDropContainer} from './drop-container';
54
54
*/
55
55
const POINTER_DIRECTION_CHANGE_THRESHOLD = 5 ;
56
56
57
+ /**
58
+ * Time in milliseconds for which to ignore mouse events, after
59
+ * receiving a touch event. Used to avoid doing double work for
60
+ * touch devices where the browser fires fake mouse events, in
61
+ * addition to touch events.
62
+ */
63
+ const MOUSE_EVENT_IGNORE_TIME = 800 ;
64
+
57
65
/** Element that can be moved inside a CdkDrop container. */
58
66
@Directive ( {
59
67
selector : '[cdkDrag]' ,
@@ -129,6 +137,13 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
129
137
/** Root element that will be dragged by the user. */
130
138
private _rootElement : HTMLElement ;
131
139
140
+ /**
141
+ * Time at which the last touch event occurred. Used to avoid firing the same
142
+ * events multiple times on touch devices where the browser will fire a fake
143
+ * mouse event for each touch event, after a certain time.
144
+ */
145
+ private _lastTouchEventTime : number ;
146
+
132
147
/** Elements that can be used to drag the draggable item. */
133
148
@ContentChildren ( CdkDragHandle ) _handles : QueryList < CdkDragHandle > ;
134
149
@@ -276,9 +291,13 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
276
291
event : MouseEvent | TouchEvent ) => {
277
292
278
293
const isDragging = this . _isDragging ( ) ;
294
+ const isTouchEvent = this . _isTouchEvent ( event ) ;
295
+ const isAuxiliaryMouseButton = ! isTouchEvent && ( event as MouseEvent ) . button !== 0 ;
296
+ const isSyntheticEvent = ! isTouchEvent && this . _lastTouchEventTime &&
297
+ this . _lastTouchEventTime + MOUSE_EVENT_IGNORE_TIME > Date . now ( ) ;
279
298
280
299
// Abort if the user is already dragging or is using a mouse button other than the primary one.
281
- if ( isDragging || ( ! this . _isTouchEvent ( event ) && event . button !== 0 ) ) {
300
+ if ( isDragging || isAuxiliaryMouseButton || isSyntheticEvent ) {
282
301
return ;
283
302
}
284
303
@@ -309,6 +328,10 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
309
328
// Emit the event on the item before the one on the container.
310
329
this . started . emit ( { source : this } ) ;
311
330
331
+ if ( isTouchEvent ) {
332
+ this . _lastTouchEventTime = Date . now ( ) ;
333
+ }
334
+
312
335
if ( this . dropContainer ) {
313
336
const element = this . _rootElement ;
314
337
@@ -375,19 +398,21 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
375
398
return ;
376
399
}
377
400
378
- this . _dragDropRegistry . stopDragging ( this ) ;
379
-
380
401
if ( ! this . dropContainer ) {
381
402
// Convert the active transform into a passive one. This means that next time
382
403
// the user starts dragging the item, its position will be calculated relatively
383
404
// to the new passive transform.
384
405
this . _passiveTransform . x = this . _activeTransform . x ;
385
406
this . _passiveTransform . y = this . _activeTransform . y ;
386
407
this . _ngZone . run ( ( ) => this . ended . emit ( { source : this } ) ) ;
408
+ this . _dragDropRegistry . stopDragging ( this ) ;
387
409
return ;
388
410
}
389
411
390
- this . _animatePreviewToPlaceholder ( ) . then ( ( ) => this . _cleanupDragArtifacts ( ) ) ;
412
+ this . _animatePreviewToPlaceholder ( ) . then ( ( ) => {
413
+ this . _cleanupDragArtifacts ( ) ;
414
+ this . _dragDropRegistry . stopDragging ( this ) ;
415
+ } ) ;
391
416
}
392
417
393
418
/** Cleans up the DOM artifacts that were added to facilitate the element being dragged. */
0 commit comments