license import { Directionality } from '@angular/cdk/bidi' ; import { getRtlScrollAxisType , RtlScrollAxisType , supportsScrollBehavior , } from '@angular/cdk/platform' ; import { Directive , ElementRef , NgZone , OnDestroy , OnInit , Optional } from '@angular/core' ; import { fromEvent , Observable , Subject , Observer } from 'rxjs' ; import { takeUntil } from 'rxjs/operators' ; import { ScrollDispatcher } from './scroll-dispatcher' ; export type _Without < T > = { [ P in keyof T ] ? : never ; } ; export type _XOR < T , U > = ( _Without < T > & U ) | ( _Without < U > & T ) ; export type _Top = { top ? : number ; } ; export type _Bottom = { bottom ? : number ; } ; export type _Left = { left ? : number ; } ; export type _Right = { right ? : number ; } ; export type _Start = { start ? : number ; } ; export type _End = { end ? : number ; } ; export type _XAxis = _XOR < _XOR < _Left , _Right > , _XOR < _Start , _End > > ; export type _YAxis = _XOR < _Top , _Bottom > ; /**
 * An extended version of ScrollToOptions that allows expressing scroll offsets relative to the
 * top, bottom, left, right, start, or end of the viewport rather than just the top and left.
 * Please note: the top and bottom properties are mutually exclusive, as are the left, right,
 * start, and end properties.
 */ export type ExtendedScrollToOptions = _XAxis & _YAxis & ScrollOptions ; /**
 * Sends an event when the directive's element is scrolled. Registers itself with the
 * ScrollDispatcher service to include itself as part of its collection of scrolling events that it
 * can be listened to through the service.
 */ @ Directive ( { selector : '[cdk-scrollable], [cdkScrollable]' , } ) export class CdkScrollable implements OnInit , OnDestroy { private readonly _destroyed = new Subject < void > ( ) ; private _elementScrolled : Observable < Event > = new Observable ( ( observer ) => this . ngZone . runOutsideAngular ( ( ) => fromEvent ( this . elementRef . nativeElement , 'scroll' ) . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( observer ) ) ) ; constructor ( protected elementRef , protected scrollDispatcher , protected ngZone , @ Optional ( ) protected dir ? ) { } ngOnInit ( ) { this . scrollDispatcher . register ( this ) ; } ngOnDestroy ( ) { this . scrollDispatcher . deregister ( this ) ; this . _destroyed . next ( ) ; this . _destroyed . complete ( ) ; } /** Returns observable that emits when a scroll event is fired on the host element. */ elementScrolled ( ) { return this . _elementScrolled ; } /** Gets the ElementRef for the viewport. */ getElementRef ( ) { return this . elementRef ; } param options scrollTo ( options ) { const el = this . elementRef . nativeElement ; const isRtl = this . dir && this . dir . value == 'rtl' ; if ( options . left == null ) { options . left = isRtl ? options . end : options . start ; } if ( options . right == null ) { options . right = isRtl ? options . start : options . end ; } if ( options . bottom != null ) { ( options as _Without < _Bottom > & _Top ) . top = el . scrollHeight - el . clientHeight - options . bottom ; } if ( isRtl && getRtlScrollAxisType ( ) != RtlScrollAxisType . NORMAL ) { if ( options . left != null ) { ( options as _Without < _Left > & _Right ) . right = el . scrollWidth - el . clientWidth - options . left ; } if ( getRtlScrollAxisType ( ) == RtlScrollAxisType . INVERTED ) { options . left = options . right ; } else if ( getRtlScrollAxisType ( ) == RtlScrollAxisType . NEGATED ) { options . left = options . right ? - options . right : options . right ; } } else { if ( options . right != null ) { ( options as _Without < _Right > & _Left ) . left = el . scrollWidth - el . clientWidth - options . right ; } } this . _applyScrollToOptions ( options ) ; } private _applyScrollToOptions ( options ) { const el = this . elementRef . nativeElement ; if ( supportsScrollBehavior ( ) ) { el . scrollTo ( options ) ; } else { if ( options . top != null ) { el . scrollTop = options . top ; } if ( options . left != null ) { el . scrollLeft = options . left ; } } } param from measureScrollOffset ( from ) { const LEFT = 'left' ; const RIGHT = 'right' ; const el = this . elementRef . nativeElement ; if ( from == 'top' ) { return el . scrollTop ; } if ( from == 'bottom' ) { return el . scrollHeight - el . clientHeight - el . scrollTop ; } const isRtl = this . dir && this . dir . value == 'rtl' ; if ( from == 'start' ) { from = isRtl ? RIGHT : LEFT ; } else if ( from == 'end' ) { from = isRtl ? LEFT : RIGHT ; } if ( isRtl && getRtlScrollAxisType ( ) == RtlScrollAxisType . INVERTED ) { if ( from == LEFT ) { return el . scrollWidth - el . clientWidth - el . scrollLeft ; } else { return el . scrollLeft ; } } else if ( isRtl && getRtlScrollAxisType ( ) == RtlScrollAxisType . NEGATED ) { if ( from == LEFT ) { return el . scrollLeft + el . scrollWidth - el . clientWidth ; } else { return - el . scrollLeft ; } } else { if ( from == LEFT ) { return el . scrollLeft ; } else { return el . scrollWidth - el . clientWidth - el . scrollLeft ; } } } }