license import { Injectable , NgZone , OnDestroy , Inject } from '@angular/core' ; import { DOCUMENT } from '@angular/common' ; import { normalizePassiveListenerOptions } from '@angular/cdk/platform' ; import { Subject } from 'rxjs' ; /** Event options that can be used to bind an active, capturing event. */ const activeCapturingEventOptions = normalizePassiveListenerOptions ( { passive : false , capture : true } ) ; docs-private @ Injectable ( { providedIn : 'root' } ) export class DragDropRegistry < I , C extends { id : string ; } > implements OnDestroy { private _document : Document ; /** Registered drop container instances. */ private _dropInstances = new Set < C > ( ) ; /** Registered drag item instances. */ private _dragInstances = new Set < I > ( ) ; /** Drag item instances that are currently being dragged. */ private _activeDragInstances = new Set < I > ( ) ; /** Keeps track of the event listeners that we've bound to the `document`. */ private _globalListeners = new Map < string , { handler : ( event : Event ) => void ; options ? : AddEventListenerOptions | boolean ; } > ( ) ; /**
     * Emits the `touchmove` or `mousemove` events that are dispatched
     * while the user is dragging a drag item instance.
     */ readonly pointerMove : Subject < TouchEvent | MouseEvent > = new Subject < TouchEvent | MouseEvent > ( ) ; /**
     * Emits the `touchend` or `mouseup` events that are dispatched
     * while the user is dragging a drag item instance.
     */ readonly pointerUp : Subject < TouchEvent | MouseEvent > = new Subject < TouchEvent | MouseEvent > ( ) ; constructor ( private _ngZone , @ Inject ( DOCUMENT ) _document ) { this . _document = _document ; } /** Adds a drop container to the registry. */ registerDropContainer ( drop ) { if ( ! this . _dropInstances . has ( drop ) ) { if ( this . getDropContainer ( drop . id ) ) { throw Error ( `Drop instance with id "${ drop . id }" has already been registered.` ) ; } this . _dropInstances . add ( drop ) ; } } /** Adds a drag item instance to the registry. */ registerDragItem ( drag ) { this . _dragInstances . add ( drag ) ; if ( this . _dragInstances . size === 1 ) { this . _ngZone . runOutsideAngular ( ( ) => { this . _document . addEventListener ( 'touchmove' , this . _preventDefaultWhileDragging , activeCapturingEventOptions ) ; } ) ; } } /** Removes a drop container from the registry. */ removeDropContainer ( drop ) { this . _dropInstances . delete ( drop ) ; } /** Removes a drag item instance from the registry. */ removeDragItem ( drag ) { this . _dragInstances . delete ( drag ) ; this . stopDragging ( drag ) ; if ( this . _dragInstances . size === 0 ) { this . _document . removeEventListener ( 'touchmove' , this . _preventDefaultWhileDragging , activeCapturingEventOptions ) ; } } param drag param event startDragging ( drag , event ) { this . _activeDragInstances . add ( drag ) ; if ( this . _activeDragInstances . size === 1 ) { const isTouchEvent = event . type . startsWith ( 'touch' ) ; const moveEvent = isTouchEvent ? 'touchmove' : 'mousemove' ; const upEvent = isTouchEvent ? 'touchend' : 'mouseup' ; this . _globalListeners . set ( moveEvent , { handler : ( e ) => this . pointerMove . next ( e as TouchEvent | MouseEvent ) , options : activeCapturingEventOptions } ) . set ( upEvent , { handler : ( e ) => this . pointerUp . next ( e as TouchEvent | MouseEvent ) , options : true } ) . set ( 'selectstart' , { handler : this . _preventDefaultWhileDragging , options : activeCapturingEventOptions } ) ; if ( ! isTouchEvent ) { this . _globalListeners . set ( 'wheel' , { handler : this . _preventDefaultWhileDragging , options : activeCapturingEventOptions } ) ; } this . _ngZone . runOutsideAngular ( ( ) => { this . _globalListeners . forEach ( ( config , name ) => { this . _document . addEventListener ( name , config . handler , config . options ) ; } ) ; } ) ; } } /** Stops dragging a drag item instance. */ stopDragging ( drag ) { this . _activeDragInstances . delete ( drag ) ; if ( this . _activeDragInstances . size === 0 ) { this . _clearGlobalListeners ( ) ; } } /** Gets whether a drag item instance is currently being dragged. */ isDragging ( drag ) { return this . _activeDragInstances . has ( drag ) ; } deprecated breaking-change getDropContainer ( id ) { return Array . from ( this . _dropInstances ) . find ( instance => instance . id === id ) ; } ngOnDestroy ( ) { this . _dragInstances . forEach ( instance => this . removeDragItem ( instance ) ) ; this . _dropInstances . forEach ( instance => this . removeDropContainer ( instance ) ) ; this . _clearGlobalListeners ( ) ; this . pointerMove . complete ( ) ; this . pointerUp . complete ( ) ; } param event private _preventDefaultWhileDragging = ( event ) => { if ( this . _activeDragInstances . size ) { event . preventDefault ( ) ; } } ; /** Clears out the global event listeners from the `document`. */ private _clearGlobalListeners ( ) { this . _globalListeners . forEach ( ( config , name ) => { this . _document . removeEventListener ( name , config . handler , config . options ) ; } ) ; this . _globalListeners . clear ( ) ; } }