import { OnDestroy , OnInit , NgZone , Directive } from '@angular/core' ; import { Platform } from '@angular/cdk/platform' ; import { fromEvent , merge , Observable , Subject } from 'rxjs' ; import { distinctUntilChanged , map , switchMap , takeUntil , tap } from 'rxjs/operators' ; import { NgScrollbarBase } from '../ng-scrollbar-base' ; import { ThumbAdapter } from './thumb/thumb' ; import { TrackAdapter } from './track/track' ; import { isWithinBounds , stopPropagation } from './common' ; @ Directive ( ) export abstract class Scrollbar implements OnInit , OnDestroy { readonly thumb : ThumbAdapter | undefined ; readonly track : TrackAdapter | undefined ; protected readonly destroyed = new Subject < void > ( ) ; /**
     * Viewport pointer events
     * The following streams are only activated when (pointerEventsMethod === 'viewport')
     */ protected viewportTrackClicked ! : Subject < MouseEvent > ; protected viewportThumbClicked ! : Subject < MouseEvent > ; protected abstract get viewportScrollSize ( ) : number ; protected constructor ( protected el , public cmp , protected platform , protected document , protected zone ) { } /**
     * Activate scrollbar pointer events
     */ private activatePointerEvents ( ) { let thumbDragEvent ; let trackClickEvent ; let trackHoveredEvent ; if ( this . cmp . pointerEventsMethod === 'viewport' ) { this . viewportTrackClicked = new Subject < MouseEvent > ( ) ; this . viewportThumbClicked = new Subject < MouseEvent > ( ) ; this . cmp . viewport ! . activatePointerEvents ( this . cmp . viewportPropagateMouseMove , this . destroyed ) ; thumbDragEvent = this . viewportThumbClicked ; trackClickEvent = this . viewportTrackClicked ; trackHoveredEvent = this . cmp . viewport ! . hovered . pipe ( map ( ( e ) => e ? isWithinBounds ( e , this . el . getBoundingClientRect ( ) ) : false ) , distinctUntilChanged ( ) , tap ( ( hovered ) => this . document . onselectstart = hovered ? ( ) => false : null ) ) ; this . cmp . viewport ! . clicked . pipe ( tap ( ( e ) => { if ( e ) { if ( isWithinBounds ( e , this . thumb ! . clientRect ) ) { this . viewportThumbClicked . next ( e ) ; } else if ( isWithinBounds ( e , this . track ! . clientRect ) ) { this . cmp . setClicked ( true ) ; this . viewportTrackClicked . next ( e ) ; } } else { this . cmp . setClicked ( false ) ; } } ) , takeUntil ( this . destroyed ) ) . subscribe ( ) ; } else { thumbDragEvent = this . thumb ! . clicked ; trackClickEvent = this . track ! . clicked ; trackHoveredEvent = this . hovered ; } return merge ( trackHoveredEvent . pipe ( tap ( ( e ) => this . setHovered ( e ) ) ) , thumbDragEvent . pipe ( switchMap ( ( e ) => this . thumb ! . dragged ( e ) ) ) , trackClickEvent . pipe ( switchMap ( ( e ) => this . track ! . onTrackClicked ( e , this . thumb ! . size , this . viewportScrollSize ) ) ) ) ; } protected get hovered ( ) : Observable < boolean > { const mouseEnter = fromEvent < MouseEvent > ( this . el , 'mouseenter' , { passive : true } ) . pipe ( stopPropagation ( ) , map ( ( ) => true ) ) ; const mouseLeave = fromEvent < MouseEvent > ( this . el , 'mouseleave' , { passive : true } ) . pipe ( stopPropagation ( ) , map ( ( ) => false ) ) ; return merge ( mouseEnter , mouseLeave ) ; } ngOnInit ( ) { this . zone . runOutsideAngular ( ( ) => { if ( ! ( this . platform . IOS || this . platform . ANDROID ) && ! this . cmp . pointerEventsDisabled ) { this . activatePointerEvents ( ) . pipe ( takeUntil ( this . destroyed ) ) . subscribe ( ) ; } merge ( this . cmp . scrolled , this . cmp . updated ) . pipe ( tap ( ( ) => this . thumb ?. update ( ) ) , takeUntil ( this . destroyed ) ) . subscribe ( ) ; } ) ; } ngOnDestroy ( ) { this . destroyed . next ( ) ; this . destroyed . complete ( ) ; if ( this . viewportThumbClicked && this . viewportTrackClicked ) { this . viewportTrackClicked . complete ( ) ; this . viewportThumbClicked . complete ( ) ; } } protected abstract setHovered ( value ) ; }