import { Directive , Optional , Input , Output , OnInit , OnDestroy , NgZone } from '@angular/core' ; import { Directionality } from '@angular/cdk/bidi' ; import { RtlScrollAxisType } from '@angular/cdk/platform' ; import { NgScrollbar } from 'ngx-scrollbar' ; import { Observable , Subject , Subscription , Subscriber } from 'rxjs' ; import { filter , map , tap , distinctUntilChanged } from 'rxjs/operators' ; type ElementEvent = Event & { target : Element ; } ; class ReachedFunctions { static reachedTop ( offset , e ) { return ReachedFunctions . reached ( - e . target . scrollTop , 0 , offset ) ; } static reachedBottom ( offset , e ) { return ReachedFunctions . reached ( e . target . scrollTop + e . target . clientHeight , e . target . scrollHeight , offset ) ; } static reachedStart ( offset , e , direction , rtlScrollAxisType ) { if ( direction === 'rtl' ) { if ( rtlScrollAxisType === RtlScrollAxisType . NEGATED ) { return ReachedFunctions . reached ( e . target . scrollLeft , 0 , offset ) ; } if ( rtlScrollAxisType === RtlScrollAxisType . INVERTED ) { return ReachedFunctions . reached ( - e . target . scrollLeft , 0 , offset ) ; } return ReachedFunctions . reached ( e . target . scrollLeft + e . target . clientWidth , e . target . scrollWidth , offset ) ; } return ReachedFunctions . reached ( - e . target . scrollLeft , 0 , offset ) ; } static reachedEnd ( offset , e , direction , rtlScrollAxisType ) { if ( direction === 'rtl' ) { if ( rtlScrollAxisType === RtlScrollAxisType . NEGATED ) { return ReachedFunctions . reached ( - ( e . target . scrollLeft - e . target . clientWidth ) , e . target . scrollWidth , offset ) ; } if ( rtlScrollAxisType === RtlScrollAxisType . INVERTED ) { return ReachedFunctions . reached ( - ( e . target . scrollLeft + e . target . clientWidth ) , e . target . scrollWidth , offset ) ; } return ReachedFunctions . reached ( - e . target . scrollLeft , 0 , offset ) ; } return ReachedFunctions . reached ( e . target . scrollLeft + e . target . clientWidth , e . target . scrollWidth , offset ) ; } static reached ( currPosition , targetPosition , offset ) { return currPosition >= targetPosition - offset ; } } @ Directive ( ) abstract class ScrollReached implements OnDestroy { /** offset: Reached offset value in px */ @ Input ( 'reachedOffset' ) offset = 0 ; /**
     * Stream that emits scroll event when `NgScrollbar.scrolled` is initialized.
     *
     * **NOTE:** This subject is used to hold the place of `NgScrollbar.scrolled` when it's not initialized yet
     */ protected scrollEvent = new Subject < ElementEvent > ( ) ; /** subscription: Scrolled event subscription, used to unsubscribe from the event on destroy */ protected subscription = Subscription . EMPTY ; /** A stream used to assign the reached output */ protected reachedEvent = new Observable ( ( subscriber ) => this . scrollReached ( ) . subscribe ( _ => Promise . resolve ( ) . then ( ( ) => this . zone . run ( ( ) => subscriber . next ( _ ) ) ) ) ) ; protected constructor ( @ Optional ( ) protected scrollbar , protected zone ) { if ( ! scrollbar ) { console . warn ( '[NgScrollbarReached Directive]: Host element must be an NgScrollbar component.' ) ; } } ngOnDestroy ( ) { this . subscription . unsubscribe ( ) ; } protected scrollReached ( ) { let currEvent ; return this . scrollEvent . pipe ( tap ( ( e ) => currEvent = e ) , map ( ( e ) => this . reached ( this . offset , e ) ) , distinctUntilChanged ( ) , filter ( ( reached ) => reached ) , map ( ( ) => currEvent ) ) ; } protected abstract reached ( offset , e ? ) ; } @ Directive ( ) abstract class VerticalScrollReached extends ScrollReached implements OnInit { protected constructor ( @ Optional ( ) protected scrollbar , protected zone ) { super ( scrollbar , zone ) ; } ngOnInit ( ) { this . subscription = this . scrollbar . verticalScrolled ! . subscribe ( this . scrollEvent ) ; } } @ Directive ( ) abstract class HorizontalScrollReached extends ScrollReached implements OnInit { protected constructor ( @ Optional ( ) protected scrollbar , protected zone ) { super ( scrollbar , zone ) ; } ngOnInit ( ) { this . subscription = this . scrollbar . horizontalScrolled ! . subscribe ( this . scrollEvent ) ; } } @ Directive ( { selector : '[reachedTop], [reached-top]' , } ) export class NgScrollbarReachedTop extends VerticalScrollReached implements OnInit { /** Stream that emits when scroll has reached the top */ @ Output ( ) reachedTop : Observable < ElementEvent > = this . reachedEvent ; constructor ( @ Optional ( ) protected scrollbar , protected zone ) { super ( scrollbar , zone ) ; } ngOnInit ( ) { super . ngOnInit ( ) ; } param offset param e protected reached ( offset , e ) { return ReachedFunctions . reachedTop ( offset , e ) ; } } @ Directive ( { selector : '[reachedBottom], [reached-bottom]' , } ) export class NgScrollbarReachedBottom extends VerticalScrollReached implements OnInit { /** Stream that emits when scroll has reached the bottom */ @ Output ( ) reachedBottom : Observable < ElementEvent > = this . reachedEvent ; constructor ( @ Optional ( ) protected scrollbar , protected zone ) { super ( scrollbar , zone ) ; } ngOnInit ( ) { super . ngOnInit ( ) ; } param offset param e protected reached ( offset , e ) { return ReachedFunctions . reachedBottom ( offset , e ) ; } } @ Directive ( { selector : '[reachedStart], [reached-start]' , } ) export class NgScrollbarReachedStart extends HorizontalScrollReached implements OnInit { /** Stream that emits when scroll has reached the start */ @ Output ( ) reachedStart : Observable < ElementEvent > = this . reachedEvent ; constructor ( @ Optional ( ) protected scrollbar , protected zone , private dir ) { super ( scrollbar , zone ) ; } ngOnInit ( ) { super . ngOnInit ( ) ; } param offset param e protected reached ( offset , e ) { return ReachedFunctions . reachedStart ( offset , e , this . dir . value , this . scrollbar . manager . rtlScrollAxisType ) ; } } @ Directive ( { selector : '[reachedEnd], [reached-end]' , } ) export class NgScrollbarReachedEnd extends HorizontalScrollReached implements OnInit { /** Stream that emits when scroll has reached the end */ @ Output ( ) reachedEnd : Observable < ElementEvent > = this . reachedEvent ; constructor ( @ Optional ( ) protected scrollbar , protected zone , private dir ) { super ( scrollbar , zone ) ; } ngOnInit ( ) { super . ngOnInit ( ) ; } param offset param e protected reached ( offset , e ) { return ReachedFunctions . reachedEnd ( offset , e , this . dir . value , this . scrollbar . manager . rtlScrollAxisType ) ; } }