@limble/limble-tree 2.0.0 → 4.0.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 -0
- package/esm2022/lib/components/branch/branch.component.mjs +79 -0
- package/esm2022/lib/components/dragover-no-change-detect.mjs +39 -0
- package/{esm2020 → esm2022}/lib/components/dropzone/dropzone.component.mjs +4 -4
- package/{esm2020 → esm2022}/lib/components/root/root.component.mjs +5 -5
- package/esm2022/lib/core/tree-branch/branch-controller.mjs +99 -0
- package/esm2022/lib/core/tree-branch/tree-branch.mjs +429 -0
- package/esm2022/lib/core/tree-node-base.mjs +77 -0
- package/esm2022/lib/core/tree-root/tree-root.mjs +193 -0
- package/{esm2020 → esm2022}/lib/core/tree-service/tree.service.mjs +4 -4
- package/{esm2020 → esm2022}/lib/extras/collapse/collapse.module.mjs +5 -5
- package/{esm2020 → esm2022}/lib/extras/collapse/collapse.service.mjs +4 -4
- package/esm2022/lib/extras/drag-and-drop/drag-and-drop.mjs +83 -0
- package/{esm2020 → esm2022}/lib/extras/drag-and-drop/drag-and-drop.module.mjs +5 -5
- package/{esm2020 → esm2022}/lib/extras/drag-and-drop/drag-and-drop.service.mjs +4 -4
- package/{esm2020 → esm2022}/lib/extras/drag-and-drop/draggable.directive.mjs +5 -5
- package/esm2022/lib/extras/drag-and-drop/dropzone-renderer.mjs +176 -0
- package/esm2022/lib/legacy/legacy-tree.mjs +73 -0
- package/esm2022/lib/legacy/limble-tree-legacy.module.mjs +20 -0
- package/esm2022/lib/legacy/limble-tree-root/limble-tree-root.component.mjs +78 -0
- package/{esm2020 → esm2022}/lib/limble-tree.module.mjs +5 -5
- package/esm2022/shared/assert.mjs +7 -0
- package/{fesm2020 → fesm2022}/limble-limble-tree.mjs +72 -75
- package/fesm2022/limble-limble-tree.mjs.map +1 -0
- package/lib/components/branch/branch.component.d.ts +1 -1
- package/lib/components/dropzone/dropzone.component.d.ts +1 -1
- package/lib/core/tree-node-base.d.ts +2 -1
- package/lib/extras/drag-and-drop/draggable.directive.d.ts +1 -1
- package/lib/legacy/limble-tree-root/limble-tree-root.component.d.ts +2 -2
- package/package.json +7 -13
- package/esm2020/lib/components/branch/branch.component.mjs +0 -79
- package/esm2020/lib/components/dragover-no-change-detect.mjs +0 -39
- package/esm2020/lib/core/tree-branch/branch-controller.mjs +0 -99
- package/esm2020/lib/core/tree-branch/tree-branch.mjs +0 -429
- package/esm2020/lib/core/tree-node-base.mjs +0 -80
- package/esm2020/lib/core/tree-root/tree-root.mjs +0 -193
- package/esm2020/lib/extras/drag-and-drop/drag-and-drop.mjs +0 -83
- package/esm2020/lib/extras/drag-and-drop/dropzone-renderer.mjs +0 -176
- package/esm2020/lib/legacy/legacy-tree.mjs +0 -73
- package/esm2020/lib/legacy/limble-tree-legacy.module.mjs +0 -20
- package/esm2020/lib/legacy/limble-tree-root/limble-tree-root.component.mjs +0 -78
- package/esm2020/shared/assert.mjs +0 -7
- package/fesm2015/limble-limble-tree.mjs +0 -1812
- package/fesm2015/limble-limble-tree.mjs.map +0 -1
- package/fesm2020/limble-limble-tree.mjs.map +0 -1
- /package/{esm2020 → esm2022}/lib/components/branch/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/components/dropzone/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/components/host-component.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/components/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/components/node-component.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/components/root/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/branch-options.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/branchable.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/component-container.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/configuration/configuration.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/configuration/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/configuration/tree-options.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/tree-branch/graftable.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/tree-branch/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/tree-node.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/tree-plot.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/tree-root/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/tree-root/root-controller.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/core/tree-service/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/errors/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/errors/tree-error.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/drag/drag-end-event.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/drag/drag-start-event.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/drag/drop-event.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/drag/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/general/destruction-event.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/general/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/relational/graft-event.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/relational/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/relational/prune-event.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/relational/relational-tree-event.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/relational/tree-relationship.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/events/tree-event.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/extras/collapse/collapse.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/extras/collapse/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/extras/drag-and-drop/drag-state.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/extras/drag-and-drop/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/legacy/index.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/legacy/legacy-component-obj.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/legacy/legacy-tree-data.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/legacy/legacy-tree-options.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/limble-limble-tree.mjs +0 -0
- /package/{esm2020 → esm2022}/public-api.mjs +0 -0
- /package/{esm2020 → esm2022}/shared/has-property.mjs +0 -0
- /package/{esm2020 → esm2022}/shared/index.mjs +0 -0
|
@@ -1,1812 +0,0 @@
|
|
|
1
|
-
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, NgModule, EventEmitter, Directive, Output, Component, Input, NgZone, ViewContainerRef, ViewChild, ViewChildren, createComponent, EnvironmentInjector, HostListener } from '@angular/core';
|
|
3
|
-
import { BehaviorSubject, fromEvent, merge, map, filter, Subject, first } from 'rxjs';
|
|
4
|
-
import * as i1 from '@angular/common';
|
|
5
|
-
import { CommonModule } from '@angular/common';
|
|
6
|
-
|
|
7
|
-
class TreeCollapser {
|
|
8
|
-
constructor() {
|
|
9
|
-
this.tempStorage = new Map();
|
|
10
|
-
}
|
|
11
|
-
collapse(treeBranch) {
|
|
12
|
-
if (treeBranch.branches().length === 0)
|
|
13
|
-
return;
|
|
14
|
-
const branches = [];
|
|
15
|
-
this.tempStorage.set(treeBranch, branches);
|
|
16
|
-
treeBranch.branches().forEach((branch) => {
|
|
17
|
-
branch.prune();
|
|
18
|
-
branches.push(branch);
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
expand(treeBranch) {
|
|
22
|
-
const branches = this.tempStorage.get(treeBranch);
|
|
23
|
-
if (branches === undefined)
|
|
24
|
-
return;
|
|
25
|
-
branches.forEach((branch) => {
|
|
26
|
-
branch.graftTo(treeBranch);
|
|
27
|
-
});
|
|
28
|
-
this.tempStorage.delete(treeBranch);
|
|
29
|
-
treeBranch.detectChanges();
|
|
30
|
-
}
|
|
31
|
-
isCollapsed(treeBranch) {
|
|
32
|
-
return this.tempStorage.has(treeBranch);
|
|
33
|
-
}
|
|
34
|
-
storePrecollapsedNode(parent, branch) {
|
|
35
|
-
var _a;
|
|
36
|
-
this.tempStorage.set(parent, ((_a = this.tempStorage.get(parent)) !== null && _a !== void 0 ? _a : []).concat(branch));
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
const treeCollapser = new TreeCollapser();
|
|
40
|
-
|
|
41
|
-
/** A service that collapses and expands tree branches */
|
|
42
|
-
class TreeCollapseService {
|
|
43
|
-
/**
|
|
44
|
-
* Causes a TreeBranch to collapse, temporarily pruning all of its children
|
|
45
|
-
* from the tree.
|
|
46
|
-
*
|
|
47
|
-
* @param treeBranch - The branch to collapse.
|
|
48
|
-
*/
|
|
49
|
-
collapse(treeBranch) {
|
|
50
|
-
treeCollapser.collapse(treeBranch);
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Causes a TreeBranch to expand, restoring all of its children which were
|
|
54
|
-
* previously pruned by a call to `collapse()`.
|
|
55
|
-
*
|
|
56
|
-
* @param treeBranch - The branch to expand.
|
|
57
|
-
*/
|
|
58
|
-
expand(treeBranch) {
|
|
59
|
-
treeCollapser.expand(treeBranch);
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Determines whether a TreeBranch currently has any children which are
|
|
63
|
-
* pruned from the tree due to a call to the `collapse()` method.
|
|
64
|
-
*
|
|
65
|
-
* @remarks
|
|
66
|
-
* Child branches which are pruned manually from the tree, rather than
|
|
67
|
-
* through the `collapse()` method, will not be considered.
|
|
68
|
-
*
|
|
69
|
-
* @param treeBranch - The branch to check.
|
|
70
|
-
*
|
|
71
|
-
* @returns `true` if the branch is currently collapsed; `false` if it is not.
|
|
72
|
-
*/
|
|
73
|
-
isCollapsed(treeBranch) {
|
|
74
|
-
return treeCollapser.isCollapsed(treeBranch);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
TreeCollapseService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeCollapseService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
78
|
-
TreeCollapseService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeCollapseService });
|
|
79
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeCollapseService, decorators: [{
|
|
80
|
-
type: Injectable
|
|
81
|
-
}] });
|
|
82
|
-
|
|
83
|
-
/** A module containing the entities which provide collapse functionality */
|
|
84
|
-
class TreeCollapseModule {
|
|
85
|
-
}
|
|
86
|
-
TreeCollapseModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeCollapseModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
87
|
-
TreeCollapseModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: TreeCollapseModule });
|
|
88
|
-
TreeCollapseModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeCollapseModule, providers: [TreeCollapseService] });
|
|
89
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeCollapseModule, decorators: [{
|
|
90
|
-
type: NgModule,
|
|
91
|
-
args: [{
|
|
92
|
-
providers: [TreeCollapseService]
|
|
93
|
-
}]
|
|
94
|
-
}] });
|
|
95
|
-
|
|
96
|
-
function assert(condition) {
|
|
97
|
-
if (condition) {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
throw new Error("Assertion Failed!");
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function hasProperty(input, prop) {
|
|
104
|
-
return typeof input === "object" && input !== null && prop in input;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
var DragStates;
|
|
108
|
-
(function (DragStates) {
|
|
109
|
-
DragStates[DragStates["Idle"] = 0] = "Idle";
|
|
110
|
-
DragStates[DragStates["Starting"] = 1] = "Starting";
|
|
111
|
-
DragStates[DragStates["Dragging"] = 2] = "Dragging";
|
|
112
|
-
DragStates[DragStates["Dropped"] = 3] = "Dropped";
|
|
113
|
-
})(DragStates || (DragStates = {}));
|
|
114
|
-
class DragState {
|
|
115
|
-
constructor() {
|
|
116
|
-
this._state = DragStates.Idle;
|
|
117
|
-
this.state$ = new BehaviorSubject(DragStates.Idle);
|
|
118
|
-
this.state$.subscribe((state) => {
|
|
119
|
-
this._state = state;
|
|
120
|
-
});
|
|
121
|
-
this.dragData = undefined;
|
|
122
|
-
}
|
|
123
|
-
getDragData() {
|
|
124
|
-
return this.dragData;
|
|
125
|
-
}
|
|
126
|
-
starting(treeBranch) {
|
|
127
|
-
assert(this._state === DragStates.Idle);
|
|
128
|
-
this.dragData = treeBranch;
|
|
129
|
-
this.state$.next(DragStates.Starting);
|
|
130
|
-
}
|
|
131
|
-
dragging() {
|
|
132
|
-
assert(this._state === DragStates.Starting);
|
|
133
|
-
this.state$.next(DragStates.Dragging);
|
|
134
|
-
}
|
|
135
|
-
dropped() {
|
|
136
|
-
assert(this._state === DragStates.Dragging);
|
|
137
|
-
this.state$.next(DragStates.Dropped);
|
|
138
|
-
}
|
|
139
|
-
restart() {
|
|
140
|
-
this.dragData = undefined;
|
|
141
|
-
this.state$.next(DragStates.Idle);
|
|
142
|
-
}
|
|
143
|
-
events() {
|
|
144
|
-
return this.state$;
|
|
145
|
-
}
|
|
146
|
-
state() {
|
|
147
|
-
return this._state;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
const dragState = new DragState();
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Works just like Angular's built-in `(dragover)` event binding, but is much
|
|
154
|
-
* more performant. It throttles the event to a configurable rate (default once
|
|
155
|
-
* every 25ms) and runs outside of Angular's change detection.
|
|
156
|
-
*/
|
|
157
|
-
class DragoverNoChangeDetectDirective {
|
|
158
|
-
constructor(ngZone, el) {
|
|
159
|
-
this.ngZone = ngZone;
|
|
160
|
-
this.el = el;
|
|
161
|
-
this.dragoverNoChangeDetect = new EventEmitter();
|
|
162
|
-
}
|
|
163
|
-
ngOnInit() {
|
|
164
|
-
this.ngZone.runOutsideAngular(() => {
|
|
165
|
-
this.eventSubscription = fromEvent(this.el.nativeElement, "dragover").subscribe(($event) => {
|
|
166
|
-
this.dragoverNoChangeDetect.emit($event);
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
ngOnDestroy() {
|
|
171
|
-
if (this.eventSubscription !== undefined) {
|
|
172
|
-
this.eventSubscription.unsubscribe();
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
DragoverNoChangeDetectDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: DragoverNoChangeDetectDirective, deps: [{ token: i0.NgZone }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
177
|
-
DragoverNoChangeDetectDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: DragoverNoChangeDetectDirective, isStandalone: true, selector: "[dragoverNoChangeDetect]", outputs: { dragoverNoChangeDetect: "dragoverNoChangeDetect" }, ngImport: i0 });
|
|
178
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: DragoverNoChangeDetectDirective, decorators: [{
|
|
179
|
-
type: Directive,
|
|
180
|
-
args: [{
|
|
181
|
-
standalone: true,
|
|
182
|
-
selector: "[dragoverNoChangeDetect]"
|
|
183
|
-
}]
|
|
184
|
-
}], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.ElementRef }]; }, propDecorators: { dragoverNoChangeDetect: [{
|
|
185
|
-
type: Output
|
|
186
|
-
}] } });
|
|
187
|
-
|
|
188
|
-
class DropzoneComponent {
|
|
189
|
-
constructor() {
|
|
190
|
-
this.dropped = new EventEmitter();
|
|
191
|
-
this.active = false;
|
|
192
|
-
}
|
|
193
|
-
dragenterHandler() {
|
|
194
|
-
this.active = true;
|
|
195
|
-
}
|
|
196
|
-
dragleaveHandler() {
|
|
197
|
-
this.active = false;
|
|
198
|
-
}
|
|
199
|
-
dragoverHandler(event) {
|
|
200
|
-
event.preventDefault();
|
|
201
|
-
event.dataTransfer.dropEffect = "move";
|
|
202
|
-
}
|
|
203
|
-
dropHandler(event) {
|
|
204
|
-
this.dropped.emit(event);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
DropzoneComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: DropzoneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
208
|
-
DropzoneComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: DropzoneComponent, isStandalone: true, selector: "dropzone", inputs: { placement: "placement" }, outputs: { dropped: "dropped" }, ngImport: i0, template: "<div\n class=\"dropzone\"\n [ngClass]=\"{ active: active }\"\n (dragenter)=\"dragenterHandler()\"\n (dragleave)=\"dragleaveHandler()\"\n (dragoverNoChangeDetect)=\"dragoverHandler($event)\"\n (drop)=\"dropHandler($event)\"\n></div>\n", styles: [".dropzone{border-radius:8px;border:1px dashed #727374;background-color:#ededed;height:36px;margin:8px 0;transition:height .3s ease-out;animation:animation .3s ease-out}.dropzone.active{border-color:#289e49;border-width:2px;background-color:#d0e8d6;height:72px}@keyframes animation{0%{height:0px;opacity:0}to{height:36px;opacity:1}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: DragoverNoChangeDetectDirective, selector: "[dragoverNoChangeDetect]", outputs: ["dragoverNoChangeDetect"] }] });
|
|
209
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: DropzoneComponent, decorators: [{
|
|
210
|
-
type: Component,
|
|
211
|
-
args: [{ standalone: true, selector: "dropzone", imports: [CommonModule, DragoverNoChangeDetectDirective], template: "<div\n class=\"dropzone\"\n [ngClass]=\"{ active: active }\"\n (dragenter)=\"dragenterHandler()\"\n (dragleave)=\"dragleaveHandler()\"\n (dragoverNoChangeDetect)=\"dragoverHandler($event)\"\n (drop)=\"dropHandler($event)\"\n></div>\n", styles: [".dropzone{border-radius:8px;border:1px dashed #727374;background-color:#ededed;height:36px;margin:8px 0;transition:height .3s ease-out;animation:animation .3s ease-out}.dropzone.active{border-color:#289e49;border-width:2px;background-color:#d0e8d6;height:72px}@keyframes animation{0%{height:0px;opacity:0}to{height:36px;opacity:1}}\n"] }]
|
|
212
|
-
}], propDecorators: { placement: [{
|
|
213
|
-
type: Input
|
|
214
|
-
}], dropped: [{
|
|
215
|
-
type: Output
|
|
216
|
-
}] } });
|
|
217
|
-
|
|
218
|
-
class BranchComponent {
|
|
219
|
-
constructor(appRef) {
|
|
220
|
-
this.appRef = appRef;
|
|
221
|
-
this.branchesContainer = undefined;
|
|
222
|
-
this.contentContainer = undefined;
|
|
223
|
-
this.dropzones = undefined;
|
|
224
|
-
this.contentCreated = new EventEmitter();
|
|
225
|
-
this.showDropzones = new EventEmitter();
|
|
226
|
-
this.dropped = new EventEmitter();
|
|
227
|
-
this.showInnerDropzone = false;
|
|
228
|
-
this.showLateralDropzone = false;
|
|
229
|
-
}
|
|
230
|
-
ngAfterViewInit() {
|
|
231
|
-
assert(this.contentContainer !== undefined);
|
|
232
|
-
assert(this.contentToHost !== undefined);
|
|
233
|
-
this.hostedContent = this.contentContainer.createComponent(this.contentToHost);
|
|
234
|
-
this.contentCreated.emit(this.hostedContent.instance);
|
|
235
|
-
assert(this.dropzones !== undefined);
|
|
236
|
-
const inner = this.dropzones.get(0);
|
|
237
|
-
const lateral = this.dropzones.get(1);
|
|
238
|
-
assert(inner !== undefined && lateral !== undefined);
|
|
239
|
-
merge(inner.dropped.pipe(map(() => "inner")), lateral.dropped.pipe(map(() => "lateral"))).subscribe(this.dropped);
|
|
240
|
-
this.hostedContent.changeDetectorRef.detectChanges();
|
|
241
|
-
}
|
|
242
|
-
getHostedContent() {
|
|
243
|
-
return this.hostedContent;
|
|
244
|
-
}
|
|
245
|
-
triggerChangeDetection() {
|
|
246
|
-
if (!NgZone.isInAngularZone()) {
|
|
247
|
-
this.appRef.tick();
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
dragoverHandler(event) {
|
|
251
|
-
const elementHeight = event.currentTarget.getBoundingClientRect().height;
|
|
252
|
-
if (event.offsetY < elementHeight / 2) {
|
|
253
|
-
this.showDropzones.emit("upper");
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
this.showDropzones.emit("lower");
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
ngOnDestroy() {
|
|
260
|
-
//I'm not 100% sure why, but we have to remove any reference to the
|
|
261
|
-
//componentRef otherwise Angular will never release it for garbage
|
|
262
|
-
//collection.
|
|
263
|
-
this.hostedContent = undefined;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
BranchComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: BranchComponent, deps: [{ token: i0.ApplicationRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
267
|
-
BranchComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: BranchComponent, isStandalone: true, selector: "branch", inputs: { contentToHost: "contentToHost" }, outputs: { contentCreated: "contentCreated", showDropzones: "showDropzones", dropped: "dropped" }, viewQueries: [{ propertyName: "branchesContainer", first: true, predicate: ["branchesContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "contentContainer", first: true, predicate: ["contentContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "dropzones", predicate: DropzoneComponent, descendants: true }], ngImport: i0, template: "<div class=\"content\" (dragoverNoChangeDetect)=\"dragoverHandler($event)\">\n <div #contentContainer></div>\n</div>\n<div class=\"branches-container\">\n <dropzone placement=\"inner\" [hidden]=\"!showInnerDropzone\"></dropzone>\n <div #branchesContainer></div>\n</div>\n<dropzone placement=\"lateral\" [hidden]=\"!showLateralDropzone\"></dropzone>\n", styles: [".branches-container{margin-left:16px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DropzoneComponent, selector: "dropzone", inputs: ["placement"], outputs: ["dropped"] }, { kind: "directive", type: DragoverNoChangeDetectDirective, selector: "[dragoverNoChangeDetect]", outputs: ["dragoverNoChangeDetect"] }] });
|
|
268
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: BranchComponent, decorators: [{
|
|
269
|
-
type: Component,
|
|
270
|
-
args: [{ standalone: true, selector: "branch", imports: [CommonModule, DropzoneComponent, DragoverNoChangeDetectDirective], template: "<div class=\"content\" (dragoverNoChangeDetect)=\"dragoverHandler($event)\">\n <div #contentContainer></div>\n</div>\n<div class=\"branches-container\">\n <dropzone placement=\"inner\" [hidden]=\"!showInnerDropzone\"></dropzone>\n <div #branchesContainer></div>\n</div>\n<dropzone placement=\"lateral\" [hidden]=\"!showLateralDropzone\"></dropzone>\n", styles: [".branches-container{margin-left:16px}\n"] }]
|
|
271
|
-
}], ctorParameters: function () { return [{ type: i0.ApplicationRef }]; }, propDecorators: { branchesContainer: [{
|
|
272
|
-
type: ViewChild,
|
|
273
|
-
args: ["branchesContainer", { read: ViewContainerRef }]
|
|
274
|
-
}], contentContainer: [{
|
|
275
|
-
type: ViewChild,
|
|
276
|
-
args: ["contentContainer", { read: ViewContainerRef }]
|
|
277
|
-
}], dropzones: [{
|
|
278
|
-
type: ViewChildren,
|
|
279
|
-
args: [DropzoneComponent]
|
|
280
|
-
}], contentToHost: [{
|
|
281
|
-
type: Input
|
|
282
|
-
}], contentCreated: [{
|
|
283
|
-
type: Output
|
|
284
|
-
}], showDropzones: [{
|
|
285
|
-
type: Output
|
|
286
|
-
}], dropped: [{
|
|
287
|
-
type: Output
|
|
288
|
-
}] } });
|
|
289
|
-
|
|
290
|
-
class RootComponent {
|
|
291
|
-
constructor() {
|
|
292
|
-
this.branchesContainer = undefined;
|
|
293
|
-
this.dropzone = undefined;
|
|
294
|
-
this.afterViewInit = new EventEmitter();
|
|
295
|
-
this.dropped = new EventEmitter();
|
|
296
|
-
this.showInnerDropzone = false;
|
|
297
|
-
}
|
|
298
|
-
ngAfterViewInit() {
|
|
299
|
-
this.afterViewInit.emit();
|
|
300
|
-
assert(this.dropzone !== undefined);
|
|
301
|
-
this.dropzone.dropped.subscribe(this.dropped);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
RootComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RootComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
305
|
-
RootComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: RootComponent, isStandalone: true, selector: "root", outputs: { afterViewInit: "afterViewInit", dropped: "dropped" }, viewQueries: [{ propertyName: "branchesContainer", first: true, predicate: ["branchesContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "dropzone", first: true, predicate: DropzoneComponent, descendants: true }], ngImport: i0, template: "<div class=\"branches-container\">\n <dropzone placement=\"inner\" [hidden]=\"!showInnerDropzone\"></dropzone>\n <div #branchesContainer></div>\n</div>\n", styles: [".branches-container{min-width:64px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DropzoneComponent, selector: "dropzone", inputs: ["placement"], outputs: ["dropped"] }] });
|
|
306
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RootComponent, decorators: [{
|
|
307
|
-
type: Component,
|
|
308
|
-
args: [{ standalone: true, selector: "root", imports: [CommonModule, DropzoneComponent], template: "<div class=\"branches-container\">\n <dropzone placement=\"inner\" [hidden]=\"!showInnerDropzone\"></dropzone>\n <div #branchesContainer></div>\n</div>\n", styles: [".branches-container{min-width:64px}\n"] }]
|
|
309
|
-
}], propDecorators: { branchesContainer: [{
|
|
310
|
-
type: ViewChild,
|
|
311
|
-
args: ["branchesContainer", { read: ViewContainerRef }]
|
|
312
|
-
}], dropzone: [{
|
|
313
|
-
type: ViewChild,
|
|
314
|
-
args: [DropzoneComponent]
|
|
315
|
-
}], afterViewInit: [{
|
|
316
|
-
type: Output
|
|
317
|
-
}], dropped: [{
|
|
318
|
-
type: Output
|
|
319
|
-
}] } });
|
|
320
|
-
|
|
321
|
-
class Configuration {
|
|
322
|
-
constructor() {
|
|
323
|
-
this.configStorage = new Map();
|
|
324
|
-
this.configStorage = new Map();
|
|
325
|
-
}
|
|
326
|
-
setConfig(root, options) {
|
|
327
|
-
this.configStorage.set(root, options);
|
|
328
|
-
}
|
|
329
|
-
getConfig(root) {
|
|
330
|
-
return this.configStorage.get(root);
|
|
331
|
-
}
|
|
332
|
-
delete(root) {
|
|
333
|
-
this.configStorage.delete(root);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
const config = new Configuration();
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* A wrapper around the BranchComponent that helps instantiate it and handles its events.
|
|
340
|
-
*/
|
|
341
|
-
class BranchController {
|
|
342
|
-
constructor(treeBranch, parentBranchesContainer) {
|
|
343
|
-
this.treeBranch = treeBranch;
|
|
344
|
-
this.outputBindingSubscriptions = [];
|
|
345
|
-
this.branchComponentRef = createComponent(BranchComponent, {
|
|
346
|
-
environmentInjector: parentBranchesContainer.injector.get(EnvironmentInjector)
|
|
347
|
-
});
|
|
348
|
-
this.branchComponentRef.instance.contentToHost =
|
|
349
|
-
this.treeBranch.branchOptions.component;
|
|
350
|
-
this.instanceSubscriptions = this.getInstanceSubscriptions(this.branchComponentRef.instance);
|
|
351
|
-
}
|
|
352
|
-
destroy() {
|
|
353
|
-
this.instanceSubscriptions.forEach((sub) => {
|
|
354
|
-
sub.unsubscribe();
|
|
355
|
-
});
|
|
356
|
-
this.outputBindingSubscriptions.forEach((sub) => {
|
|
357
|
-
sub.unsubscribe();
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
detectChanges() {
|
|
361
|
-
this.branchComponentRef.changeDetectorRef.detectChanges();
|
|
362
|
-
}
|
|
363
|
-
getBranchesContainer() {
|
|
364
|
-
return this.branchComponentRef.instance.branchesContainer;
|
|
365
|
-
}
|
|
366
|
-
getComponentInstance() {
|
|
367
|
-
return this.branchComponentRef.instance;
|
|
368
|
-
}
|
|
369
|
-
getHostView() {
|
|
370
|
-
return this.branchComponentRef.hostView;
|
|
371
|
-
}
|
|
372
|
-
getNativeElement() {
|
|
373
|
-
return this.branchComponentRef.location.nativeElement;
|
|
374
|
-
}
|
|
375
|
-
getUserlandComponentRef() {
|
|
376
|
-
return this.branchComponentRef.instance.getHostedContent();
|
|
377
|
-
}
|
|
378
|
-
getContentCreatedSub(instance) {
|
|
379
|
-
return instance.contentCreated.subscribe((userlandComponentInstance) => {
|
|
380
|
-
var _a, _b;
|
|
381
|
-
const component = userlandComponentInstance;
|
|
382
|
-
Object.entries((_a = this.treeBranch.branchOptions.inputBindings) !== null && _a !== void 0 ? _a : {}).forEach(([key, value]) => {
|
|
383
|
-
component[key] = value;
|
|
384
|
-
});
|
|
385
|
-
Object.entries((_b = this.treeBranch.branchOptions.outputBindings) !== null && _b !== void 0 ? _b : {}).forEach(([key, value]) => {
|
|
386
|
-
this.outputBindingSubscriptions.push(component[key].subscribe(value));
|
|
387
|
-
});
|
|
388
|
-
component.treeBranch = this.treeBranch;
|
|
389
|
-
const dropzones = instance.dropzones;
|
|
390
|
-
assert(dropzones !== undefined);
|
|
391
|
-
dropzoneRenderer.registerDropzones(dropzones, this.treeBranch);
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
getInstanceSubscriptions(instance) {
|
|
395
|
-
const droppedSub = instance.dropped.subscribe((placement) => {
|
|
396
|
-
dropzoneRenderer.handleDrop(this.treeBranch, placement);
|
|
397
|
-
});
|
|
398
|
-
return [
|
|
399
|
-
this.getContentCreatedSub(instance),
|
|
400
|
-
this.getShowLowerZonesSub(instance),
|
|
401
|
-
this.getShowUpperZonesSub(instance),
|
|
402
|
-
droppedSub
|
|
403
|
-
];
|
|
404
|
-
}
|
|
405
|
-
getShowLowerZonesSub(instance) {
|
|
406
|
-
return instance.showDropzones
|
|
407
|
-
.pipe(filter((direction) => direction === "lower"))
|
|
408
|
-
.subscribe(() => {
|
|
409
|
-
const currentDropzoneDisplayed = dropzoneRenderer.getCurrentDisplay();
|
|
410
|
-
if ((currentDropzoneDisplayed === null || currentDropzoneDisplayed === void 0 ? void 0 : currentDropzoneDisplayed.treeBranch) === this.treeBranch &&
|
|
411
|
-
currentDropzoneDisplayed.direction === "lower") {
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
dropzoneRenderer.showLowerZones(this.treeBranch);
|
|
415
|
-
instance.triggerChangeDetection();
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
getShowUpperZonesSub(instance) {
|
|
419
|
-
return instance.showDropzones
|
|
420
|
-
.pipe(filter((direction) => direction === "upper"))
|
|
421
|
-
.subscribe(() => {
|
|
422
|
-
const currentDropzoneDisplayed = dropzoneRenderer.getCurrentDisplay();
|
|
423
|
-
if ((currentDropzoneDisplayed === null || currentDropzoneDisplayed === void 0 ? void 0 : currentDropzoneDisplayed.treeBranch) === this.treeBranch &&
|
|
424
|
-
currentDropzoneDisplayed.direction === "upper") {
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
dropzoneRenderer.showUpperZones(this.treeBranch);
|
|
428
|
-
instance.triggerChangeDetection();
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
class TreeError extends Error {
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
/** Emitted when a drag-and-drop operation has completed */
|
|
437
|
-
class DragEndEvent {
|
|
438
|
-
constructor(source, endpoints) {
|
|
439
|
-
this._source = source;
|
|
440
|
-
this._oldParent = endpoints.oldParent;
|
|
441
|
-
this._oldIndex = endpoints.oldIndex;
|
|
442
|
-
this._newParent = endpoints.newParent;
|
|
443
|
-
this._newIndex = endpoints.newIndex;
|
|
444
|
-
}
|
|
445
|
-
/** @returns The new index of the dropped branch */
|
|
446
|
-
newIndex() {
|
|
447
|
-
return this._newIndex;
|
|
448
|
-
}
|
|
449
|
-
/** @returns The new parent of the dropped branch */
|
|
450
|
-
newParent() {
|
|
451
|
-
return this._newParent;
|
|
452
|
-
}
|
|
453
|
-
/** @returns The index of the dropped branch before it was dragged */
|
|
454
|
-
oldIndex() {
|
|
455
|
-
return this._oldIndex;
|
|
456
|
-
}
|
|
457
|
-
/** @returns The parent of the dropped branch before it was dragged */
|
|
458
|
-
oldParent() {
|
|
459
|
-
return this._oldParent;
|
|
460
|
-
}
|
|
461
|
-
source() {
|
|
462
|
-
return this._source;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
/** Emitted when a TreeBranch begins being dragged */
|
|
467
|
-
class DragStartEvent {
|
|
468
|
-
constructor(source) {
|
|
469
|
-
this._source = source;
|
|
470
|
-
}
|
|
471
|
-
source() {
|
|
472
|
-
return this._source;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
/** Emitted when a TreeBranch is dropped into a valid Dropzone */
|
|
477
|
-
class DropEvent {
|
|
478
|
-
constructor(source, parent, index) {
|
|
479
|
-
this._source = source;
|
|
480
|
-
this._parent = parent;
|
|
481
|
-
this._index = index;
|
|
482
|
-
}
|
|
483
|
-
source() {
|
|
484
|
-
return this._source;
|
|
485
|
-
}
|
|
486
|
-
index() {
|
|
487
|
-
return this._index;
|
|
488
|
-
}
|
|
489
|
-
parent() {
|
|
490
|
-
return this._parent;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
/** Emitted when a node is destroyed */
|
|
495
|
-
class DestructionEvent {
|
|
496
|
-
constructor(source) {
|
|
497
|
-
this._source = source;
|
|
498
|
-
}
|
|
499
|
-
source() {
|
|
500
|
-
return this._source;
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
/** Emits when a branch is grafted to another tree node */
|
|
505
|
-
class GraftEvent {
|
|
506
|
-
constructor(source, relationship) {
|
|
507
|
-
this._source = source;
|
|
508
|
-
this._child = relationship.child;
|
|
509
|
-
this._parent = relationship.parent;
|
|
510
|
-
this._index = relationship.index;
|
|
511
|
-
}
|
|
512
|
-
child() {
|
|
513
|
-
return this._child;
|
|
514
|
-
}
|
|
515
|
-
index() {
|
|
516
|
-
return this._index;
|
|
517
|
-
}
|
|
518
|
-
parent() {
|
|
519
|
-
return this._parent;
|
|
520
|
-
}
|
|
521
|
-
source() {
|
|
522
|
-
return this._source;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
/** Emitted when a branch is pruned from its parent branch */
|
|
527
|
-
class PruneEvent {
|
|
528
|
-
constructor(source, relationship) {
|
|
529
|
-
this._source = source;
|
|
530
|
-
this._child = relationship.child;
|
|
531
|
-
this._parent = relationship.parent;
|
|
532
|
-
this._index = relationship.index;
|
|
533
|
-
}
|
|
534
|
-
child() {
|
|
535
|
-
return this._child;
|
|
536
|
-
}
|
|
537
|
-
index() {
|
|
538
|
-
return this._index;
|
|
539
|
-
}
|
|
540
|
-
parent() {
|
|
541
|
-
return this._parent;
|
|
542
|
-
}
|
|
543
|
-
source() {
|
|
544
|
-
return this._source;
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
class TreeNodeBase {
|
|
549
|
-
constructor() {
|
|
550
|
-
this.destroyed = false;
|
|
551
|
-
this._branches = [];
|
|
552
|
-
this.events$ = new Subject();
|
|
553
|
-
this.subscriptions = [
|
|
554
|
-
this.graftsToSelf().subscribe((event) => {
|
|
555
|
-
this.registerChildRelationship(event.child(), event.index());
|
|
556
|
-
}),
|
|
557
|
-
this.prunesToSelf().subscribe((event) => {
|
|
558
|
-
this.deregisterChildRelationship(event.child());
|
|
559
|
-
})
|
|
560
|
-
];
|
|
561
|
-
}
|
|
562
|
-
branches() {
|
|
563
|
-
return [...this._branches];
|
|
564
|
-
}
|
|
565
|
-
destroy() {
|
|
566
|
-
this.branches().forEach((branch) => {
|
|
567
|
-
branch.destroy();
|
|
568
|
-
});
|
|
569
|
-
this.subscriptions.forEach((sub) => {
|
|
570
|
-
sub.unsubscribe();
|
|
571
|
-
});
|
|
572
|
-
this.destroyed = true;
|
|
573
|
-
}
|
|
574
|
-
dispatch(event) {
|
|
575
|
-
this.events$.next(event);
|
|
576
|
-
}
|
|
577
|
-
events() {
|
|
578
|
-
return this.events$;
|
|
579
|
-
}
|
|
580
|
-
getBranch(index) {
|
|
581
|
-
return this._branches[index];
|
|
582
|
-
}
|
|
583
|
-
handleUserlandError(error) {
|
|
584
|
-
const message = hasProperty(error, "message")
|
|
585
|
-
? error.message
|
|
586
|
-
: "Unknown error";
|
|
587
|
-
throw new TreeError(`Failed to grow branch: ${message}`, {
|
|
588
|
-
// This cast to `any` is due to an issue in typescript that has been
|
|
589
|
-
// resolved at least by version 4.9.5. When we upgrade our typescript
|
|
590
|
-
// version we can remove the cast.
|
|
591
|
-
cause: error
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
isDestroyed() {
|
|
595
|
-
return this.destroyed;
|
|
596
|
-
}
|
|
597
|
-
plot() {
|
|
598
|
-
return new Map(this.branches().map((branch, index) => [index, branch.plot()]));
|
|
599
|
-
}
|
|
600
|
-
traverse(callback) {
|
|
601
|
-
this.branches().forEach((branch) => {
|
|
602
|
-
branch.traverse(callback);
|
|
603
|
-
});
|
|
604
|
-
}
|
|
605
|
-
deregisterChildRelationship(child) {
|
|
606
|
-
const index = this.branches().findIndex((branch) => branch === child);
|
|
607
|
-
this._branches.splice(index, 1);
|
|
608
|
-
}
|
|
609
|
-
graftsToSelf() {
|
|
610
|
-
return this.events().pipe(filter((event) => event instanceof GraftEvent), filter((event) => event.parent().events() === this.events$));
|
|
611
|
-
}
|
|
612
|
-
prunesToSelf() {
|
|
613
|
-
return this.events().pipe(filter((event) => event instanceof PruneEvent), filter((event) => event.parent().events() === this.events$));
|
|
614
|
-
}
|
|
615
|
-
registerChildRelationship(child, index) {
|
|
616
|
-
const branches = this.branches();
|
|
617
|
-
if (index < 0 || index > branches.length) {
|
|
618
|
-
throw new TreeError(`Can't register child at index ${index}. Out of range.`);
|
|
619
|
-
}
|
|
620
|
-
this._branches.splice(index, 0, child);
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
/**
|
|
625
|
-
* A wrapper around the BranchComponent that helps instantiate it and handles its events.
|
|
626
|
-
*/
|
|
627
|
-
class RootController {
|
|
628
|
-
constructor(treeRoot, viewContainerRef) {
|
|
629
|
-
this.treeRoot = treeRoot;
|
|
630
|
-
this.rootComponentRef = viewContainerRef.createComponent(RootComponent);
|
|
631
|
-
const viewInitSub = this.rootComponentRef.instance.afterViewInit.subscribe(() => {
|
|
632
|
-
const dropzone = this.rootComponentRef.instance.dropzone;
|
|
633
|
-
assert(dropzone !== undefined);
|
|
634
|
-
dropzoneRenderer.registerDropzone(dropzone, this.treeRoot);
|
|
635
|
-
});
|
|
636
|
-
const droppedSub = this.rootComponentRef.instance.dropped.subscribe(() => {
|
|
637
|
-
dropzoneRenderer.handleDrop(this.treeRoot, "inner");
|
|
638
|
-
});
|
|
639
|
-
this.instanceSubscriptions = [viewInitSub, droppedSub];
|
|
640
|
-
}
|
|
641
|
-
destroy() {
|
|
642
|
-
this.instanceSubscriptions.forEach((sub) => {
|
|
643
|
-
sub.unsubscribe();
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
|
-
detectChanges() {
|
|
647
|
-
this.rootComponentRef.changeDetectorRef.detectChanges();
|
|
648
|
-
}
|
|
649
|
-
getBranchesContainer() {
|
|
650
|
-
return this.rootComponentRef.instance.branchesContainer;
|
|
651
|
-
}
|
|
652
|
-
getComponentInstance() {
|
|
653
|
-
return this.rootComponentRef.instance;
|
|
654
|
-
}
|
|
655
|
-
getHostView() {
|
|
656
|
-
return this.rootComponentRef.hostView;
|
|
657
|
-
}
|
|
658
|
-
getNativeElement() {
|
|
659
|
-
return this.rootComponentRef.location.nativeElement;
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
/**
|
|
664
|
-
* Represents the base of the tree. It renders a very simple container for child
|
|
665
|
-
* branches. It has methods for creating and accessing those branches. It emits
|
|
666
|
-
* events when things happen in the tree.
|
|
667
|
-
*/
|
|
668
|
-
class TreeRoot {
|
|
669
|
-
constructor(viewContainerRef) {
|
|
670
|
-
this.viewContainerRef = viewContainerRef;
|
|
671
|
-
this.treeNodeBase = new TreeNodeBase();
|
|
672
|
-
this.rootController = new RootController(this, viewContainerRef);
|
|
673
|
-
this.detectChanges();
|
|
674
|
-
}
|
|
675
|
-
/** @returns All child branches as an array of TreeBranch instances */
|
|
676
|
-
branches() {
|
|
677
|
-
return this.treeNodeBase.branches();
|
|
678
|
-
}
|
|
679
|
-
/**
|
|
680
|
-
* Recursively destroys all branches of the tree, as well as itself.
|
|
681
|
-
*
|
|
682
|
-
* @remarks
|
|
683
|
-
* This releases all resources held or consumed by the tree.
|
|
684
|
-
*
|
|
685
|
-
* It is important to call this method when a tree is discarded, otherwise
|
|
686
|
-
* the tree will remain in memory and continue to consume resources.
|
|
687
|
-
*/
|
|
688
|
-
destroy() {
|
|
689
|
-
if (this.isDestroyed()) {
|
|
690
|
-
throw new TreeError("Cannot destroy a destroyed tree root");
|
|
691
|
-
}
|
|
692
|
-
dropzoneRenderer.clearTreeFromRegistry(this);
|
|
693
|
-
this.treeNodeBase.destroy();
|
|
694
|
-
this.rootController.destroy();
|
|
695
|
-
this.viewContainerRef.clear();
|
|
696
|
-
config.delete(this);
|
|
697
|
-
this.dispatch(new DestructionEvent(this));
|
|
698
|
-
}
|
|
699
|
-
/** Run Angular change detection on the root of the tree */
|
|
700
|
-
detectChanges() {
|
|
701
|
-
this.rootController.detectChanges();
|
|
702
|
-
}
|
|
703
|
-
/**
|
|
704
|
-
* Emits the specified TreeEvent.
|
|
705
|
-
*
|
|
706
|
-
* @remarks
|
|
707
|
-
* Caution: It is not recommended to manually emit TreeEvents that are already
|
|
708
|
-
* provided by the library. For example, it is not recommended to emit a
|
|
709
|
-
* `GraftEvent`, `DestructionEvent`, etc. These events may be used by the tree,
|
|
710
|
-
* and emitting them manually may cause unexpected behavior. Instead, we
|
|
711
|
-
* recommend implementing the TreeEvent interface with your own custom events
|
|
712
|
-
* and dispatching those.
|
|
713
|
-
*
|
|
714
|
-
* @param event - The TreeEvent that will be emitted.
|
|
715
|
-
*/
|
|
716
|
-
dispatch(event) {
|
|
717
|
-
this.treeNodeBase.dispatch(event);
|
|
718
|
-
}
|
|
719
|
-
/**
|
|
720
|
-
* @returns
|
|
721
|
-
* An observable that emits TreeEvents whenever an event is dispatched
|
|
722
|
-
* in the root or any of its descendant branches.
|
|
723
|
-
*/
|
|
724
|
-
events() {
|
|
725
|
-
return this.treeNodeBase.events();
|
|
726
|
-
}
|
|
727
|
-
/**
|
|
728
|
-
* @returns
|
|
729
|
-
* The child branch at the specified index, or undefined if there is
|
|
730
|
-
* no child branch at the specified index.
|
|
731
|
-
*/
|
|
732
|
-
getBranch(index) {
|
|
733
|
-
return this.treeNodeBase.getBranch(index);
|
|
734
|
-
}
|
|
735
|
-
/** @returns The ViewContainerRef in which child branches are rendered */
|
|
736
|
-
getBranchesContainer() {
|
|
737
|
-
if (this.isDestroyed()) {
|
|
738
|
-
throw new TreeError("Cannot get branches container from a destroyed tree root");
|
|
739
|
-
}
|
|
740
|
-
return this.rootController.getBranchesContainer();
|
|
741
|
-
}
|
|
742
|
-
/**
|
|
743
|
-
* Retrieves the RootComponent.
|
|
744
|
-
*
|
|
745
|
-
* @remarks
|
|
746
|
-
* The RootComponent holds the BranchesContainer, as well as a single Dropzone
|
|
747
|
-
* for drag-and-drop operations.
|
|
748
|
-
*
|
|
749
|
-
* @returns The instance of RootComponent that is rendered by this class.
|
|
750
|
-
*/
|
|
751
|
-
getComponentInstance() {
|
|
752
|
-
if (this.isDestroyed()) {
|
|
753
|
-
throw new TreeError("Cannot get component instance from a destroyed tree root");
|
|
754
|
-
}
|
|
755
|
-
return this.rootController.getComponentInstance();
|
|
756
|
-
}
|
|
757
|
-
/** @returns The Host View in which the RootComponent is rendered */
|
|
758
|
-
getHostView() {
|
|
759
|
-
if (this.isDestroyed()) {
|
|
760
|
-
throw new TreeError("Cannot get component host view from a destroyed tree root");
|
|
761
|
-
}
|
|
762
|
-
return this.rootController.getHostView();
|
|
763
|
-
}
|
|
764
|
-
/** @returns The RootComponent as a native HTML Element */
|
|
765
|
-
getNativeElement() {
|
|
766
|
-
if (this.isDestroyed()) {
|
|
767
|
-
throw new TreeError("Cannot get native element from a destroyed tree root");
|
|
768
|
-
}
|
|
769
|
-
return this.rootController.getNativeElement();
|
|
770
|
-
}
|
|
771
|
-
/**
|
|
772
|
-
* Appends a new child branch to this branch. The child branch will render
|
|
773
|
-
* the specified component according to the (optional) configuration parameter.
|
|
774
|
-
*
|
|
775
|
-
* @param component - The component to render in the new child branch.
|
|
776
|
-
* @param options - Configuration options for the new child branch.
|
|
777
|
-
*
|
|
778
|
-
* @returns
|
|
779
|
-
* The newly-created child branch.
|
|
780
|
-
*/
|
|
781
|
-
grow(component, options) {
|
|
782
|
-
if (this.isDestroyed()) {
|
|
783
|
-
throw new TreeError("Cannot grow a branch on a destroyed tree root");
|
|
784
|
-
}
|
|
785
|
-
try {
|
|
786
|
-
return new TreeBranch(this, Object.assign({ component }, options));
|
|
787
|
-
}
|
|
788
|
-
catch (error) {
|
|
789
|
-
this.handleUserlandError(error);
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
/** @returns `true` if the tree is destroyed, `false` otherwise */
|
|
793
|
-
isDestroyed() {
|
|
794
|
-
return this.treeNodeBase.isDestroyed();
|
|
795
|
-
}
|
|
796
|
-
/**
|
|
797
|
-
* Provides a model describing the shape of the tree.
|
|
798
|
-
*
|
|
799
|
-
* @returns A multi-dimensional Map which describes the shape of the tree.
|
|
800
|
-
*
|
|
801
|
-
* @example
|
|
802
|
-
* For example, an empty tree will return an empty Map. A tree with a single
|
|
803
|
-
* branch will return a Map with a single entry, where the key is the index
|
|
804
|
-
* of the branch (zero) and the value is an empty Map. A Tree like this:
|
|
805
|
-
*
|
|
806
|
-
* ```
|
|
807
|
-
* ---Branch-------Branch
|
|
808
|
-
* /
|
|
809
|
-
* Root-------Branch
|
|
810
|
-
* \
|
|
811
|
-
* ---Branch
|
|
812
|
-
* ```
|
|
813
|
-
* Will return a Map of matching shape:
|
|
814
|
-
* ```
|
|
815
|
-
* Map {
|
|
816
|
-
* 0: Map { 0: Map {}},
|
|
817
|
-
* 1: Map {},
|
|
818
|
-
* 2: Map {}
|
|
819
|
-
* }
|
|
820
|
-
* ```
|
|
821
|
-
*/
|
|
822
|
-
plot() {
|
|
823
|
-
return this.treeNodeBase.plot();
|
|
824
|
-
}
|
|
825
|
-
/** @returns Itself */
|
|
826
|
-
root() {
|
|
827
|
-
return this;
|
|
828
|
-
}
|
|
829
|
-
/**
|
|
830
|
-
* Traverses the tree in depth-first pre-order, executing the provided
|
|
831
|
-
* callback function on each node. Traversal includes the Root.
|
|
832
|
-
*
|
|
833
|
-
* @param callback - A function to execute on each node.
|
|
834
|
-
*/
|
|
835
|
-
traverse(callback) {
|
|
836
|
-
callback(this);
|
|
837
|
-
this.treeNodeBase.traverse(callback);
|
|
838
|
-
}
|
|
839
|
-
handleUserlandError(error) {
|
|
840
|
-
// When an error occurs in a userland component during a tree operation,
|
|
841
|
-
// it can cause undefined, bizarre behavior in the tree. To prevent this,
|
|
842
|
-
// we destroy the tree and throw an error instead. This helps protect
|
|
843
|
-
// the end-user's data from corruption.
|
|
844
|
-
this.destroy();
|
|
845
|
-
this.treeNodeBase.handleUserlandError(error);
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
/** Represents a standard node in a tree. Renders a BranchComponent.
|
|
850
|
-
*
|
|
851
|
-
* @remarks
|
|
852
|
-
* This class renders a branch component, which does the following:
|
|
853
|
-
* 1. Renders a component provided by the user
|
|
854
|
-
* 2. Provides a container in which child branches may be rendered
|
|
855
|
-
* 3. Contains two Dropzones: one for dropping branches below this branch (as a
|
|
856
|
-
* sibling), and one for dropping branches as a first child of this branch.
|
|
857
|
-
*/
|
|
858
|
-
class TreeBranch {
|
|
859
|
-
constructor(parent, branchOptions) {
|
|
860
|
-
this.branchOptions = branchOptions;
|
|
861
|
-
this.detachedView = null;
|
|
862
|
-
this.treeNodeBase = new TreeNodeBase();
|
|
863
|
-
const parentBranchesContainer = parent.getBranchesContainer();
|
|
864
|
-
assert(parentBranchesContainer !== undefined);
|
|
865
|
-
this.branchController = new BranchController(this, parentBranchesContainer);
|
|
866
|
-
const hostView = this.branchController.getHostView();
|
|
867
|
-
if (parent instanceof TreeBranch &&
|
|
868
|
-
parent.branchOptions.defaultCollapsed === true) {
|
|
869
|
-
treeCollapser.storePrecollapsedNode(parent, this);
|
|
870
|
-
this.detachedView = hostView;
|
|
871
|
-
}
|
|
872
|
-
else {
|
|
873
|
-
parentBranchesContainer.insert(hostView);
|
|
874
|
-
this._parent = parent;
|
|
875
|
-
this.dispatch(new GraftEvent(this, {
|
|
876
|
-
parent: this._parent,
|
|
877
|
-
child: this,
|
|
878
|
-
index: this._parent.branches().length
|
|
879
|
-
}));
|
|
880
|
-
this.setIndentation();
|
|
881
|
-
}
|
|
882
|
-
this.detectChanges();
|
|
883
|
-
}
|
|
884
|
-
/** @returns All child branches as an array of TreeBranch instances, in order. */
|
|
885
|
-
branches() {
|
|
886
|
-
return this.treeNodeBase.branches();
|
|
887
|
-
}
|
|
888
|
-
/**
|
|
889
|
-
* Recursively destroys all descendant branches, as well as itself. This
|
|
890
|
-
* releases all resources held or consumed by this branch and its descendants.
|
|
891
|
-
*
|
|
892
|
-
* @remarks
|
|
893
|
-
* It is important to call this method when a branch is discarded, otherwise
|
|
894
|
-
* the branch will remain in memory and continue to consume resources.
|
|
895
|
-
*/
|
|
896
|
-
destroy() {
|
|
897
|
-
if (this.isDestroyed()) {
|
|
898
|
-
throw new TreeError("Cannot destroy a destroyed tree branch");
|
|
899
|
-
}
|
|
900
|
-
this.prune();
|
|
901
|
-
treeCollapser.expand(this);
|
|
902
|
-
dropzoneRenderer.clearTreeFromRegistry(this);
|
|
903
|
-
this.branchController.getHostView().destroy();
|
|
904
|
-
this.treeNodeBase.destroy();
|
|
905
|
-
this.branchController.destroy();
|
|
906
|
-
this.dispatch(new DestructionEvent(this));
|
|
907
|
-
}
|
|
908
|
-
/** Run Angular change detection on this branch */
|
|
909
|
-
detectChanges() {
|
|
910
|
-
this.branchController.detectChanges();
|
|
911
|
-
}
|
|
912
|
-
/**
|
|
913
|
-
* Emits the specified TreeEvent.
|
|
914
|
-
*
|
|
915
|
-
* @remarks
|
|
916
|
-
* Caution: It is not recommended to manually emit TreeEvents that are already
|
|
917
|
-
* provided by the library. For example, it is not recommended to emit a
|
|
918
|
-
* `GraftEvent`, `DestructionEvent`, etc. These events may be used by the tree,
|
|
919
|
-
* and emitting them manually may cause unexpected behavior. Instead, we
|
|
920
|
-
* recommend implementing the TreeEvent interface with your own custom events
|
|
921
|
-
* and dispatching those.
|
|
922
|
-
*
|
|
923
|
-
* @param event - The TreeEvent that will be emitted.
|
|
924
|
-
*/
|
|
925
|
-
dispatch(event) {
|
|
926
|
-
var _a;
|
|
927
|
-
this.treeNodeBase.dispatch(event);
|
|
928
|
-
(_a = this._parent) === null || _a === void 0 ? void 0 : _a.dispatch(event);
|
|
929
|
-
}
|
|
930
|
-
/**
|
|
931
|
-
* @returns
|
|
932
|
-
* An observable that emits TreeEvents whenever an event is dispatched
|
|
933
|
-
* in this branch or any of its descendant branches.
|
|
934
|
-
*/
|
|
935
|
-
events() {
|
|
936
|
-
return this.treeNodeBase.events();
|
|
937
|
-
}
|
|
938
|
-
/**
|
|
939
|
-
* @param index - The index of the child branch to retrieve.
|
|
940
|
-
*
|
|
941
|
-
* @returns
|
|
942
|
-
* The child branch at the specified index, or undefined if there is
|
|
943
|
-
* no child branch at the specified index.
|
|
944
|
-
*/
|
|
945
|
-
getBranch(index) {
|
|
946
|
-
return this.treeNodeBase.getBranch(index);
|
|
947
|
-
}
|
|
948
|
-
/** @returns The ViewContainerRef in which child branches are rendered */
|
|
949
|
-
getBranchesContainer() {
|
|
950
|
-
if (this.isDestroyed()) {
|
|
951
|
-
throw new TreeError("Cannot get branches container from a destroyed tree branch");
|
|
952
|
-
}
|
|
953
|
-
return this.branchController.getBranchesContainer();
|
|
954
|
-
}
|
|
955
|
-
/** @returns The instance of BranchComponent that is rendered by this class. */
|
|
956
|
-
getComponentInstance() {
|
|
957
|
-
if (this.isDestroyed()) {
|
|
958
|
-
throw new TreeError("Cannot get component instance from a destroyed tree branch");
|
|
959
|
-
}
|
|
960
|
-
return this.branchController.getComponentInstance();
|
|
961
|
-
}
|
|
962
|
-
/** @returns The Host View in which the BranchComponent is rendered */
|
|
963
|
-
getHostView() {
|
|
964
|
-
if (this.isDestroyed()) {
|
|
965
|
-
throw new TreeError("Cannot get component host view from a destroyed tree branch");
|
|
966
|
-
}
|
|
967
|
-
return this.branchController.getHostView();
|
|
968
|
-
}
|
|
969
|
-
/** @returns The BranchComponent as a native HTML Element */
|
|
970
|
-
getNativeElement() {
|
|
971
|
-
if (this.isDestroyed()) {
|
|
972
|
-
throw new TreeError("Cannot get native element from a destroyed tree branch");
|
|
973
|
-
}
|
|
974
|
-
return this.branchController.getNativeElement();
|
|
975
|
-
}
|
|
976
|
-
/**
|
|
977
|
-
* @returns
|
|
978
|
-
* A ComponentRef containing the instance of the user-provided
|
|
979
|
-
* component which is rendered by this branch.
|
|
980
|
-
*/
|
|
981
|
-
getUserlandComponentRef() {
|
|
982
|
-
if (this.isDestroyed()) {
|
|
983
|
-
throw new TreeError("Cannot get userland component from a destroyed tree branch");
|
|
984
|
-
}
|
|
985
|
-
return this.branchController.getUserlandComponentRef();
|
|
986
|
-
}
|
|
987
|
-
/**
|
|
988
|
-
* Attaches a branch to a new parent node.
|
|
989
|
-
*
|
|
990
|
-
* @remarks
|
|
991
|
-
* If not already pruned, this method prunes (removes) this branch from its
|
|
992
|
-
* current position in the tree; then grafts (reattaches) it as a child of the
|
|
993
|
-
* specified parent branch at the specified index. If no index is specified,
|
|
994
|
-
* the branch is appended as the last child of the parent. This causes this
|
|
995
|
-
* branch's associated BranchComponent to be re-rendered in the DOM at the
|
|
996
|
-
* new location.
|
|
997
|
-
*
|
|
998
|
-
* @param newParent - The new parent branch unto which this branch will be grafted.
|
|
999
|
-
* @param index - The index at which this branch will be grafted. If not specified,
|
|
1000
|
-
* this branch will be appended as the last child of the new parent.
|
|
1001
|
-
*
|
|
1002
|
-
* @returns The index at which this branch was grafted.
|
|
1003
|
-
*/
|
|
1004
|
-
graftTo(newParent, index) {
|
|
1005
|
-
this.checkGraftLocationValidity(newParent, index);
|
|
1006
|
-
const ownIndex = this.index();
|
|
1007
|
-
if (ownIndex !== undefined) {
|
|
1008
|
-
this.prune();
|
|
1009
|
-
}
|
|
1010
|
-
this._parent = newParent;
|
|
1011
|
-
const newIndex = index !== null && index !== void 0 ? index : newParent.branches().length;
|
|
1012
|
-
this.reattachView(newIndex);
|
|
1013
|
-
this.dispatch(new GraftEvent(this, {
|
|
1014
|
-
parent: newParent,
|
|
1015
|
-
child: this,
|
|
1016
|
-
index: newIndex
|
|
1017
|
-
}));
|
|
1018
|
-
return newIndex;
|
|
1019
|
-
}
|
|
1020
|
-
/**
|
|
1021
|
-
* Appends a new child branch to this branch. The child branch will render
|
|
1022
|
-
* the specified component according to the (optional) configuration parameter.
|
|
1023
|
-
*
|
|
1024
|
-
* @param component - The component to render in the new child branch.
|
|
1025
|
-
* @param options - Configuration options for the new child branch.
|
|
1026
|
-
*
|
|
1027
|
-
* @returns
|
|
1028
|
-
* The newly-created child branch.
|
|
1029
|
-
*/
|
|
1030
|
-
grow(component, options) {
|
|
1031
|
-
if (this.isDestroyed()) {
|
|
1032
|
-
throw new TreeError("Cannot grow a branch on a destroyed tree branch");
|
|
1033
|
-
}
|
|
1034
|
-
try {
|
|
1035
|
-
return new TreeBranch(this, Object.assign({ component }, options));
|
|
1036
|
-
}
|
|
1037
|
-
catch (error) {
|
|
1038
|
-
this.handleUserlandError(error);
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
/**
|
|
1042
|
-
* Determines this branch's index in relation to its sibling branches.
|
|
1043
|
-
*
|
|
1044
|
-
* @remarks
|
|
1045
|
-
* For example, if it is the first child of its parent, this method will return
|
|
1046
|
-
* 0. If it is the second child of its parent, this method will return 1.
|
|
1047
|
-
*
|
|
1048
|
-
* If this branch has no parent, (eg, if this branch has been pruned) this
|
|
1049
|
-
* method will return undefined.
|
|
1050
|
-
*
|
|
1051
|
-
* @returns
|
|
1052
|
-
* The index of this branch in relation to its sibling branches, or undefined.
|
|
1053
|
-
*/
|
|
1054
|
-
index() {
|
|
1055
|
-
if (!this._parent) {
|
|
1056
|
-
return undefined;
|
|
1057
|
-
}
|
|
1058
|
-
const index = this._parent
|
|
1059
|
-
.branches()
|
|
1060
|
-
.findIndex((branch) => branch === this);
|
|
1061
|
-
assert(index >= 0);
|
|
1062
|
-
return index;
|
|
1063
|
-
}
|
|
1064
|
-
/** @returns `true` if the branch is destroyed, `false` otherwise */
|
|
1065
|
-
isDestroyed() {
|
|
1066
|
-
return this.treeNodeBase.isDestroyed();
|
|
1067
|
-
}
|
|
1068
|
-
/**
|
|
1069
|
-
* @returns
|
|
1070
|
-
* The data that was passed into the `branchOptions`' `meta` property
|
|
1071
|
-
* at construction.
|
|
1072
|
-
*/
|
|
1073
|
-
meta() {
|
|
1074
|
-
var _a;
|
|
1075
|
-
return (_a = this.branchOptions.meta) !== null && _a !== void 0 ? _a : {};
|
|
1076
|
-
}
|
|
1077
|
-
/**
|
|
1078
|
-
* @returns
|
|
1079
|
-
* This branch's parent node (which may be a TreeBranch or TreeRoot).
|
|
1080
|
-
* If this branch has no parent, (eg, if this branch has been pruned) this
|
|
1081
|
-
* method will return undefined.
|
|
1082
|
-
*/
|
|
1083
|
-
parent() {
|
|
1084
|
-
return this._parent;
|
|
1085
|
-
}
|
|
1086
|
-
/**
|
|
1087
|
-
* Provides a model describing this branch's descendants.
|
|
1088
|
-
*
|
|
1089
|
-
* @returns
|
|
1090
|
-
* A multi-dimensional Map which describes the shape of this branch's
|
|
1091
|
-
* descendants.
|
|
1092
|
-
*
|
|
1093
|
-
* @example
|
|
1094
|
-
* A branch with no children will return an empty Map. A branch with
|
|
1095
|
-
* a single child will return a Map with a single entry, where the key is the index
|
|
1096
|
-
* of the branch (zero) and the value is an empty Map. A Tree like this:
|
|
1097
|
-
*
|
|
1098
|
-
* ```
|
|
1099
|
-
* ---Branch-------Branch
|
|
1100
|
-
* /
|
|
1101
|
-
* Branch-------Branch
|
|
1102
|
-
* \
|
|
1103
|
-
* ---Branch
|
|
1104
|
-
* ```
|
|
1105
|
-
* Will return a Map of matching shape:
|
|
1106
|
-
* ```
|
|
1107
|
-
* Map {
|
|
1108
|
-
* 0: Map { 0: Map {}},
|
|
1109
|
-
* 1: Map {},
|
|
1110
|
-
* 2: Map {}
|
|
1111
|
-
* }
|
|
1112
|
-
* ```
|
|
1113
|
-
*/
|
|
1114
|
-
plot() {
|
|
1115
|
-
return this.treeNodeBase.plot();
|
|
1116
|
-
}
|
|
1117
|
-
/**
|
|
1118
|
-
* Calculates the branch's position in the tree relative to the Root.
|
|
1119
|
-
*
|
|
1120
|
-
* @remarks
|
|
1121
|
-
* The position is described as an array of numbers, where each number
|
|
1122
|
-
* represents the index of the branch at that level of the tree.
|
|
1123
|
-
*
|
|
1124
|
-
* For example, if this branch is the first child of the Root, this method
|
|
1125
|
-
* will return [0]. If this branch is the second child of the first child
|
|
1126
|
-
* of the Root, this method will return [0, 1].
|
|
1127
|
-
*
|
|
1128
|
-
* If the branch is not related to a TreeRoot, (such as when it has been
|
|
1129
|
-
* pruned,) this method will throw an error.
|
|
1130
|
-
*
|
|
1131
|
-
* @returns
|
|
1132
|
-
* An array of numbers which describe the branch's position in the tree
|
|
1133
|
-
* relative to the Root.
|
|
1134
|
-
*/
|
|
1135
|
-
position() {
|
|
1136
|
-
const index = this.index();
|
|
1137
|
-
if (index === undefined) {
|
|
1138
|
-
throw new TreeError("branch has no parent. Position cannot be determined.");
|
|
1139
|
-
}
|
|
1140
|
-
if (this._parent instanceof TreeBranch) {
|
|
1141
|
-
const parentPosition = this._parent.position();
|
|
1142
|
-
return [...parentPosition, index];
|
|
1143
|
-
}
|
|
1144
|
-
return [index];
|
|
1145
|
-
}
|
|
1146
|
-
/**
|
|
1147
|
-
* Removes a branch from its tree without destroying it.
|
|
1148
|
-
*
|
|
1149
|
-
* @remarks
|
|
1150
|
-
* Removes this branch from its parent and detaches its associated
|
|
1151
|
-
* BranchComponent from the DOM. This puts the branch in a "pruned" state,
|
|
1152
|
-
* which may affect the behavior of other methods.
|
|
1153
|
-
*
|
|
1154
|
-
* A pruned branch can be reattached to any other node using the `graftTo` method.
|
|
1155
|
-
*
|
|
1156
|
-
* @returns
|
|
1157
|
-
* Itself, or undefined if it is already in a pruned state.
|
|
1158
|
-
*/
|
|
1159
|
-
prune() {
|
|
1160
|
-
if (this.isDestroyed()) {
|
|
1161
|
-
throw new TreeError("Cannot prune a destroyed tree branch");
|
|
1162
|
-
}
|
|
1163
|
-
const parent = this._parent;
|
|
1164
|
-
const index = this.index();
|
|
1165
|
-
if (index === undefined || parent === undefined)
|
|
1166
|
-
return;
|
|
1167
|
-
const container = parent.getBranchesContainer();
|
|
1168
|
-
assert(container !== undefined);
|
|
1169
|
-
this.detachedView = container.detach(index);
|
|
1170
|
-
assert(this.detachedView !== null);
|
|
1171
|
-
this.detachedView.detach();
|
|
1172
|
-
this.dispatch(new PruneEvent(this, {
|
|
1173
|
-
parent: parent,
|
|
1174
|
-
child: this,
|
|
1175
|
-
index: index
|
|
1176
|
-
}));
|
|
1177
|
-
this._parent = undefined;
|
|
1178
|
-
return this;
|
|
1179
|
-
}
|
|
1180
|
-
/**
|
|
1181
|
-
* Get the root of the tree to which this Branch is attached.
|
|
1182
|
-
*
|
|
1183
|
-
* @returns
|
|
1184
|
-
* The TreeRoot of the tree this branch is in. If this branch is
|
|
1185
|
-
* does not have a root (such as when it has been pruned) this method will
|
|
1186
|
-
* return undefined.
|
|
1187
|
-
*/
|
|
1188
|
-
root() {
|
|
1189
|
-
const parent = this.parent();
|
|
1190
|
-
if (parent instanceof TreeBranch) {
|
|
1191
|
-
return parent.root();
|
|
1192
|
-
}
|
|
1193
|
-
assert(parent instanceof TreeRoot || parent === undefined);
|
|
1194
|
-
return parent;
|
|
1195
|
-
}
|
|
1196
|
-
/**
|
|
1197
|
-
* Traverses this branch's descendants in depth-first pre-order, executing
|
|
1198
|
-
* the provided callback function on each node. Traversal includes this branch.
|
|
1199
|
-
*
|
|
1200
|
-
* @param callback - A function to execute on each node.
|
|
1201
|
-
*/
|
|
1202
|
-
traverse(callback) {
|
|
1203
|
-
callback(this);
|
|
1204
|
-
this.treeNodeBase.traverse(callback);
|
|
1205
|
-
}
|
|
1206
|
-
checkGraftLocationValidity(newParent, index) {
|
|
1207
|
-
if (this.isDestroyed()) {
|
|
1208
|
-
throw new TreeError("Cannot graft a destroyed tree branch");
|
|
1209
|
-
}
|
|
1210
|
-
if (newParent.isDestroyed()) {
|
|
1211
|
-
throw new TreeError("Cannot graft to a destroyed tree branch");
|
|
1212
|
-
}
|
|
1213
|
-
if (typeof index === "number" &&
|
|
1214
|
-
this.indexIsOutOfRange(newParent, index)) {
|
|
1215
|
-
throw new TreeError(`Cannot graft branch at index ${index} of the parent. Out of range.`);
|
|
1216
|
-
}
|
|
1217
|
-
this.traverse((node) => {
|
|
1218
|
-
if (node === newParent) {
|
|
1219
|
-
throw new TreeError("Cannot graft a branch to itself or any of its own descendants");
|
|
1220
|
-
}
|
|
1221
|
-
});
|
|
1222
|
-
}
|
|
1223
|
-
handleUserlandError(error) {
|
|
1224
|
-
// When an error occurs in a userland component during a tree operation,
|
|
1225
|
-
// it can cause undefined, bizarre behavior in the tree. To prevent this,
|
|
1226
|
-
// we destroy the tree and throw an error instead. This helps protect
|
|
1227
|
-
// the end-user's data from corruption.
|
|
1228
|
-
this.furthestAncestor().destroy();
|
|
1229
|
-
this.treeNodeBase.handleUserlandError(error);
|
|
1230
|
-
}
|
|
1231
|
-
indexIsOutOfRange(parent, index) {
|
|
1232
|
-
return index < 0 || index > parent.branches().length;
|
|
1233
|
-
}
|
|
1234
|
-
furthestAncestor() {
|
|
1235
|
-
// eslint-disable-next-line typescript/no-this-alias -- This code is for an iteration, not to make `this` available in other scopes (which is what the rule is intended to protect against).
|
|
1236
|
-
let node = this;
|
|
1237
|
-
while (node instanceof TreeBranch) {
|
|
1238
|
-
const parent = node.parent();
|
|
1239
|
-
if (parent === undefined)
|
|
1240
|
-
break;
|
|
1241
|
-
node = parent;
|
|
1242
|
-
}
|
|
1243
|
-
return node;
|
|
1244
|
-
}
|
|
1245
|
-
reattachView(index) {
|
|
1246
|
-
assert(this._parent !== undefined);
|
|
1247
|
-
assert(this.detachedView !== null);
|
|
1248
|
-
const container = this._parent.getBranchesContainer();
|
|
1249
|
-
assert(container !== undefined);
|
|
1250
|
-
this.detachedView.reattach();
|
|
1251
|
-
container.insert(this.detachedView, index);
|
|
1252
|
-
this.detachedView = null;
|
|
1253
|
-
this.setIndentation();
|
|
1254
|
-
}
|
|
1255
|
-
setIndentation() {
|
|
1256
|
-
var _a;
|
|
1257
|
-
assert(this._parent !== undefined);
|
|
1258
|
-
const root = this._parent.root();
|
|
1259
|
-
if (root === undefined) {
|
|
1260
|
-
return;
|
|
1261
|
-
}
|
|
1262
|
-
const options = config.getConfig(root);
|
|
1263
|
-
const branchesContainerEl = this.branchController
|
|
1264
|
-
.getNativeElement()
|
|
1265
|
-
.getElementsByClassName("branches-container")
|
|
1266
|
-
.item(0);
|
|
1267
|
-
assert(branchesContainerEl instanceof HTMLElement);
|
|
1268
|
-
branchesContainerEl.style.marginLeft = `${(_a = options === null || options === void 0 ? void 0 : options.indentation) !== null && _a !== void 0 ? _a : 16}px`;
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
/** Responsible for the creation of new trees. */
|
|
1273
|
-
class TreeService {
|
|
1274
|
-
/**
|
|
1275
|
-
* Creates a new, empty tree structure inside the provided container.
|
|
1276
|
-
*
|
|
1277
|
-
* @returns A `TreeRoot` representing the base of the new tree.
|
|
1278
|
-
*/
|
|
1279
|
-
createEmptyTree(container, options = {}) {
|
|
1280
|
-
container.clear();
|
|
1281
|
-
const root = new TreeRoot(container);
|
|
1282
|
-
config.setConfig(root, options);
|
|
1283
|
-
return root;
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
TreeService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1287
|
-
TreeService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeService, providedIn: "root" });
|
|
1288
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeService, decorators: [{
|
|
1289
|
-
type: Injectable,
|
|
1290
|
-
args: [{ providedIn: "root" }]
|
|
1291
|
-
}] });
|
|
1292
|
-
|
|
1293
|
-
class DragAndDrop {
|
|
1294
|
-
constructor() {
|
|
1295
|
-
this.dragAborted$ = new Subject();
|
|
1296
|
-
}
|
|
1297
|
-
dragStart(treeBranch, event) {
|
|
1298
|
-
if (!this.draggingAllowed(treeBranch)) {
|
|
1299
|
-
event.preventDefault();
|
|
1300
|
-
return;
|
|
1301
|
-
}
|
|
1302
|
-
treeBranch.dispatch(new DragStartEvent(treeBranch));
|
|
1303
|
-
this.setDragEffects(treeBranch, event);
|
|
1304
|
-
this.watchForDragend(treeBranch, event);
|
|
1305
|
-
// We have to do a setTimeout because DOM changes are not allowed during a
|
|
1306
|
-
// dragstart event.
|
|
1307
|
-
setTimeout(() => {
|
|
1308
|
-
dragState.starting(treeBranch);
|
|
1309
|
-
treeBranch.prune();
|
|
1310
|
-
dragState.dragging();
|
|
1311
|
-
});
|
|
1312
|
-
}
|
|
1313
|
-
drop(parent, index) {
|
|
1314
|
-
const treeBranch = dragState.getDragData();
|
|
1315
|
-
if (treeBranch === undefined) {
|
|
1316
|
-
throw new TreeError("Cannot get dragged branch");
|
|
1317
|
-
}
|
|
1318
|
-
this.graftDraggedBranch(treeBranch, parent, index);
|
|
1319
|
-
treeBranch.dispatch(new DropEvent(treeBranch, parent, index));
|
|
1320
|
-
}
|
|
1321
|
-
getDragImageOffsets(event, element) {
|
|
1322
|
-
const bounds = element.getBoundingClientRect();
|
|
1323
|
-
const xOffset = event.clientX - bounds.left;
|
|
1324
|
-
const yOffset = event.clientY - bounds.top;
|
|
1325
|
-
return [xOffset, yOffset];
|
|
1326
|
-
}
|
|
1327
|
-
setDragEffects(treeBranch, event) {
|
|
1328
|
-
const dataTransfer = event.dataTransfer;
|
|
1329
|
-
assert(dataTransfer instanceof DataTransfer);
|
|
1330
|
-
const nativeElement = treeBranch.getNativeElement();
|
|
1331
|
-
const [xOffset, yOffset] = this.getDragImageOffsets(event, nativeElement);
|
|
1332
|
-
dataTransfer.setDragImage(nativeElement, xOffset, yOffset);
|
|
1333
|
-
}
|
|
1334
|
-
watchForDragend(treeBranch, event) {
|
|
1335
|
-
var _a;
|
|
1336
|
-
const oldParent = treeBranch.parent();
|
|
1337
|
-
const oldIndex = treeBranch.index();
|
|
1338
|
-
assert(oldParent !== undefined && oldIndex !== undefined);
|
|
1339
|
-
(_a = event.target) === null || _a === void 0 ? void 0 : _a.addEventListener("dragend", (dragend) => {
|
|
1340
|
-
if (dragState.state() !== DragStates.Dropped) {
|
|
1341
|
-
//The drag ended but a drop never occurred, so put the dragged branch back where it started.
|
|
1342
|
-
this.dragAborted$.next(dragend);
|
|
1343
|
-
this.graftDraggedBranch(treeBranch, oldParent, oldIndex);
|
|
1344
|
-
}
|
|
1345
|
-
dragState.restart();
|
|
1346
|
-
const newParent = treeBranch.parent();
|
|
1347
|
-
assert(newParent !== undefined);
|
|
1348
|
-
const newIndex = treeBranch.index();
|
|
1349
|
-
assert(newIndex !== undefined);
|
|
1350
|
-
treeBranch.dispatch(new DragEndEvent(treeBranch, {
|
|
1351
|
-
oldParent,
|
|
1352
|
-
oldIndex,
|
|
1353
|
-
newParent,
|
|
1354
|
-
newIndex
|
|
1355
|
-
}));
|
|
1356
|
-
}, { once: true });
|
|
1357
|
-
}
|
|
1358
|
-
draggingAllowed(treeBranch) {
|
|
1359
|
-
var _a, _b, _c;
|
|
1360
|
-
const allowDragging = (_c = (_b = (_a = config.getConfig(treeBranch.root())) === null || _a === void 0 ? void 0 : _a.dragAndDrop) === null || _b === void 0 ? void 0 : _b.allowDragging) !== null && _c !== void 0 ? _c : (() => true);
|
|
1361
|
-
return allowDragging(treeBranch);
|
|
1362
|
-
}
|
|
1363
|
-
graftDraggedBranch(treeBranch, parent, index) {
|
|
1364
|
-
treeBranch.graftTo(parent, index);
|
|
1365
|
-
treeBranch.getNativeElement().style.display = "block";
|
|
1366
|
-
dragState.dropped();
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
const dragAndDrop = new DragAndDrop();
|
|
1370
|
-
|
|
1371
|
-
class DropzoneRenderer {
|
|
1372
|
-
constructor() {
|
|
1373
|
-
this.registry = new Map();
|
|
1374
|
-
this.currentDisplay = null;
|
|
1375
|
-
dragAndDrop.dragAborted$.subscribe(() => {
|
|
1376
|
-
this.clearCurrentDisplay();
|
|
1377
|
-
});
|
|
1378
|
-
dragState
|
|
1379
|
-
.events()
|
|
1380
|
-
.pipe(filter((event) => event === DragStates.Starting))
|
|
1381
|
-
.subscribe(() => {
|
|
1382
|
-
var _a, _b;
|
|
1383
|
-
const branch = dragState.getDragData();
|
|
1384
|
-
assert(branch !== undefined);
|
|
1385
|
-
let cursor = (_a = branch.parent()) === null || _a === void 0 ? void 0 : _a.getBranch(((_b = branch.index()) !== null && _b !== void 0 ? _b : 0) - 1);
|
|
1386
|
-
let final = branch.parent();
|
|
1387
|
-
while (cursor !== undefined) {
|
|
1388
|
-
final = cursor;
|
|
1389
|
-
cursor = cursor.branches().at(-1);
|
|
1390
|
-
}
|
|
1391
|
-
branch
|
|
1392
|
-
.events()
|
|
1393
|
-
.pipe(filter((event) => event instanceof PruneEvent), first())
|
|
1394
|
-
.subscribe(() => {
|
|
1395
|
-
assert(final !== undefined);
|
|
1396
|
-
this.showLowerZones(final);
|
|
1397
|
-
});
|
|
1398
|
-
});
|
|
1399
|
-
}
|
|
1400
|
-
clearCurrentDisplay() {
|
|
1401
|
-
if (this.currentDisplay === null)
|
|
1402
|
-
return;
|
|
1403
|
-
for (const branch of this.registry.values()) {
|
|
1404
|
-
const instance = branch.getComponentInstance();
|
|
1405
|
-
instance.showInnerDropzone = false;
|
|
1406
|
-
if (instance instanceof BranchComponent) {
|
|
1407
|
-
instance.showLateralDropzone = false;
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
this.currentDisplay = null;
|
|
1411
|
-
}
|
|
1412
|
-
clearTreeFromRegistry(tree) {
|
|
1413
|
-
const nodes = [];
|
|
1414
|
-
tree.traverse((node) => nodes.push(node));
|
|
1415
|
-
for (const [dropzoneComponent, treeNode] of this.registry) {
|
|
1416
|
-
if (nodes.includes(treeNode)) {
|
|
1417
|
-
this.registry.delete(dropzoneComponent);
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
getCurrentDisplay() {
|
|
1422
|
-
if (this.currentDisplay === null)
|
|
1423
|
-
return null;
|
|
1424
|
-
return Object.assign({}, this.currentDisplay);
|
|
1425
|
-
}
|
|
1426
|
-
getDropzoneLocation(dropzone) {
|
|
1427
|
-
const branch = this.registry.get(dropzone);
|
|
1428
|
-
const placement = dropzone.placement;
|
|
1429
|
-
if (branch === undefined) {
|
|
1430
|
-
throw new Error("dropzone not found in registry");
|
|
1431
|
-
}
|
|
1432
|
-
if (placement === undefined) {
|
|
1433
|
-
throw new Error("dropzone has an undefined placement");
|
|
1434
|
-
}
|
|
1435
|
-
return [branch, placement];
|
|
1436
|
-
}
|
|
1437
|
-
handleDrop(treeNode, placement) {
|
|
1438
|
-
if (placement === "inner") {
|
|
1439
|
-
dragAndDrop.drop(treeNode, 0);
|
|
1440
|
-
}
|
|
1441
|
-
else if (treeNode instanceof TreeBranch && placement === "lateral") {
|
|
1442
|
-
const currentParent = treeNode.parent();
|
|
1443
|
-
const index = treeNode.index();
|
|
1444
|
-
if (currentParent === undefined || index === undefined) {
|
|
1445
|
-
throw new Error("branch must have a parent");
|
|
1446
|
-
}
|
|
1447
|
-
dragAndDrop.drop(currentParent, index + 1);
|
|
1448
|
-
}
|
|
1449
|
-
this.clearCurrentDisplay();
|
|
1450
|
-
}
|
|
1451
|
-
registerDropzone(dropzone, treeNode) {
|
|
1452
|
-
this.registry.set(dropzone, treeNode);
|
|
1453
|
-
}
|
|
1454
|
-
registerDropzones(dropzones, treeBranch) {
|
|
1455
|
-
for (const dropzone of dropzones) {
|
|
1456
|
-
this.registry.set(dropzone, treeBranch);
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
showLowerZones(treeNode) {
|
|
1460
|
-
this.clearCurrentDisplay();
|
|
1461
|
-
this.showInnerZone(treeNode);
|
|
1462
|
-
if (treeNode.branches().length === 0) {
|
|
1463
|
-
this.loopThroughLowerZones(treeNode);
|
|
1464
|
-
}
|
|
1465
|
-
this.currentDisplay = { treeBranch: treeNode, direction: "lower" };
|
|
1466
|
-
}
|
|
1467
|
-
showUpperZones(treeBranch) {
|
|
1468
|
-
this.clearCurrentDisplay();
|
|
1469
|
-
this.loopThroughUpperZones(treeBranch);
|
|
1470
|
-
this.currentDisplay = { treeBranch, direction: "upper" };
|
|
1471
|
-
}
|
|
1472
|
-
loopThroughLowerZones(treeNode) {
|
|
1473
|
-
let cursor = treeNode;
|
|
1474
|
-
while (cursor instanceof TreeBranch) {
|
|
1475
|
-
this.showLateralZone(cursor);
|
|
1476
|
-
const parent = cursor.parent();
|
|
1477
|
-
const index = cursor.index();
|
|
1478
|
-
assert(parent !== undefined && index !== undefined);
|
|
1479
|
-
if (parent.branches().length > index + 1) {
|
|
1480
|
-
return;
|
|
1481
|
-
}
|
|
1482
|
-
cursor = cursor.parent();
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
loopThroughUpperZones(treeBranch) {
|
|
1486
|
-
var _a, _b;
|
|
1487
|
-
let cursor = (_a = treeBranch
|
|
1488
|
-
.parent()) === null || _a === void 0 ? void 0 : _a.getBranch(((_b = treeBranch.index()) !== null && _b !== void 0 ? _b : 0) - 1);
|
|
1489
|
-
let final = treeBranch.parent();
|
|
1490
|
-
while (cursor !== undefined) {
|
|
1491
|
-
this.showLateralZone(cursor);
|
|
1492
|
-
final = cursor;
|
|
1493
|
-
cursor = cursor.branches().at(-1);
|
|
1494
|
-
}
|
|
1495
|
-
if (final !== undefined &&
|
|
1496
|
-
(final instanceof TreeRoot || final instanceof TreeBranch)) {
|
|
1497
|
-
this.showInnerZone(final);
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
nestingAllowed(treeNode) {
|
|
1501
|
-
var _a, _b, _c;
|
|
1502
|
-
if (treeNode instanceof TreeRoot) {
|
|
1503
|
-
return true;
|
|
1504
|
-
}
|
|
1505
|
-
if (treeNode instanceof TreeBranch) {
|
|
1506
|
-
const allowNesting = (_c = (_b = (_a = config.getConfig(treeNode.root())) === null || _a === void 0 ? void 0 : _a.dragAndDrop) === null || _b === void 0 ? void 0 : _b.allowNesting) !== null && _c !== void 0 ? _c : (() => true);
|
|
1507
|
-
return allowNesting(treeNode);
|
|
1508
|
-
}
|
|
1509
|
-
throw new Error("unsupported treeNode type");
|
|
1510
|
-
}
|
|
1511
|
-
dropAllowed(parent, index) {
|
|
1512
|
-
var _a, _b, _c, _d, _e, _f;
|
|
1513
|
-
const sourceNode = dragState.getDragData();
|
|
1514
|
-
assert(sourceNode instanceof TreeBranch);
|
|
1515
|
-
if (parent instanceof TreeRoot) {
|
|
1516
|
-
const allowDrop = (_c = (_b = (_a = config.getConfig(parent)) === null || _a === void 0 ? void 0 : _a.dragAndDrop) === null || _b === void 0 ? void 0 : _b.allowDrop) !== null && _c !== void 0 ? _c : (() => true);
|
|
1517
|
-
return allowDrop(sourceNode, parent, index);
|
|
1518
|
-
}
|
|
1519
|
-
if (parent instanceof TreeBranch) {
|
|
1520
|
-
const allowDrop = (_f = (_e = (_d = config.getConfig(parent.root())) === null || _d === void 0 ? void 0 : _d.dragAndDrop) === null || _e === void 0 ? void 0 : _e.allowDrop) !== null && _f !== void 0 ? _f : (() => true);
|
|
1521
|
-
return allowDrop(sourceNode, parent, index);
|
|
1522
|
-
}
|
|
1523
|
-
throw new Error("unsupported treeNode type");
|
|
1524
|
-
}
|
|
1525
|
-
showInnerZone(treeNode) {
|
|
1526
|
-
if (!this.nestingAllowed(treeNode) || !this.dropAllowed(treeNode, 0))
|
|
1527
|
-
return;
|
|
1528
|
-
treeNode.getComponentInstance().showInnerDropzone = true;
|
|
1529
|
-
}
|
|
1530
|
-
showLateralZone(treeBranch) {
|
|
1531
|
-
const index = treeBranch.index();
|
|
1532
|
-
assert(index !== undefined);
|
|
1533
|
-
if (!this.dropAllowed(treeBranch.parent(), index + 1))
|
|
1534
|
-
return;
|
|
1535
|
-
treeBranch.getComponentInstance().showLateralDropzone = true;
|
|
1536
|
-
}
|
|
1537
|
-
}
|
|
1538
|
-
const dropzoneRenderer = new DropzoneRenderer();
|
|
1539
|
-
|
|
1540
|
-
class TreeDragAndDropService {
|
|
1541
|
-
/** Hides all Dropzones */
|
|
1542
|
-
clearDropzones() {
|
|
1543
|
-
dropzoneRenderer.clearCurrentDisplay();
|
|
1544
|
-
}
|
|
1545
|
-
/**
|
|
1546
|
-
* @returns An object that indicates which dropzones are currently being displayed.
|
|
1547
|
-
* If no dropzones are being displayed, then null is returned.
|
|
1548
|
-
*/
|
|
1549
|
-
getCurrentlyDisplayedDropzoneFamily() {
|
|
1550
|
-
return dropzoneRenderer.getCurrentDisplay();
|
|
1551
|
-
}
|
|
1552
|
-
/**
|
|
1553
|
-
* Causes the dropzone of the TreeRoot to be displayed.
|
|
1554
|
-
*
|
|
1555
|
-
* @remarks
|
|
1556
|
-
* This is a useful function when you want to show the dropzone of a TreeRoot
|
|
1557
|
-
* that has no child branches.
|
|
1558
|
-
*
|
|
1559
|
-
* @param root - The TreeRoot whose dropzone you want to show.
|
|
1560
|
-
*/
|
|
1561
|
-
showRootDropzone(root) {
|
|
1562
|
-
dropzoneRenderer.showLowerZones(root);
|
|
1563
|
-
}
|
|
1564
|
-
/**
|
|
1565
|
-
* @returns An observable that emits a number whenever the drag state changes.
|
|
1566
|
-
*
|
|
1567
|
-
* @remarks
|
|
1568
|
-
* See the `DragStates` enum for a list of possible states.
|
|
1569
|
-
*/
|
|
1570
|
-
state() {
|
|
1571
|
-
return dragState.events();
|
|
1572
|
-
}
|
|
1573
|
-
}
|
|
1574
|
-
TreeDragAndDropService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeDragAndDropService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1575
|
-
TreeDragAndDropService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeDragAndDropService });
|
|
1576
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeDragAndDropService, decorators: [{
|
|
1577
|
-
type: Injectable
|
|
1578
|
-
}] });
|
|
1579
|
-
|
|
1580
|
-
/** Makes an TreeBranch draggable when the host element is dragged */
|
|
1581
|
-
class DraggableDirective {
|
|
1582
|
-
constructor(renderer, hostElement) {
|
|
1583
|
-
renderer.setAttribute(hostElement.nativeElement, "draggable", "true");
|
|
1584
|
-
renderer.setStyle(hostElement.nativeElement, "cursor", "grab");
|
|
1585
|
-
}
|
|
1586
|
-
onDragstart(event) {
|
|
1587
|
-
if (this.limbleTreeDraggable === undefined)
|
|
1588
|
-
return;
|
|
1589
|
-
dragAndDrop.dragStart(this.limbleTreeDraggable, event);
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
DraggableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: DraggableDirective, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1593
|
-
DraggableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: DraggableDirective, isStandalone: true, selector: "[limbleTreeDraggable]", inputs: { limbleTreeDraggable: "limbleTreeDraggable" }, host: { listeners: { "dragstart": "onDragstart($event)" } }, ngImport: i0 });
|
|
1594
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: DraggableDirective, decorators: [{
|
|
1595
|
-
type: Directive,
|
|
1596
|
-
args: [{
|
|
1597
|
-
selector: "[limbleTreeDraggable]",
|
|
1598
|
-
standalone: true
|
|
1599
|
-
}]
|
|
1600
|
-
}], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ElementRef }]; }, propDecorators: { limbleTreeDraggable: [{
|
|
1601
|
-
type: Input
|
|
1602
|
-
}], onDragstart: [{
|
|
1603
|
-
type: HostListener,
|
|
1604
|
-
args: ["dragstart", ["$event"]]
|
|
1605
|
-
}] } });
|
|
1606
|
-
|
|
1607
|
-
/**
|
|
1608
|
-
* An Angular module containing all of the entities which provide Drag-And-Drop
|
|
1609
|
-
* functionality.
|
|
1610
|
-
*/
|
|
1611
|
-
class TreeDragAndDropModule {
|
|
1612
|
-
}
|
|
1613
|
-
TreeDragAndDropModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeDragAndDropModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1614
|
-
TreeDragAndDropModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: TreeDragAndDropModule, imports: [DraggableDirective], exports: [DraggableDirective] });
|
|
1615
|
-
TreeDragAndDropModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeDragAndDropModule, providers: [TreeDragAndDropService] });
|
|
1616
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TreeDragAndDropModule, decorators: [{
|
|
1617
|
-
type: NgModule,
|
|
1618
|
-
args: [{
|
|
1619
|
-
imports: [DraggableDirective],
|
|
1620
|
-
providers: [TreeDragAndDropService],
|
|
1621
|
-
exports: [DraggableDirective]
|
|
1622
|
-
}]
|
|
1623
|
-
}] });
|
|
1624
|
-
|
|
1625
|
-
/**
|
|
1626
|
-
* A shim to help with the transition from v0 to v1.
|
|
1627
|
-
* @deprecated
|
|
1628
|
-
*/
|
|
1629
|
-
class LegacyTree {
|
|
1630
|
-
/** Creates a v1 tree structure from a v0 data array and v0 tree options. */
|
|
1631
|
-
createTreeFromLegacyArray(container, data, treeOptions = {}) {
|
|
1632
|
-
const root = new TreeRoot(container);
|
|
1633
|
-
config.setConfig(root, this.upgradeOptions(treeOptions));
|
|
1634
|
-
for (const node of data) {
|
|
1635
|
-
this.renderTreeNode(root, node, treeOptions);
|
|
1636
|
-
}
|
|
1637
|
-
return root;
|
|
1638
|
-
}
|
|
1639
|
-
upgradeOptions(legacyOptions) {
|
|
1640
|
-
return {
|
|
1641
|
-
indentation: legacyOptions.indent,
|
|
1642
|
-
dragAndDrop: {
|
|
1643
|
-
allowNesting: (branch) => {
|
|
1644
|
-
if (legacyOptions.listMode === true) {
|
|
1645
|
-
return false;
|
|
1646
|
-
}
|
|
1647
|
-
if (legacyOptions.allowNesting === undefined) {
|
|
1648
|
-
return true;
|
|
1649
|
-
}
|
|
1650
|
-
if (typeof legacyOptions.allowNesting === "boolean") {
|
|
1651
|
-
return legacyOptions.allowNesting;
|
|
1652
|
-
}
|
|
1653
|
-
return legacyOptions.allowNesting(branch);
|
|
1654
|
-
},
|
|
1655
|
-
allowDragging: (branch) => {
|
|
1656
|
-
if (legacyOptions.allowDragging === undefined) {
|
|
1657
|
-
return true;
|
|
1658
|
-
}
|
|
1659
|
-
if (typeof legacyOptions.allowDragging === "boolean") {
|
|
1660
|
-
return legacyOptions.allowDragging;
|
|
1661
|
-
}
|
|
1662
|
-
return legacyOptions.allowDragging(branch);
|
|
1663
|
-
},
|
|
1664
|
-
allowDrop: (source, parent, index) => {
|
|
1665
|
-
if (legacyOptions.allowDrop === undefined) {
|
|
1666
|
-
return true;
|
|
1667
|
-
}
|
|
1668
|
-
return legacyOptions.allowDrop(source, parent, index);
|
|
1669
|
-
}
|
|
1670
|
-
}
|
|
1671
|
-
};
|
|
1672
|
-
}
|
|
1673
|
-
renderTreeNode(parent, node, options) {
|
|
1674
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1675
|
-
const component = (_b = (_a = node.component) === null || _a === void 0 ? void 0 : _a.class) !== null && _b !== void 0 ? _b : (_c = options.defaultComponent) === null || _c === void 0 ? void 0 : _c.class;
|
|
1676
|
-
if (component === undefined) {
|
|
1677
|
-
throw new TreeError("A component must be provided");
|
|
1678
|
-
}
|
|
1679
|
-
const bindings = ((_g = (_e = (_d = node.component) === null || _d === void 0 ? void 0 : _d.bindings) !== null && _e !== void 0 ? _e : (_f = options.defaultComponent) === null || _f === void 0 ? void 0 : _f.bindings) !== null && _g !== void 0 ? _g : {});
|
|
1680
|
-
const nodeData = node;
|
|
1681
|
-
const branch = parent.grow(component, {
|
|
1682
|
-
inputBindings: bindings,
|
|
1683
|
-
meta: { nodeData }
|
|
1684
|
-
});
|
|
1685
|
-
for (const childNode of (_h = node.nodes) !== null && _h !== void 0 ? _h : []) {
|
|
1686
|
-
this.renderTreeNode(branch, childNode, options);
|
|
1687
|
-
}
|
|
1688
|
-
if (node.collapsed === true) {
|
|
1689
|
-
treeCollapser.collapse(branch);
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
}
|
|
1693
|
-
|
|
1694
|
-
/** @deprecated */
|
|
1695
|
-
class LimbleTreeRootComponent {
|
|
1696
|
-
constructor() {
|
|
1697
|
-
this.itemsPerPage = Infinity;
|
|
1698
|
-
this.page = 1;
|
|
1699
|
-
this.treeChange = new EventEmitter();
|
|
1700
|
-
this.treeDrop = new EventEmitter();
|
|
1701
|
-
this.legacyTree = new LegacyTree();
|
|
1702
|
-
}
|
|
1703
|
-
ngAfterViewInit() {
|
|
1704
|
-
this.update();
|
|
1705
|
-
}
|
|
1706
|
-
ngOnChanges() {
|
|
1707
|
-
if (this.host !== undefined && this.data !== undefined) {
|
|
1708
|
-
this.update();
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
ngOnDestroy() {
|
|
1712
|
-
var _a, _b;
|
|
1713
|
-
(_a = this.dropSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
|
1714
|
-
(_b = this.root) === null || _b === void 0 ? void 0 : _b.destroy();
|
|
1715
|
-
}
|
|
1716
|
-
getRoot() {
|
|
1717
|
-
return this.root;
|
|
1718
|
-
}
|
|
1719
|
-
update() {
|
|
1720
|
-
var _a, _b;
|
|
1721
|
-
if (this.data === undefined) {
|
|
1722
|
-
throw new TreeError("LimbleTreeRootComponent's `data` input is required");
|
|
1723
|
-
}
|
|
1724
|
-
if (this.host === undefined) {
|
|
1725
|
-
throw new TreeError("LimbleTreeRootComponent's `host` property is not defined");
|
|
1726
|
-
}
|
|
1727
|
-
(_a = this.root) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
1728
|
-
(_b = this.dropSubscription) === null || _b === void 0 ? void 0 : _b.unsubscribe();
|
|
1729
|
-
const dataSlice = this.paginatedData();
|
|
1730
|
-
this.root = this.legacyTree.createTreeFromLegacyArray(this.host, dataSlice, this.options);
|
|
1731
|
-
this.dropSubscription = this.root
|
|
1732
|
-
.events()
|
|
1733
|
-
.pipe(filter((event) => event instanceof DragEndEvent))
|
|
1734
|
-
.subscribe(this.treeDrop);
|
|
1735
|
-
this.treeChange.emit(this.root);
|
|
1736
|
-
}
|
|
1737
|
-
paginatedData() {
|
|
1738
|
-
var _a;
|
|
1739
|
-
assert(this.data !== undefined);
|
|
1740
|
-
if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.listMode) !== true) {
|
|
1741
|
-
return this.data;
|
|
1742
|
-
}
|
|
1743
|
-
return this.data.slice((this.page - 1) * this.itemsPerPage, this.page * this.itemsPerPage);
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
1746
|
-
LimbleTreeRootComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: LimbleTreeRootComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1747
|
-
LimbleTreeRootComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: LimbleTreeRootComponent, isStandalone: true, selector: "limble-tree-root", inputs: { data: "data", options: "options", itemsPerPage: "itemsPerPage", page: "page" }, outputs: { treeChange: "treeChange", treeDrop: "treeDrop" }, viewQueries: [{ propertyName: "host", first: true, predicate: ["host"], descendants: true, read: ViewContainerRef }], usesOnChanges: true, ngImport: i0, template: "<div #host></div>\n" });
|
|
1748
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: LimbleTreeRootComponent, decorators: [{
|
|
1749
|
-
type: Component,
|
|
1750
|
-
args: [{ selector: "limble-tree-root", standalone: true, template: "<div #host></div>\n" }]
|
|
1751
|
-
}], ctorParameters: function () { return []; }, propDecorators: { data: [{
|
|
1752
|
-
type: Input
|
|
1753
|
-
}], options: [{
|
|
1754
|
-
type: Input
|
|
1755
|
-
}], itemsPerPage: [{
|
|
1756
|
-
type: Input
|
|
1757
|
-
}], page: [{
|
|
1758
|
-
type: Input
|
|
1759
|
-
}], host: [{
|
|
1760
|
-
type: ViewChild,
|
|
1761
|
-
args: ["host", { read: ViewContainerRef }]
|
|
1762
|
-
}], treeChange: [{
|
|
1763
|
-
type: Output
|
|
1764
|
-
}], treeDrop: [{
|
|
1765
|
-
type: Output
|
|
1766
|
-
}] } });
|
|
1767
|
-
|
|
1768
|
-
/** @deprecated */
|
|
1769
|
-
class LimbleTreeLegacyModule {
|
|
1770
|
-
}
|
|
1771
|
-
LimbleTreeLegacyModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: LimbleTreeLegacyModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1772
|
-
LimbleTreeLegacyModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: LimbleTreeLegacyModule, imports: [LimbleTreeRootComponent], exports: [LimbleTreeRootComponent] });
|
|
1773
|
-
LimbleTreeLegacyModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: LimbleTreeLegacyModule, providers: [LegacyTree], imports: [LimbleTreeRootComponent] });
|
|
1774
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: LimbleTreeLegacyModule, decorators: [{
|
|
1775
|
-
type: NgModule,
|
|
1776
|
-
args: [{
|
|
1777
|
-
declarations: [],
|
|
1778
|
-
imports: [LimbleTreeRootComponent],
|
|
1779
|
-
providers: [LegacyTree],
|
|
1780
|
-
exports: [LimbleTreeRootComponent]
|
|
1781
|
-
}]
|
|
1782
|
-
}] });
|
|
1783
|
-
|
|
1784
|
-
/**
|
|
1785
|
-
* Import this Angular module into your application to gain access to the
|
|
1786
|
-
* components, directives, and services provided by Limble Tree.
|
|
1787
|
-
*/
|
|
1788
|
-
class LimbleTreeModule {
|
|
1789
|
-
}
|
|
1790
|
-
LimbleTreeModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: LimbleTreeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1791
|
-
LimbleTreeModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: LimbleTreeModule, imports: [LimbleTreeLegacyModule, TreeCollapseModule, TreeDragAndDropModule], exports: [LimbleTreeLegacyModule, TreeCollapseModule, TreeDragAndDropModule] });
|
|
1792
|
-
LimbleTreeModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: LimbleTreeModule, providers: [TreeService], imports: [LimbleTreeLegacyModule, TreeCollapseModule, TreeDragAndDropModule, LimbleTreeLegacyModule, TreeCollapseModule, TreeDragAndDropModule] });
|
|
1793
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: LimbleTreeModule, decorators: [{
|
|
1794
|
-
type: NgModule,
|
|
1795
|
-
args: [{
|
|
1796
|
-
declarations: [],
|
|
1797
|
-
imports: [LimbleTreeLegacyModule, TreeCollapseModule, TreeDragAndDropModule],
|
|
1798
|
-
providers: [TreeService],
|
|
1799
|
-
exports: [LimbleTreeLegacyModule, TreeCollapseModule, TreeDragAndDropModule]
|
|
1800
|
-
}]
|
|
1801
|
-
}] });
|
|
1802
|
-
|
|
1803
|
-
/*
|
|
1804
|
-
* Public API Surface of limble-tree
|
|
1805
|
-
*/
|
|
1806
|
-
|
|
1807
|
-
/**
|
|
1808
|
-
* Generated bundle index. Do not edit.
|
|
1809
|
-
*/
|
|
1810
|
-
|
|
1811
|
-
export { BranchComponent, DestructionEvent, DragEndEvent, DragStartEvent, DraggableDirective, DragoverNoChangeDetectDirective, DropEvent, GraftEvent, LimbleTreeLegacyModule, LimbleTreeModule, LimbleTreeRootComponent, PruneEvent, RootComponent, TreeBranch, TreeCollapseModule, TreeCollapseService, TreeDragAndDropModule, TreeDragAndDropService, TreeError, TreeRoot, TreeService };
|
|
1812
|
-
//# sourceMappingURL=limble-limble-tree.mjs.map
|