@blackbaud/angular-tree-component
Version:
A simple yet powerful tree component for Angular 14+
186 lines • 19.8 kB
JavaScript
import { Component, ContentChild, EventEmitter, HostListener, Input, Output, ViewChild } from '@angular/core';
import { TreeModel } from '../models/tree.model';
import * as i0 from "@angular/core";
import * as i1 from "../models/tree.model";
import * as i2 from "../models/tree-dragged-element.model";
import * as i3 from "@angular/common";
import * as i4 from "./tree-node-drop-slot.component";
import * as i5 from "./tree-node-collection.component";
import * as i6 from "./tree-viewport.component";
export class TreeComponent {
constructor(treeModel, treeDraggedElement) {
this.treeModel = treeModel;
this.treeDraggedElement = treeDraggedElement;
treeModel.eventNames.forEach((name) => this[name] = new EventEmitter());
treeModel.subscribeToState((state) => this.stateChange.emit(state));
}
// Will be handled in ngOnChanges
set nodes(nodes) {
}
;
set options(options) {
}
;
set focused(value) {
this.treeModel.setFocus(value);
}
set state(state) {
this.treeModel.setState(state);
}
onKeydown($event) {
if (!this.treeModel.isFocused)
return;
if (['input', 'textarea'].includes(document.activeElement.tagName.toLowerCase()))
return;
const focusedNode = this.treeModel.getFocusedNode();
this.treeModel.performKeyAction(focusedNode, $event);
}
onMousedown($event) {
function isOutsideClick(startElement, nodeName) {
return !startElement ? true : startElement.localName === nodeName ? false : isOutsideClick(startElement.parentElement, nodeName);
}
if (isOutsideClick($event.target, 'tree-root')) {
this.treeModel.setFocus(false);
}
}
ngOnChanges(changes) {
if (changes.options || changes.nodes) {
this.treeModel.setData({
options: changes.options && changes.options.currentValue,
nodes: changes.nodes && changes.nodes.currentValue,
events: this.pick(this, this.treeModel.eventNames)
});
}
}
sizeChanged() {
this.viewportComponent.setViewport();
}
pick(object, keys) {
return keys.reduce((obj, key) => {
if (object && object.hasOwnProperty(key)) {
obj[key] = object[key];
}
return obj;
}, {});
}
}
/** @nocollapse */ TreeComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TreeComponent, deps: [{ token: i1.TreeModel }, { token: i2.TreeDraggedElement }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ TreeComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: TreeComponent, selector: "Tree, tree-root", inputs: { nodes: "nodes", options: "options", focused: "focused", state: "state" }, outputs: { toggleExpanded: "toggleExpanded", activate: "activate", deactivate: "deactivate", nodeActivate: "nodeActivate", nodeDeactivate: "nodeDeactivate", select: "select", deselect: "deselect", focus: "focus", blur: "blur", updateData: "updateData", initialized: "initialized", moveNode: "moveNode", copyNode: "copyNode", loadNodeChildren: "loadNodeChildren", changeFilter: "changeFilter", event: "event", stateChange: "stateChange" }, host: { listeners: { "body: keydown": "onKeydown($event)", "body: mousedown": "onMousedown($event)" } }, providers: [TreeModel], queries: [{ propertyName: "loadingTemplate", first: true, predicate: ["loadingTemplate"], descendants: true }, { propertyName: "treeNodeTemplate", first: true, predicate: ["treeNodeTemplate"], descendants: true }, { propertyName: "treeNodeWrapperTemplate", first: true, predicate: ["treeNodeWrapperTemplate"], descendants: true }, { propertyName: "treeNodeFullTemplate", first: true, predicate: ["treeNodeFullTemplate"], descendants: true }], viewQueries: [{ propertyName: "viewportComponent", first: true, predicate: ["viewport"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
<tree-viewport #viewport>
<div
class="angular-tree-component"
[class.node-dragging]="treeDraggedElement.isDragging()"
[class.angular-tree-component-rtl]="treeModel.options.rtl">
<tree-node-collection
*ngIf="treeModel.roots"
[nodes]="treeModel.roots"
[treeModel]="treeModel"
[templates]="{
loadingTemplate: loadingTemplate,
treeNodeTemplate: treeNodeTemplate,
treeNodeWrapperTemplate: treeNodeWrapperTemplate,
treeNodeFullTemplate: treeNodeFullTemplate
}">
</tree-node-collection>
<tree-node-drop-slot
class="empty-tree-drop-slot"
*ngIf="treeModel.isEmptyTree()"
[dropIndex]="0"
[node]="treeModel.virtualRoot">
</tree-node-drop-slot>
</div>
</tree-viewport>
`, isInline: true, dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4.TreeNodeDropSlot, selector: "TreeNodeDropSlot, tree-node-drop-slot", inputs: ["node", "dropIndex"] }, { kind: "component", type: i5.TreeNodeCollectionComponent, selector: "tree-node-collection", inputs: ["nodes", "treeModel", "templates"] }, { kind: "component", type: i6.TreeViewportComponent, selector: "tree-viewport" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TreeComponent, decorators: [{
type: Component,
args: [{ selector: 'Tree, tree-root', providers: [TreeModel], template: `
<tree-viewport #viewport>
<div
class="angular-tree-component"
[class.node-dragging]="treeDraggedElement.isDragging()"
[class.angular-tree-component-rtl]="treeModel.options.rtl">
<tree-node-collection
*ngIf="treeModel.roots"
[nodes]="treeModel.roots"
[treeModel]="treeModel"
[templates]="{
loadingTemplate: loadingTemplate,
treeNodeTemplate: treeNodeTemplate,
treeNodeWrapperTemplate: treeNodeWrapperTemplate,
treeNodeFullTemplate: treeNodeFullTemplate
}">
</tree-node-collection>
<tree-node-drop-slot
class="empty-tree-drop-slot"
*ngIf="treeModel.isEmptyTree()"
[dropIndex]="0"
[node]="treeModel.virtualRoot">
</tree-node-drop-slot>
</div>
</tree-viewport>
` }]
}], ctorParameters: function () { return [{ type: i1.TreeModel }, { type: i2.TreeDraggedElement }]; }, propDecorators: { loadingTemplate: [{
type: ContentChild,
args: ['loadingTemplate', { static: false }]
}], treeNodeTemplate: [{
type: ContentChild,
args: ['treeNodeTemplate', { static: false }]
}], treeNodeWrapperTemplate: [{
type: ContentChild,
args: ['treeNodeWrapperTemplate', { static: false }]
}], treeNodeFullTemplate: [{
type: ContentChild,
args: ['treeNodeFullTemplate', { static: false }]
}], viewportComponent: [{
type: ViewChild,
args: ['viewport', { static: false }]
}], nodes: [{
type: Input
}], options: [{
type: Input
}], focused: [{
type: Input
}], state: [{
type: Input
}], toggleExpanded: [{
type: Output
}], activate: [{
type: Output
}], deactivate: [{
type: Output
}], nodeActivate: [{
type: Output
}], nodeDeactivate: [{
type: Output
}], select: [{
type: Output
}], deselect: [{
type: Output
}], focus: [{
type: Output
}], blur: [{
type: Output
}], updateData: [{
type: Output
}], initialized: [{
type: Output
}], moveNode: [{
type: Output
}], copyNode: [{
type: Output
}], loadNodeChildren: [{
type: Output
}], changeFilter: [{
type: Output
}], event: [{
type: Output
}], stateChange: [{
type: Output
}], onKeydown: [{
type: HostListener,
args: ['body: keydown', ['$event']]
}], onMousedown: [{
type: HostListener,
args: ['body: mousedown', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLXRyZWUtY29tcG9uZW50L3NyYy9saWIvY29tcG9uZW50cy90cmVlLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBYSxNQUFNLEVBQWUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3RJLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQzs7Ozs7Ozs7QUFxQ2pELE1BQU0sT0FBTyxhQUFhO0lBMkN4QixZQUNTLFNBQW9CLEVBQ3BCLGtCQUFzQztRQUR0QyxjQUFTLEdBQVQsU0FBUyxDQUFXO1FBQ3BCLHVCQUFrQixHQUFsQixrQkFBa0IsQ0FBb0I7UUFFN0MsU0FBUyxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDLENBQUM7UUFDeEUsU0FBUyxDQUFDLGdCQUFnQixDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ3RFLENBQUM7SUF2Q0QsaUNBQWlDO0lBQ2pDLElBQWEsS0FBSyxDQUFDLEtBQVk7SUFDL0IsQ0FBQztJQUFBLENBQUM7SUFFRixJQUFhLE9BQU8sQ0FBQyxPQUFxQjtJQUMxQyxDQUFDO0lBQUEsQ0FBQztJQUVGLElBQWEsT0FBTyxDQUFDLEtBQWM7UUFDakMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUVELElBQWEsS0FBSyxDQUFDLEtBQUs7UUFDdEIsSUFBSSxDQUFDLFNB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QUUsTUFBTSxFQUFFLEtBQUssRUFBRTtnQkFDYixpQkFBaUI7c0JBQTFELFNBQVM7dUJBQUMsVUFBVSxFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRTtnQkFHM0IsS0FBSztzQkFBakIsS0FBSztnQkFHTyxPQUFPO3NCQUFuQixLQUFLO2dCQUdPLE9BQU87c0JBQW5CLEtBQUs7Z0JBSU8sS0FBSztzQkFBakIsS0FBSztnQkFJSSxjQUFjO3NCQUF2QixNQUFNO2dCQUNHLFFBQVE7c0JBQWpCLE1BQU07Z0JBQ0csVUFBVTtzQkFBbkIsTUFBTTtnQkFDRyxZQUFZO3NCQUFyQixNQUFNO2dCQUNHLGNBQWM7c0JBQXZCLE1BQU07Z0JBQ0csTUFBTTtzQkFBZixNQUFNO2dCQUNHLFFBQVE7c0JBQWpCLE1BQU07Z0JBQ0csS0FBSztzQkFBZCxNQUFNO2dCQUNHLElBQUk7c0JBQWIsTUFBTTtnQkFDRyxVQUFVO3NCQUFuQixNQUFNO2dCQUNHLFdBQVc7c0JBQXBCLE1BQU07Z0JBQ0csUUFBUTtzQkFBakIsTUFBTTtnQkFDRyxRQUFRO3NCQUFqQixNQUFNO2dCQUNHLGdCQUFnQjtzQkFBekIsTUFBTTtnQkFDRyxZQUFZO3NCQUFyQixNQUFNO2dCQUNHLEtBQUs7c0JBQWQsTUFBTTtnQkFDRyxXQUFXO3NCQUFwQixNQUFNO2dCQVdQLFNBQVM7c0JBRFIsWUFBWTt1QkFBQyxlQUFlLEVBQUUsQ0FBQyxRQUFRLENBQUM7Z0JBV3pDLFdBQVc7c0JBRFYsWUFBWTt1QkFBQyxpQkFBaUIsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgQ29udGVudENoaWxkLCBFdmVudEVtaXR0ZXIsIEhvc3RMaXN0ZW5lciwgSW5wdXQsIE9uQ2hhbmdlcywgT3V0cHV0LCBUZW1wbGF0ZVJlZiwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBUcmVlTW9kZWwgfSBmcm9tICcuLi9tb2RlbHMvdHJlZS5tb2RlbCc7XG5pbXBvcnQgeyBUcmVlRHJhZ2dlZEVsZW1lbnQgfSBmcm9tICcuLi9tb2RlbHMvdHJlZS1kcmFnZ2VkLWVsZW1lbnQubW9kZWwnO1xuaW1wb3J0IHsgVHJlZU9wdGlvbnMgfSBmcm9tICcuLi9tb2RlbHMvdHJlZS1vcHRpb25zLm1vZGVsJztcbmltcG9ydCB7IElUcmVlT3B0aW9ucyB9IGZyb20gJy4uL2RlZnMvYXBpJztcbmltcG9ydCB7IFRyZWVWaWV3cG9ydENvbXBvbmVudCB9IGZyb20gJy4vdHJlZS12aWV3cG9ydC5jb21wb25lbnQnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdUcmVlLCB0cmVlLXJvb3QnLFxuICBwcm92aWRlcnM6IFtUcmVlTW9kZWxdLFxuICBzdHlsZXM6IFtdLFxuICB0ZW1wbGF0ZTogYFxuICAgICAgPHRyZWUtdmlld3BvcnQgI3ZpZXdwb3J0PlxuICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgICAgICAgIGNsYXNzPVwiYW5ndWxhci10cmVlLWNvbXBvbmVudFwiXG4gICAgICAgICAgICAgICAgICBbY2xhc3Mubm9kZS1kcmFnZ2luZ109XCJ0cmVlRHJhZ2dlZEVsZW1lbnQuaXNEcmFnZ2luZygpXCJcbiAgICAgICAgICAgICAgICAgIFtjbGFzcy5hbmd1bGFyLXRyZWUtY29tcG9uZW50LXJ0bF09XCJ0cmVlTW9kZWwub3B0aW9ucy5ydGxcIj5cbiAgICAgICAgICAgICAgPHRyZWUtbm9kZS1jb2xsZWN0aW9uXG4gICAgICAgICAgICAgICAgICAgICAgKm5nSWY9XCJ0cmVlTW9kZWwucm9vdHNcIlxuICAgICAgICAgICAgICAgICAgICAgIFtub2Rlc109XCJ0cmVlTW9kZWwucm9vdHNcIlxuICAgICAgICAgICAgICAgICAgICAgIFt0cmVlTW9kZWxdPVwidHJlZU1vZGVsXCJcbiAgICAgICAgICAgICAgICAgICAgICBbdGVtcGxhdGVzXT1cIntcbiAgICAgICAgICAgIGxvYWRpbmdUZW1wbGF0ZTogbG9hZGluZ1RlbXBsYXRlLFxuICAgICAgICAgICAgdHJlZU5vZGVUZW1wbGF0ZTogdHJlZU5vZGVUZW1wbGF0ZSxcbiAgICAgICAgICAgIHRyZWVOb2RlV3JhcHBlclRlbXBsYXRlOiB0cmVlTm9kZVdyYXBwZXJUZW1wbGF0ZSxcbiAgICAgICAgICAgIHRyZWVOb2RlRnVsbFRlbXBsYXRlOiB0cmVlTm9kZUZ1bGxUZW1wbGF0ZVxuICAgICAgICAgIH1cIj5cbiAgICAgICAgICAgICAgPC90cmVlLW5vZGUtY29sbGVjdGlvbj5cbiAgICAgICAgICAgICAgPHRyZWUtbm9kZS1kcm9wLXNsb3RcbiAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImVtcHR5LXRyZWUtZHJvcC1zbG90XCJcbiAgICAgICAgICAgICAgICAgICAgICAqbmdJZj1cInRyZWVNb2RlbC5pc0VtcHR5VHJlZSgpXCJcbiAgICAgICAgICAgICAgICAgICAgICBbZHJvcEluZGV4XT1cIjBcIlxuICAgICAgICAgICAgICAgICAgICAgIFtub2RlXT1cInRyZWVNb2RlbC52aXJ0dWFsUm9vdFwiPlxuICAgICAgICAgICAgICA8L3RyZWUtbm9kZS1kcm9wLXNsb3Q+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICA8L3RyZWUtdmlld3BvcnQ+XG4gIGBcbn0pXG5leHBvcnQgY2xhc3MgVHJlZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XG4gIF9ub2RlczogYW55W107XG4gIF9vcHRpb25zOiBUcmVlT3B0aW9ucztcblxuICBAQ29udGVudENoaWxkKCdsb2FkaW5nVGVtcGxhdGUnLCB7IHN0YXRpYzogZmFsc2UgfSkgbG9hZGluZ1RlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+O1xuICBAQ29udGVudENoaWxkKCd0cmVlTm9kZVRlbXBsYXRlJywgeyBzdGF0aWM6IGZhbHNlIH0pIHRyZWVOb2RlVGVtcGxhdGU6IFRlbXBsYXRlUmVmPGFueT47XG4gIEBDb250ZW50Q2hpbGQoJ3RyZWVOb2RlV3JhcHBlclRlbXBsYXRlJywgeyBzdGF0aWM6IGZhbHNlIH0pIHRyZWVOb2RlV3JhcHBlclRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+O1xuICBAQ29udGVudENoaWxkKCd0cmVlTm9kZUZ1bGxUZW1wbGF0ZScsIHsgc3RhdGljOiBmYWxzZSB9KSB0cmVlTm9kZUZ1bGxUZW1wbGF0ZTogVGVtcGxhdGVSZWY8YW55PjtcbiAgQFZpZXdDaGlsZCgndmlld3BvcnQnLCB7IHN0YXRpYzogZmFsc2UgfSkgdmlld3BvcnRDb21wb25lbnQ6IFRyZWVWaWV3cG9ydENvbXBvbmVudDtcblxuICAvLyBXaWxsIGJlIGhhbmRsZWQgaW4gbmdPbkNoYW5nZXNcbiAgQElucHV0KCkgc2V0IG5vZGVzKG5vZGVzOiBhbnlbXSkge1xuICB9O1xuXG4gIEBJbnB1dCgpIHNldCBvcHRpb25zKG9wdGlvbnM6IElUcmVlT3B0aW9ucykge1xuICB9O1xuXG4gIEBJbnB1dCgpIHNldCBmb2N1c2VkKHZhbHVlOiBib29sZWFuKSB7XG4gICAgdGhpcy50cmVlTW9kZWwuc2V0Rm9jdXModmFsdWUpO1xuICB9XG5cbiAgQElucHV0KCkgc2V0IHN0YXRlKHN0YXRlKSB7XG4gICAgdGhpcy50cmVlTW9kZWwuc2V0U3RhdGUoc3RhdGUpO1xuICB9XG5cbiAgQE91dHB1dCgpIHRvZ2dsZUV4cGFuZGVkO1xuICBAT3V0cHV0KCkgYWN0aXZhdGU7XG4gIEBPdXRwdXQoKSBkZWFjdGl2YXRlO1xuICBAT3V0cHV0KCkgbm9kZUFjdGl2YXRlO1xuICBAT3V0cHV0KCkgbm9kZURlYWN0aXZhdGU7XG4gIEBPdXRwdXQoKSBzZWxlY3Q7XG4gIEBPdXRwdXQoKSBkZXNlbGVjdDtcbiAgQE91dHB1dCgpIGZvY3VzO1xuICBAT3V0cHV0KCkgYmx1cjtcbiAgQE91dHB1dCgpIHVwZGF0ZURhdGE7XG4gIEBPdXRwdXQoKSBpbml0aWFsaXplZDtcbiAgQE91dHB1dCgpIG1vdmVOb2RlO1xuICBAT3V0cHV0KCkgY29weU5vZGU7XG4gIEBPdXRwdXQoKSBsb2FkTm9kZUNoaWxkcmVuO1xuICBAT3V0cHV0KCkgY2hhbmdlRmlsdGVyO1xuICBAT3V0cHV0KCkgZXZlbnQ7XG4gIEBPdXRwdXQoKSBzdGF0ZUNoYW5nZTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwdWJsaWMgdHJlZU1vZGVsOiBUcmVlTW9kZWwsXG4gICAgcHVibGljIHRyZWVEcmFnZ2VkRWxlbWVudDogVHJlZURyYWdnZWRFbGVtZW50KSB7XG5cbiAgICB0cmVlTW9kZWwuZXZlbnROYW1lcy5mb3JFYWNoKChuYW1lKSA9PiB0aGlzW25hbWVdID0gbmV3IEV2ZW50RW1pdHRlcigpKTtcbiAgICB0cmVlTW9kZWwuc3Vic2NyaWJlVG9TdGF0ZSgoc3RhdGUpID0+IHRoaXMuc3RhdGVDaGFuZ2UuZW1pdChzdGF0ZSkpO1xuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignYm9keToga2V5ZG93bicsIFsnJGV2ZW50J10pXG4gIG9uS2V5ZG93bigkZXZlbnQpIHtcbiAgICBpZiAoIXRoaXMudHJlZU1vZGVsLmlzRm9jdXNlZCkgcmV0dXJuO1xuICAgIGlmIChbJ2lucHV0JywgJ3RleHRhcmVhJ10uaW5jbHVkZXMoZG9jdW1lbnQuYWN0aXZlRWxlbWVudC50YWdOYW1lLnRvTG93ZXJDYXNlKCkpKSByZXR1cm47XG5cbiAgICBjb25zdCBmb2N1c2VkTm9kZSA9IHRoaXMudHJlZU1vZGVsLmdldEZvY3VzZWROb2RlKCk7XG5cbiAgICB0aGlzLnRyZWVNb2RlbC5wZXJmb3JtS2V5QWN0aW9uKGZvY3VzZWROb2RlLCAkZXZlbnQpO1xuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignYm9keTogbW91c2Vkb3duJywgWyckZXZlbnQnXSlcbiAgb25Nb3VzZWRvd24oJGV2ZW50KSB7XG4gICAgZnVuY3Rpb24gaXNPdXRzaWRlQ2xpY2soc3RhcnRFbGVtZW50OiBFbGVtZW50LCBub2RlTmFtZTogc3RyaW5nKSB7XG4gICAgICByZXR1cm4gIXN0YXJ0RWxlbWVudCA/IHRydWUgOiBzdGFydEVsZW1lbnQubG9jYWxOYW1lID09PSBub2RlTmFtZSA/IGZhbHNlIDogaXNPdXRzaWRlQ2xpY2soc3RhcnRFbGVtZW50LnBhcmVudEVsZW1lbnQsIG5vZGVOYW1lKTtcbiAgICB9XG5cbiAgICBpZiAoaXNPdXRzaWRlQ2xpY2soJGV2ZW50LnRhcmdldCwgJ3RyZWUtcm9vdCcpKSB7XG4gICAgICB0aGlzLnRyZWVNb2RlbC5zZXRGb2N1cyhmYWxzZSk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlcykge1xuICAgIGlmIChjaGFuZ2VzLm9wdGlvbnMgfHwgY2hhbmdlcy5ub2Rlcykge1xuICAgICAgdGhpcy50cmVlTW9kZWwuc2V0RGF0YSh7XG4gICAgICAgIG9wdGlvbnM6IGNoYW5nZXMub3B0aW9ucyAmJiBjaGFuZ2VzLm9wdGlvbnMuY3VycmVudFZhbHVlLFxuICAgICAgICBub2RlczogY2hhbmdlcy5ub2RlcyAmJiBjaGFuZ2VzLm5vZGVzLmN1cnJlbnRWYWx1ZSxcbiAgICAgICAgZXZlbnRzOiB0aGlzLnBpY2sodGhpcywgdGhpcy50cmVlTW9kZWwuZXZlbnROYW1lcylcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHNpemVDaGFuZ2VkKCkge1xuICAgIHRoaXMudmlld3BvcnRDb21wb25lbnQuc2V0Vmlld3BvcnQoKTtcbiAgfVxuXG4gIHByaXZhdGUgcGljayhvYmplY3QsIGtleXMpIHtcbiAgICByZXR1cm4ga2V5cy5yZWR1Y2UoKG9iaiwga2V5KSA9PiB7XG4gICAgICBpZiAob2JqZWN0ICYmIG9iamVjdC5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgIG9ialtrZXldID0gb2JqZWN0W2tleV07XG4gICAgICB9XG4gICAgICByZXR1cm4gb2JqO1xuICAgIH0sIHt9KTtcbiAgfVxufVxuIl19