UNPKG

@hkjeffchan/ngx-scroll-to

Version:

A simple Angular 4+ plugin enabling you to smooth scroll to any element on your page and enhance scroll-based features in your app.

273 lines 33.2 kB
import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; import { DOCUMENT, isPlatformBrowser } from '@angular/common'; import { ScrollToAnimation } from './scroll-to-animation'; import { DEFAULTS, isElementRef, isNativeElement, isNumber, isString, isWindow, stripHash } from './scroll-to-helpers'; import { ReplaySubject, throwError } from 'rxjs'; import * as i0 from "@angular/core"; /** * The Scroll To Service handles starting, interrupting * and ending the actual Scroll Animation. It provides * some utilities to find the proper HTML Element on a * given page to setup Event Listeners and calculate * distances for the Animation. */ export class ScrollToService { /** * Construct and setup required paratemeters. * * @param document A Reference to the Document * @param platformId Angular Platform ID */ constructor(document, platformId) { this.document = document; this.platformId = platformId; this.interruptiveEvents = ['mousewheel', 'DOMMouseScroll', 'touchstart']; } /** * Target an Element to scroll to. Notice that the `TimeOut` decorator * ensures the executing to take place in the next Angular lifecycle. * This allows for scrolling to elements that are e.g. initially hidden * by means of `*ngIf`, but ought to be scrolled to eventually. * * @todo type 'any' in Observable should become custom type like 'ScrollToEvent' (base class), see issue comment: * - https://github.com/nicky-lenaers/ngx-scroll-to/issues/10#issuecomment-317198481 * * @param options Configuration Object * @returns Observable */ scrollTo(options) { if (!isPlatformBrowser(this.platformId)) { return new ReplaySubject().asObservable(); } return this.start(options); } /** * Start a new Animation. * * @todo Emit proper events from subscription * * @param options Configuration Object * @returns Observable */ start(options) { // Merge config with default values const mergedConfigOptions = { ...DEFAULTS, ...options }; if (this.animation) { this.animation.stop(); } const targetNode = this.getNode(mergedConfigOptions.target); if (mergedConfigOptions.target && !targetNode) { return throwError(() => new Error('Unable to find Target Element')); } const container = this.getContainer(mergedConfigOptions, targetNode); if (mergedConfigOptions.container && !container) { return throwError(() => new Error('Unable to find Container Element')); } const listenerTarget = this.getListenerTarget(container) || window; let to = container ? container.getBoundingClientRect().top : 0; if (targetNode) { to = isWindow(listenerTarget) ? window.scrollY + targetNode.getBoundingClientRect().top : targetNode.getBoundingClientRect().top; } // Create Animation this.animation = new ScrollToAnimation(container, listenerTarget, isWindow(listenerTarget), to, mergedConfigOptions, isPlatformBrowser(this.platformId)); const onInterrupt = () => this.animation.stop(); this.addInterruptiveEventListeners(listenerTarget, onInterrupt); // Start Animation const animation$ = this.animation.start(); this.subscribeToAnimation(animation$, listenerTarget, onInterrupt); return animation$; } /** * Subscribe to the events emitted from the Scrolling * Animation. Events might be used for e.g. unsubscribing * once finished. * * @param animation$ The Animation Observable * @param listenerTarget The Listener Target for events * @param onInterrupt The handler for Interruptive Events * @returns Void */ subscribeToAnimation(animation$, listenerTarget, onInterrupt) { const subscription = animation$ .subscribe({ complete: () => { this.removeInterruptiveEventListeners(this.interruptiveEvents, listenerTarget, onInterrupt); subscription.unsubscribe(); } }); } /** * Get the container HTML Element in which * the scrolling should happen. * * @param options The Merged Configuration Object * @param targetNode the targeted HTMLElement */ getContainer(options, targetNode) { let container = null; if (options.container) { container = this.getNode(options.container, true); } else if (targetNode) { container = this.getFirstScrollableParent(targetNode); } return container; } /** * Add listeners for the Animation Interruptive Events * to the Listener Target. * * @param events List of events to listen to * @param listenerTarget Target to attach the listener on * @param handler Handler for when the listener fires * @returns Void */ addInterruptiveEventListeners(listenerTarget, handler) { if (!listenerTarget) { listenerTarget = window; } this.interruptiveEvents .forEach(event => listenerTarget .addEventListener(event, handler, this.supportPassive() ? { passive: true } : false)); } /** * Feature-detect support for passive event listeners. * * @returns Whether or not passive event listeners are supported */ supportPassive() { let supportsPassive = false; try { const opts = Object.defineProperty({}, 'passive', { get: () => { supportsPassive = true; } }); window.addEventListener('testPassive', null, opts); window.removeEventListener('testPassive', null, opts); } catch (e) { } return supportsPassive; } /** * Remove listeners for the Animation Interrupt Event from * the Listener Target. Specifying the correct handler prevents * memory leaks and makes the allocated memory available for * Garbage Collection. * * @param events List of Interruptive Events to remove * @param listenerTarget Target to attach the listener on * @param handler Handler for when the listener fires * @returns Void */ removeInterruptiveEventListeners(events, listenerTarget, handler) { if (!listenerTarget) { listenerTarget = window; } events.forEach(event => listenerTarget.removeEventListener(event, handler)); } /** * Find the first scrollable parent Node of a given * Element. The DOM Tree gets searched upwards * to find this first scrollable parent. Parents might * be ignored by CSS styles applied to the HTML Element. * * @param nativeElement The Element to search the DOM Tree upwards from * @returns The first scrollable parent HTML Element */ getFirstScrollableParent(nativeElement) { let style = window.getComputedStyle(nativeElement); const overflowRegex = /(auto|scroll|overlay)/; if (style.position === 'fixed') { return null; } let parent = nativeElement; while (parent.parentElement) { parent = parent.parentElement; style = window.getComputedStyle(parent); if (style.position === 'absolute' || style.overflow === 'hidden' || style.overflowY === 'hidden') { continue; } if (overflowRegex.test(style.overflow + style.overflowY) || parent.tagName === 'BODY') { return parent; } } return null; } /** * Get the Target Node to scroll to. * * @param id The given ID of the node, either a string or * an element reference * @param allowBodyTag Indicate whether or not the Document Body is * considered a valid Target Node * @returns The Target Node to scroll to */ getNode(id, allowBodyTag = false) { let targetNode; if (isString(id)) { if (allowBodyTag && (id === 'body' || id === 'BODY')) { targetNode = this.document.body; } else { targetNode = this.document.getElementById(stripHash(id)); } } else if (isNumber(id)) { targetNode = this.document.getElementById(String(id)); } else if (isElementRef(id)) { targetNode = id.nativeElement; } else if (isNativeElement(id)) { targetNode = id; } return targetNode; } /** * Retrieve the Listener target. This Listener Target is used * to attach Event Listeners on. In case of the target being * the Document Body, we need the actual `window` to listen * for events. * * @param container The HTML Container element * @returns The Listener Target to attach events on */ getListenerTarget(container) { if (!container) { return null; } return this.isDocumentBody(container) ? window : container; } /** * Test if a given HTML Element is the Document Body. * * @param element The given HTML Element * @returns Whether or not the Element is the * Document Body Element */ isDocumentBody(element) { return element.tagName.toUpperCase() === 'BODY'; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ScrollToService, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ScrollToService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ScrollToService, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Nyb2xsLXRvLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtc2Nyb2xsLXRvL3NyYy9saWIvc2Nyb2xsLXRvLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxRQUFRLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQVE5RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsUUFBUSxFQUFFLFlBQVksRUFBRSxlQUFlLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkgsT0FBTyxFQUFjLGFBQWEsRUFBRSxVQUFVLEVBQUUsTUFBTSxNQUFNLENBQUM7O0FBRTdEOzs7Ozs7R0FNRztBQUVILE1BQU0sT0FBTyxlQUFlO0lBaUIxQjs7Ozs7T0FLRztJQUNILFlBQzRCLFFBQWEsRUFDVixVQUFlO1FBRGxCLGFBQVEsR0FBUixRQUFRLENBQUs7UUFDVixlQUFVLEdBQVYsVUFBVSxDQUFLO1FBRTVDLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxDQUFDLFlBQVksRUFBRSxnQkFBZ0IsRUFBRSxZQUFZLENBQUMsQ0FBQztJQUMzRSxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxRQUFRLENBQUMsT0FBOEI7UUFFckMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQ3hDLE9BQU8sSUFBSSxhQUFhLEVBQUUsQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUM1QyxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzdCLENBQUM7SUFF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Q0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUM3RCxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ssY0FBYyxDQUFDLE9BQW9CO1FBQ3pDLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsS0FBSyxNQUFNLENBQUM7SUFDbEQsQ0FBQzsrR0E3VFUsZUFBZSxrQkF3QmhCLFFBQVEsYUFDUixXQUFXO21IQXpCVixlQUFlOzs0RkFBZixlQUFlO2tCQUQzQixVQUFVOzswQkF5Qk4sTUFBTTsyQkFBQyxRQUFROzswQkFDZixNQUFNOzJCQUFDLFdBQVciLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUsIFBMQVRGT1JNX0lEIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBET0NVTUVOVCwgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuXG5pbXBvcnQge1xuICBTY3JvbGxUb0NvbmZpZ09wdGlvbnMsXG4gIFNjcm9sbFRvQ29uZmlnT3B0aW9uc1RhcmdldCxcbiAgU2Nyb2xsVG9MaXN0ZW5lclRhcmdldCxcbiAgU2Nyb2xsVG9UYXJnZXRcbn0gZnJvbSAnLi9zY3JvbGwtdG8tY29uZmlnLmludGVyZmFjZSc7XG5pbXBvcnQgeyBTY3JvbGxUb0FuaW1hdGlvbiB9IGZyb20gJy4vc2Nyb2xsLXRvLWFuaW1hdGlvbic7XG5pbXBvcnQgeyBERUZBVUxUUywgaXNFbGVtZW50UmVmLCBpc05hdGl2ZUVsZW1lbnQsIGlzTnVtYmVyLCBpc1N0cmluZywgaXNXaW5kb3csIHN0cmlwSGFzaCB9IGZyb20gJy4vc2Nyb2xsLXRvLWhlbHBlcnMnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgUmVwbGF5U3ViamVjdCwgdGhyb3dFcnJvciB9IGZyb20gJ3J4anMnO1xuXG4vKipcbiAqIFRoZSBTY3JvbGwgVG8gU2VydmljZSBoYW5kbGVzIHN0YXJ0aW5nLCBpbnRlcnJ1cHRpbmdcbiAqIGFuZCBlbmRpbmcgdGhlIGFjdHVhbCBTY3JvbGwgQW5pbWF0aW9uLiBJdCBwcm92aWRlc1xuICogc29tZSB1dGlsaXRpZXMgdG8gZmluZCB0aGUgcHJvcGVyIEhUTUwgRWxlbWVudCBvbiBhXG4gKiBnaXZlbiBwYWdlIHRvIHNldHVwIEV2ZW50IExpc3RlbmVycyBhbmQgY2FsY3VsYXRlXG4gKiBkaXN0YW5jZXMgZm9yIHRoZSBBbmltYXRpb24uXG4gKi9cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBTY3JvbGxUb1NlcnZpY2Uge1xuXG4gIC8qKlxuICAgKiBUaGUgYW5pbWF0aW9uIHRoYXQgcHJvdmlkZXMgdGhlIHNjcm9sbGluZ1xuICAgKiB0byBoYXBwZW4gc21vb3RobHkgb3ZlciB0aW1lLiBEZWZpbmluZyBpdCBoZXJlXG4gICAqIGFsbG93cyBmb3IgdXNhZ2Ugb2YgZS5nLiBgc3RhcnRgIGFuZCBgc3RvcGBcbiAgICogbWV0aG9kcyB3aXRoaW4gdGhpcyBBbmd1bGFyIFNlcnZpY2UuXG4gICAqL1xuICBwcml2YXRlIGFuaW1hdGlvbjogU2Nyb2xsVG9BbmltYXRpb247XG5cbiAgLyoqXG4gICAqIEludGVycnVwdGl2ZSBFdmVudHMgYWxsb3cgdG8gc2Nyb2xsaW5nIGFuaW1hdGlvblxuICAgKiB0byBiZSBpbnRlcnJ1cHRlZCBiZWZvcmUgaXQgaXMgZmluaXNoZWQuIFRoZSBsaXN0XG4gICAqIG9mIEludGVycnVwdGl2ZSBFdmVudHMgcmVwcmVzZW50cyB0aG9zZS5cbiAgICovXG4gIHByaXZhdGUgaW50ZXJydXB0aXZlRXZlbnRzOiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQ29uc3RydWN0IGFuZCBzZXR1cCByZXF1aXJlZCBwYXJhdGVtZXRlcnMuXG4gICAqXG4gICAqIEBwYXJhbSBkb2N1bWVudCAgICAgICAgIEEgUmVmZXJlbmNlIHRvIHRoZSBEb2N1bWVudFxuICAgKiBAcGFyYW0gcGxhdGZvcm1JZCAgICAgICBBbmd1bGFyIFBsYXRmb3JtIElEXG4gICAqL1xuICBjb25zdHJ1Y3RvcihcbiAgICBASW5qZWN0KERPQ1VNRU5UKSBwcml2YXRlIGRvY3VtZW50OiBhbnksXG4gICAgQEluamVjdChQTEFURk9STV9JRCkgcHJpdmF0ZSBwbGF0Zm9ybUlkOiBhbnlcbiAgKSB7XG4gICAgdGhpcy5pbnRlcnJ1cHRpdmVFdmVudHMgPSBbJ21vdXNld2hlZWwnLCAnRE9NTW91c2VTY3JvbGwnLCAndG91Y2hzdGFydCddO1xuICB9XG5cbiAgLyoqXG4gICAqIFRhcmdldCBhbiBFbGVtZW50IHRvIHNjcm9sbCB0by4gTm90aWNlIHRoYXQgdGhlIGBUaW1lT3V0YCBkZWNvcmF0b3JcbiAgICogZW5zdXJlcyB0aGUgZXhlY3V0aW5nIHRvIHRha2UgcGxhY2UgaW4gdGhlIG5leHQgQW5ndWxhciBsaWZlY3ljbGUuXG4gICAqIFRoaXMgYWxsb3dzIGZvciBzY3JvbGxpbmcgdG8gZWxlbWVudHMgdGhhdCBhcmUgZS5nLiBpbml0aWFsbHkgaGlkZGVuXG4gICAqIGJ5IG1lYW5zIG9mIGAqbmdJZmAsIGJ1dCBvdWdodCB0byBiZSBzY3JvbGxlZCB0byBldmVudHVhbGx5LlxuICAgKlxuICAgKiBAdG9kbyB0eXBlICdhbnknIGluIE9ic2VydmFibGUgc2hvdWxkIGJlY29tZSBjdXN0b20gdHlwZSBsaWtlICdTY3JvbGxUb0V2ZW50JyAoYmFzZSBjbGFzcyksIHNlZSBpc3N1ZSBjb21tZW50OlxuICAgKiAgLSBodHRwczovL2dpdGh1Yi5jb20vbmlja3ktbGVuYWVycy9uZ3gtc2Nyb2xsLXRvL2lzc3Vlcy8xMCNpc3N1ZWNvbW1lbnQtMzE3MTk4NDgxXG4gICAqXG4gICAqIEBwYXJhbSBvcHRpb25zICAgICAgICAgQ29uZmlndXJhdGlvbiBPYmplY3RcbiAgICogQHJldHVybnMgICAgICAgICAgICAgICBPYnNlcnZhYmxlXG4gICAqL1xuICBzY3JvbGxUbyhvcHRpb25zOiBTY3JvbGxUb0NvbmZpZ09wdGlvbnMpOiBPYnNlcnZhYmxlPGFueT4ge1xuXG4gICAgaWYgKCFpc1BsYXRmb3JtQnJvd3Nlcih0aGlzLnBsYXRmb3JtSWQpKSB7XG4gICAgICByZXR1cm4gbmV3IFJlcGxheVN1YmplY3QoKS5hc09ic2VydmFibGUoKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5zdGFydChvcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFydCBhIG5ldyBBbmltYXRpb24uXG4gICAqXG4gICAqIEB0b2RvIEVtaXQgcHJvcGVyIGV2ZW50cyBmcm9tIHN1YnNjcmlwdGlvblxuICAgKlxuICAgKiBAcGFyYW0gb3B0aW9ucyAgICAgICAgIENvbmZpZ3VyYXRpb24gT2JqZWN0XG4gICAqIEByZXR1cm5zICAgICAgICAgICAgICAgT2JzZXJ2YWJsZVxuICAgKi9cbiAgcHJpdmF0ZSBzdGFydChvcHRpb25zOiBTY3JvbGxUb0NvbmZpZ09wdGlvbnMpOiBPYnNlcnZhYmxlPG51bWJlcj4ge1xuXG4gICAgLy8gTWVyZ2UgY29uZmlnIHdpdGggZGVmYXVsdCB2YWx1ZXNcbiAgICBjb25zdCBtZXJnZWRDb25maWdPcHRpb25zID0ge1xuICAgICAgLi4uREVGQVVMVFMgYXMgU2Nyb2xsVG9Db25maWdPcHRpb25zLFxuICAgICAgLi4ub3B0aW9uc1xuICAgIH0gYXMgU2Nyb2xsVG9Db25maWdPcHRpb25zVGFyZ2V0O1xuXG4gICAgaWYgKHRoaXMuYW5pbWF0aW9uKSB7XG4gICAgICB0aGlzLmFuaW1hdGlvbi5zdG9wKCk7XG4gICAgfVxuXG4gICAgY29uc3QgdGFyZ2V0Tm9kZSA9IHRoaXMuZ2V0Tm9kZShtZXJnZWRDb25maWdPcHRpb25zLnRhcmdldCk7XG4gICAgaWYgKG1lcmdlZENvbmZpZ09wdGlvbnMudGFyZ2V0ICYmICF0YXJnZXROb2RlKSB7XG4gICAgICByZXR1cm4gdGhyb3dFcnJvcigoKSA9PiBuZXcgRXJyb3IoJ1VuYWJsZSB0byBmaW5kIFRhcmdldCBFbGVtZW50JykpO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbnRhaW5lcjogSFRNTEVsZW1lbnQgPSB0aGlzLmdldENvbnRhaW5lcihtZXJnZWRDb25maWdPcHRpb25zLCB0YXJnZXROb2RlKTtcbiAgICBpZiAobWVyZ2VkQ29uZmlnT3B0aW9ucy5jb250YWluZXIgJiYgIWNvbnRhaW5lcikge1xuICAgICAgcmV0dXJuIHRocm93RXJyb3IoKCkgPT4gbmV3IEVycm9yKCdVbmFibGUgdG8gZmluZCBDb250YWluZXIgRWxlbWVudCcpKTtcbiAgICB9XG5cbiAgICBjb25zdCBsaXN0ZW5lclRhcmdldCA9IHRoaXMuZ2V0TGlzdGVuZXJUYXJnZXQoY29udGFpbmVyKSB8fCB3aW5kb3c7XG5cbiAgICBsZXQgdG8gPSBjb250YWluZXIgPyBjb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkudG9wIDogMDtcblxuICAgIGlmICh0YXJnZXROb2RlKSB7XG4gICAgICB0byA9IGlzV2luZG93KGxpc3RlbmVyVGFyZ2V0KSA/XG4gICAgICAgIHdpbmRvdy5zY3JvbGxZICsgdGFyZ2V0Tm9kZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3AgOlxuICAgICAgICB0YXJnZXROb2RlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcDtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgQW5pbWF0aW9uXG4gICAgdGhpcy5hbmltYXRpb24gPSBuZXcgU2Nyb2xsVG9BbmltYXRpb24oXG4gICAgICBjb250YWluZXIsXG4gICAgICBsaXN0ZW5lclRhcmdldCxcbiAgICAgIGlzV2luZG93KGxpc3RlbmVyVGFyZ2V0KSxcbiAgICAgIHRvLFxuICAgICAgbWVyZ2VkQ29uZmlnT3B0aW9ucyxcbiAgICAgIGlzUGxhdGZvcm1Ccm93c2VyKHRoaXMucGxhdGZvcm1JZClcbiAgICApO1xuICAgIGNvbnN0IG9uSW50ZXJydXB0ID0gKCkgPT4gdGhpcy5hbmltYXRpb24uc3RvcCgpO1xuICAgIHRoaXMuYWRkSW50ZXJydXB0aXZlRXZlbnRMaXN0ZW5lcnMobGlzdGVuZXJUYXJnZXQsIG9uSW50ZXJydXB0KTtcblxuICAgIC8vIFN0YXJ0IEFuaW1hdGlvblxuICAgIGNvbnN0IGFuaW1hdGlvbiQgPSB0aGlzLmFuaW1hdGlvbi5zdGFydCgpO1xuICAgIHRoaXMuc3Vic2NyaWJlVG9BbmltYXRpb24oYW5pbWF0aW9uJCwgbGlzdGVuZXJUYXJnZXQsIG9uSW50ZXJydXB0KTtcblxuICAgIHJldHVybiBhbmltYXRpb24kO1xuICB9XG5cbiAgLyoqXG4gICAqIFN1YnNjcmliZSB0byB0aGUgZXZlbnRzIGVtaXR0ZWQgZnJvbSB0aGUgU2Nyb2xsaW5nXG4gICAqIEFuaW1hdGlvbi4gRXZlbnRzIG1pZ2h0IGJlIHVzZWQgZm9yIGUuZy4gdW5zdWJzY3JpYmluZ1xuICAgKiBvbmNlIGZpbmlzaGVkLlxuICAgKlxuICAgKiBAcGFyYW0gYW5pbWF0aW9uJCAgICAgICAgICAgICAgVGhlIEFuaW1hdGlvbiBPYnNlcnZhYmxlXG4gICAqIEBwYXJhbSBsaXN0ZW5lclRhcmdldCAgICAgICAgICBUaGUgTGlzdGVuZXIgVGFyZ2V0IGZvciBldmVudHNcbiAgICogQHBhcmFtIG9uSW50ZXJydXB0ICAgICAgICAgICAgIFRoZSBoYW5kbGVyIGZvciBJbnRlcnJ1cHRpdmUgRXZlbnRzXG4gICAqIEByZXR1cm5zICAgICAgICAgICAgICAgICAgICAgICBWb2lkXG4gICAqL1xuICBwcml2YXRlIHN1YnNjcmliZVRvQW5pbWF0aW9uKFxuICAgIGFuaW1hdGlvbiQ6IE9ic2VydmFibGU8YW55PixcbiAgICBsaXN0ZW5lclRhcmdldDogU2Nyb2xsVG9MaXN0ZW5lclRhcmdldCxcbiAgICBvbkludGVycnVwdDogRXZlbnRMaXN0ZW5lck9yRXZlbnRMaXN0ZW5lck9iamVjdFxuICApIHtcbiAgICBjb25zdCBzdWJzY3JpcHRpb24gPSBhbmltYXRpb24kXG4gICAgICAuc3Vic2NyaWJlKFxuICAgICAgICB7XG4gICAgICAgICAgY29tcGxldGU6ICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMucmVtb3ZlSW50ZXJydXB0aXZlRXZlbnRMaXN0ZW5lcnModGhpcy5pbnRlcnJ1cHRpdmVFdmVudHMsIGxpc3RlbmVyVGFyZ2V0LCBvbkludGVycnVwdCk7XG4gICAgICAgICAgICBzdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBjb250YWluZXIgSFRNTCBFbGVtZW50IGluIHdoaWNoXG4gICAqIHRoZSBzY3JvbGxpbmcgc2hvdWxkIGhhcHBlbi5cbiAgICpcbiAgICogQHBhcmFtIG9wdGlvbnMgICAgICAgICBUaGUgTWVyZ2VkIENvbmZpZ3VyYXRpb24gT2JqZWN0XG4gICAqIEBwYXJhbSB0YXJnZXROb2RlICAgIHRoZSB0YXJnZXRlZCBIVE1MRWxlbWVudFxuICAgKi9cbiAgcHJpdmF0ZSBnZXRDb250YWluZXIob3B0aW9uczogU2Nyb2xsVG9Db25maWdPcHRpb25zLCB0YXJnZXROb2RlOiBIVE1MRWxlbWVudCk6IEhUTUxFbGVtZW50IHwgbnVsbCB7XG5cbiAgICBsZXQgY29udGFpbmVyOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xuXG4gICAgaWYgKG9wdGlvbnMuY29udGFpbmVyKSB7XG4gICAgICBjb250YWluZXIgPSB0aGlzLmdldE5vZGUob3B0aW9ucy5jb250YWluZXIsIHRydWUpO1xuICAgIH0gZWxzZSBpZiAodGFyZ2V0Tm9kZSkge1xuICAgICAgY29udGFpbmVyID0gdGhpcy5nZXRGaXJzdFNjcm9sbGFibGVQYXJlbnQodGFyZ2V0Tm9kZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvbnRhaW5lcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgbGlzdGVuZXJzIGZvciB0aGUgQW5pbWF0aW9uIEludGVycnVwdGl2ZSBFdmVudHNcbiAgICogdG8gdGhlIExpc3RlbmVyIFRhcmdldC5cbiAgICpcbiAgICogQHBhcmFtIGV2ZW50cyAgICAgICAgICAgIExpc3Qgb2YgZXZlbnRzIHRvIGxpc3RlbiB0b1xuICAgKiBAcGFyYW0gbGlzdGVuZXJUYXJnZXQgICAgVGFyZ2V0IHRvIGF0dGFjaCB0aGUgbGlzdGVuZXIgb25cbiAgICogQHBhcmFtIGhhbmRsZXIgICAgICAgICAgIEhhbmRsZXIgZm9yIHdoZW4gdGhlIGxpc3RlbmVyIGZpcmVzXG4gICAqIEByZXR1cm5zICAgICAgICAgICAgICAgICBWb2lkXG4gICAqL1xuICBwcml2YXRlIGFkZEludGVycnVwdGl2ZUV2ZW50TGlzdGVuZXJzKFxuICAgIGxpc3RlbmVyVGFyZ2V0OiBTY3JvbGxUb0xpc3RlbmVyVGFyZ2V0LFxuICAgIGhhbmRsZXI6IEV2ZW50TGlzdGVuZXJPckV2ZW50TGlzdGVuZXJPYmplY3QpOiB2b2lkIHtcblxuICAgIGlmICghbGlzdGVuZXJUYXJnZXQpIHtcbiAgICAgIGxpc3RlbmVyVGFyZ2V0ID0gd2luZG93O1xuICAgIH1cblxuICAgIHRoaXMuaW50ZXJydXB0aXZlRXZlbnRzXG4gICAgICAuZm9yRWFjaChldmVudCA9PiBsaXN0ZW5lclRhcmdldFxuICAgICAgICAuYWRkRXZlbnRMaXN0ZW5lcihldmVudCwgaGFuZGxlciwgdGhpcy5zdXBwb3J0UGFzc2l2ZSgpID8ge3Bhc3NpdmU6IHRydWV9IDogZmFsc2UpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGZWF0dXJlLWRldGVjdCBzdXBwb3J0IGZvciBwYXNzaXZlIGV2ZW50IGxpc3RlbmVycy5cbiAgICpcbiAgICogQHJldHVybnMgICAgICAgV2hldGhlciBvciBub3QgcGFzc2l2ZSBldmVudCBsaXN0ZW5lcnMgYXJlIHN1cHBvcnRlZFxuICAgKi9cbiAgcHJpdmF0ZSBzdXBwb3J0UGFzc2l2ZSgpOiBib29sZWFuIHtcblxuICAgIGxldCBzdXBwb3J0c1Bhc3NpdmUgPSBmYWxzZTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBvcHRzID0gT2JqZWN0LmRlZmluZVByb3BlcnR5KHt9LCAncGFzc2l2ZScsIHtcbiAgICAgICAgZ2V0OiAoKSA9PiB7XG4gICAgICAgICAgc3VwcG9ydHNQYXNzaXZlID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigndGVzdFBhc3NpdmUnLCBudWxsLCBvcHRzKTtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCd0ZXN0UGFzc2l2ZScsIG51bGwsIG9wdHMpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICB9XG5cbiAgICByZXR1cm4gc3VwcG9ydHNQYXNzaXZlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZSBsaXN0ZW5lcnMgZm9yIHRoZSBBbmltYXRpb24gSW50ZXJydXB0IEV2ZW50IGZyb21cbiAgICogdGhlIExpc3RlbmVyIFRhcmdldC4gU3BlY2lmeWluZyB0aGUgY29ycmVjdCBoYW5kbGVyIHByZXZlbnRzXG4gICAqIG1lbW9yeSBsZWFrcyBhbmQgbWFrZXMgdGhlIGFsbG9jYXRlZCBtZW1vcnkgYXZhaWxhYmxlIGZvclxuICAgKiBHYXJiYWdlIENvbGxlY3Rpb24uXG4gICAqXG4gICAqIEBwYXJhbSBldmVudHMgICAgICAgICAgICBMaXN0IG9mIEludGVycnVwdGl2ZSBFdmVudHMgdG8gcmVtb3ZlXG4gICAqIEBwYXJhbSBsaXN0ZW5lclRhcmdldCAgICBUYXJnZXQgdG8gYXR0YWNoIHRoZSBsaXN0ZW5lciBvblxuICAgKiBAcGFyYW0gaGFuZGxlciAgICAgICAgICAgSGFuZGxlciBmb3Igd2hlbiB0aGUgbGlzdGVuZXIgZmlyZXNcbiAgICogQHJldHVybnMgICAgICAgICAgICAgICAgIFZvaWRcbiAgICovXG4gIHByaXZhdGUgcmVtb3ZlSW50ZXJydXB0aXZlRXZlbnRMaXN0ZW5lcnMoXG4gICAgZXZlbnRzOiBzdHJpbmdbXSxcbiAgICBsaXN0ZW5lclRhcmdldDogU2Nyb2xsVG9MaXN0ZW5lclRhcmdldCxcbiAgICBoYW5kbGVyOiBFdmVudExpc3RlbmVyT3JFdmVudExpc3RlbmVyT2JqZWN0KTogdm9pZCB7XG5cbiAgICBpZiAoIWxpc3RlbmVyVGFyZ2V0KSB7XG4gICAgICBsaXN0ZW5lclRhcmdldCA9IHdpbmRvdztcbiAgICB9XG4gICAgZXZlbnRzLmZvckVhY2goZXZlbnQgPT4gbGlzdGVuZXJUYXJnZXQucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudCwgaGFuZGxlcikpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmQgdGhlIGZpcnN0IHNjcm9sbGFibGUgcGFyZW50IE5vZGUgb2YgYSBnaXZlblxuICAgKiBFbGVtZW50LiBUaGUgRE9NIFRyZWUgZ2V0cyBzZWFyY2hlZCB1cHdhcmRzXG4gICAqIHRvIGZpbmQgdGhpcyBmaXJzdCBzY3JvbGxhYmxlIHBhcmVudC4gUGFyZW50cyBtaWdodFxuICAgKiBiZSBpZ25vcmVkIGJ5IENTUyBzdHlsZXMgYXBwbGllZCB0byB0aGUgSFRNTCBFbGVtZW50LlxuICAgKlxuICAgKiBAcGFyYW0gbmF0aXZlRWxlbWVudCAgICAgVGhlIEVsZW1lbnQgdG8gc2VhcmNoIHRoZSBET00gVHJlZSB1cHdhcmRzIGZyb21cbiAgICogQHJldHVybnMgICAgICAgICAgICAgICAgIFRoZSBmaXJzdCBzY3JvbGxhYmxlIHBhcmVudCBIVE1MIEVsZW1lbnRcbiAgICovXG4gIHByaXZhdGUgZ2V0Rmlyc3RTY3JvbGxhYmxlUGFyZW50KG5hdGl2ZUVsZW1lbnQ6IEhUTUxFbGVtZW50KTogSFRNTEVsZW1lbnQge1xuXG4gICAgbGV0IHN0eWxlOiBDU1NTdHlsZURlY2xhcmF0aW9uID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUobmF0aXZlRWxlbWVudCk7XG5cbiAgICBjb25zdCBvdmVyZmxvd1JlZ2V4OiBSZWdFeHAgPSAvKGF1dG98c2Nyb2xsfG92ZXJsYXkpLztcblxuICAgIGlmIChzdHlsZS5wb3NpdGlvbiA9PT0gJ2ZpeGVkJykge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgbGV0IHBhcmVudCA9IG5hdGl2ZUVsZW1lbnQ7XG4gICAgd2hpbGUgKHBhcmVudC5wYXJlbnRFbGVtZW50KSB7XG4gICAgICBwYXJlbnQgPSBwYXJlbnQucGFyZW50RWxlbWVudDtcbiAgICAgIHN0eWxlID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUocGFyZW50KTtcblxuICAgICAgaWYgKHN0eWxlLnBvc2l0aW9uID09PSAnYWJzb2x1dGUnXG4gICAgICAgIHx8IHN0eWxlLm92ZXJmbG93ID09PSAnaGlkZGVuJ1xuICAgICAgICB8fCBzdHlsZS5vdmVyZmxvd1kgPT09ICdoaWRkZW4nKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAob3ZlcmZsb3dSZWdleC50ZXN0KHN0eWxlLm92ZXJmbG93ICsgc3R5bGUub3ZlcmZsb3dZKVxuICAgICAgICB8fCBwYXJlbnQudGFnTmFtZSA9PT0gJ0JPRFknKSB7XG4gICAgICAgIHJldHVybiBwYXJlbnQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBUYXJnZXQgTm9kZSB0byBzY3JvbGwgdG8uXG4gICAqXG4gICAqIEBwYXJhbSBpZCAgICAgICAgICAgICAgVGhlIGdpdmVuIElEIG9mIHRoZSBub2RlLCBlaXRoZXIgYSBzdHJpbmcgb3JcbiAgICogICAgICAgICAgICAgICAgICAgICAgICBhbiBlbGVtZW50IHJlZmVyZW5jZVxuICAgKiBAcGFyYW0gYWxsb3dCb2R5VGFnICAgIEluZGljYXRlIHdoZXRoZXIgb3Igbm90IHRoZSBEb2N1bWVudCBCb2R5IGlzXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgY29uc2lkZXJlZCBhIHZhbGlkIFRhcmdldCBOb2RlXG4gICAqIEByZXR1cm5zICAgICAgICAgICAgICAgVGhlIFRhcmdldCBOb2RlIHRvIHNjcm9sbCB0b1xuICAgKi9cbiAgcHJpdmF0ZSBnZXROb2RlKGlkOiBTY3JvbGxUb1RhcmdldCwgYWxsb3dCb2R5VGFnOiBib29sZWFuID0gZmFsc2UpOiBIVE1MRWxlbWVudCB7XG5cbiAgICBsZXQgdGFyZ2V0Tm9kZTogSFRNTEVsZW1lbnQ7XG5cbiAgICBpZiAoaXNTdHJpbmcoaWQpKSB7XG4gICAgICBpZiAoYWxsb3dCb2R5VGFnICYmIChpZCA9PT0gJ2JvZHknIHx8IGlkID09PSAnQk9EWScpKSB7XG4gICAgICAgIHRhcmdldE5vZGUgPSB0aGlzLmRvY3VtZW50LmJvZHk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0YXJnZXROb2RlID0gdGhpcy5kb2N1bWVudC5nZXRFbGVtZW50QnlJZChzdHJpcEhhc2goaWQpKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGlzTnVtYmVyKGlkKSkge1xuICAgICAgdGFyZ2V0Tm9kZSA9IHRoaXMuZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoU3RyaW5nKGlkKSk7XG4gICAgfSBlbHNlIGlmIChpc0VsZW1lbnRSZWYoaWQpKSB7XG4gICAgICB0YXJnZXROb2RlID0gaWQubmF0aXZlRWxlbWVudDtcbiAgICB9IGVsc2UgaWYgKGlzTmF0aXZlRWxlbWVudChpZCkpIHtcbiAgICAgIHRhcmdldE5vZGUgPSBpZDtcbiAgICB9XG5cbiAgICByZXR1cm4gdGFyZ2V0Tm9kZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZSB0aGUgTGlzdGVuZXIgdGFyZ2V0LiBUaGlzIExpc3RlbmVyIFRhcmdldCBpcyB1c2VkXG4gICAqIHRvIGF0dGFjaCBFdmVudCBMaXN0ZW5lcnMgb24uIEluIGNhc2Ugb2YgdGhlIHRhcmdldCBiZWluZ1xuICAgKiB0aGUgRG9jdW1lbnQgQm9keSwgd2UgbmVlZCB0aGUgYWN0dWFsIGB3aW5kb3dgIHRvIGxpc3RlblxuICAgKiBmb3IgZXZlbnRzLlxuICAgKlxuICAgKiBAcGFyYW0gY29udGFpbmVyICAgICAgICAgICBUaGUgSFRNTCBDb250YWluZXIgZWxlbWVudFxuICAgKiBAcmV0dXJucyAgICAgICAgICAgICAgICAgICBUaGUgTGlzdGVuZXIgVGFyZ2V0IHRvIGF0dGFjaCBldmVudHMgb25cbiAgICovXG4gIHByaXZhdGUgZ2V0TGlzdGVuZXJUYXJnZXQoY29udGFpbmVyOiBIVE1MRWxlbWVudCk6IFNjcm9sbFRvTGlzdGVuZXJUYXJnZXQge1xuICAgIGlmICghY29udGFpbmVyKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaXNEb2N1bWVudEJvZHkoY29udGFpbmVyKSA/IHdpbmRvdyA6IGNvbnRhaW5lcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBUZXN0IGlmIGEgZ2l2ZW4gSFRNTCBFbGVtZW50IGlzIHRoZSBEb2N1bWVudCBCb2R5LlxuICAgKlxuICAgKiBAcGFyYW0gZWxlbWVudCAgICAgICAgICAgICBUaGUgZ2l2ZW4gSFRNTCBFbGVtZW50XG4gICAqIEByZXR1cm5zICAgICAgICAgICAgICAgICAgIFdoZXRoZXIgb3Igbm90IHRoZSBFbGVtZW50IGlzIHRoZVxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEb2N1bWVudCBCb2R5IEVsZW1lbnRcbiAgICovXG4gIHByaXZhdGUgaXNEb2N1bWVudEJvZHkoZWxlbWVudDogSFRNTEVsZW1lbnQpOiBlbGVtZW50IGlzIEhUTUxCb2R5RWxlbWVudCB7XG4gICAgcmV0dXJuIGVsZW1lbnQudGFnTmFtZS50b1VwcGVyQ2FzZSgpID09PSAnQk9EWSc7XG4gIH1cbn1cbiJdfQ==