ngx-hide-on-scroll
Version:
Hide an element on scroll down or up in Angular.
150 lines • 19.9 kB
JavaScript
import { Directive, ElementRef, Inject, PLATFORM_ID, Input, Renderer2, Output, EventEmitter } from '@angular/core';
import { fromEvent, Subject } from 'rxjs';
import { distinctUntilChanged, filter, map, pairwise, share, takeUntil, throttleTime } from 'rxjs/operators';
import { isPlatformServer } from '@angular/common';
// Inspired by: https://netbasal.com/reactive-sticky-header-in-angular-12dbffb3f1d3
/**
* The `ngxHideOnScroll` directive allows you to hide an html element (e.g. navbar) on scroll down and show it again on scroll up.
*/
export class NgxHideOnScrollDirective {
constructor(elementRef, renderer2, platformId) {
this.elementRef = elementRef;
this.renderer2 = renderer2;
this.platformId = platformId;
/**
* `'Down'`: The element will be hidden on scroll down and it will be shown again on scroll up.<br/>`Up`: The element will be hidden on scroll up and it will be shown again on scroll down.
*/
this.hideOnScroll = 'Down';
/**
* CSS class name added to the element to hide it. When this property is set, `propertyUsedToHide`, `valueWhenHidden`, and `valueWhenShown` have not effect.
*/
this.classNameWhenHidden = '';
/**
* The CSS property used to hide/show the element.
*
* @default
* 'transform'
*/
this.propertyUsedToHide = 'transform';
/**
* The value of `propertyUsedToHide` when the element is hidden.
*
* @default
* 'translateY(-100%)'
*/
this.valueWhenHidden = 'translateY(-100%)';
/**
* The value of `propertyUsedToHide` when the element is shown.
*
* @default
* 'translateY(0)'
*/
this.valueWhenShown = 'translateY(0)';
/**
* The selector of the element you want to listen the scroll event, in case it is not the default browser scrolling element (`document.scrollingElement` or `document.documentElement`). For example [` .mat-sidenav-content`]( https://stackoverflow.com/a/52931772/12954396) if you are using [Angular Material Sidenav]( https://material.angular.io/components/sidenav)
*/
this.scrollingElementSelector = '';
/**
* Emitted when the element is hidden.
*/
this.eventElementHidden = new EventEmitter();
/**
* Emitted when the element is shown.
*/
this.eventElementShown = new EventEmitter();
this.unsubscribeNotifier = new Subject();
}
ngAfterViewInit() {
if (isPlatformServer(this.platformId)) {
return;
}
let elementToListenScrollEvent;
let scrollingElement;
if (!this.scrollingElementSelector) {
elementToListenScrollEvent = window;
scrollingElement = this.getDefaultScrollingElement();
}
else {
scrollingElement = document.querySelector(this.scrollingElementSelector);
if (!scrollingElement) {
console.error(`NgxHideOnScroll: scrollingElementSelector\nElement with selector: "${this.scrollingElementSelector}" not found.`);
return;
}
elementToListenScrollEvent = scrollingElement;
}
const scroll$ = fromEvent(elementToListenScrollEvent, 'scroll').pipe(takeUntil(this.unsubscribeNotifier), throttleTime(50), // only emit every 50 ms
map(() => scrollingElement.scrollTop), // get vertical scroll position
pairwise(), // look at this and the last emitted element
// compare this and the last element to figure out scrolling direction
map(([y1, y2]) => (y2 < y1 ? ScrollDirection.Up : ScrollDirection.Down)), distinctUntilChanged(), // only emit when scrolling direction changed
share() // share a single subscription to the underlying sequence in case of multiple subscribers
);
const scrollUp$ = scroll$.pipe(filter(direction => direction === ScrollDirection.Up));
const scrollDown$ = scroll$.pipe(filter(direction => direction === ScrollDirection.Down));
let scrollUpAction;
let scrollDownAction;
if (this.hideOnScroll === 'Up') {
scrollUpAction = () => this.hideElement();
scrollDownAction = () => this.showElement();
}
else {
scrollUpAction = () => this.showElement();
scrollDownAction = () => this.hideElement();
}
scrollUp$.subscribe(() => scrollUpAction());
scrollDown$.subscribe(() => scrollDownAction());
}
ngOnDestroy() {
this.unsubscribeNotifier.next();
this.unsubscribeNotifier.complete();
}
hideElement() {
const nativeElement = this.elementRef.nativeElement;
if (this.classNameWhenHidden) {
this.renderer2.addClass(nativeElement, this.classNameWhenHidden);
}
else {
this.renderer2.setStyle(nativeElement, this.propertyUsedToHide, this.valueWhenHidden);
}
this.eventElementHidden.emit();
}
showElement() {
const nativeElement = this.elementRef.nativeElement;
if (this.classNameWhenHidden) {
this.renderer2.removeClass(nativeElement, this.classNameWhenHidden);
}
else {
this.renderer2.setStyle(nativeElement, this.propertyUsedToHide, this.valueWhenShown);
}
this.eventElementShown.emit();
}
getDefaultScrollingElement() {
return (document.scrollingElement || document.documentElement);
}
}
NgxHideOnScrollDirective.decorators = [
{ type: Directive, args: [{
selector: '[ngxHideOnScroll]'
},] }
];
NgxHideOnScrollDirective.ctorParameters = () => [
{ type: ElementRef },
{ type: Renderer2 },
{ type: String, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
];
NgxHideOnScrollDirective.propDecorators = {
hideOnScroll: [{ type: Input }],
classNameWhenHidden: [{ type: Input }],
propertyUsedToHide: [{ type: Input }],
valueWhenHidden: [{ type: Input }],
valueWhenShown: [{ type: Input }],
scrollingElementSelector: [{ type: Input }],
eventElementHidden: [{ type: Output }],
eventElementShown: [{ type: Output }]
};
var ScrollDirection;
(function (ScrollDirection) {
ScrollDirection["Up"] = "Up";
ScrollDirection["Down"] = "Down";
})(ScrollDirection || (ScrollDirection = {}));
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWhpZGUtb24tc2Nyb2xsLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1oaWRlLW9uLXNjcm9sbC9zcmMvbGliL25neC1oaWRlLW9uLXNjcm9sbC5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQWlCLE1BQU0sRUFBRSxXQUFXLEVBQWEsS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzdJLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzFDLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsTUFBTSxFQUNOLEdBQUcsRUFDSCxRQUFRLEVBQ1IsS0FBSyxFQUNMLFNBQVMsRUFDVCxZQUFZLEVBQ2IsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUVuRCxtRkFBbUY7QUFFbkY7O0dBRUc7QUFJSCxNQUFNLE9BQU8sd0JBQXdCO0lBcURuQyxZQUNVLFVBQW1DLEVBQ25DLFNBQW9CLEVBQ0MsVUFBa0I7UUFGdkMsZUFBVSxHQUFWLFVBQVUsQ0FBeUI7UUFDbkMsY0FBUyxHQUFULFNBQVMsQ0FBVztRQUNDLGVBQVUsR0FBVixVQUFVLENBQVE7UUF0RGpEOztXQUVHO1FBQ00saUJBQVksR0FBa0IsTUFBTSxDQUFDO1FBRTlDOztXQUVHO1FBQ00sd0JBQW1CLEdBQVcsRUFBRSxDQUFDO1FBRTFDOzs7OztXQUtHO1FBQ00sdUJBQWtCLEdBQThDLFdBQVcsQ0FBQztRQUVyRjs7Ozs7V0FLRztRQUNNLG9CQUFlLEdBQVcsbUJBQW1CLENBQUM7UUFFdkQ7Ozs7O1dBS0c7UUFDTSxtQkFBYyxHQUFXLGVBQWUsQ0FBQztRQUVsRDs7V0FFRztRQUNNLDZCQUF3QixHQUFX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QyxXQUFXOzs7MkJBbkRwQixLQUFLO2tDQUtMLEtBQUs7aUNBUUwsS0FBSzs4QkFRTCxLQUFLOzZCQVFMLEtBQUs7dUNBS0wsS0FBSztpQ0FLTCxNQUFNO2dDQUtOLE1BQU07O0FBNEZULElBQUssZUFHSjtBQUhELFdBQUssZUFBZTtJQUNsQiw0QkFBUyxDQUFBO0lBQ1QsZ0NBQWEsQ0FBQTtBQUNmLENBQUMsRUFISSxlQUFlLEtBQWYsZUFBZSxRQUduQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERpcmVjdGl2ZSwgRWxlbWVudFJlZiwgQWZ0ZXJWaWV3SW5pdCwgSW5qZWN0LCBQTEFURk9STV9JRCwgT25EZXN0cm95LCBJbnB1dCwgUmVuZGVyZXIyLCBPdXRwdXQsIEV2ZW50RW1pdHRlciB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBmcm9tRXZlbnQsIFN1YmplY3QgfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHtcclxuICBkaXN0aW5jdFVudGlsQ2hhbmdlZCxcclxuICBmaWx0ZXIsXHJcbiAgbWFwLFxyXG4gIHBhaXJ3aXNlLFxyXG4gIHNoYXJlLFxyXG4gIHRha2VVbnRpbCxcclxuICB0aHJvdHRsZVRpbWVcclxufSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XHJcbmltcG9ydCB7IGlzUGxhdGZvcm1TZXJ2ZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5cclxuLy8gSW5zcGlyZWQgYnk6IGh0dHBzOi8vbmV0YmFzYWwuY29tL3JlYWN0aXZlLXN0aWNreS1oZWFkZXItaW4tYW5ndWxhci0xMmRiZmZiM2YxZDNcclxuXHJcbi8qKlxyXG4gKiBUaGUgYG5neEhpZGVPblNjcm9sbGAgZGlyZWN0aXZlIGFsbG93cyB5b3UgdG8gaGlkZSBhbiBodG1sIGVsZW1lbnQgKGUuZy4gbmF2YmFyKSBvbiBzY3JvbGwgZG93biBhbmQgc2hvdyBpdCBhZ2FpbiBvbiBzY3JvbGwgdXAuXHJcbiAqL1xyXG5ARGlyZWN0aXZlKHtcclxuICBzZWxlY3RvcjogJ1tuZ3hIaWRlT25TY3JvbGxdJ1xyXG59KVxyXG5leHBvcnQgY2xhc3MgTmd4SGlkZU9uU2Nyb2xsRGlyZWN0aXZlIGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcclxuXHJcbiAgLyoqXHJcbiAgICogYCdEb3duJ2A6IFRoZSBlbGVtZW50IHdpbGwgYmUgaGlkZGVuIG9uIHNjcm9sbCBkb3duIGFuZCBpdCB3aWxsIGJlIHNob3duIGFnYWluIG9uIHNjcm9sbCB1cC48YnIvPmBVcGA6IFRoZSBlbGVtZW50IHdpbGwgYmUgaGlkZGVuIG9uIHNjcm9sbCB1cCBhbmQgaXQgd2lsbCBiZSBzaG93biBhZ2FpbiBvbiBzY3JvbGwgZG93bi5cclxuICAgKi9cclxuICBASW5wdXQoKSBoaWRlT25TY3JvbGw6ICdEb3duJyB8ICdVcCcgPSAnRG93bic7XHJcblxyXG4gIC8qKlxyXG4gICAqIENTUyBjbGFzcyBuYW1lIGFkZGVkIHRvIHRoZSBlbGVtZW50IHRvIGhpZGUgaXQuIFdoZW4gdGhpcyBwcm9wZXJ0eSBpcyBzZXQsIGBwcm9wZXJ0eVVzZWRUb0hpZGVgLCBgdmFsdWVXaGVuSGlkZGVuYCwgYW5kIGB2YWx1ZVdoZW5TaG93bmAgaGF2ZSBub3QgZWZmZWN0LlxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIGNsYXNzTmFtZVdoZW5IaWRkZW46IHN0cmluZyA9ICcnO1xyXG5cclxuICAvKipcclxuICAgKiBUaGUgQ1NTIHByb3BlcnR5IHVzZWQgdG8gaGlkZS9zaG93IHRoZSBlbGVtZW50LlxyXG4gICAqIFxyXG4gICAqIEBkZWZhdWx0XHJcbiAgICogJ3RyYW5zZm9ybSdcclxuICAgKi9cclxuICBASW5wdXQoKSBwcm9wZXJ0eVVzZWRUb0hpZGU6ICd0cmFuc2Zvcm0nIHwgJ3RvcCcgfCAnYm90dG9tJyB8ICdoZWlnaHQnID0gJ3RyYW5zZm9ybSc7XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSB2YWx1ZSBvZiBgcHJvcGVydHlVc2VkVG9IaWRlYCB3aGVuIHRoZSBlbGVtZW50IGlzIGhpZGRlbi5cclxuICAgKiBcclxuICAgKiBAZGVmYXVsdFxyXG4gICAqICd0cmFuc2xhdGVZKC0xMDAlKSdcclxuICAgKi9cclxuICBASW5wdXQoKSB2YWx1ZVdoZW5IaWRkZW46IHN0cmluZyA9ICd0cmFuc2xhdGVZKC0xMDAlKSc7XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSB2YWx1ZSBvZiBgcHJvcGVydHlVc2VkVG9IaWRlYCB3aGVuIHRoZSBlbGVtZW50IGlzIHNob3duLlxyXG4gICAqIFxyXG4gICAqIEBkZWZhdWx0XHJcbiAgICogJ3RyYW5zbGF0ZVkoMCknXHJcbiAgICovXHJcbiAgQElucHV0KCkgdmFsdWVXaGVuU2hvd246IHN0cmluZyA9ICd0cmFuc2xhdGVZKDApJztcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIHNlbGVjdG9yIG9mIHRoZSBlbGVtZW50IHlvdSB3YW50IHRvIGxpc3RlbiB0aGUgc2Nyb2xsIGV2ZW50LCBpbiBjYXNlIGl0IGlzIG5vdCB0aGUgZGVmYXVsdCBicm93c2VyIHNjcm9sbGluZyBlbGVtZW50IChgZG9jdW1lbnQuc2Nyb2xsaW5nRWxlbWVudGAgb3IgYGRvY3VtZW50LmRvY3VtZW50RWxlbWVudGApLiBGb3IgZXhhbXBsZSBbYCAubWF0LXNpZGVuYXYtY29udGVudGBdKCBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvNTI5MzE3NzIvMTI5NTQzOTYpIGlmIHlvdSBhcmUgdXNpbmcgW0FuZ3VsYXIgTWF0ZXJpYWwgU2lkZW5hdl0oIGh0dHBzOi8vbWF0ZXJpYWwuYW5ndWxhci5pby9jb21wb25lbnRzL3NpZGVuYXYpXHJcbiAgICovXHJcbiAgQElucHV0KCkgc2Nyb2xsaW5nRWxlbWVudFNlbGVjdG9yOiBzdHJpbmcgPSAnJztcclxuXHJcbiAgLyoqXHJcbiAgICogRW1pdHRlZCB3aGVuIHRoZSBlbGVtZW50IGlzIGhpZGRlbi5cclxuICAgKi9cclxuICBAT3V0cHV0KCkgZXZlbnRFbGVtZW50SGlkZGVuID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG5cclxuICAvKipcclxuICAgKiBFbWl0dGVkIHdoZW4gdGhlIGVsZW1lbnQgaXMgc2hvd24uXHJcbiAgICovXHJcbiAgQE91dHB1dCgpIGV2ZW50RWxlbWVudFNob3duID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG5cclxuICBwcml2YXRlIHVuc3Vic2NyaWJlTm90aWZpZXIgPSBuZXcgU3ViamVjdCgpO1xyXG5cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIHByaXZhdGUgZWxlbWVudFJlZjogRWxlbWVudFJlZjxIVE1MRWxlbWVudD4sXHJcbiAgICBwcml2YXRlIHJlbmRlcmVyMjogUmVuZGVyZXIyLFxyXG4gICAgQEluamVjdChQTEFURk9STV9JRCkgcHJpdmF0ZSBwbGF0Zm9ybUlkOiBzdHJpbmdcclxuICApIHsgfVxyXG5cclxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XHJcbiAgICBpZiAoaXNQbGF0Zm9ybVNlcnZlcih0aGlzLnBsYXRmb3JtSWQpKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgZWxlbWVudFRvTGlzdGVuU2Nyb2xsRXZlbnQ7XHJcbiAgICBsZXQgc2Nyb2xsaW5nRWxlbWVudDogSFRNTEVsZW1lbnQ7XHJcbiAgICBpZiAoIXRoaXMuc2Nyb2xsaW5nRWxlbWVudFNlbGVjdG9yKSB7XHJcbiAgICAgIGVsZW1lbnRUb0xpc3RlblNjcm9sbEV2ZW50ID0gd2luZG93O1xyXG4gICAgICBzY3JvbGxpbmdFbGVtZW50ID0gdGhpcy5nZXREZWZhdWx0U2Nyb2xsaW5nRWxlbWVudCgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgc2Nyb2xsaW5nRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5zY3JvbGxpbmdFbGVtZW50U2VsZWN0b3IpIGFzIEhUTUxFbGVtZW50O1xyXG4gICAgICBpZiAoIXNjcm9sbGluZ0VsZW1lbnQpIHtcclxuICAgICAgICBjb25zb2xlLmVycm9yKGBOZ3hIaWRlT25TY3JvbGw6IEBJbnB1dCgpIHNjcm9sbGluZ0VsZW1lbnRTZWxlY3RvclxcbkVsZW1lbnQgd2l0aCBzZWxlY3RvcjogXCIke3RoaXMuc2Nyb2xsaW5nRWxlbWVudFNlbGVjdG9yfVwiIG5vdCBmb3VuZC5gKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuICAgICAgZWxlbWVudFRvTGlzdGVuU2Nyb2xsRXZlbnQgPSBzY3JvbGxpbmdFbGVtZW50O1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHNjcm9sbCQgPSBmcm9tRXZlbnQoZWxlbWVudFRvTGlzdGVuU2Nyb2xsRXZlbnQsICdzY3JvbGwnKS5waXBlKFxyXG4gICAgICB0YWtlVW50aWwodGhpcy51bnN1YnNjcmliZU5vdGlmaWVyKSxcclxuICAgICAgdGhyb3R0bGVUaW1lKDUwKSwgLy8gb25seSBlbWl0IGV2ZXJ5IDUwIG1zXHJcbiAgICAgIG1hcCgoKSA9PiBzY3JvbGxpbmdFbGVtZW50LnNjcm9sbFRvcCksIC8vIGdldCB2ZXJ0aWNhbCBzY3JvbGwgcG9zaXRpb25cclxuICAgICAgcGFpcndpc2UoKSwgIC8vIGxvb2sgYXQgdGhpcyBhbmQgdGhlIGxhc3QgZW1pdHRlZCBlbGVtZW50XHJcbiAgICAgIC8vIGNvbXBhcmUgdGhpcyBhbmQgdGhlIGxhc3QgZWxlbWVudCB0byBmaWd1cmUgb3V0IHNjcm9sbGluZyBkaXJlY3Rpb25cclxuICAgICAgbWFwKChbeTEsIHkyXSk6IFNjcm9sbERpcmVjdGlvbiA9PiAoeTIgPCB5MSA/IFNjcm9sbERpcmVjdGlvbi5VcCA6IFNjcm9sbERpcmVjdGlvbi5Eb3duKSksXHJcbiAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKCksIC8vIG9ubHkgZW1pdCB3aGVuIHNjcm9sbGluZyBkaXJlY3Rpb24gY2hhbmdlZFxyXG4gICAgICBzaGFyZSgpIC8vIHNoYXJlIGEgc2luZ2xlIHN1YnNjcmlwdGlvbiB0byB0aGUgdW5kZXJseWluZyBzZXF1ZW5jZSBpbiBjYXNlIG9mIG11bHRpcGxlIHN1YnNjcmliZXJzXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IHNjcm9sbFVwJCA9IHNjcm9sbCQucGlwZShcclxuICAgICAgZmlsdGVyKGRpcmVjdGlvbiA9PiBkaXJlY3Rpb24gPT09IFNjcm9sbERpcmVjdGlvbi5VcClcclxuICAgICk7XHJcblxyXG4gICAgY29uc3Qgc2Nyb2xsRG93biQgPSBzY3JvbGwkLnBpcGUoXHJcbiAgICAgIGZpbHRlcihkaXJlY3Rpb24gPT4gZGlyZWN0aW9uID09PSBTY3JvbGxEaXJlY3Rpb24uRG93bilcclxuICAgICk7XHJcblxyXG4gICAgbGV0IHNjcm9sbFVwQWN0aW9uOiAoKSA9PiB2b2lkO1xyXG4gICAgbGV0IHNjcm9sbERvd25BY3Rpb246ICgpID0+IHZvaWQ7XHJcbiAgICBpZiAodGhpcy5oaWRlT25TY3JvbGwgPT09ICdVcCcpIHtcclxuICAgICAgc2Nyb2xsVXBBY3Rpb24gPSAoKSA9PiB0aGlzLmhpZGVFbGVtZW50KCk7XHJcbiAgICAgIHNjcm9sbERvd25BY3Rpb24gPSAoKSA9PiB0aGlzLnNob3dFbGVtZW50KCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBzY3JvbGxVcEFjdGlvbiA9ICgpID0+IHRoaXMuc2hvd0VsZW1lbnQoKTtcclxuICAgICAgc2Nyb2xsRG93bkFjdGlvbiA9ICgpID0+IHRoaXMuaGlkZUVsZW1lbnQoKTtcclxuICAgIH1cclxuXHJcbiAgICBzY3JvbGxVcCQuc3Vic2NyaWJlKCgpID0+IHNjcm9sbFVwQWN0aW9uKCkpO1xyXG4gICAgc2Nyb2xsRG93biQuc3Vic2NyaWJlKCgpID0+IHNjcm9sbERvd25BY3Rpb24oKSk7XHJcbiAgfVxyXG5cclxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuICAgIHRoaXMudW5zdWJzY3JpYmVOb3RpZmllci5uZXh0KCk7XHJcbiAgICB0aGlzLnVuc3Vic2NyaWJlTm90aWZpZXIuY29tcGxldGUoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgaGlkZUVsZW1lbnQoKTogdm9pZCB7XHJcbiAgICBjb25zdCBuYXRpdmVFbGVtZW50ID0gdGhpcy5lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQ7XHJcbiAgICBpZiAodGhpcy5jbGFzc05hbWVXaGVuSGlkZGVuKSB7XHJcbiAgICAgIHRoaXMucmVuZGVyZXIyLmFkZENsYXNzKG5hdGl2ZUVsZW1lbnQsIHRoaXMuY2xhc3NOYW1lV2hlbkhpZGRlbik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLnJlbmRlcmVyMi5zZXRTdHlsZShuYXRpdmVFbGVtZW50LCB0aGlzLnByb3BlcnR5VXNlZFRvSGlkZSwgdGhpcy52YWx1ZVdoZW5IaWRkZW4pO1xyXG4gICAgfVxyXG4gICAgdGhpcy5ldmVudEVsZW1lbnRIaWRkZW4uZW1pdCgpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzaG93RWxlbWVudCgpOiB2b2lkIHtcclxuICAgIGNvbnN0IG5hdGl2ZUVsZW1lbnQgPSB0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudDtcclxuICAgIGlmICh0aGlzLmNsYXNzTmFtZVdoZW5IaWRkZW4pIHtcclxuICAgICAgdGhpcy5yZW5kZXJlcjIucmVtb3ZlQ2xhc3MobmF0aXZlRWxlbWVudCwgdGhpcy5jbGFzc05hbWVXaGVuSGlkZGVuKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMucmVuZGVyZXIyLnNldFN0eWxlKG5hdGl2ZUVsZW1lbnQsIHRoaXMucHJvcGVydHlVc2VkVG9IaWRlLCB0aGlzLnZhbHVlV2hlblNob3duKTtcclxuICAgIH1cclxuICAgIHRoaXMuZXZlbnRFbGVtZW50U2hvd24uZW1pdCgpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBnZXREZWZhdWx0U2Nyb2xsaW5nRWxlbWVudCgpOiBIVE1MRWxlbWVudCB7XHJcbiAgICByZXR1cm4gKGRvY3VtZW50LnNjcm9sbGluZ0VsZW1lbnQgfHwgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50KSBhcyBIVE1MRWxlbWVudDtcclxuICB9XHJcbn1cclxuXHJcbmVudW0gU2Nyb2xsRGlyZWN0aW9uIHtcclxuICBVcCA9ICdVcCcsXHJcbiAgRG93biA9ICdEb3duJ1xyXG59Il19