ng-table-virtual-scroll
Version:
Virtual scroll for for Angular Material Table
117 lines • 18.4 kB
JavaScript
import { Injectable } from '@angular/core';
import { distinctUntilChanged } from 'rxjs/operators';
import { BehaviorSubject, Subject } from 'rxjs';
import * as i0 from "@angular/core";
export class FixedSizeTableVirtualScrollStrategy {
constructor() {
this.indexChange = new Subject();
this.stickyChange = new Subject();
this.renderedRangeStream = new BehaviorSubject({ start: 0, end: 0 });
this.scrolledIndexChange = this.indexChange.pipe(distinctUntilChanged());
this._dataLength = 0;
}
get dataLength() {
return this._dataLength;
}
set dataLength(value) {
if (value !== this._dataLength) {
this._dataLength = value;
this.onDataLengthChanged();
}
}
attach(viewport) {
this.viewport = viewport;
this.viewport.renderedRangeStream.subscribe(this.renderedRangeStream);
this.stickyChange.next(0);
this.onDataLengthChanged();
}
detach() {
this.indexChange.complete();
this.stickyChange.complete();
this.renderedRangeStream.complete();
}
onContentScrolled() {
this.updateContent();
}
onDataLengthChanged() {
if (this.viewport) {
const contentSize = this.dataLength * this.rowHeight + this.headerHeight + this.footerHeight;
this.viewport.setTotalContentSize(contentSize);
const viewportSize = this.viewport.getViewportSize();
if (this.viewport.measureScrollOffset() + viewportSize >= contentSize) {
this.viewport.scrollToOffset(contentSize - viewportSize);
}
}
this.updateContent();
}
onContentRendered() {
}
onRenderedOffsetChanged() {
// no-op
}
scrollToIndex(index, behavior) {
if (!this.viewport || !this.rowHeight) {
return;
}
this.viewport.scrollToOffset((index - 1) * this.rowHeight + this.headerHeight, behavior);
}
setConfig(configs) {
const { rowHeight, headerHeight, footerHeight, bufferMultiplier } = configs;
if (this.rowHeight === rowHeight
&& this.headerHeight === headerHeight
&& this.footerHeight === footerHeight
&& this.bufferMultiplier === bufferMultiplier) {
return;
}
this.rowHeight = rowHeight;
this.headerHeight = headerHeight;
this.footerHeight = footerHeight;
this.bufferMultiplier = bufferMultiplier;
this.onDataLengthChanged();
}
updateContent() {
if (!this.viewport || !this.rowHeight) {
return;
}
const renderedOffset = this.viewport.getOffsetToRenderedContentStart();
const start = renderedOffset / this.rowHeight;
const itemsDisplayed = Math.ceil(this.viewport.getViewportSize() / this.rowHeight);
const bufferItems = Math.ceil(itemsDisplayed * this.bufferMultiplier);
const end = start + itemsDisplayed + 2 * bufferItems;
const bufferOffset = renderedOffset + bufferItems * this.rowHeight;
const scrollOffset = this.viewport.measureScrollOffset();
// How far the scroll offset is from the lower buffer, which is usually where items start being displayed
const relativeScrollOffset = scrollOffset - bufferOffset;
const rowsScrolled = relativeScrollOffset / this.rowHeight;
const displayed = scrollOffset / this.rowHeight;
this.indexChange.next(displayed);
// Only bother updating the displayed information if we've scrolled more than a row
const rowSensitivity = 1.0;
if (Math.abs(rowsScrolled) < rowSensitivity) {
this.viewport.setRenderedContentOffset(renderedOffset);
this.viewport.setRenderedRange({ start, end });
return;
}
// Special case for the start of the table.
// At the top of the table, the first few rows are first rendered because they're visible, and then still rendered
// Because they move into the buffer. So we only need to change what's rendered once the user scrolls far enough down.
if (renderedOffset === 0 && rowsScrolled < 0) {
this.viewport.setRenderedContentOffset(renderedOffset);
this.viewport.setRenderedRange({ start, end });
return;
}
const rowsToMove = Math.sign(rowsScrolled) * Math.floor(Math.abs(rowsScrolled));
const adjustedRenderedOffset = Math.max(0, renderedOffset + rowsToMove * this.rowHeight);
this.viewport.setRenderedContentOffset(adjustedRenderedOffset);
const adjustedStart = Math.max(0, start + rowsToMove);
const adjustedEnd = adjustedStart + itemsDisplayed + 2 * bufferItems;
this.viewport.setRenderedRange({ start: adjustedStart, end: adjustedEnd });
this.stickyChange.next(adjustedRenderedOffset);
}
}
FixedSizeTableVirtualScrollStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: FixedSizeTableVirtualScrollStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
FixedSizeTableVirtualScrollStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: FixedSizeTableVirtualScrollStrategy });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: FixedSizeTableVirtualScrollStrategy, decorators: [{
type: Injectable
}] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZml4ZWQtc2l6ZS10YWJsZS12aXJ0dWFsLXNjcm9sbC1zdHJhdGVneS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25nLXRhYmxlLXZpcnR1YWwtc2Nyb2xsL3NyYy9saWIvZml4ZWQtc2l6ZS10YWJsZS12aXJ0dWFsLXNjcm9sbC1zdHJhdGVneS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxlQUFlLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDOztBQVloRCxNQUFNLE9BQU8sbUNBQW1DO0lBRGhEO1FBTVUsZ0JBQVcsR0FBRyxJQUFJLE9BQU8sRUFBVSxDQUFDO1FBQ3JDLGlCQUFZLEdBQUcsSUFBSSxPQUFPLEVBQVUsQ0FBQztRQUlyQyx3QkFBbUIsR0FBRyxJQUFJLGVBQWUsQ0FBWSxFQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBQyxDQUFDLENBQUM7UUFFekUsd0JBQW1CLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQyxDQUFDO1FBYW5FLGdCQUFXLEdBQUcsQ0FBQyxDQUFDO0tBK0d6QjtJQTFIQyxJQUFJLFVBQVU7UUFDWixPQUFPLElBQUksQ0FBQyxXQUFXLENBQUM7SUFDMUIsQ0FBQztJQUVELElBQUksVUFBVSxDQUFDLEtBQWE7UUFDMUIsSUFBSSxLQUFLLEtBQUssSUFBSSxDQUFDLFdBQVcsRUFBRTtZQUM5QixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQztZQUN6QixJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztTQUM1QjtJQUNILENBQUM7SUFJTSxNQUFNLENBQUMsUUFBa0M7UUFDOUMsSUFBSSxDQUFDLFFBQVEsR0FB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QUN2RCxJQUFJLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFDLEVBQUMsS0FBSyxFQUFFLEdBQUcsRUFBQyxDQUFDLENBQUM7WUFDN0MsT0FBTztTQUNSO1FBRUQsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQztRQUNoRixNQUFNLHNCQUFzQixHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLGNBQWMsR0FBRyxVQUFVLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3pGLElBQUksQ0FBQyxRQUFRLENBQUMsd0JBQXdCLENBQUMsc0JBQXNCLENBQUMsQ0FBQztRQUUvRCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxLQUFLLEdBQUcsVUFBVSxDQUFDLENBQUM7UUFDdEQsTUFBTSxXQUFXLEdBQUcsYUFBYSxHQUFHLGNBQWMsR0FBRyxDQUFDLEdBQUcsV0FBVyxDQUFDO1FBQ3JFLElBQUksQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLENBQUMsRUFBQyxLQUFLLEVBQUUsYUFBYSxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUMsQ0FBQyxDQUFDO1FBRXpFLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLENBQUM7SUFDakQsQ0FBQzs7Z0lBdklVLG1DQUFtQztvSUFBbkMsbUNBQW1DOzJGQUFuQyxtQ0FBbUM7a0JBRC9DLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBkaXN0aW5jdFVudGlsQ2hhbmdlZCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQ2RrVmlydHVhbFNjcm9sbFZpZXdwb3J0LCBWaXJ0dWFsU2Nyb2xsU3RyYXRlZ3kgfSBmcm9tICdAYW5ndWxhci9jZGsvc2Nyb2xsaW5nJztcbmltcG9ydCB7IExpc3RSYW5nZSB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9jb2xsZWN0aW9ucyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVFNWU3RyYXRlZ3lDb25maWdzIHtcbiAgcm93SGVpZ2h0OiBudW1iZXI7XG4gIGhlYWRlckhlaWdodDogbnVtYmVyO1xuICBmb290ZXJIZWlnaHQ6IG51bWJlcjtcbiAgYnVmZmVyTXVsdGlwbGllcjogbnVtYmVyO1xufVxuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgRml4ZWRTaXplVGFibGVWaXJ0dWFsU2Nyb2xsU3RyYXRlZ3kgaW1wbGVtZW50cyBWaXJ0dWFsU2Nyb2xsU3RyYXRlZ3kge1xuICBwcml2YXRlIHJvd0hlaWdodCE6IG51bWJlcjtcbiAgcHJpdmF0ZSBoZWFkZXJIZWlnaHQhOiBudW1iZXI7XG4gIHByaXZhdGUgZm9vdGVySGVpZ2h0ITogbnVtYmVyO1xuICBwcml2YXRlIGJ1ZmZlck11bHRpcGxpZXIhOiBudW1iZXI7XG4gIHByaXZhdGUgaW5kZXhDaGFuZ2UgPSBuZXcgU3ViamVjdDxudW1iZXI+KCk7XG4gIHB1YmxpYyBzdGlja3lDaGFuZ2UgPSBuZXcgU3ViamVjdDxudW1iZXI+KCk7XG5cbiAgcHVibGljIHZpZXdwb3J0OiBDZGtWaXJ0dWFsU2Nyb2xsVmlld3BvcnQ7XG5cbiAgcHVibGljIHJlbmRlcmVkUmFuZ2VTdHJlYW0gPSBuZXcgQmVoYXZpb3JTdWJqZWN0PExpc3RSYW5nZT4oe3N0YXJ0OiAwLCBlbmQ6IDB9KTtcblxuICBwdWJsaWMgc2Nyb2xsZWRJbmRleENoYW5nZSA9IHRoaXMuaW5kZXhDaGFuZ2UucGlwZShkaXN0aW5jdFVudGlsQ2hhbmdlZCgpKTtcblxuICBnZXQgZGF0YUxlbmd0aCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLl9kYXRhTGVuZ3RoO1xuICB9XG5cbiAgc2V0IGRhdGFMZW5ndGgodmFsdWU6IG51bWJlcikge1xuICAgIGlmICh2YWx1ZSAhPT0gdGhpcy5fZGF0YUxlbmd0aCkge1xuICAgICAgdGhpcy5fZGF0YUxlbmd0aCA9IHZhbHVlO1xuICAgICAgdGhpcy5vbkRhdGFMZW5ndGhDaGFuZ2VkKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBfZGF0YUxlbmd0aCA9IDA7XG5cbiAgcHVibGljIGF0dGFjaCh2aWV3cG9ydDogQ2RrVmlydHVhbFNjcm9sbFZpZXdwb3J0KTogdm9pZCB7XG4gICAgdGhpcy52aWV3cG9ydCA9IHZpZXdwb3J0O1xuICAgIHRoaXMudmlld3BvcnQucmVuZGVyZWRSYW5nZVN0cmVhbS5zdWJzY3JpYmUodGhpcy5yZW5kZXJlZFJhbmdlU3RyZWFtKTtcbiAgICB0aGlzLnN0aWNreUNoYW5nZS5uZXh0KDApO1xuICAgIHRoaXMub25EYXRhTGVuZ3RoQ2hhbmdlZCgpO1xuICB9XG5cbiAgcHVibGljIGRldGFjaCgpOiB2b2lkIHtcbiAgICB0aGlzLmluZGV4Q2hhbmdlLmNvbXBsZXRlKCk7XG4gICAgdGhpcy5zdGlja3lDaGFuZ2UuY29tcGxldGUoKTtcbiAgICB0aGlzLnJlbmRlcmVkUmFuZ2VTdHJlYW0uY29tcGxldGUoKTtcbiAgfVxuXG4gIHB1YmxpYyBvbkNvbnRlbnRTY3JvbGxlZCgpOiB2b2lkIHtcbiAgICB0aGlzLnVwZGF0ZUNvbnRlbnQoKTtcbiAgfVxuXG4gIHB1YmxpYyBvbkRhdGFMZW5ndGhDaGFuZ2VkKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnZpZXdwb3J0KSB7XG4gICAgICBjb25zdCBjb250ZW50U2l6ZSA9IHRoaXMuZGF0YUxlbmd0aCAqIHRoaXMucm93SGVpZ2h0ICsgdGhpcy5oZWFkZXJIZWlnaHQgKyB0aGlzLmZvb3RlckhlaWdodDtcbiAgICAgIHRoaXMudmlld3BvcnQuc2V0VG90YWxDb250ZW50U2l6ZShjb250ZW50U2l6ZSk7XG4gICAgICBjb25zdCB2aWV3cG9ydFNpemUgPSB0aGlzLnZpZXdwb3J0LmdldFZpZXdwb3J0U2l6ZSgpO1xuICAgICAgaWYgKHRoaXMudmlld3BvcnQubWVhc3VyZVNjcm9sbE9mZnNldCgpICsgdmlld3BvcnRTaXplID49IGNvbnRlbnRTaXplKSB7XG4gICAgICAgIHRoaXMudmlld3BvcnQuc2Nyb2xsVG9PZmZzZXQoY29udGVudFNpemUgLSB2aWV3cG9ydFNpemUpO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLnVwZGF0ZUNvbnRlbnQoKTtcbiAgfVxuXG4gIHB1YmxpYyBvbkNvbnRlbnRSZW5kZXJlZCgpOiB2b2lkIHtcbiAgfVxuXG4gIHB1YmxpYyBvblJlbmRlcmVkT2Zmc2V0Q2hhbmdlZCgpOiB2b2lkIHtcbiAgICAvLyBuby1vcFxuICB9XG5cbiAgcHVibGljIHNjcm9sbFRvSW5kZXgoaW5kZXg6IG51bWJlciwgYmVoYXZpb3I/OiBTY3JvbGxCZWhhdmlvcik6IHZvaWQge1xuICAgIGlmICghdGhpcy52aWV3cG9ydCB8fCAhdGhpcy5yb3dIZWlnaHQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy52aWV3cG9ydC5zY3JvbGxUb09mZnNldCgoaW5kZXggLSAxICkgKiB0aGlzLnJvd0hlaWdodCArIHRoaXMuaGVhZGVySGVpZ2h0LCBiZWhhdmlvcik7XG4gIH1cblxuICBwdWJsaWMgc2V0Q29uZmlnKGNvbmZpZ3M6IFRTVlN0cmF0ZWd5Q29uZmlncykge1xuICAgIGNvbnN0IHtyb3dIZWlnaHQsIGhlYWRlckhlaWdodCwgZm9vdGVySGVpZ2h0LCBidWZmZXJNdWx0aXBsaWVyfSA9IGNvbmZpZ3M7XG4gICAgaWYgKFxuICAgICAgdGhpcy5yb3dIZWlnaHQgPT09IHJvd0hlaWdodFxuICAgICAgJiYgdGhpcy5oZWFkZXJIZWlnaHQgPT09IGhlYWRlckhlaWdodFxuICAgICAgJiYgdGhpcy5mb290ZXJIZWlnaHQgPT09IGZvb3RlckhlaWdodFxuICAgICAgJiYgdGhpcy5idWZmZXJNdWx0aXBsaWVyID09PSBidWZmZXJNdWx0aXBsaWVyXG4gICAgKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMucm93SGVpZ2h0ID0gcm93SGVpZ2h0O1xuICAgIHRoaXMuaGVhZGVySGVpZ2h0ID0gaGVhZGVySGVpZ2h0O1xuICAgIHRoaXMuZm9vdGVySGVpZ2h0ID0gZm9vdGVySGVpZ2h0O1xuICAgIHRoaXMuYnVmZmVyTXVsdGlwbGllciA9IGJ1ZmZlck11bHRpcGxpZXI7XG4gICAgdGhpcy5vbkRhdGFMZW5ndGhDaGFuZ2VkKCk7XG4gIH1cblxuICBwcml2YXRlIHVwZGF0ZUNvbnRlbnQoKSB7XG4gICAgaWYgKCF0aGlzLnZpZXdwb3J0IHx8ICF0aGlzLnJvd0hlaWdodCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHJlbmRlcmVkT2Zmc2V0ID0gdGhpcy52aWV3cG9ydC5nZXRPZmZzZXRUb1JlbmRlcmVkQ29udGVudFN0YXJ0KCk7XG4gICAgY29uc3Qgc3RhcnQgPSByZW5kZXJlZE9mZnNldCAvIHRoaXMucm93SGVpZ2h0O1xuICAgIGNvbnN0IGl0ZW1zRGlzcGxheWVkID0gTWF0aC5jZWlsKHRoaXMudmlld3BvcnQuZ2V0Vmlld3BvcnRTaXplKCkgLyB0aGlzLnJvd0hlaWdodCk7XG4gICAgY29uc3QgYnVmZmVySXRlbXMgPSBNYXRoLmNlaWwoaXRlbXNEaXNwbGF5ZWQgKiB0aGlzLmJ1ZmZlck11bHRpcGxpZXIpO1xuICAgIGNvbnN0IGVuZCA9IHN0YXJ0ICsgaXRlbXNEaXNwbGF5ZWQgKyAyICogYnVmZmVySXRlbXM7XG5cblxuICAgIGNvbnN0IGJ1ZmZlck9mZnNldCA9IHJlbmRlcmVkT2Zmc2V0ICsgYnVmZmVySXRlbXMgKiB0aGlzLnJvd0hlaWdodDtcbiAgICBjb25zdCBzY3JvbGxPZmZzZXQgPSB0aGlzLnZpZXdwb3J0Lm1lYXN1cmVTY3JvbGxPZmZzZXQoKTtcblxuICAgIC8vIEhvdyBmYXIgdGhlIHNjcm9sbCBvZmZzZXQgaXMgZnJvbSB0aGUgbG93ZXIgYnVmZmVyLCB3aGljaCBpcyB1c3VhbGx5IHdoZXJlIGl0ZW1zIHN0YXJ0IGJlaW5nIGRpc3BsYXllZFxuICAgIGNvbnN0IHJlbGF0aXZlU2Nyb2xsT2Zmc2V0ID0gc2Nyb2xsT2Zmc2V0IC0gYnVmZmVyT2Zmc2V0O1xuICAgIGNvbnN0IHJvd3NTY3JvbGxlZCA9IHJlbGF0aXZlU2Nyb2xsT2Zmc2V0IC8gdGhpcy5yb3dIZWlnaHQ7XG5cbiAgICBjb25zdCBkaXNwbGF5ZWQgPSBzY3JvbGxPZmZzZXQgLyB0aGlzLnJvd0hlaWdodDtcbiAgICB0aGlzLmluZGV4Q2hhbmdlLm5leHQoZGlzcGxheWVkKTtcblxuICAgIC8vIE9ubHkgYm90aGVyIHVwZGF0aW5nIHRoZSBkaXNwbGF5ZWQgaW5mb3JtYXRpb24gaWYgd2UndmUgc2Nyb2xsZWQgbW9yZSB0aGFuIGEgcm93XG4gICAgY29uc3Qgcm93U2Vuc2l0aXZpdHkgPSAxLjA7XG4gICAgaWYgKE1hdGguYWJzKHJvd3NTY3JvbGxlZCkgPCByb3dTZW5zaXRpdml0eSkge1xuICAgICAgdGhpcy52aWV3cG9ydC5zZXRSZW5kZXJlZENvbnRlbnRPZmZzZXQocmVuZGVyZWRPZmZzZXQpO1xuICAgICAgdGhpcy52aWV3cG9ydC5zZXRSZW5kZXJlZFJhbmdlKHtzdGFydCwgZW5kfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gU3BlY2lhbCBjYXNlIGZvciB0aGUgc3RhcnQgb2YgdGhlIHRhYmxlLlxuICAgIC8vIEF0IHRoZSB0b3Agb2YgdGhlIHRhYmxlLCB0aGUgZmlyc3QgZmV3IHJvd3MgYXJlIGZpcnN0IHJlbmRlcmVkIGJlY2F1c2UgdGhleSdyZSB2aXNpYmxlLCBhbmQgdGhlbiBzdGlsbCByZW5kZXJlZFxuICAgIC8vIEJlY2F1c2UgdGhleSBtb3ZlIGludG8gdGhlIGJ1ZmZlci4gU28gd2Ugb25seSBuZWVkIHRvIGNoYW5nZSB3aGF0J3MgcmVuZGVyZWQgb25jZSB0aGUgdXNlciBzY3JvbGxzIGZhciBlbm91Z2ggZG93bi5cbiAgICBpZiAocmVuZGVyZWRPZmZzZXQgPT09IDAgJiYgcm93c1Njcm9sbGVkIDwgMCkge1xuICAgICAgdGhpcy52aWV3cG9ydC5zZXRSZW5kZXJlZENvbnRlbnRPZmZzZXQocmVuZGVyZWRPZmZzZXQpO1xuICAgICAgdGhpcy52aWV3cG9ydC5zZXRSZW5kZXJlZFJhbmdlKHtzdGFydCwgZW5kfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgcm93c1RvTW92ZSA9IE1hdGguc2lnbihyb3dzU2Nyb2xsZWQpICogTWF0aC5mbG9vcihNYXRoLmFicyhyb3dzU2Nyb2xsZWQpKTtcbiAgICBjb25zdCBhZGp1c3RlZFJlbmRlcmVkT2Zmc2V0ID0gTWF0aC5tYXgoMCwgcmVuZGVyZWRPZmZzZXQgKyByb3dzVG9Nb3ZlICogdGhpcy5yb3dIZWlnaHQpO1xuICAgIHRoaXMudmlld3BvcnQuc2V0UmVuZGVyZWRDb250ZW50T2Zmc2V0KGFkanVzdGVkUmVuZGVyZWRPZmZzZXQpO1xuXG4gICAgY29uc3QgYWRqdXN0ZWRTdGFydCA9IE1hdGgubWF4KDAsIHN0YXJ0ICsgcm93c1RvTW92ZSk7XG4gICAgY29uc3QgYWRqdXN0ZWRFbmQgPSBhZGp1c3RlZFN0YXJ0ICsgaXRlbXNEaXNwbGF5ZWQgKyAyICogYnVmZmVySXRlbXM7XG4gICAgdGhpcy52aWV3cG9ydC5zZXRSZW5kZXJlZFJhbmdlKHtzdGFydDogYWRqdXN0ZWRTdGFydCwgZW5kOiBhZGp1c3RlZEVuZH0pO1xuXG4gICAgdGhpcy5zdGlja3lDaGFuZ2UubmV4dChhZGp1c3RlZFJlbmRlcmVkT2Zmc2V0KTtcbiAgfVxufVxuIl19