@ali-hm/angular-tree-component 18.0.5 → 19.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/fesm2022/ali-hm-angular-tree-component.mjs +80 -71
- package/fesm2022/ali-hm-angular-tree-component.mjs.map +1 -1
- package/package.json +4 -6
- package/esm2022/ali-hm-angular-tree-component.mjs +0 -5
- package/esm2022/lib/angular-tree-component.module.mjs +0 -100
- package/esm2022/lib/components/loading.component.mjs +0 -32
- package/esm2022/lib/components/tree-node-checkbox.component.mjs +0 -34
- package/esm2022/lib/components/tree-node-collection.component.mjs +0 -284
- package/esm2022/lib/components/tree-node-content.component.mjs +0 -32
- package/esm2022/lib/components/tree-node-drop-slot.component.mjs +0 -39
- package/esm2022/lib/components/tree-node-expander.component.mjs +0 -43
- package/esm2022/lib/components/tree-node-wrapper.component.mjs +0 -81
- package/esm2022/lib/components/tree-viewport.component.mjs +0 -66
- package/esm2022/lib/components/tree.component.mjs +0 -186
- package/esm2022/lib/constants/events.mjs +0 -20
- package/esm2022/lib/constants/keys.mjs +0 -10
- package/esm2022/lib/defs/api.mjs +0 -2
- package/esm2022/lib/directives/tree-animate-open.directive.mjs +0 -101
- package/esm2022/lib/directives/tree-drag.directive.mjs +0 -65
- package/esm2022/lib/directives/tree-drop.directive.mjs +0 -127
- package/esm2022/lib/mobx-angular/mobx-proxy.mjs +0 -17
- package/esm2022/lib/mobx-angular/tree-mobx-autorun.directive.mjs +0 -40
- package/esm2022/lib/models/tree-dragged-element.model.mjs +0 -25
- package/esm2022/lib/models/tree-node.model.mjs +0 -390
- package/esm2022/lib/models/tree-options.model.mjs +0 -150
- package/esm2022/lib/models/tree-virtual-scroll.model.mjs +0 -197
- package/esm2022/lib/models/tree.model.mjs +0 -546
- package/esm2022/public-api.mjs +0 -5
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
};
|
|
7
|
-
import { Injectable } from '@angular/core';
|
|
8
|
-
import { observable, computed, action, autorun, reaction } from 'mobx';
|
|
9
|
-
import { TREE_EVENTS } from '../constants/events';
|
|
10
|
-
import * as i0 from "@angular/core";
|
|
11
|
-
import * as i1 from "./tree.model";
|
|
12
|
-
const Y_OFFSET = 500; // Extra pixels outside the viewport, in each direction, to render nodes in
|
|
13
|
-
const Y_EPSILON = 150; // Minimum pixel change required to recalculate the rendered nodes
|
|
14
|
-
export class TreeVirtualScroll {
|
|
15
|
-
get y() {
|
|
16
|
-
return this.yBlocks * Y_EPSILON;
|
|
17
|
-
}
|
|
18
|
-
get totalHeight() {
|
|
19
|
-
return this.treeModel.virtualRoot ? this.treeModel.virtualRoot.height : 0;
|
|
20
|
-
}
|
|
21
|
-
constructor(treeModel) {
|
|
22
|
-
this.treeModel = treeModel;
|
|
23
|
-
this.yBlocks = 0;
|
|
24
|
-
this.x = 0;
|
|
25
|
-
this.viewportHeight = null;
|
|
26
|
-
this.viewport = null;
|
|
27
|
-
treeModel.virtualScroll = this;
|
|
28
|
-
this._dispose = [autorun(() => this.fixScroll())];
|
|
29
|
-
}
|
|
30
|
-
fireEvent(event) {
|
|
31
|
-
this.treeModel.fireEvent(event);
|
|
32
|
-
}
|
|
33
|
-
init() {
|
|
34
|
-
const fn = this.recalcPositions.bind(this);
|
|
35
|
-
fn();
|
|
36
|
-
this._dispose = [
|
|
37
|
-
...this._dispose,
|
|
38
|
-
reaction(() => this.treeModel.roots, fn),
|
|
39
|
-
reaction(() => this.treeModel.expandedNodeIds, fn),
|
|
40
|
-
reaction(() => this.treeModel.hiddenNodeIds, fn)
|
|
41
|
-
];
|
|
42
|
-
this.treeModel.subscribe(TREE_EVENTS.loadNodeChildren, fn);
|
|
43
|
-
}
|
|
44
|
-
isEnabled() {
|
|
45
|
-
return this.treeModel.options.useVirtualScroll;
|
|
46
|
-
}
|
|
47
|
-
_setYBlocks(value) {
|
|
48
|
-
this.yBlocks = value;
|
|
49
|
-
}
|
|
50
|
-
recalcPositions() {
|
|
51
|
-
this.treeModel.virtualRoot.height = this._getPositionAfter(this.treeModel.getVisibleRoots(), 0);
|
|
52
|
-
}
|
|
53
|
-
_getPositionAfter(nodes, startPos) {
|
|
54
|
-
let position = startPos;
|
|
55
|
-
nodes.forEach((node) => {
|
|
56
|
-
node.position = position;
|
|
57
|
-
position = this._getPositionAfterNode(node, position);
|
|
58
|
-
});
|
|
59
|
-
return position;
|
|
60
|
-
}
|
|
61
|
-
_getPositionAfterNode(node, startPos) {
|
|
62
|
-
let position = node.getSelfHeight() + startPos;
|
|
63
|
-
if (node.children && node.isExpanded) { // TBD: consider loading component as well
|
|
64
|
-
position = this._getPositionAfter(node.visibleChildren, position);
|
|
65
|
-
}
|
|
66
|
-
node.height = position - startPos;
|
|
67
|
-
return position;
|
|
68
|
-
}
|
|
69
|
-
clear() {
|
|
70
|
-
this._dispose.forEach((d) => d());
|
|
71
|
-
}
|
|
72
|
-
setViewport(viewport) {
|
|
73
|
-
Object.assign(this, {
|
|
74
|
-
viewport,
|
|
75
|
-
x: viewport.scrollLeft,
|
|
76
|
-
yBlocks: Math.round(viewport.scrollTop / Y_EPSILON),
|
|
77
|
-
viewportHeight: viewport.getBoundingClientRect ? viewport.getBoundingClientRect().height : 0
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
scrollIntoView(node, force, scrollToMiddle = true) {
|
|
81
|
-
if (node.options.scrollContainer) {
|
|
82
|
-
const scrollContainer = node.options.scrollContainer;
|
|
83
|
-
const scrollContainerHeight = scrollContainer.getBoundingClientRect().height;
|
|
84
|
-
const scrollContainerTop = scrollContainer.getBoundingClientRect().top;
|
|
85
|
-
const nodeTop = this.viewport.getBoundingClientRect().top + node.position - scrollContainerTop;
|
|
86
|
-
if (force || // force scroll to node
|
|
87
|
-
nodeTop < scrollContainer.scrollTop || // node is above scroll container
|
|
88
|
-
nodeTop + node.getSelfHeight() > scrollContainer.scrollTop + scrollContainerHeight) { // node is below container
|
|
89
|
-
scrollContainer.scrollTop = scrollToMiddle ?
|
|
90
|
-
nodeTop - scrollContainerHeight / 2 : // scroll to middle
|
|
91
|
-
nodeTop; // scroll to start
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
if (force || // force scroll to node
|
|
96
|
-
node.position < this.y || // node is above viewport
|
|
97
|
-
node.position + node.getSelfHeight() > this.y + this.viewportHeight) { // node is below viewport
|
|
98
|
-
if (this.viewport) {
|
|
99
|
-
this.viewport.scrollTop = scrollToMiddle ?
|
|
100
|
-
node.position - this.viewportHeight / 2 : // scroll to middle
|
|
101
|
-
node.position; // scroll to start
|
|
102
|
-
this._setYBlocks(Math.floor(this.viewport.scrollTop / Y_EPSILON));
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
getViewportNodes(nodes) {
|
|
108
|
-
if (!nodes)
|
|
109
|
-
return [];
|
|
110
|
-
const visibleNodes = nodes.filter((node) => !node.isHidden);
|
|
111
|
-
if (!this.isEnabled())
|
|
112
|
-
return visibleNodes;
|
|
113
|
-
if (!this.viewportHeight || !visibleNodes.length)
|
|
114
|
-
return [];
|
|
115
|
-
// When loading children async this method is called before their height and position is calculated.
|
|
116
|
-
// In that case firstIndex === 0 and lastIndex === visibleNodes.length - 1 (e.g. 1000),
|
|
117
|
-
// which means that it loops through every visibleNodes item and push them into viewportNodes array.
|
|
118
|
-
// We can prevent nodes from being pushed to the array and wait for the appropriate calculations to take place
|
|
119
|
-
const lastVisibleNode = visibleNodes.slice(-1)[0];
|
|
120
|
-
if (!lastVisibleNode.height && lastVisibleNode.position === 0)
|
|
121
|
-
return [];
|
|
122
|
-
// Search for first node in the viewport using binary search
|
|
123
|
-
// Look for first node that starts after the beginning of the viewport (with buffer)
|
|
124
|
-
// Or that ends after the beginning of the viewport
|
|
125
|
-
const firstIndex = binarySearch(visibleNodes, (node) => {
|
|
126
|
-
return (node.position + Y_OFFSET > this.y) ||
|
|
127
|
-
(node.position + node.height > this.y);
|
|
128
|
-
});
|
|
129
|
-
// Search for last node in the viewport using binary search
|
|
130
|
-
// Look for first node that starts after the end of the viewport (with buffer)
|
|
131
|
-
const lastIndex = binarySearch(visibleNodes, (node) => {
|
|
132
|
-
return node.position - Y_OFFSET > this.y + this.viewportHeight;
|
|
133
|
-
}, firstIndex);
|
|
134
|
-
const viewportNodes = [];
|
|
135
|
-
for (let i = firstIndex; i <= lastIndex; i++) {
|
|
136
|
-
viewportNodes.push(visibleNodes[i]);
|
|
137
|
-
}
|
|
138
|
-
return viewportNodes;
|
|
139
|
-
}
|
|
140
|
-
fixScroll() {
|
|
141
|
-
const maxY = Math.max(0, this.totalHeight - this.viewportHeight);
|
|
142
|
-
if (this.y < 0)
|
|
143
|
-
this._setYBlocks(0);
|
|
144
|
-
if (this.y > maxY)
|
|
145
|
-
this._setYBlocks(maxY / Y_EPSILON);
|
|
146
|
-
}
|
|
147
|
-
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: TreeVirtualScroll, deps: [{ token: i1.TreeModel }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
148
|
-
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: TreeVirtualScroll }); }
|
|
149
|
-
}
|
|
150
|
-
__decorate([
|
|
151
|
-
observable
|
|
152
|
-
], TreeVirtualScroll.prototype, "yBlocks", void 0);
|
|
153
|
-
__decorate([
|
|
154
|
-
observable
|
|
155
|
-
], TreeVirtualScroll.prototype, "x", void 0);
|
|
156
|
-
__decorate([
|
|
157
|
-
observable
|
|
158
|
-
], TreeVirtualScroll.prototype, "viewportHeight", void 0);
|
|
159
|
-
__decorate([
|
|
160
|
-
computed
|
|
161
|
-
], TreeVirtualScroll.prototype, "y", null);
|
|
162
|
-
__decorate([
|
|
163
|
-
computed
|
|
164
|
-
], TreeVirtualScroll.prototype, "totalHeight", null);
|
|
165
|
-
__decorate([
|
|
166
|
-
action
|
|
167
|
-
], TreeVirtualScroll.prototype, "_setYBlocks", null);
|
|
168
|
-
__decorate([
|
|
169
|
-
action
|
|
170
|
-
], TreeVirtualScroll.prototype, "recalcPositions", null);
|
|
171
|
-
__decorate([
|
|
172
|
-
action
|
|
173
|
-
], TreeVirtualScroll.prototype, "setViewport", null);
|
|
174
|
-
__decorate([
|
|
175
|
-
action
|
|
176
|
-
], TreeVirtualScroll.prototype, "scrollIntoView", null);
|
|
177
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: TreeVirtualScroll, decorators: [{
|
|
178
|
-
type: Injectable
|
|
179
|
-
}], ctorParameters: () => [{ type: i1.TreeModel }], propDecorators: { yBlocks: [], x: [], viewportHeight: [], y: [], totalHeight: [], _setYBlocks: [], recalcPositions: [], setViewport: [], scrollIntoView: [] } });
|
|
180
|
-
function binarySearch(nodes, condition, firstIndex = 0) {
|
|
181
|
-
let index = firstIndex;
|
|
182
|
-
let toIndex = nodes.length - 1;
|
|
183
|
-
while (index !== toIndex) {
|
|
184
|
-
let midIndex = Math.floor((index + toIndex) / 2);
|
|
185
|
-
if (condition(nodes[midIndex])) {
|
|
186
|
-
toIndex = midIndex;
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
if (index === midIndex)
|
|
190
|
-
index = toIndex;
|
|
191
|
-
else
|
|
192
|
-
index = midIndex;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return index;
|
|
196
|
-
}
|
|
197
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS12aXJ0dWFsLXNjcm9sbC5tb2RlbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXItdHJlZS1jb21wb25lbnQvc3JjL2xpYi9tb2RlbHMvdHJlZS12aXJ0dWFsLXNjcm9sbC5tb2RlbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRXZFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQzs7O0FBRWxELE1BQU0sUUFBUSxHQUFHLEdBQUcsQ0FBQyxDQUFDLDJFQUEyRTtBQUNqRyxNQUFNLFNBQVMsR0FBRyxHQUFHLENBQUMsQ0FBQyxrRUFBa0U7QUFHekYsTUFBTSxPQUFPLGlCQUFpQjtJQVFsQixJQUFJLENBQUM7UUFDYixPQUFPLElBQUksQ0FBQyxPQUFPLEdBQUcsU0FBUyxDQUFDO0lBQ2xDLENBQUM7SUFFUyxJQUFJLFdBQVc7UUFDdkIsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDNUUsQ0FBQztJQUVELFlBQW9CLFNBQW9CO1FBQXBCLGNBQVMsR0FBVCxTQUFTLENBQVc7UUFiNUIsWUFBTyxHQUFHLENBQUMsQ0FBQztRQUNaLE1BQUMsR0FBRyxDQUFDLENBQUM7UUFDTixtQkFBYyxHQUFHLElBQUksQ0FBQztRQUNsQyxhQUFRLEdBQUcsSUFBSSxDQUFDO1FBV2QsU0FBUyxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUM7UUFDL0IsSUFBSSxDQUFDLFFBQVEsR0FBRyxDQUFDLE9BQU8sQ0FB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L2NvcmUnO1xyXG5pbXBvcnQgeyBvYnNlcnZhYmxlLCBjb21wdXRlZCwgYWN0aW9uLCBhdXRvcnVuLCByZWFjdGlvbiB9IGZyb20gJ21vYngnO1xyXG5pbXBvcnQgeyBUcmVlTW9kZWwgfSBmcm9tICcuL3RyZWUubW9kZWwnO1xyXG5pbXBvcnQgeyBUUkVFX0VWRU5UUyB9IGZyb20gJy4uL2NvbnN0YW50cy9ldmVudHMnO1xyXG5cclxuY29uc3QgWV9PRkZTRVQgPSA1MDA7IC8vIEV4dHJhIHBpeGVscyBvdXRzaWRlIHRoZSB2aWV3cG9ydCwgaW4gZWFjaCBkaXJlY3Rpb24sIHRvIHJlbmRlciBub2RlcyBpblxyXG5jb25zdCBZX0VQU0lMT04gPSAxNTA7IC8vIE1pbmltdW0gcGl4ZWwgY2hhbmdlIHJlcXVpcmVkIHRvIHJlY2FsY3VsYXRlIHRoZSByZW5kZXJlZCBub2Rlc1xyXG5cclxuQEluamVjdGFibGUoKVxyXG5leHBvcnQgY2xhc3MgVHJlZVZpcnR1YWxTY3JvbGwge1xyXG4gIHByaXZhdGUgX2Rpc3Bvc2U6IGFueTtcclxuXHJcbiAgQG9ic2VydmFibGUgeUJsb2NrcyA9IDA7XHJcbiAgQG9ic2VydmFibGUgeCA9IDA7XHJcbiAgQG9ic2VydmFibGUgdmlld3BvcnRIZWlnaHQgPSBudWxsO1xyXG4gIHZpZXdwb3J0ID0gbnVsbDtcclxuXHJcbiAgQGNvbXB1dGVkIGdldCB5KCkge1xyXG4gICAgcmV0dXJuIHRoaXMueUJsb2NrcyAqIFlfRVBTSUxPTjtcclxuICB9XHJcblxyXG4gIEBjb21wdXRlZCBnZXQgdG90YWxIZWlnaHQoKSB7XHJcbiAgICByZXR1cm4gdGhpcy50cmVlTW9kZWwudmlydHVhbFJvb3QgPyB0aGlzLnRyZWVNb2RlbC52aXJ0dWFsUm9vdC5oZWlnaHQgOiAwO1xyXG4gIH1cclxuXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSB0cmVlTW9kZWw6IFRyZWVNb2RlbCkge1xyXG4gICAgdHJlZU1vZGVsLnZpcnR1YWxTY3JvbGwgPSB0aGlzO1xyXG4gICAgdGhpcy5fZGlzcG9zZSA9IFthdXRvcnVuKCgpID0+IHRoaXMuZml4U2Nyb2xsKCkpXTtcclxuICB9XHJcblxyXG4gIGZpcmVFdmVudChldmVudCkge1xyXG4gICAgdGhpcy50cmVlTW9kZWwuZmlyZUV2ZW50KGV2ZW50KTtcclxuICB9XHJcblxyXG4gIGluaXQoKSB7XHJcbiAgICBjb25zdCBmbiA9IHRoaXMucmVjYWxjUG9zaXRpb25zLmJpbmQodGhpcyk7XHJcblxyXG4gICAgZm4oKTtcclxuICAgIHRoaXMuX2Rpc3Bvc2UgPSBbXHJcbiAgICAgIC4uLnRoaXMuX2Rpc3Bvc2UsXHJcbiAgICAgIHJlYWN0aW9uKCgpID0+IHRoaXMudHJlZU1vZGVsLnJvb3RzLCBmbiksXHJcbiAgICAgIHJlYWN0aW9uKCgpID0+IHRoaXMudHJlZU1vZGVsLmV4cGFuZGVkTm9kZUlkcywgZm4pLFxyXG4gICAgICByZWFjdGlvbigoKSA9PiB0aGlzLnRyZWVNb2RlbC5oaWRkZW5Ob2RlSWRzLCBmbilcclxuICAgIF07XHJcbiAgICB0aGlzLnRyZWVNb2RlbC5zdWJzY3JpYmUoVFJFRV9FVkVOVFMubG9hZE5vZGVDaGlsZHJlbiwgZm4pO1xyXG4gIH1cclxuXHJcbiAgaXNFbmFibGVkKCkge1xyXG4gICAgcmV0dXJuIHRoaXMudHJlZU1vZGVsLm9wdGlvbnMudXNlVmlydHVhbFNjcm9sbDtcclxuICB9XHJcblxyXG4gIEBhY3Rpb24gcHJpdmF0ZSBfc2V0WUJsb2Nrcyh2YWx1ZSkge1xyXG4gICAgdGhpcy55QmxvY2tzID0gdmFsdWU7XHJcbiAgfVxyXG5cclxuICBAYWN0aW9uIHJlY2FsY1Bvc2l0aW9ucygpIHtcclxuICAgIHRoaXMudHJlZU1vZGVsLnZpcnR1YWxSb290LmhlaWdodCA9IHRoaXMuX2dldFBvc2l0aW9uQWZ0ZXIodGhpcy50cmVlTW9kZWwuZ2V0VmlzaWJsZVJvb3RzKCksIDApO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBfZ2V0UG9zaXRpb25BZnRlcihub2Rlcywgc3RhcnRQb3MpIHtcclxuICAgIGxldCBwb3NpdGlvbiA9IHN0YXJ0UG9zO1xyXG5cclxuICAgIG5vZGVzLmZvckVhY2goKG5vZGUpID0+IHtcclxuICAgICAgbm9kZS5wb3NpdGlvbiA9IHBvc2l0aW9uO1xyXG4gICAgICBwb3NpdGlvbiA9IHRoaXMuX2dldFBvc2l0aW9uQWZ0ZXJOb2RlKG5vZGUsIHBvc2l0aW9uKTtcclxuICAgIH0pO1xyXG4gICAgcmV0dXJuIHBvc2l0aW9uO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBfZ2V0UG9zaXRpb25BZnRlck5vZGUobm9kZSwgc3RhcnRQb3MpIHtcclxuICAgIGxldCBwb3NpdGlvbiA9IG5vZGUuZ2V0U2VsZkhlaWdodCgpICsgc3RhcnRQb3M7XHJcblxyXG4gICAgaWYgKG5vZGUuY2hpbGRyZW4gJiYgbm9kZS5pc0V4cGFuZGVkKSB7IC8vIFRCRDogY29uc2lkZXIgbG9hZGluZyBjb21wb25lbnQgYXMgd2VsbFxyXG4gICAgICBwb3NpdGlvbiA9IHRoaXMuX2dldFBvc2l0aW9uQWZ0ZXIobm9kZS52aXNpYmxlQ2hpbGRyZW4sIHBvc2l0aW9uKTtcclxuICAgIH1cclxuICAgIG5vZGUuaGVpZ2h0ID0gcG9zaXRpb24gLSBzdGFydFBvcztcclxuICAgIHJldHVybiBwb3NpdGlvbjtcclxuICB9XHJcblxyXG5cclxuICBjbGVhcigpIHtcclxuICAgIHRoaXMuX2Rpc3Bvc2UuZm9yRWFjaCgoZCkgPT4gZCgpKTtcclxuICB9XHJcblxyXG4gIEBhY3Rpb24gc2V0Vmlld3BvcnQodmlld3BvcnQpIHtcclxuICAgIE9iamVjdC5hc3NpZ24odGhpcywge1xyXG4gICAgICB2aWV3cG9ydCxcclxuICAgICAgeDogdmlld3BvcnQuc2Nyb2xsTGVmdCxcclxuICAgICAgeUJsb2NrczogTWF0aC5yb3VuZCh2aWV3cG9ydC5zY3JvbGxUb3AgLyBZX0VQU0lMT04pLFxyXG4gICAgICB2aWV3cG9ydEhlaWdodDogdmlld3BvcnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0ID8gdmlld3BvcnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0IDogMFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBAYWN0aW9uIHNjcm9sbEludG9WaWV3KG5vZGUsIGZvcmNlLCBzY3JvbGxUb01pZGRsZSA9IHRydWUpIHtcclxuICAgIGlmIChub2RlLm9wdGlvbnMuc2Nyb2xsQ29udGFpbmVyKSB7XHJcbiAgICAgIGNvbnN0IHNjcm9sbENvbnRhaW5lciA9IG5vZGUub3B0aW9ucy5zY3JvbGxDb250YWluZXI7XHJcbiAgICAgIGNvbnN0IHNjcm9sbENvbnRhaW5lckhlaWdodCA9IHNjcm9sbENvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5oZWlnaHQ7XHJcbiAgICAgIGNvbnN0IHNjcm9sbENvbnRhaW5lclRvcCA9IHNjcm9sbENvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3A7XHJcbiAgICAgIGNvbnN0IG5vZGVUb3AgPSB0aGlzLnZpZXdwb3J0LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCArIG5vZGUucG9zaXRpb24gLSBzY3JvbGxDb250YWluZXJUb3A7XHJcblxyXG4gICAgICBpZiAoZm9yY2UgfHwgLy8gZm9yY2Ugc2Nyb2xsIHRvIG5vZGVcclxuICAgICAgICBub2RlVG9wIDwgc2Nyb2xsQ29udGFpbmVyLnNjcm9sbFRvcCB8fCAvLyBub2RlIGlzIGFib3ZlIHNjcm9sbCBjb250YWluZXJcclxuICAgICAgICBub2RlVG9wICsgbm9kZS5nZXRTZWxmSGVpZ2h0KCkgPiBzY3JvbGxDb250YWluZXIuc2Nyb2xsVG9wICsgc2Nyb2xsQ29udGFpbmVySGVpZ2h0KSB7IC8vIG5vZGUgaXMgYmVsb3cgY29udGFpbmVyXHJcbiAgICAgICAgc2Nyb2xsQ29udGFpbmVyLnNjcm9sbFRvcCA9IHNjcm9sbFRvTWlkZGxlID9cclxuICAgICAgICAgIG5vZGVUb3AgLSBzY3JvbGxDb250YWluZXJIZWlnaHQgLyAyIDogLy8gc2Nyb2xsIHRvIG1pZGRsZVxyXG4gICAgICAgICAgbm9kZVRvcDsgLy8gc2Nyb2xsIHRvIHN0YXJ0XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGlmIChmb3JjZSB8fCAvLyBmb3JjZSBzY3JvbGwgdG8gbm9kZVxyXG4gICAgICAgIG5vZGUucG9zaXRpb24gPCB0aGlzLnkgfHwgLy8gbm9kZSBpcyBhYm92ZSB2aWV3cG9ydFxyXG4gICAgICAgIG5vZGUucG9zaXRpb24gKyBub2RlLmdldFNlbGZIZWlnaHQoKSA+IHRoaXMueSArIHRoaXMudmlld3BvcnRIZWlnaHQpIHsgLy8gbm9kZSBpcyBiZWxvdyB2aWV3cG9ydFxyXG4gICAgICAgIGlmICh0aGlzLnZpZXdwb3J0KSB7XHJcbiAgICAgICAgICB0aGlzLnZpZXdwb3J0LnNjcm9sbFRvcCA9IHNjcm9sbFRvTWlkZGxlID9cclxuICAgICAgICAgIG5vZGUucG9zaXRpb24gLSB0aGlzLnZpZXdwb3J0SGVpZ2h0IC8gMiA6IC8vIHNjcm9sbCB0byBtaWRkbGVcclxuICAgICAgICAgIG5vZGUucG9zaXRpb247IC8vIHNjcm9sbCB0byBzdGFydFxyXG5cclxuICAgICAgICAgIHRoaXMuX3NldFlCbG9ja3MoTWF0aC5mbG9vcih0aGlzLnZpZXdwb3J0LnNjcm9sbFRvcCAvIFlfRVBTSUxPTikpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZ2V0Vmlld3BvcnROb2Rlcyhub2Rlcykge1xyXG4gICAgaWYgKCFub2RlcykgcmV0dXJuIFtdO1xyXG5cclxuICAgIGNvbnN0IHZpc2libGVOb2RlcyA9IG5vZGVzLmZpbHRlcigobm9kZSkgPT4gIW5vZGUuaXNIaWRkZW4pO1xyXG5cclxuICAgIGlmICghdGhpcy5pc0VuYWJsZWQoKSkgcmV0dXJuIHZpc2libGVOb2RlcztcclxuXHJcbiAgICBpZiAoIXRoaXMudmlld3BvcnRIZWlnaHQgfHwgIXZpc2libGVOb2Rlcy5sZW5ndGgpIHJldHVybiBbXTtcclxuXHJcbiAgICAvLyBXaGVuIGxvYWRpbmcgY2hpbGRyZW4gYXN5bmMgdGhpcyBtZXRob2QgaXMgY2FsbGVkIGJlZm9yZSB0aGVpciBoZWlnaHQgYW5kIHBvc2l0aW9uIGlzIGNhbGN1bGF0ZWQuXHJcbiAgICAvLyBJbiB0aGF0IGNhc2UgZmlyc3RJbmRleCA9PT0gMCBhbmQgbGFzdEluZGV4ID09PSB2aXNpYmxlTm9kZXMubGVuZ3RoIC0gMSAoZS5nLiAxMDAwKSxcclxuICAgIC8vIHdoaWNoIG1lYW5zIHRoYXQgaXQgbG9vcHMgdGhyb3VnaCBldmVyeSB2aXNpYmxlTm9kZXMgaXRlbSBhbmQgcHVzaCB0aGVtIGludG8gdmlld3BvcnROb2RlcyBhcnJheS5cclxuICAgIC8vIFdlIGNhbiBwcmV2ZW50IG5vZGVzIGZyb20gYmVpbmcgcHVzaGVkIHRvIHRoZSBhcnJheSBhbmQgd2FpdCBmb3IgdGhlIGFwcHJvcHJpYXRlIGNhbGN1bGF0aW9ucyB0byB0YWtlIHBsYWNlXHJcbiAgICBjb25zdCBsYXN0VmlzaWJsZU5vZGUgPSB2aXNpYmxlTm9kZXMuc2xpY2UoLTEpWzBdXHJcbiAgICBpZiAoIWxhc3RWaXNpYmxlTm9kZS5oZWlnaHQgJiYgbGFzdFZpc2libGVOb2RlLnBvc2l0aW9uID09PSAwKSByZXR1cm4gW107XHJcblxyXG4gICAgLy8gU2VhcmNoIGZvciBmaXJzdCBub2RlIGluIHRoZSB2aWV3cG9ydCB1c2luZyBiaW5hcnkgc2VhcmNoXHJcbiAgICAvLyBMb29rIGZvciBmaXJzdCBub2RlIHRoYXQgc3RhcnRzIGFmdGVyIHRoZSBiZWdpbm5pbmcgb2YgdGhlIHZpZXdwb3J0ICh3aXRoIGJ1ZmZlcilcclxuICAgIC8vIE9yIHRoYXQgZW5kcyBhZnRlciB0aGUgYmVnaW5uaW5nIG9mIHRoZSB2aWV3cG9ydFxyXG4gICAgY29uc3QgZmlyc3RJbmRleCA9IGJpbmFyeVNlYXJjaCh2aXNpYmxlTm9kZXMsIChub2RlKSA9PiB7XHJcbiAgICAgIHJldHVybiAobm9kZS5wb3NpdGlvbiArIFlfT0ZGU0VUID4gdGhpcy55KSB8fFxyXG4gICAgICAgICAgICAgKG5vZGUucG9zaXRpb24gKyBub2RlLmhlaWdodCA+IHRoaXMueSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZWFyY2ggZm9yIGxhc3Qgbm9kZSBpbiB0aGUgdmlld3BvcnQgdXNpbmcgYmluYXJ5IHNlYXJjaFxyXG4gICAgLy8gTG9vayBmb3IgZmlyc3Qgbm9kZSB0aGF0IHN0YXJ0cyBhZnRlciB0aGUgZW5kIG9mIHRoZSB2aWV3cG9ydCAod2l0aCBidWZmZXIpXHJcbiAgICBjb25zdCBsYXN0SW5kZXggPSBiaW5hcnlTZWFyY2godmlzaWJsZU5vZGVzLCAobm9kZSkgPT4ge1xyXG4gICAgICByZXR1cm4gbm9kZS5wb3NpdGlvbiAtIFlfT0ZGU0VUID4gdGhpcy55ICsgdGhpcy52aWV3cG9ydEhlaWdodDtcclxuICAgIH0sIGZpcnN0SW5kZXgpO1xyXG5cclxuICAgIGNvbnN0IHZpZXdwb3J0Tm9kZXMgPSBbXTtcclxuXHJcbiAgICBmb3IgKGxldCBpID0gZmlyc3RJbmRleDsgaSA8PSBsYXN0SW5kZXg7IGkrKykge1xyXG4gICAgICB2aWV3cG9ydE5vZGVzLnB1c2godmlzaWJsZU5vZGVzW2ldKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdmlld3BvcnROb2RlcztcclxuICB9XHJcblxyXG4gIGZpeFNjcm9sbCgpIHtcclxuICAgIGNvbnN0IG1heFkgPSBNYXRoLm1heCgwLCB0aGlzLnRvdGFsSGVpZ2h0IC0gdGhpcy52aWV3cG9ydEhlaWdodCk7XHJcblxyXG4gICAgaWYgKHRoaXMueSA8IDApIHRoaXMuX3NldFlCbG9ja3MoMCk7XHJcbiAgICBpZiAodGhpcy55ID4gbWF4WSkgdGhpcy5fc2V0WUJsb2NrcyhtYXhZIC8gWV9FUFNJTE9OKTtcclxuICB9XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGJpbmFyeVNlYXJjaChub2RlcywgY29uZGl0aW9uLCBmaXJzdEluZGV4ID0gMCkge1xyXG4gIGxldCBpbmRleCA9IGZpcnN0SW5kZXg7XHJcbiAgbGV0IHRvSW5kZXggPSBub2Rlcy5sZW5ndGggLSAxO1xyXG5cclxuICB3aGlsZSAoaW5kZXggIT09IHRvSW5kZXgpIHtcclxuICAgIGxldCBtaWRJbmRleCA9IE1hdGguZmxvb3IoKGluZGV4ICsgdG9JbmRleCkgLyAyKTtcclxuXHJcbiAgICBpZiAoY29uZGl0aW9uKG5vZGVzW21pZEluZGV4XSkpIHtcclxuICAgICAgdG9JbmRleCA9IG1pZEluZGV4O1xyXG4gICAgfVxyXG4gICAgZWxzZSB7XHJcbiAgICAgIGlmIChpbmRleCA9PT0gbWlkSW5kZXgpIGluZGV4ID0gdG9JbmRleDtcclxuICAgICAgZWxzZSBpbmRleCA9IG1pZEluZGV4O1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5kZXg7XHJcbn1cclxuIl19
|