ngx-sortable
Version:
An angular 4 and above component for sorting list supporting drag and drop sort.
178 lines • 27.6 kB
JavaScript
import { Component, Input, Output, ContentChild, EventEmitter, TemplateRef, HostListener, } from "@angular/core";
import { CommandKey } from "../../types/ngx-sortable.types";
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
export class NgxSortableComponent {
constructor() {
this.items = [];
this.showHeader = true;
this.removeOnDropOutside = false;
this.dragStart = new EventEmitter();
this.dropped = new EventEmitter();
this.moveDown = new EventEmitter();
this.moveUp = new EventEmitter();
this.remove = new EventEmitter();
this.listStyle = {
height: "250px",
width: "300px",
dropZoneHeight: "50px",
};
this.listSorted = new EventEmitter();
this.commandKey = CommandKey.CtrlKey;
this.draggedIndex = -1;
this.onDragOverIndex = -1;
// console.log('Intializing...');
}
onArrowKeyDown($event) {
/** istanbul ignore else */
if (this.arrowKeySort) {
/** istanbul ignore else */
if ($event.key === "ArrowUp" && $event[this.commandKey]) {
this.onMoveUp($event);
}
/** istanbul ignore else */
if ($event.key === "ArrowDown" && $event[this.commandKey]) {
this.onMoveDown($event);
}
$event.preventDefault();
}
}
onDragEnd() {
if (this.removeOnDropOutside) {
this.onRemoveDrop();
}
else {
this.draggedIndex = -1;
this.onDragOverIndex = -1;
}
}
selectItem(item) {
this.selectedItem = item;
}
onMoveUp($event) {
const index = this.items.indexOf(this.selectedItem);
/** istanbul ignore else */
if (index === 0) {
return;
}
this.swapElements(index, index - 1);
this.moveUp.emit({
event: $event,
itemIndex: index,
newIndex: index - 1,
item: this.selectedItem,
});
this.listSorted.emit(this.items);
}
onMoveDown($event) {
const index = this.items.indexOf(this.selectedItem);
if (index === this.items.length - 1) {
return;
}
this.swapElements(index, index + 1);
this.moveDown.emit({
event: $event,
itemIndex: index,
newIndex: index + 1,
item: this.selectedItem,
});
this.listSorted.emit(this.items);
}
onDrop($event, index) {
// index is of the element on which the item is dropped
/** istanbul ignore else */
if (index === this.draggedIndex) {
this.draggedIndex = -1;
this.onDragOverIndex = -1;
return;
}
const dragIndex = this.draggedIndex;
this.handleDrop(index);
this.dropped.emit({
event: $event,
itemIndex: dragIndex,
newIndex: index,
item: this.selectedItem,
});
}
allowDrop($event, index) {
// index is of the item on which the item is currently hovered
this.onDragOverIndex = index;
$event.preventDefault();
}
onDragStart($event, index) {
this.selectItem(this.items[index]);
this.draggedIndex = index;
this.dragStart.emit({
event: $event,
itemIndex: index,
newIndex: -1,
item: this.selectedItem,
});
}
handleDrop(droppedIndex) {
const item = this.items[this.draggedIndex];
this.items.splice(this.draggedIndex, 1);
this.items.splice(droppedIndex, 0, item);
this.draggedIndex = -1;
this.onDragOverIndex = -1;
this.listSorted.emit(this.items);
}
swapElements(oldIndex, newIndex) {
const temp = this.items[oldIndex];
this.items[oldIndex] = this.items[newIndex];
this.items[newIndex] = temp;
}
onRemoveDrop() {
this.items.splice(this.draggedIndex, 1);
this.remove.emit({
item: this.selectedItem,
itemIndex: this.draggedIndex,
});
this.draggedIndex = -1;
this.onDragOverIndex = -1;
this.listSorted.emit(this.items);
}
}
NgxSortableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: NgxSortableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
NgxSortableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.1.3", type: NgxSortableComponent, selector: "ngx-sortable", inputs: { items: "items", name: "name", showHeader: "showHeader", removeOnDropOutside: "removeOnDropOutside", listStyle: "listStyle", arrowKeySort: "arrowKeySort", commandKey: "commandKey" }, outputs: { dragStart: "dragStart", dropped: "dropped", moveDown: "moveDown", moveUp: "moveUp", remove: "remove", listSorted: "listSorted" }, host: { listeners: { "document:keydown": "onArrowKeyDown($event)", "document:dragend": "onDragEnd()" } }, queries: [{ propertyName: "itemTemplate", first: true, predicate: TemplateRef, descendants: true }], ngImport: i0, template: "<div class=\"sortable-container\" [style.width]='listStyle.width'>\n <div class=\"sortable-header\" *ngIf=\"showHeader\">\n <label class=\"sortable-name\">{{name}}</label>\n <div class=\"sortable-buttons\">\n <button (click)=\"onMoveUp()\" [disabled]=\"!selectedItem\" title=\"Move Up\">⇧</button>\n <button (click)=\"onMoveDown()\" [disabled]=\"!selectedItem\" title=\"Move Down\">⇩</button>\n </div>\n </div>\n <ul class=\"sortable-list\" [style.height]='listStyle.height'>\n <li draggable=\"true\" (click)=\"selectItem(item)\" *ngFor=\"let item of items; let i = index;\"\n [ngClass]=\"{'active': item == selectedItem}\" (drop)=\"onDrop($event, i)\" (dragover)=\"allowDrop($event,i)\"\n (dragstart)=\"onDragStart($event, i)\">\n <div class=\"drop-zone\" [style.height]=\"listStyle.dropZoneHeight\" *ngIf=\"onDragOverIndex == i && i==0\">\n </div>\n <ng-template [ngTemplateOutlet]=\"itemTemplate\" [ngTemplateOutletContext]=\"{\n item: item,\n index: i\n }\">\n </ng-template>\n <div class=\"drop-zone\" [style.height]=\"listStyle.dropZoneHeight\" *ngIf=\"onDragOverIndex == i && i!=0\">\n </div>\n </li>\n </ul>\n</div>", styles: [".sortable-container{width:100%;border:1px solid #d9d9d9;position:static;border-radius:3px}.sortable-container .sortable-header{width:auto;padding:5px;background:lightgray;border-bottom:1px solid #d9d9d9;height:30px;background-image:linear-gradient(rgb(246,247,249) 0%,rgb(235,237,240) 100%);box-sizing:content-box;color:#000}.sortable-container .sortable-header .sortable-name{vertical-align:middle;font-size:25px}.sortable-container .sortable-header .sortable-buttons{float:right;height:100%;box-sizing:border-box}.sortable-container .sortable-header .sortable-buttons button{height:30px;width:30px;vertical-align:middle;display:inline-block;box-sizing:border-box;margin-left:5px;border:1px solid #2399e5;color:#fff;background:#2399e5;transition:background-color .2s;border-radius:5px;outline:none}.sortable-container .sortable-header .sortable-buttons button:disabled{cursor:not-allowed}.sortable-container .sortable-header .sortable-buttons button:active,.sortable-container .sortable-header .sortable-buttons button:hover{border:1px solid #156090;background:#186ba0;color:#fff}.sortable-container .sortable-header .sortable-buttons button:active:enabled,.sortable-container .sortable-header .sortable-buttons button:hover:enabled{cursor:pointer}.sortable-container .sortable-list{list-style-type:none;margin:0;padding:0;overflow:auto;position:static}.sortable-container .sortable-list .drop-zone{background:rgba(225,219,250,.5);opacity:.5px;border:2px dotted rgb(225,219,250)}.sortable-container .sortable-list .remove{background:rgba(248,210,181,.5);text-align:center}.sortable-container .sortable-list .active{cursor:grab;background:#3f94e9;color:#fff}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: NgxSortableComponent, decorators: [{
type: Component,
args: [{ selector: "ngx-sortable", template: "<div class=\"sortable-container\" [style.width]='listStyle.width'>\n <div class=\"sortable-header\" *ngIf=\"showHeader\">\n <label class=\"sortable-name\">{{name}}</label>\n <div class=\"sortable-buttons\">\n <button (click)=\"onMoveUp()\" [disabled]=\"!selectedItem\" title=\"Move Up\">⇧</button>\n <button (click)=\"onMoveDown()\" [disabled]=\"!selectedItem\" title=\"Move Down\">⇩</button>\n </div>\n </div>\n <ul class=\"sortable-list\" [style.height]='listStyle.height'>\n <li draggable=\"true\" (click)=\"selectItem(item)\" *ngFor=\"let item of items; let i = index;\"\n [ngClass]=\"{'active': item == selectedItem}\" (drop)=\"onDrop($event, i)\" (dragover)=\"allowDrop($event,i)\"\n (dragstart)=\"onDragStart($event, i)\">\n <div class=\"drop-zone\" [style.height]=\"listStyle.dropZoneHeight\" *ngIf=\"onDragOverIndex == i && i==0\">\n </div>\n <ng-template [ngTemplateOutlet]=\"itemTemplate\" [ngTemplateOutletContext]=\"{\n item: item,\n index: i\n }\">\n </ng-template>\n <div class=\"drop-zone\" [style.height]=\"listStyle.dropZoneHeight\" *ngIf=\"onDragOverIndex == i && i!=0\">\n </div>\n </li>\n </ul>\n</div>", styles: [".sortable-container{width:100%;border:1px solid #d9d9d9;position:static;border-radius:3px}.sortable-container .sortable-header{width:auto;padding:5px;background:lightgray;border-bottom:1px solid #d9d9d9;height:30px;background-image:linear-gradient(rgb(246,247,249) 0%,rgb(235,237,240) 100%);box-sizing:content-box;color:#000}.sortable-container .sortable-header .sortable-name{vertical-align:middle;font-size:25px}.sortable-container .sortable-header .sortable-buttons{float:right;height:100%;box-sizing:border-box}.sortable-container .sortable-header .sortable-buttons button{height:30px;width:30px;vertical-align:middle;display:inline-block;box-sizing:border-box;margin-left:5px;border:1px solid #2399e5;color:#fff;background:#2399e5;transition:background-color .2s;border-radius:5px;outline:none}.sortable-container .sortable-header .sortable-buttons button:disabled{cursor:not-allowed}.sortable-container .sortable-header .sortable-buttons button:active,.sortable-container .sortable-header .sortable-buttons button:hover{border:1px solid #156090;background:#186ba0;color:#fff}.sortable-container .sortable-header .sortable-buttons button:active:enabled,.sortable-container .sortable-header .sortable-buttons button:hover:enabled{cursor:pointer}.sortable-container .sortable-list{list-style-type:none;margin:0;padding:0;overflow:auto;position:static}.sortable-container .sortable-list .drop-zone{background:rgba(225,219,250,.5);opacity:.5px;border:2px dotted rgb(225,219,250)}.sortable-container .sortable-list .remove{background:rgba(248,210,181,.5);text-align:center}.sortable-container .sortable-list .active{cursor:grab;background:#3f94e9;color:#fff}\n"] }]
}], ctorParameters: function () { return []; }, propDecorators: { items: [{
type: Input
}], name: [{
type: Input
}], showHeader: [{
type: Input
}], removeOnDropOutside: [{
type: Input
}], dragStart: [{
type: Output
}], dropped: [{
type: Output
}], moveDown: [{
type: Output
}], moveUp: [{
type: Output
}], remove: [{
type: Output
}], listStyle: [{
type: Input
}], listSorted: [{
type: Output
}], itemTemplate: [{
type: ContentChild,
args: [TemplateRef]
}], arrowKeySort: [{
type: Input
}], commandKey: [{
type: Input
}], onArrowKeyDown: [{
type: HostListener,
args: ["document:keydown", ["$event"]]
}], onDragEnd: [{
type: HostListener,
args: ["document:dragend"]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXNvcnRhYmxlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1zb3J0YWJsZS9zcmMvbGliL2NvbXBvbmVudHMvbmd4LXNvcnRhYmxlL25neC1zb3J0YWJsZS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtc29ydGFibGUvc3JjL2xpYi9jb21wb25lbnRzL25neC1zb3J0YWJsZS9uZ3gtc29ydGFibGUuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUNMLFNBQVMsRUFDVCxLQUFLLEVBQ0wsTUFBTSxFQUNOLFlBQVksRUFDWixZQUFZLEVBQ1osV0FBVyxFQUNYLFlBQVksR0FDYixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsVUFBVSxFQUFpQixNQUFNLGdDQUFnQyxDQUFDOzs7QUFNM0UsTUFBTSxPQUFPLG9CQUFvQjtJQXdCL0I7UUF2QmdCLFVBQUssR0FBVSxFQUFFLENBQUM7UUFFbEIsZUFBVSxHQUFHLElBQUksQ0FBQztRQUNsQix3QkFBbUIsR0FBRyxLQUFLLENBQUM7UUFDM0IsY0FBUyxHQUFnQyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQzVELFlBQU8sR0FBZ0MsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUMxRCxhQUFRLEdBQWdDLElBQUksWUFBWSxFQUFFLENBQUM7UUFDM0QsV0FBTSxHQUFnQyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ3pELFdBQU0sR0FBZ0MsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUMxRCxjQUFTLEdBQVE7WUFDL0IsTUFBTSxFQUFFLE9BQU87WUFDZixLQUFLLEVBQUUsT0FBTztZQUNkLGNBQWMsRUFBRSxNQUFNO1NBQ3ZCLENBQUM7UUFDZSxlQUFVLEdBQXNCLElBQUksWUFBWSxFQUFFLENBQUM7UUFLM0QsZUFBVSxHQUFlLFVBQVUsQ0FBQyxPQUFPLENB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O3NCQUFsQyxLQUFLO2dCQUNXLFNBQVM7c0JBQXpCLE1BQU07Z0JBQ1UsT0FBTztzQkFBdkIsTUFBTTtnQkFDVSxRQUFRO3NCQUF4QixNQUFNO2dCQUNVLE1BQU07c0JBQXRCLE1BQU07Z0JBQ1UsTUFBTTtzQkFBdEIsTUFBTTtnQkFDUyxTQUFTO3NCQUF4QixLQUFLO2dCQUtXLFVBQVU7c0JBQTFCLE1BQU07Z0JBQzJCLFlBQVk7c0JBQTdDLFlBQVk7dUJBQUMsV0FBVztnQkFHaEIsWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxVQUFVO3NCQUFsQixLQUFLO2dCQVErQyxjQUFjO3NCQUFsRSxZQUFZO3VCQUFDLGtCQUFrQixFQUFFLENBQUMsUUFBUSxDQUFDO2dCQWlCSCxTQUFTO3NCQUFqRCxZQUFZO3VCQUFDLGtCQUFrQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE5nRm9yT2ZDb250ZXh0IH0gZnJvbSBcIkBhbmd1bGFyL2NvbW1vblwiO1xuaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBJbnB1dCxcbiAgT3V0cHV0LFxuICBDb250ZW50Q2hpbGQsXG4gIEV2ZW50RW1pdHRlcixcbiAgVGVtcGxhdGVSZWYsXG4gIEhvc3RMaXN0ZW5lcixcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7IENvbW1hbmRLZXksIFNvcnRhYmxlRXZlbnQgfSBmcm9tIFwiLi4vLi4vdHlwZXMvbmd4LXNvcnRhYmxlLnR5cGVzXCI7XG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6IFwibmd4LXNvcnRhYmxlXCIsXG4gIHRlbXBsYXRlVXJsOiBcIi4vbmd4LXNvcnRhYmxlLmNvbXBvbmVudC5odG1sXCIsXG4gIHN0eWxlVXJsczogW1wiLi9uZ3gtc29ydGFibGUuY29tcG9uZW50LnNjc3NcIl0sXG59KVxuZXhwb3J0IGNsYXNzIE5neFNvcnRhYmxlQ29tcG9uZW50IHtcbiAgQElucHV0KCkgcHVibGljIGl0ZW1zOiBhbnlbXSA9IFtdO1xuICBASW5wdXQoKSBwdWJsaWMgbmFtZTogc3RyaW5nO1xuICBASW5wdXQoKSBwdWJsaWMgc2hvd0hlYWRlciA9IHRydWU7XG4gIEBJbnB1dCgpIHB1YmxpYyByZW1vdmVPbkRyb3BPdXRzaWRlID0gZmFsc2U7XG4gIEBPdXRwdXQoKSBwdWJsaWMgZHJhZ1N0YXJ0OiBFdmVudEVtaXR0ZXI8U29ydGFibGVFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gIEBPdXRwdXQoKSBwdWJsaWMgZHJvcHBlZDogRXZlbnRFbWl0dGVyPFNvcnRhYmxlRXZlbnQ+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBAT3V0cHV0KCkgcHVibGljIG1vdmVEb3duOiBFdmVudEVtaXR0ZXI8U29ydGFibGVFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gIEBPdXRwdXQoKSBwdWJsaWMgbW92ZVVwOiBFdmVudEVtaXR0ZXI8U29ydGFibGVFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gIEBPdXRwdXQoKSBwdWJsaWMgcmVtb3ZlOiBFdmVudEVtaXR0ZXI8U29ydGFibGVFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gIEBJbnB1dCgpIHB1YmxpYyBsaXN0U3R5bGU6IGFueSA9IHtcbiAgICBoZWlnaHQ6IFwiMjUwcHhcIixcbiAgICB3aWR0aDogXCIzMDBweFwiLFxuICAgIGRyb3Bab25lSGVpZ2h0OiBcIjUwcHhcIixcbiAgfTtcbiAgQE91dHB1dCgpIHB1YmxpYyBsaXN0U29ydGVkOiBFdmVudEVtaXR0ZXI8YW55PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgQENvbnRlbnRDaGlsZChUZW1wbGF0ZVJlZikgcHVibGljIGl0ZW1UZW1wbGF0ZTogVGVtcGxhdGVSZWY8XG4gICAgTmdGb3JPZkNvbnRleHQ8YW55PlxuICA+O1xuICBASW5wdXQoKSBhcnJvd0tleVNvcnQ6IGJvb2xlYW47XG4gIEBJbnB1dCgpIGNvbW1hbmRLZXk6IENvbW1hbmRLZXkgPSBDb21tYW5kS2V5LkN0cmxLZXk7XG4gIHB1YmxpYyBzZWxlY3RlZEl0ZW06IGFueTtcbiAgcHVibGljIGRyYWdnZWRJbmRleCA9IC0xO1xuICBwdWJsaWMgb25EcmFnT3ZlckluZGV4ID0gLTE7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIC8vIGNvbnNvbGUubG9nKCdJbnRpYWxpemluZy4uLicpO1xuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcihcImRvY3VtZW50OmtleWRvd25cIiwgW1wiJGV2ZW50XCJdKSBwdWJsaWMgb25BcnJvd0tleURvd24oXG4gICAgJGV2ZW50OiBLZXlib2FyZEV2ZW50XG4gICkge1xuICAgIC8qKiBpc3RhbmJ1bCBpZ25vcmUgZWxzZSAqL1xuICAgIGlmICh0aGlzLmFycm93S2V5U29ydCkge1xuICAgICAgLyoqIGlzdGFuYnVsIGlnbm9yZSBlbHNlICovXG4gICAgICBpZiAoJGV2ZW50LmtleSA9PT0gXCJBcnJvd1VwXCIgJiYgJGV2ZW50W3RoaXMuY29tbWFuZEtleV0pIHtcbiAgICAgICAgdGhpcy5vbk1vdmVVcCgkZXZlbnQpO1xuICAgICAgfVxuICAgICAgLyoqIGlzdGFuYnVsIGlnbm9yZSBlbHNlICovXG4gICAgICBpZiAoJGV2ZW50LmtleSA9PT0gXCJBcnJvd0Rvd25cIiAmJiAkZXZlbnRbdGhpcy5jb21tYW5kS2V5XSkge1xuICAgICAgICB0aGlzLm9uTW92ZURvd24oJGV2ZW50KTtcbiAgICAgIH1cbiAgICAgICRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH1cbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoXCJkb2N1bWVudDpkcmFnZW5kXCIpIHB1YmxpYyBvbkRyYWdFbmQoKSB7XG4gICAgaWYgKHRoaXMucmVtb3ZlT25Ecm9wT3V0c2lkZSkge1xuICAgICAgdGhpcy5vblJlbW92ZURyb3AoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5kcmFnZ2VkSW5kZXggPSAtMTtcbiAgICAgIHRoaXMub25EcmFnT3ZlckluZGV4ID0gLTE7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIHNlbGVjdEl0ZW0oaXRlbTogYW55KSB7XG4gICAgdGhpcy5zZWxlY3RlZEl0ZW0gPSBpdGVtO1xuICB9XG5cbiAgcHVibGljIG9uTW92ZVVwKCRldmVudD86IGFueSkge1xuICAgIGNvbnN0IGluZGV4ID0gdGhpcy5pdGVtcy5pbmRleE9mKHRoaXMuc2VsZWN0ZWRJdGVtKTtcbiAgICAvKiogaXN0YW5idWwgaWdub3JlIGVsc2UgKi9cbiAgICBpZiAoaW5kZXggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5zd2FwRWxlbWVudHMoaW5kZXgsIGluZGV4IC0gMSk7XG4gICAgdGhpcy5tb3ZlVXAuZW1pdCh7XG4gICAgICBldmVudDogJGV2ZW50LFxuICAgICAgaXRlbUluZGV4OiBpbmRleCxcbiAgICAgIG5ld0luZGV4OiBpbmRleCAtIDEsXG4gICAgICBpdGVtOiB0aGlzLnNlbGVjdGVkSXRlbSxcbiAgICB9KTtcbiAgICB0aGlzLmxpc3RTb3J0ZWQuZW1pdCh0aGlzLml0ZW1zKTtcbiAgfVxuXG4gIHB1YmxpYyBvbk1vdmVEb3duKCRldmVudD86IGFueSkge1xuICAgIGNvbnN0IGluZGV4ID0gdGhpcy5pdGVtcy5pbmRleE9mKHRoaXMuc2VsZWN0ZWRJdGVtKTtcbiAgICBpZiAoaW5kZXggPT09IHRoaXMuaXRlbXMubGVuZ3RoIC0gMSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLnN3YXBFbGVtZW50cyhpbmRleCwgaW5kZXggKyAxKTtcbiAgICB0aGlzLm1vdmVEb3duLmVtaXQoe1xuICAgICAgZXZlbnQ6ICRldmVudCxcbiAgICAgIGl0ZW1JbmRleDogaW5kZXgsXG4gICAgICBuZXdJbmRleDogaW5kZXggKyAxLFxuICAgICAgaXRlbTogdGhpcy5zZWxlY3RlZEl0ZW0sXG4gICAgfSk7XG4gICAgdGhpcy5saXN0U29ydGVkLmVtaXQodGhpcy5pdGVtcyk7XG4gIH1cbiAgcHVibGljIG9uRHJvcCgkZXZlbnQ6IGFueSwgaW5kZXg6IG51bWJlcikge1xuICAgIC8vIGluZGV4IGlzIG9mIHRoZSBlbGVtZW50IG9uIHdoaWNoIHRoZSBpdGVtIGlzIGRyb3BwZWRcbiAgICAvKiogaXN0YW5idWwgaWdub3JlIGVsc2UgKi9cbiAgICBpZiAoaW5kZXggPT09IHRoaXMuZHJhZ2dlZEluZGV4KSB7XG4gICAgICB0aGlzLmRyYWdnZWRJbmRleCA9IC0xO1xuICAgICAgdGhpcy5vbkRyYWdPdmVySW5kZXggPSAtMTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgZHJhZ0luZGV4ID0gdGhpcy5kcmFnZ2VkSW5kZXg7XG4gICAgdGhpcy5oYW5kbGVEcm9wKGluZGV4KTtcbiAgICB0aGlzLmRyb3BwZWQuZW1pdCh7XG4gICAgICBldmVudDogJGV2ZW50LFxuICAgICAgaXRlbUluZGV4OiBkcmFnSW5kZXgsXG4gICAgICBuZXdJbmRleDogaW5kZXgsXG4gICAgICBpdGVtOiB0aGlzLnNlbGVjdGVkSXRlbSxcbiAgICB9KTtcbiAgfVxuICBwdWJsaWMgYWxsb3dEcm9wKCRldmVudDogYW55LCBpbmRleDogbnVtYmVyKSB7XG4gICAgLy8gaW5kZXggaXMgb2YgdGhlIGl0ZW0gb24gd2hpY2ggdGhlIGl0ZW0gaXMgY3VycmVudGx5IGhvdmVyZWRcbiAgICB0aGlzLm9uRHJhZ092ZXJJbmRleCA9IGluZGV4O1xuICAgICRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICB9XG4gIHB1YmxpYyBvbkRyYWdTdGFydCgkZXZlbnQ6IGFueSwgaW5kZXg6IG51bWJlcikge1xuICAgIHRoaXMuc2VsZWN0SXRlbSh0aGlzLml0ZW1zW2luZGV4XSk7XG4gICAgdGhpcy5kcmFnZ2VkSW5kZXggPSBpbmRleDtcbiAgICB0aGlzLmRyYWdTdGFydC5lbWl0KHtcbiAgICAgIGV2ZW50OiAkZXZlbnQsXG4gICAgICBpdGVtSW5kZXg6IGluZGV4LFxuICAgICAgbmV3SW5kZXg6IC0xLFxuICAgICAgaXRlbTogdGhpcy5zZWxlY3RlZEl0ZW0sXG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgaGFuZGxlRHJvcChkcm9wcGVkSW5kZXg6IG51bWJlcikge1xuICAgIGNvbnN0IGl0ZW0gPSB0aGlzLml0ZW1zW3RoaXMuZHJhZ2dlZEluZGV4XTtcbiAgICB0aGlzLml0ZW1zLnNwbGljZSh0aGlzLmRyYWdnZWRJbmRleCwgMSk7XG4gICAgdGhpcy5pdGVtcy5zcGxpY2UoZHJvcHBlZEluZGV4LCAwLCBpdGVtKTtcbiAgICB0aGlzLmRyYWdnZWRJbmRleCA9IC0xO1xuICAgIHRoaXMub25EcmFnT3ZlckluZGV4ID0gLTE7XG4gICAgdGhpcy5saXN0U29ydGVkLmVtaXQodGhpcy5pdGVtcyk7XG4gIH1cblxuICBwdWJsaWMgc3dhcEVsZW1lbnRzKG9sZEluZGV4OiBudW1iZXIsIG5ld0luZGV4OiBudW1iZXIpIHtcbiAgICBjb25zdCB0ZW1wID0gdGhpcy5pdGVtc1tvbGRJbmRleF07XG4gICAgdGhpcy5pdGVtc1tvbGRJbmRleF0gPSB0aGlzLml0ZW1zW25ld0luZGV4XTtcbiAgICB0aGlzLml0ZW1zW25ld0luZGV4XSA9IHRlbXA7XG4gIH1cblxuICBwdWJsaWMgb25SZW1vdmVEcm9wKCkge1xuICAgIHRoaXMuaXRlbXMuc3BsaWNlKHRoaXMuZHJhZ2dlZEluZGV4LCAxKTtcbiAgICB0aGlzLnJlbW92ZS5lbWl0KHtcbiAgICAgIGl0ZW06IHRoaXMuc2VsZWN0ZWRJdGVtLFxuICAgICAgaXRlbUluZGV4OiB0aGlzLmRyYWdnZWRJbmRleCxcbiAgICB9KTtcbiAgICB0aGlzLmRyYWdnZWRJbmRleCA9IC0xO1xuICAgIHRoaXMub25EcmFnT3ZlckluZGV4ID0gLTE7XG4gICAgdGhpcy5saXN0U29ydGVkLmVtaXQodGhpcy5pdGVtcyk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJzb3J0YWJsZS1jb250YWluZXJcIiBbc3R5bGUud2lkdGhdPSdsaXN0U3R5bGUud2lkdGgnPlxuICA8ZGl2IGNsYXNzPVwic29ydGFibGUtaGVhZGVyXCIgKm5nSWY9XCJzaG93SGVhZGVyXCI+XG4gICAgPGxhYmVsIGNsYXNzPVwic29ydGFibGUtbmFtZVwiPnt7bmFtZX19PC9sYWJlbD5cbiAgICA8ZGl2IGNsYXNzPVwic29ydGFibGUtYnV0dG9uc1wiPlxuICAgICAgPGJ1dHRvbiAoY2xpY2spPVwib25Nb3ZlVXAoKVwiIFtkaXNhYmxlZF09XCIhc2VsZWN0ZWRJdGVtXCIgdGl0bGU9XCJNb3ZlIFVwXCI+JiM4Njc5OzwvYnV0dG9uPlxuICAgICAgPGJ1dHRvbiAoY2xpY2spPVwib25Nb3ZlRG93bigpXCIgW2Rpc2FibGVkXT1cIiFzZWxlY3RlZEl0ZW1cIiB0aXRsZT1cIk1vdmUgRG93blwiPiYjODY4MTs8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG4gIDx1bCBjbGFzcz1cInNvcnRhYmxlLWxpc3RcIiBbc3R5bGUuaGVpZ2h0XT0nbGlzdFN0eWxlLmhlaWdodCc+XG4gICAgPGxpIGRyYWdnYWJsZT1cInRydWVcIiAoY2xpY2spPVwic2VsZWN0SXRlbShpdGVtKVwiICpuZ0Zvcj1cImxldCBpdGVtIG9mIGl0ZW1zOyBsZXQgaSA9IGluZGV4O1wiXG4gICAgICBbbmdDbGFzc109XCJ7J2FjdGl2ZSc6IGl0ZW0gPT0gc2VsZWN0ZWRJdGVtfVwiIChkcm9wKT1cIm9uRHJvcCgkZXZlbnQsIGkpXCIgKGRyYWdvdmVyKT1cImFsbG93RHJvcCgkZXZlbnQsaSlcIlxuICAgICAgKGRyYWdzdGFydCk9XCJvbkRyYWdTdGFydCgkZXZlbnQsIGkpXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiZHJvcC16b25lXCIgW3N0eWxlLmhlaWdodF09XCJsaXN0U3R5bGUuZHJvcFpvbmVIZWlnaHRcIiAqbmdJZj1cIm9uRHJhZ092ZXJJbmRleCA9PSBpICYmIGk9PTBcIj5cbiAgICAgIDwvZGl2PlxuICAgICAgPG5nLXRlbXBsYXRlIFtuZ1RlbXBsYXRlT3V0bGV0XT1cIml0ZW1UZW1wbGF0ZVwiIFtuZ1RlbXBsYXRlT3V0bGV0Q29udGV4dF09XCJ7XG4gICAgICAgIGl0ZW06IGl0ZW0sXG4gICAgICAgIGluZGV4OiBpXG4gICAgICB9XCI+XG4gICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgPGRpdiBjbGFzcz1cImRyb3Atem9uZVwiIFtzdHlsZS5oZWlnaHRdPVwibGlzdFN0eWxlLmRyb3Bab25lSGVpZ2h0XCIgKm5nSWY9XCJvbkRyYWdPdmVySW5kZXggPT0gaSAmJiBpIT0wXCI+XG4gICAgICA8L2Rpdj5cbiAgICA8L2xpPlxuICA8L3VsPlxuPC9kaXY+Il19