ngx-tree-dnd
Version:
Angular 7 support tree with drag-and-drop sortable data tree. It`s fast and smart.
848 lines • 55.3 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import * as tslib_1 from "tslib";
/*
Copyright (C) 2018 Yaroslav Kikot
This project is licensed under the terms of the MIT license.
https://github.com/Zicrael/ngx-tree-dnd
*/
import { Injectable } from '@angular/core';
import { Subject, BehaviorSubject, Observable } from 'rxjs';
import * as i0 from "@angular/core";
var NgxTreeService = /** @class */ (function () {
function NgxTreeService() {
this.treeStorage = [];
this.onDragStart = new Subject();
this.onDragEnter = new Subject();
this.onDragLeave = new Subject();
this.onDrop = new Subject();
this.onDrag = new Subject();
this.onAllowDrop = new Subject();
this.onDragEnd = new Subject();
this.onAddItem = new Subject();
this.onRenameItem = new Subject();
this.onStartRenameItem = new Subject();
this.onFinishRenameItem = new Subject();
this.onStartDeleteItem = new Subject();
this.onFinishDeleteItem = new Subject();
this.onCancelDeleteItem = new Subject();
this.config = new BehaviorSubject(null);
// set default config
this.defaulConfig = {
showActionButtons: true,
showAddButtons: true,
showRenameButtons: true,
showDeleteButtons: true,
showRootActionButtons: true,
enableExpandButtons: true,
enableDragging: true,
rootTitle: 'Root',
validationText: 'Enter valid name',
minCharacterLength: 1,
setItemsAsLinks: false,
setFontSize: 16,
setIconSize: 14
};
}
/*
get data and set it on observable.
if data = null set empty data array
*/
/*
get data and set it on observable.
if data = null set empty data array
*/
/**
* @param {?} item
* @return {?}
*/
NgxTreeService.prototype.getLocalData = /*
get data and set it on observable.
if data = null set empty data array
*/
/**
* @param {?} item
* @return {?}
*/
function (item) {
var _this = this;
/** @type {?} */
var data = new Observable(function (observer) {
_this.treeStorage = item;
if (_this.treeStorage && _this.treeStorage !== null) {
observer.next(_this.treeStorage);
}
else {
_this.treeStorage = JSON.parse('[]');
observer.next(_this.treeStorage);
}
});
return data;
};
/*
Element finder, it`s find element by id in tree.
Returns: finded element, parent array.
Watch out, this is recursive method.
*/
/*
Element finder, it`s find element by id in tree.
Returns: finded element, parent array.
Watch out, this is recursive method.
*/
/**
* @private
* @param {?} list
* @param {?} id
* @param {?=} parent
* @return {?}
*/
NgxTreeService.prototype.elementFinder = /*
Element finder, it`s find element by id in tree.
Returns: finded element, parent array.
Watch out, this is recursive method.
*/
/**
* @private
* @param {?} list
* @param {?} id
* @param {?=} parent
* @return {?}
*/
function (list, id, parent) {
var e_1, _a;
try {
for (var list_1 = tslib_1.__values(list), list_1_1 = list_1.next(); !list_1_1.done; list_1_1 = list_1.next()) {
var item = list_1_1.value;
if (item.id === id) {
this.findingResults = {
foundItem: item,
itemsList: list
};
if (parent) {
this.findingResults.parentItem = parent;
}
break;
}
else {
if (item.childrens.length > 0) {
this.elementFinder(item.childrens, id, item);
}
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (list_1_1 && !list_1_1.done && (_a = list_1.return)) _a.call(list_1);
}
finally { if (e_1) throw e_1.error; }
}
};
/*
Add new item to tree.
Its accepts 'type' for detect add root element or children.
Emit onAddItem Subject.
*/
/*
Add new item to tree.
Its accepts 'type' for detect add root element or children.
Emit onAddItem Subject.
*/
/**
* @param {?} id
* @param {?} name
* @param {?=} parent
* @return {?}
*/
NgxTreeService.prototype.addNewItem = /*
Add new item to tree.
Its accepts 'type' for detect add root element or children.
Emit onAddItem Subject.
*/
/**
* @param {?} id
* @param {?} name
* @param {?=} parent
* @return {?}
*/
function (id, name, parent) {
/** @type {?} */
var pos = 1;
if (parent && parent.childrens.length !== 0) {
/** @type {?} */
var parentPrevChildren = parent.childrens.length - 1;
/** @type {?} */
var newItemPosition = parent.childrens[parentPrevChildren].options.position + 1;
pos = newItemPosition;
}
/** @type {?} */
var createObj = {
id: id,
name: name,
options: {
position: pos,
edit: true
},
childrens: []
};
if (parent != null) {
this.elementFinder(this.treeStorage, parent ? parent.id : null);
this.findingResults && this.findingResults.foundItem.childrens.push(createObj);
}
else {
this.treeStorage.push(createObj);
}
/** @type {?} */
var eventEmit = {
element: createObj,
parent: parent ? this.findingResults.foundItem : 'root'
};
this.onAddItem.next(eventEmit);
this.clearAction();
};
/*
Delete element.
It`s accepts 'id' for find item on tree.
Emit onStartDeleteItem Subject before delete.
Emit onFinishDeleteItem Subject after submit delete.
Emit onCancelDeleteItem Subject after on cancel delete.
*/
/*
Delete element.
It`s accepts 'id' for find item on tree.
Emit onStartDeleteItem Subject before delete.
Emit onFinishDeleteItem Subject after submit delete.
Emit onCancelDeleteItem Subject after on cancel delete.
*/
/**
* @param {?} id
* @return {?}
*/
NgxTreeService.prototype.deleteItem = /*
Delete element.
It`s accepts 'id' for find item on tree.
Emit onStartDeleteItem Subject before delete.
Emit onFinishDeleteItem Subject after submit delete.
Emit onCancelDeleteItem Subject after on cancel delete.
*/
/**
* @param {?} id
* @return {?}
*/
function (id) {
this.elementFinder(this.treeStorage, id);
/** @type {?} */
var eventEmit = {
element: this.findingResults.foundItem,
parent: this.findingResults.parentItem || 'root'
};
this.onStartDeleteItem.next(eventEmit);
/** @type {?} */
var text;
if (this.findingResults.foundItem.name) {
text = "Do you really want to delete '" + this.findingResults.foundItem.name + "'?";
}
else {
text = "Cancel creating a new item?";
}
if (confirm(text)) {
this.onFinishDeleteItem.next(eventEmit);
/** @type {?} */
var i = this.findingResults.itemsList.indexOf(this.findingResults.foundItem);
this.findingResults.itemsList.splice(i, 1);
}
else {
this.onCancelDeleteItem.next(eventEmit);
}
this.clearAction();
};
/*
Trigger start rename element.
It`s accepts 'name' and 'id' for find item on tree and set the name.
Emit onRenameItem Subject.
*/
/*
Trigger start rename element.
It`s accepts 'name' and 'id' for find item on tree and set the name.
Emit onRenameItem Subject.
*/
/**
* @param {?} element
* @return {?}
*/
NgxTreeService.prototype.startRenameItem = /*
Trigger start rename element.
It`s accepts 'name' and 'id' for find item on tree and set the name.
Emit onRenameItem Subject.
*/
/**
* @param {?} element
* @return {?}
*/
function (element) {
this.elementFinder(this.treeStorage, element.id);
// event emit
/** @type {?} */
var eventEmit = {
element: this.findingResults.foundItem,
parent: this.findingResults.parentItem || 'root'
};
this.onStartRenameItem.next(eventEmit);
};
/*
Rename element.
It`s accepts 'name' and 'id' for find item on tree and set the name.
Emit onRenameItem Subject.
*/
/*
Rename element.
It`s accepts 'name' and 'id' for find item on tree and set the name.
Emit onRenameItem Subject.
*/
/**
* @param {?} name
* @param {?} id
* @return {?}
*/
NgxTreeService.prototype.finishRenameItem = /*
Rename element.
It`s accepts 'name' and 'id' for find item on tree and set the name.
Emit onRenameItem Subject.
*/
/**
* @param {?} name
* @param {?} id
* @return {?}
*/
function (name, id) {
this.elementFinder(this.treeStorage, id);
// code
this.findingResults.foundItem.name = name;
this.findingResults.foundItem.options.edit = false;
// event emit
/** @type {?} */
var eventEmit = {
element: this.findingResults.foundItem,
parent: this.findingResults.parentItem || 'root'
};
this.onFinishRenameItem.next(eventEmit);
this.clearAction();
};
/*
Event: ondragstart;
On start dragging find element my id and set option currentlyDragging true.
*/
/*
Event: ondragstart;
On start dragging find element my id and set option currentlyDragging true.
*/
/**
* @param {?} eventObj
* @return {?}
*/
NgxTreeService.prototype.startDragging = /*
Event: ondragstart;
On start dragging find element my id and set option currentlyDragging true.
*/
/**
* @param {?} eventObj
* @return {?}
*/
function (eventObj) {
this.switchDropButton(true, this.treeStorage);
this.onDragStart.next(eventObj);
};
/*
Event: ondrag;
Trigger dragging element
*/
/*
Event: ondrag;
Trigger dragging element
*/
/**
* @param {?} eventObj
* @return {?}
*/
NgxTreeService.prototype.onDragProcess = /*
Event: ondrag;
Trigger dragging element
*/
/**
* @param {?} eventObj
* @return {?}
*/
function (eventObj) {
this.onDrag.next(eventObj);
};
/*
Event: ondragend;
detect end of drag action
*/
/*
Event: ondragend;
detect end of drag action
*/
/**
* @param {?} eventObj
* @return {?}
*/
NgxTreeService.prototype.dragEndAction = /*
Event: ondragend;
detect end of drag action
*/
/**
* @param {?} eventObj
* @return {?}
*/
function (eventObj) {
this.removeDestenationBorders(this.treeStorage);
this.switchDropButton(false, this.treeStorage);
this.onDragEnd.next(eventObj);
};
/*
Event: enterdropzone;
Entering drop zone for styling items.
*/
/*
Event: enterdropzone;
Entering drop zone for styling items.
*/
/**
* @param {?} eventObj
* @return {?}
*/
NgxTreeService.prototype.enterDropZone = /*
Event: enterdropzone;
Entering drop zone for styling items.
*/
/**
* @param {?} eventObj
* @return {?}
*/
function (eventObj) {
this.onDragEnter.next(eventObj);
};
/*
Event: dragover;
Detect hover on dropable elements
*/
/*
Event: dragover;
Detect hover on dropable elements
*/
/**
* @param {?} eventObj
* @return {?}
*/
NgxTreeService.prototype.onDragOver = /*
Event: dragover;
Detect hover on dropable elements
*/
/**
* @param {?} eventObj
* @return {?}
*/
function (eventObj) {
/** @type {?} */
var el = ((/** @type {?} */ (eventObj.target)));
if (el && el.id !== this.isDragging.id) {
/** @type {?} */
var elementHalfHeight = eventObj.event.toElement.offsetHeight / 2;
if (eventObj.event.offsetY < elementHalfHeight) {
el.options.destenationBottom = false;
el.options.destenationTop = true;
}
else {
el.options.destenationBottom = true;
el.options.destenationTop = false;
}
this.onAllowDrop.next(eventObj);
}
};
/*
Event: leavedropzone;
Leave drop zone for restyling items.
*/
/*
Event: leavedropzone;
Leave drop zone for restyling items.
*/
/**
* @param {?} eventObj
* @return {?}
*/
NgxTreeService.prototype.leaveDropZone = /*
Event: leavedropzone;
Leave drop zone for restyling items.
*/
/**
* @param {?} eventObj
* @return {?}
*/
function (eventObj) {
this.removeDestenationBorders(this.treeStorage);
this.onDragLeave.next(eventObj);
};
/*
Event: ondrop;
Its use where draggable item drop not on allowed for drop zone:
set item option currentlyDragging false.
return false.
*/
/*
Event: ondrop;
Its use where draggable item drop not on allowed for drop zone:
set item option currentlyDragging false.
return false.
*/
/**
* @param {?} eventObj
* @return {?}
*/
NgxTreeService.prototype.onDropItem = /*
Event: ondrop;
Its use where draggable item drop not on allowed for drop zone:
set item option currentlyDragging false.
return false.
*/
/**
* @param {?} eventObj
* @return {?}
*/
function (eventObj) {
if (eventObj.target) {
/** @type {?} */
var elementHalfHeight = eventObj.event.toElement.offsetHeight / 2;
if (eventObj.event.offsetY < elementHalfHeight) {
this.changeItemPosition(eventObj.target, 'up');
}
else {
this.changeItemPosition(eventObj.target, 'down');
}
this.onDrop.next(eventObj);
}
else {
/** @type {?} */
var dropZoneId = parseInt(eventObj.event.target.getAttribute('data-id'), null);
this.elementFinder(this.treeStorage, this.isDragging.id);
/** @type {?} */
var i = this.findingResults.itemsList.indexOf(this.findingResults.foundItem);
/** @type {?} */
var copyItem = this.findingResults.itemsList.splice(i, 1)[0];
this.elementFinder(this.treeStorage, dropZoneId);
this.findingResults.foundItem.childrens.push(copyItem);
// this.sortTree();
eventObj.target = this.findingResults.foundItem;
this.onDrop.next(eventObj);
}
this.removeDestenationBorders(this.treeStorage);
this.switchDropButton(false, this.treeStorage);
this.clearAction();
};
/*
change position of items
need set direction before use
*/
/*
change position of items
need set direction before use
*/
/**
* @private
* @param {?} el
* @param {?} direction
* @return {?}
*/
NgxTreeService.prototype.changeItemPosition = /*
change position of items
need set direction before use
*/
/**
* @private
* @param {?} el
* @param {?} direction
* @return {?}
*/
function (el, direction) {
var _this = this;
setTimeout(function () {
var e_2, _a, e_3, _b;
_this.elementFinder(_this.treeStorage, _this.isDragging.id);
/** @type {?} */
var i = _this.findingResults.itemsList.indexOf(_this.findingResults.foundItem);
/** @type {?} */
var copyItem = _this.findingResults.itemsList.splice(i, 1)[0];
// end test
/** @type {?} */
var positionTarget = el.options.position;
_this.elementFinder(_this.treeStorage, el.id);
if (direction === 'up') {
try {
for (var _c = tslib_1.__values(_this.findingResults.itemsList), _d = _c.next(); !_d.done; _d = _c.next()) {
var items = _d.value;
if (items.options.position >= positionTarget) {
items.options.position = items.options.position + 1;
copyItem.options.position = positionTarget;
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
}
finally { if (e_2) throw e_2.error; }
}
}
else {
try {
for (var _e = tslib_1.__values(_this.findingResults.itemsList), _f = _e.next(); !_f.done; _f = _e.next()) {
var items = _f.value;
if (items.options.position <= positionTarget) {
items.options.position = items.options.position - 1;
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
}
finally { if (e_3) throw e_3.error; }
}
}
copyItem.options.position = positionTarget;
_this.findingResults.itemsList.push(copyItem);
_this.sortTree();
});
};
// get position of item
// get position of item
/**
* @param {?} item
* @return {?}
*/
NgxTreeService.prototype.getItemPosition =
// get position of item
/**
* @param {?} item
* @return {?}
*/
function (item) {
this.elementFinder(this.treeStorage, item.id);
/** @type {?} */
var position = this.findingResults.itemsList.indexOf(this.findingResults.foundItem);
return ++position;
};
// sort tree byposition
// sort tree byposition
/**
* @return {?}
*/
NgxTreeService.prototype.sortTree =
// sort tree byposition
/**
* @return {?}
*/
function () {
this.sortElements(this.treeStorage);
};
// part of sortTree()
// part of sortTree()
/**
* @private
* @param {?} tree
* @return {?}
*/
NgxTreeService.prototype.sortElements =
// part of sortTree()
/**
* @private
* @param {?} tree
* @return {?}
*/
function (tree) {
var e_4, _a;
tree.sort(this.compate);
try {
for (var tree_1 = tslib_1.__values(tree), tree_1_1 = tree_1.next(); !tree_1_1.done; tree_1_1 = tree_1.next()) {
var item = tree_1_1.value;
if (item.childrens.length > 0) {
this.sortElements(item.childrens);
}
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (tree_1_1 && !tree_1_1.done && (_a = tree_1.return)) _a.call(tree_1);
}
finally { if (e_4) throw e_4.error; }
}
};
// part of sortTree()
// part of sortTree()
/**
* @private
* @param {?} a
* @param {?} b
* @return {?}
*/
NgxTreeService.prototype.compate =
// part of sortTree()
/**
* @private
* @param {?} a
* @param {?} b
* @return {?}
*/
function (a, b) {
if (a.options.position < b.options.position) {
return -1;
}
if (a.options.position > b.options.position) {
return 1;
}
return 0;
};
// clear selectedElement && isDragging from element finder.
// clear selectedElement && isDragging from element finder.
/**
* @return {?}
*/
NgxTreeService.prototype.clearAction =
// clear selectedElement && isDragging from element finder.
/**
* @return {?}
*/
function () {
this.findingResults = null;
};
/**
* @private
* @param {?} data
* @return {?}
*/
NgxTreeService.prototype.removeDestenationBorders = /**
* @private
* @param {?} data
* @return {?}
*/
function (data) {
var e_5, _a;
try {
for (var data_1 = tslib_1.__values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
var item = data_1_1.value;
item.options.destenationBottom = false;
item.options.destenationTop = false;
if (item.childrens.length > 0) {
this.removeDestenationBorders(item.childrens);
}
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
}
finally { if (e_5) throw e_5.error; }
}
};
/**
* @private
* @param {?} bool
* @param {?} data
* @return {?}
*/
NgxTreeService.prototype.switchDropButton = /**
* @private
* @param {?} bool
* @param {?} data
* @return {?}
*/
function (bool, data) {
var e_6, _a;
try {
for (var data_2 = tslib_1.__values(data), data_2_1 = data_2.next(); !data_2_1.done; data_2_1 = data_2.next()) {
var el = data_2_1.value;
el.options.showActionButtons = !bool;
if (el.id !== this.isDragging.id) {
el.options.showDropChildZone = bool;
}
if (el.childrens.length > 0) {
this.switchDropButton(bool, el.childrens);
}
}
}
catch (e_6_1) { e_6 = { error: e_6_1 }; }
finally {
try {
if (data_2_1 && !data_2_1.done && (_a = data_2.return)) _a.call(data_2);
}
finally { if (e_6) throw e_6.error; }
}
};
NgxTreeService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] },
];
/** @nocollapse */
NgxTreeService.ctorParameters = function () { return []; };
/** @nocollapse */ NgxTreeService.ngInjectableDef = i0.defineInjectable({ factory: function NgxTreeService_Factory() { return new NgxTreeService(); }, token: NgxTreeService, providedIn: "root" });
return NgxTreeService;
}());
export { NgxTreeService };
if (false) {
/** @type {?} */
NgxTreeService.prototype.treeStorage;
/**
* @type {?}
* @private
*/
NgxTreeService.prototype.findingResults;
/** @type {?} */
NgxTreeService.prototype.isDragging;
/** @type {?} */
NgxTreeService.prototype.dragEvent;
/** @type {?} */
NgxTreeService.prototype.direction;
/** @type {?} */
NgxTreeService.prototype.lastExpandState;
/** @type {?} */
NgxTreeService.prototype.onDragStart;
/** @type {?} */
NgxTreeService.prototype.onDragEnter;
/** @type {?} */
NgxTreeService.prototype.onDragLeave;
/** @type {?} */
NgxTreeService.prototype.onDrop;
/** @type {?} */
NgxTreeService.prototype.onDrag;
/** @type {?} */
NgxTreeService.prototype.onAllowDrop;
/** @type {?} */
NgxTreeService.prototype.onDragEnd;
/** @type {?} */
NgxTreeService.prototype.onAddItem;
/** @type {?} */
NgxTreeService.prototype.onRenameItem;
/** @type {?} */
NgxTreeService.prototype.onStartRenameItem;
/** @type {?} */
NgxTreeService.prototype.onFinishRenameItem;
/** @type {?} */
NgxTreeService.prototype.onStartDeleteItem;
/** @type {?} */
NgxTreeService.prototype.onFinishDeleteItem;
/** @type {?} */
NgxTreeService.prototype.onCancelDeleteItem;
/** @type {?} */
NgxTreeService.prototype.config;
/** @type {?} */
NgxTreeService.prototype.defaulConfig;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXRyZWUtZG5kLnNlcnZpY2UuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtdHJlZS1kbmQvIiwic291cmNlcyI6WyJsaWIvbmd4LXRyZWUtZG5kLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7OztBQUtBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLE9BQU8sRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLE1BQU0sTUFBTSxDQUFDOztBQUc1RDtJQThCRTtRQTFCQSxnQkFBVyxHQUFnQixFQUFFLENBQUM7UUFTOUIsZ0JBQVcsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQ2pDLGdCQUFXLEdBQUcsSUFBSSxPQUFPLEVBQU8sQ0FBQztRQUNqQyxnQkFBVyxHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDakMsV0FBTSxHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDNUIsV0FBTSxHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDNUIsZ0JBQVcsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQ2pDLGNBQVMsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQy9CLGNBQVMsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQy9CLGlCQUFZLEdBQUcsSUFBSSxPQUFPLEVBQU8sQ0FBQztRQUNsQyxzQkFBaUIsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQ3ZDLHVCQUFrQixHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDeEMsc0JBQWlCLEdBQUcsSUFBSSxPQUFPLEVBQU8sQ0FBQztRQUN2Qyx1QkFBa0IsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQ3hDLHVCQUFrQixHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDeEMsV0FBTSxHQUFHLElBQUksZUFBZSxDQUFNLElBQUksQ0FBQyxDQUFDO1FBSXRDLHFCQUFxQjtRQUNyQixJQUFJLENBQUMsWUFBWSxHQUFH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cmlnaHQgKEMpIDIwMTggWWFyb3NsYXYgS2lrb3RcbiBUaGlzIHByb2plY3QgaXMgbGljZW5zZWQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBNSVQgbGljZW5zZS5cbiBodHRwczovL2dpdGh1Yi5jb20vWmljcmFlbC9uZ3gtdHJlZS1kbmRcbiAqL1xuaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3ViamVjdCwgQmVoYXZpb3JTdWJqZWN0LCBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBUcmVlTW9kZWwsIFRyZWVDb25maWcsIEZpbmRpbmdSZXN1bHRzIH0gZnJvbSAnLi9tb2RlbHMvdHJlZS12aWV3Lm1vZGVsJztcblxuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCdcbn0pXG5leHBvcnQgY2xhc3MgTmd4VHJlZVNlcnZpY2Uge1xuICB0cmVlU3RvcmFnZTogVHJlZU1vZGVsW10gPSBbXTtcbiAgcHJpdmF0ZSBmaW5kaW5nUmVzdWx0czogRmluZGluZ1Jlc3VsdHM7XG4gIC8vIGxpc3RPZlNlbGVjdGVkRWxlbWVudDogVHJlZU1vZGVsW107XG4gIC8vIHBhcmVudE9mU2VsZWN0ZWQ6IFRyZWVNb2RlbDtcbiAgLy8gcHJpdmF0ZSBzZWxlY3RlZEVsZW1lbnQ6IFRyZWVNb2RlbDtcbiAgaXNEcmFnZ2luZzogVHJlZU1vZGVsO1xuICBkcmFnRXZlbnQ6IHt9O1xuICBkaXJlY3Rpb246IHN0cmluZztcbiAgbGFzdEV4cGFuZFN0YXRlOiBib29sZWFuO1xuICBvbkRyYWdTdGFydCA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgb25EcmFnRW50ZXIgPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uRHJhZ0xlYXZlID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICBvbkRyb3AgPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uRHJhZyA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgb25BbGxvd0Ryb3AgPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uRHJhZ0VuZCA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgb25BZGRJdGVtID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICBvblJlbmFtZUl0ZW0gPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uU3RhcnRSZW5hbWVJdGVtID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICBvbkZpbmlzaFJlbmFtZUl0ZW0gPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uU3RhcnREZWxldGVJdGVtID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICBvbkZpbmlzaERlbGV0ZUl0ZW0gPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uQ2FuY2VsRGVsZXRlSXRlbSA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgY29uZmlnID0gbmV3IEJlaGF2aW9yU3ViamVjdDxhbnk+KG51bGwpO1xuICBkZWZhdWxDb25maWc6IFRyZWVDb25maWc7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgLy8gc2V0IGRlZmF1bHQgY29uZmlnXG4gICAgdGhpcy5kZWZhdWxDb25maWcgPSB7XG4gICAgICBzaG93QWN0aW9uQnV0dG9uczogdHJ1ZSxcbiAgICAgIHNob3dBZGRCdXR0b25zOiB0cnVlLFxuICAgICAgc2hvd1JlbmFtZUJ1dHRvbnM6IHRydWUsXG4gICAgICBzaG93RGVsZXRlQnV0dG9uczogdHJ1ZSxcbiAgICAgIHNob3dSb290QWN0aW9uQnV0dG9uczogdHJ1ZSxcbiAgICAgIGVuYWJsZUV4cGFuZEJ1dHRvbnM6IHRydWUsXG4gICAgICBlbmFibGVEcmFnZ2luZzogdHJ1ZSxcbiAgICAgIHJvb3RUaXRsZTogJ1Jvb3QnLFxuICAgICAgdmFsaWRhdGlvblRleHQ6ICdFbnRlciB2YWxpZCBuYW1lJyxcbiAgICAgIG1pbkNoYXJhY3Rlckxlbmd0aDogMSxcbiAgICAgIHNldEl0ZW1zQXNMaW5rczogZmFsc2UsXG4gICAgICBzZXRGb250U2l6ZTogMTYsXG4gICAgICBzZXRJY29uU2l6ZTogMTRcbiAgICB9O1xuICB9XG5cbiAgLypcbiAgICBnZXQgZGF0YSBhbmQgc2V0IGl0IG9uIG9ic2VydmFibGUuXG4gICAgaWYgZGF0YSA9IG51bGwgc2V0IGVtcHR5IGRhdGEgYXJyYXlcbiAgKi9cbiAgcHVibGljIGdldExvY2FsRGF0YShpdGVtKSB7XG4gICAgY29uc3QgZGF0YSA9IG5ldyBPYnNlcnZhYmxlKG9ic2VydmVyID0+IHtcbiAgICB0aGlzLnRyZWVTdG9yYWdlID0gaXRlbTtcbiAgICAgIGlmICggdGhpcy50cmVlU3RvcmFnZSAmJiB0aGlzLnRyZWVTdG9yYWdlICE9PSBudWxsICkge1xuICAgICAgICBvYnNlcnZlci5uZXh0KHRoaXMudHJlZVN0b3JhZ2UpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy50cmVlU3RvcmFnZSAgPSBKU09OLnBhcnNlKCdbXScpO1xuICAgICAgICBvYnNlcnZlci5uZXh0KHRoaXMudHJlZVN0b3JhZ2UpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBkYXRhO1xuICB9XG5cbiAgLypcbiAgIEVsZW1lbnQgZmluZGVyLCBpdGBzIGZpbmQgZWxlbWVudCBieSBpZCBpbiB0cmVlLlxuICAgUmV0dXJuczogZmluZGVkIGVsZW1lbnQsIHBhcmVudCBhcnJheS5cbiAgIFdhdGNoIG91dCwgdGhpcyBpcyByZWN1cnNpdmUgbWV0aG9kLlxuICAqL1xuICAgcHJpdmF0ZSBlbGVtZW50RmluZGVyKGxpc3QsIGlkLCBwYXJlbnQ/KSB7XG4gICAgIGZvciAoY29uc3QgaXRlbSBvZiBsaXN0KSB7XG4gICAgICAgaWYgKGl0ZW0uaWQgPT09IGlkKSB7XG4gICAgICAgICB0aGlzLmZpbmRpbmdSZXN1bHRzID0ge1xuICAgICAgICAgICBmb3VuZEl0ZW06IGl0ZW0sXG4gICAgICAgICAgIGl0ZW1zTGlzdDogbGlzdFxuICAgICAgICAgfVxuICAgICAgICAgaWYgKHBhcmVudCkge1xuICAgICAgICAgICB0aGlzLmZpbmRpbmdSZXN1bHRzLnBhcmVudEl0ZW0gPSBwYXJlbnQ7XG4gICAgICAgICB9XG4gICAgICAgICBicmVhaztcbiAgICAgICB9IGVsc2Uge1xuICAgICAgICAgaWYgKGl0ZW0uY2hpbGRyZW5zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgdGhpcy5lbGVtZW50RmluZGVyKGl0ZW0uY2hpbGRyZW5zLCBpZCwgaXRlbSk7XG4gICAgICAgICB9XG4gICAgICAgfVxuICAgICB9XG5cbiAgfVxuXG5cbiAgIC8qXG4gICBBZGQgbmV3IGl0ZW0gdG8gdHJlZS5cbiAgIEl0cyBhY2NlcHRzICd0eXBlJyBmb3IgZGV0ZWN0IGFkZCByb290IGVsZW1lbnQgb3IgY2hpbGRyZW4uXG4gICBFbWl0IG9uQWRkSXRlbSBTdWJqZWN0LlxuICAqL1xuICBwdWJsaWMgYWRkTmV3SXRlbShpZCwgbmFtZSwgcGFyZW50Pykge1xuICAgIGxldCBwb3MgPSAxO1xuICAgIGlmIChwYXJlbnQgJiYgcGFyZW50LmNoaWxkcmVucy5sZW5ndGggIT09IDApIHtcbiAgICAgIGNvbnN0IHBhcmVudFByZXZDaGlsZHJlbiA9IHBhcmVudC5jaGlsZHJlbnMubGVuZ3RoIC0gMTtcbiAgICAgIGNvbnN0IG5ld0l0ZW1Qb3NpdGlvbiA9IHBhcmVudC5jaGlsZHJlbnNbcGFyZW50UHJldkNoaWxkcmVuXS5vcHRpb25zLnBvc2l0aW9uICsgMTtcbiAgICAgIHBvcyA9IG5ld0l0ZW1Qb3NpdGlvbjtcbiAgICB9XG4gICAgY29uc3QgY3JlYXRlT2JqOiBUcmVlTW9kZWwgPSB7XG4gICAgICBpZCxcbiAgICAgIG5hbWUsXG4gICAgICBvcHRpb25zOiAge1xuICAgICAgICBwb3NpdGlvbjogcG9zLFxuICAgICAgICBlZGl0OiB0cnVlXG4gICAgICB9LFxuICAgICAgY2hpbGRyZW5zOiBbXVxuICAgIH07XG4gICAgXG4gICAgaWYocGFyZW50ICE9IG51bGwpIHtcbiAgICAgIHRoaXMuZWxlbWVudEZpbmRlcih0aGlzLnRyZWVTdG9yYWdlLCBwYXJlbnQgPyBwYXJlbnQuaWQgOiBudWxsKTtcbiAgICAgIHRoaXMuZmluZGluZ1Jlc3VsdHMgJiYgdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0uY2hpbGRyZW5zLnB1c2goY3JlYXRlT2JqKTtcbiAgICB9XG4gICAgZWxzZXtcbiAgICAgIHRoaXMudHJlZVN0b3JhZ2UucHVzaChjcmVhdGVPYmopO1xuICAgIH1cbiAgICBcbiAgICBjb25zdCBldmVudEVtaXQgPSB7XG4gICAgICBlbGVtZW50OiBjcmVhdGVPYmosXG4gICAgICBwYXJlbnQ6IHBhcmVudCA/IHRoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtIDogJ3Jvb3QnXG4gICAgfTtcblxuICAgIHRoaXMub25BZGRJdGVtLm5leHQoZXZlbnRFbWl0KTtcbiAgICB0aGlzLmNsZWFyQWN0aW9uKCk7XG4gIH1cblxuICAvKlxuICAgRGVsZXRlIGVsZW1lbnQuXG4gICBJdGBzIGFjY2VwdHMgJ2lkJyBmb3IgZmluZCBpdGVtIG9uIHRyZWUuXG4gICBFbWl0IG9uU3RhcnREZWxldGVJdGVtIFN1YmplY3QgYmVmb3JlIGRlbGV0ZS5cbiAgIEVtaXQgb25GaW5pc2hEZWxldGVJdGVtIFN1YmplY3QgYWZ0ZXIgc3VibWl0IGRlbGV0ZS5cbiAgIEVtaXQgb25DYW5jZWxEZWxldGVJdGVtIFN1YmplY3QgYWZ0ZXIgb24gY2FuY2VsIGRlbGV0ZS5cbiAgKi9cbiAgcHVibGljIGRlbGV0ZUl0ZW0oaWQpIHtcbiAgICB0aGlzLmVsZW1lbnRGaW5kZXIodGhpcy50cmVlU3RvcmFnZSwgaWQpO1xuICAgIGNvbnN0IGV2ZW50RW1pdCA9IHtcbiAgICAgIGVsZW1lbnQ6IHRoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtLFxuICAgICAgcGFyZW50OiB0aGlzLmZpbmRpbmdSZXN1bHRzLnBhcmVudEl0ZW0gfHwgJ3Jvb3QnXG4gICAgfTtcbiAgICB0aGlzLm9uU3RhcnREZWxldGVJdGVtLm5leHQoZXZlbnRFbWl0KTtcbiAgICBsZXQgdGV4dDogc3RyaW5nO1xuICAgIGlmKCB0aGlzLmZpbmRpbmdSZXN1bHRzLmZvdW5kSXRlbS5uYW1lICkge1xuICAgICAgdGV4dCA9IGBEbyB5b3UgcmVhbGx5IHdhbnQgdG8gZGVsZXRlICcke3RoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtLm5hbWV9Jz9gO1xuICAgIH0gZWxzZSB7XG4gICAgICB0ZXh0ID0gYENhbmNlbCBjcmVhdGluZyBhIG5ldyBpdGVtP2A7XG4gICAgfVxuICAgIGlmKGNvbmZpcm0odGV4dCkpIHtcbiAgICAgIHRoaXMub25GaW5pc2hEZWxldGVJdGVtLm5leHQoZXZlbnRFbWl0KTtcbiAgICAgIGNvbnN0IGkgPSB0aGlzLmZpbmRpbmdSZXN1bHRzLml0ZW1zTGlzdC5pbmRleE9mKHRoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtKTtcbiAgICAgIHRoaXMuZmluZGluZ1Jlc3VsdHMuaXRlbXNMaXN0LnNwbGljZShpLCAxKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5vbkNhbmNlbERlbGV0ZUl0ZW0ubmV4dChldmVudEVtaXQpO1xuICAgIH1cbiAgICB0aGlzLmNsZWFyQWN0aW9uKCk7XG4gIH1cblxuICAvKlxuICAgVHJpZ2dlciBzdGFydCByZW5hbWUgZWxlbWVudC5cbiAgIEl0YHMgYWNjZXB0cyAnbmFtZScgYW5kICdpZCcgZm9yIGZpbmQgaXRlbSBvbiB0cmVlIGFuZCBzZXQgdGhlIG5hbWUuXG4gICBFbWl0IG9uUmVuYW1lSXRlbSBTdWJqZWN0LlxuICAqL1xuIHB1YmxpYyBzdGFydFJlbmFtZUl0ZW0oZWxlbWVudCkge1xuICAgIHRoaXMuZWxlbWVudEZpbmRlcih0aGlzLnRyZWVTdG9yYWdlLCBlbGVtZW50LmlkKTtcbiAgICAvLyBldmVudCBlbWl0XG4gICAgY29uc3QgZXZlbnRFbWl0ID0ge1xuICAgICAgZWxlbWVudDogdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0sXG4gICAgICBwYXJlbnQ6IHRoaXMuZmluZGluZ1Jlc3VsdHMucGFyZW50SXRlbSB8fCAncm9vdCdcbiAgICB9O1xuICAgIHRoaXMub25TdGFydFJlbmFtZUl0ZW0ubmV4dChldmVudEVtaXQpO1xuICB9XG5cbiAgLypcbiAgIFJlbmFtZSBlbGVtZW50LlxuICAgSXRgcyBhY2NlcHRzICduYW1lJyBhbmQgJ2lkJyBmb3IgZmluZCBpdGVtIG9uIHRyZWUgYW5kIHNldCB0aGUgbmFtZS5cbiAgIEVtaXQgb25SZW5hbWVJdGVtIFN1YmplY3QuXG4gICovXG4gIHB1YmxpYyBmaW5pc2hSZW5hbWVJdGVtKG5hbWUsIGlkKSB7XG4gICAgdGhpcy5lbGVtZW50RmluZGVyKHRoaXMudHJlZVN0b3JhZ2UsIGlkKTtcbiAgICAvLyBjb2RlXG4gICAgdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0ubmFtZSA9IG5hbWU7XG4gICAgdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0ub3B0aW9ucy5lZGl0ID0gZmFsc2U7XG4gICAgLy8gZXZlbnQgZW1pdFxuICAgIGNvbnN0IGV2ZW50RW1pdCA9IHtcbiAgICAgIGVsZW1lbnQ6IHRoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtLFxuICAgICAgcGFyZW50OiB0aGlzLmZpbmRpbmdSZXN1bHRzLnBhcmVudEl0ZW0gfHwgJ3Jvb3QnXG4gICAgfTtcbiAgICB0aGlzLm9uRmluaXNoUmVuYW1lSXRlbS5uZXh0KGV2ZW50RW1pdCk7XG4gICAgdGhpcy5jbGVhckFjdGlvbigpO1xuICB9XG5cbiAgLypcbiAgIEV2ZW50OiBvbmRyYWdzdGFydDtcbiAgIE9uIHN0YXJ0IGRyYWdnaW5nIGZpbmQgZWxlbWVudCBteSBpZCBhbmQgc2V0IG9wdGlvbiBjdXJyZW50bHlEcmFnZ2luZyB0cnVlLlxuICAqL1xuICBwdWJsaWMgc3RhcnREcmFnZ2luZyhldmVudE9iaikge1xuICAgIHRoaXMuc3dpdGNoRHJvcEJ1dHRvbih0cnVlLCB0aGlzLnRyZWVTdG9yYWdlKTtcbiAgICB0aGlzLm9uRHJhZ1N0YXJ0Lm5leHQoZXZlbnRPYmopO1xuICB9XG5cbiAgLypcbiAgIEV2ZW50OiBvbmRyYWc7XG4gICBUcmlnZ2VyIGRyYWdnaW5nIGVsZW1lbnRcbiAgKi9cbiAgcHVibGljIG9uRHJhZ1Byb2Nlc3MoZXZlbnRPYmopIHtcbiAgICB0aGlzLm9uRHJhZy5uZXh0KGV2ZW50T2JqKTtcbiAgfVxuXG4gIC8qXG4gICBFdmVudDogb25kcmFnZW5kO1xuICAgZGV0ZWN0IGVuZCBvZiBkcmFnIGFjdGlvblxuICAqL1xuICBwdWJsaWMgZHJhZ0VuZEFjdGlvbihldmVudE9iaikge1xuICAgIHRoaXMucmVtb3ZlRGVzdGVuYXRpb25Cb3JkZXJzKHRoaXMudHJlZVN0b3JhZ2UpO1xuICAgIHRoaXMuc3dpdGNoRHJvcEJ1dHRvbihmYWxzZSwgdGhpcy50cmVlU3RvcmFnZSk7XG4gICAgdGhpcy5vbkRyYWdFbmQubmV4dChldmVudE9iaik7XG4gIH1cblxuICAvKlxuICAgIEV2ZW50OiBlbnRlcmRyb3B6b25lO1xuICAgIEVudGVyaW5nIGRyb3Agem9uZSBmb3Igc3R5bGluZyBpdGVtcy5cbiAgKi9cbiAgcHVibGljIGVudGVyRHJvcFpvbmUoZXZlbnRPYmopIHtcbiAgICB0aGlzLm9uRHJhZ0VudGVyLm5leHQoZXZlbnRPYmopO1xuICB9XG5cblxuICAvKlxuICAgIEV2ZW50OiBkcmFnb3ZlcjtcbiAgICBEZXRlY3QgaG92ZXIgb24gZHJvcGFibGUgZWxlbWVudHNcbiAgKi9cbiAgcHVibGljIG9uRHJhZ092ZXIoZXZlbnRPYmopIHtcbiAgICBjb25zdCBlbCA9IChldmVudE9iai50YXJnZXQgYXMgVHJlZU1vZGVsKTtcbiAgICBpZiAoZWwgJiYgZWwuaWQgIT09IHRoaXMuaXNEcmFnZ2luZy5pZCApIHtcbiAgICAgIGNvbnN0IGVsZW1lbnRIYWxmSGVpZ2h0ID0gZXZlbnRPYmouZXZlbnQudG9FbGVtZW50Lm9mZnNldEhlaWdodCAvIDI7XG4gICAgICBpZiAoZXZlbnRPYmouZXZlbnQub2Zmc2V0WSA8IGVsZW1lbnRIYWxmSGVpZ2h0KSB7XG4gICAgICAgIGVsLm9wdGlvbnMuZGVzdGVuYXRpb25Cb3R0b20gPSBmYWxzZTtcbiAgICAgICAgZWwub3B0aW9ucy5kZXN0ZW5hdGlvblRvcCA9IHRydWU7XG4gICAgICB9IGVsc2UgIHtcbiAgICAgICAgZWwub3B0aW9ucy5kZXN0ZW5hdGlvbkJvdHRvbSA9IHRydWU7XG4gICAgICAgIGVsLm9wdGlvbnMuZGVzdGVuYXRpb25Ub3AgPSBmYWxzZTtcbiAgICAgIH1cbiAgICAgIHRoaXMub25BbGxvd0Ryb3AubmV4dChldmVudE9iaik7XG4gICAgfVxuICB9XG5cbiAgLypcbiAgICBFdmVudDogbGVhdmVkcm9wem9uZTtcbiAgICBMZWF2ZSBkcm9wIHpvbmUgZm9yIHJlc3R5bGluZyBpdGVtcy5cbiAgKi9cbiAgcHVibGljIGxlYXZlRHJvcFpvbmUoZXZlbnRPYmopIHtcbiAgICAgIHRoaXMucmVtb3ZlRGVzdGVuYXRpb25Cb3JkZXJzKHRoaXMudHJlZVN0b3JhZ2UpO1xuICAgICAgdGhpcy5vbkRyYWdMZWF2ZS5uZXh0KGV2ZW50T2JqKTtcbiAgfVxuXG4gIC