@limble/limble-tree 1.0.0-alpha.1 → 1.0.0-beta.1
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 +450 -17
- package/esm2020/lib/components/branch/branch.component.mjs +7 -15
- package/esm2020/lib/components/dropzone/dropzone.component.mjs +2 -2
- package/esm2020/lib/components/root/root.component.mjs +3 -4
- package/esm2020/lib/core/branch-options.interface.mjs +1 -1
- package/esm2020/lib/core/configuration/configuration.mjs +1 -1
- package/esm2020/lib/core/configuration/tree-options.interface.mjs +1 -1
- package/esm2020/lib/core/index.mjs +1 -2
- package/esm2020/lib/core/relationship.interface.mjs +1 -1
- package/esm2020/lib/core/tree-branch/branch-controller.mjs +99 -0
- package/esm2020/lib/core/tree-branch/tree-branch.mjs +260 -106
- package/esm2020/lib/core/tree-node-base.mjs +10 -9
- package/esm2020/lib/core/tree-root/root-controller.mjs +42 -0
- package/esm2020/lib/core/tree-root/tree-root.mjs +138 -27
- package/esm2020/lib/core/tree-service/tree.service.mjs +7 -1
- package/esm2020/lib/events/drag/drag-end-event.mjs +9 -7
- package/esm2020/lib/events/drag/drag-start-event.mjs +2 -4
- package/esm2020/lib/events/drag/drop-event.mjs +2 -4
- package/esm2020/lib/events/general/destruction-event.mjs +10 -0
- package/esm2020/lib/events/general/index.mjs +2 -0
- package/esm2020/lib/events/index.mjs +2 -1
- package/esm2020/lib/events/relational/graft-event.mjs +2 -4
- package/esm2020/lib/events/relational/prune-event.mjs +2 -4
- package/esm2020/lib/events/relational/relational-tree-event.interface.mjs +1 -1
- package/esm2020/lib/extras/collapse/collapse.mjs +2 -2
- package/esm2020/lib/extras/collapse/collapse.module.mjs +2 -1
- package/esm2020/lib/extras/collapse/collapse.service.mjs +26 -1
- package/esm2020/lib/extras/drag-and-drop/drag-and-drop.mjs +6 -10
- package/esm2020/lib/extras/drag-and-drop/drag-and-drop.module.mjs +5 -1
- package/esm2020/lib/extras/drag-and-drop/drag-and-drop.service.mjs +21 -5
- package/esm2020/lib/extras/drag-and-drop/draggable.directive.mjs +7 -7
- package/esm2020/lib/extras/drag-and-drop/dragover-no-change-detect.mjs +10 -11
- package/esm2020/lib/extras/drag-and-drop/dropzone-renderer.mjs +9 -7
- package/esm2020/lib/legacy/legacy-component-obj.interface.mjs +1 -1
- package/esm2020/lib/legacy/legacy-tree-data.interface.mjs +1 -1
- package/esm2020/lib/legacy/legacy-tree-options.interface.mjs +1 -1
- package/esm2020/lib/legacy/legacy-tree.mjs +30 -30
- package/esm2020/lib/legacy/limble-tree-root/limble-tree-root.component.mjs +1 -1
- package/esm2020/lib/limble-tree.module.mjs +6 -2
- package/esm2020/lib/structure/branchable.interface.mjs +1 -1
- package/esm2020/lib/structure/component-container.interface.mjs +2 -0
- package/esm2020/lib/structure/index.mjs +2 -5
- package/esm2020/lib/structure/tree-branch-node.interface.mjs +1 -1
- package/esm2020/lib/structure/tree-event.interface.mjs +1 -1
- package/esm2020/lib/structure/tree-node.interface.mjs +1 -1
- package/esm2020/lib/structure/tree-relationship.interface.mjs +1 -1
- package/fesm2015/limble-limble-tree.mjs +821 -376
- package/fesm2015/limble-limble-tree.mjs.map +1 -1
- package/fesm2020/limble-limble-tree.mjs +819 -372
- package/fesm2020/limble-limble-tree.mjs.map +1 -1
- package/lib/core/branch-options.interface.d.ts +1 -1
- package/lib/core/configuration/configuration.d.ts +2 -2
- package/lib/core/configuration/tree-options.interface.d.ts +48 -29
- package/lib/core/index.d.ts +0 -1
- package/lib/core/relationship.interface.d.ts +2 -3
- package/lib/core/tree-branch/branch-controller.d.ts +25 -0
- package/lib/core/tree-branch/tree-branch.d.ts +199 -24
- package/lib/core/tree-node-base.d.ts +4 -5
- package/lib/core/tree-root/root-controller.d.ts +19 -0
- package/lib/core/tree-root/tree-root.d.ts +109 -14
- package/lib/core/tree-service/tree.service.d.ts +8 -2
- package/lib/events/drag/drag-end-event.d.ts +15 -13
- package/lib/events/drag/drag-start-event.d.ts +6 -5
- package/lib/events/drag/drop-event.d.ts +7 -10
- package/lib/events/general/destruction-event.d.ts +8 -0
- package/lib/events/general/index.d.ts +1 -0
- package/lib/events/index.d.ts +1 -0
- package/lib/events/relational/graft-event.d.ts +5 -6
- package/lib/events/relational/prune-event.d.ts +5 -6
- package/lib/events/relational/relational-tree-event.interface.d.ts +5 -1
- package/lib/extras/collapse/collapse.module.d.ts +1 -0
- package/lib/extras/collapse/collapse.service.d.ts +25 -0
- package/lib/extras/drag-and-drop/drag-and-drop.d.ts +2 -3
- package/lib/extras/drag-and-drop/drag-and-drop.module.d.ts +4 -0
- package/lib/extras/drag-and-drop/drag-and-drop.service.d.ts +22 -3
- package/lib/extras/drag-and-drop/draggable.directive.d.ts +4 -5
- package/lib/extras/drag-and-drop/dragover-no-change-detect.d.ts +7 -3
- package/lib/legacy/legacy-component-obj.interface.d.ts +1 -1
- package/lib/legacy/legacy-tree-data.interface.d.ts +1 -1
- package/lib/legacy/legacy-tree-options.interface.d.ts +2 -2
- package/lib/legacy/legacy-tree.d.ts +4 -4
- package/lib/legacy/limble-tree-root/limble-tree-root.component.d.ts +4 -4
- package/lib/limble-tree.module.d.ts +4 -0
- package/lib/structure/branchable.interface.d.ts +0 -1
- package/lib/structure/component-container.interface.d.ts +8 -0
- package/lib/structure/index.d.ts +1 -4
- package/lib/structure/tree-branch-node.interface.d.ts +3 -3
- package/lib/structure/tree-event.interface.d.ts +3 -3
- package/lib/structure/tree-node.interface.d.ts +11 -6
- package/lib/structure/tree-relationship.interface.d.ts +2 -2
- package/package.json +1 -1
- package/esm2020/lib/structure/container-tree-node.interface.mjs +0 -2
- package/esm2020/lib/structure/content-container.interface.mjs +0 -2
- package/esm2020/lib/structure/event-conduit.interface.mjs +0 -2
- package/esm2020/lib/structure/tree-root.node.interface.mjs +0 -2
- package/lib/structure/container-tree-node.interface.d.ts +0 -3
- package/lib/structure/content-container.interface.d.ts +0 -3
- package/lib/structure/event-conduit.interface.d.ts +0 -6
- package/lib/structure/tree-root.node.interface.d.ts +0 -2
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, NgModule, EventEmitter, Directive,
|
|
3
|
-
import { BehaviorSubject,
|
|
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, Subject, filter, first } from 'rxjs';
|
|
4
4
|
import * as i1 from '@angular/common';
|
|
5
5
|
import { CommonModule } from '@angular/common';
|
|
6
|
-
import { throttleTime } from 'rxjs/operators';
|
|
7
6
|
|
|
8
7
|
class TreeCollapser {
|
|
9
8
|
constructor() {
|
|
@@ -27,7 +26,7 @@ class TreeCollapser {
|
|
|
27
26
|
branch.graftTo(treeBranch);
|
|
28
27
|
});
|
|
29
28
|
this.tempStorage.delete(treeBranch);
|
|
30
|
-
treeBranch.
|
|
29
|
+
treeBranch.detectChanges();
|
|
31
30
|
}
|
|
32
31
|
isCollapsed(treeBranch) {
|
|
33
32
|
return this.tempStorage.has(treeBranch);
|
|
@@ -38,13 +37,38 @@ class TreeCollapser {
|
|
|
38
37
|
}
|
|
39
38
|
const treeCollapser = new TreeCollapser();
|
|
40
39
|
|
|
40
|
+
/** A service that collapses and expands tree branches */
|
|
41
41
|
class TreeCollapseService {
|
|
42
|
+
/**
|
|
43
|
+
* Causes a TreeBranch to collapse, temporarily pruning all of its children
|
|
44
|
+
* from the tree.
|
|
45
|
+
*
|
|
46
|
+
* @param treeBranch - The branch to collapse.
|
|
47
|
+
*/
|
|
42
48
|
collapse(treeBranch) {
|
|
43
49
|
treeCollapser.collapse(treeBranch);
|
|
44
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Causes a TreeBranch to expand, restoring all of its children which were
|
|
53
|
+
* previously pruned by a call to `collapse()`.
|
|
54
|
+
*
|
|
55
|
+
* @param treeBranch - The branch to expand.
|
|
56
|
+
*/
|
|
45
57
|
expand(treeBranch) {
|
|
46
58
|
treeCollapser.expand(treeBranch);
|
|
47
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Determines whether a TreeBranch currently has any children which are
|
|
62
|
+
* pruned from the tree due to a call to the `collapse()` method.
|
|
63
|
+
*
|
|
64
|
+
* @remarks
|
|
65
|
+
* Child branches which are pruned manually from the tree, rather than
|
|
66
|
+
* through the `collapse()` method, will not be considered.
|
|
67
|
+
*
|
|
68
|
+
* @param treeBranch - The branch to check.
|
|
69
|
+
*
|
|
70
|
+
* @returns `true` if the branch is currently collapsed; `false` if it is not.
|
|
71
|
+
*/
|
|
48
72
|
isCollapsed(treeBranch) {
|
|
49
73
|
return treeCollapser.isCollapsed(treeBranch);
|
|
50
74
|
}
|
|
@@ -55,6 +79,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
|
|
|
55
79
|
type: Injectable
|
|
56
80
|
}] });
|
|
57
81
|
|
|
82
|
+
/** A module containing the entities which provide collapse functionality */
|
|
58
83
|
class TreeCollapseModule {
|
|
59
84
|
}
|
|
60
85
|
TreeCollapseModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeCollapseModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
@@ -67,66 +92,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
|
|
|
67
92
|
}]
|
|
68
93
|
}] });
|
|
69
94
|
|
|
70
|
-
class Configuration {
|
|
71
|
-
constructor() {
|
|
72
|
-
this.configStorage = new Map();
|
|
73
|
-
this.configStorage = new Map();
|
|
74
|
-
}
|
|
75
|
-
setConfig(root, options) {
|
|
76
|
-
this.configStorage.set(root, options);
|
|
77
|
-
}
|
|
78
|
-
getConfig(root) {
|
|
79
|
-
return this.configStorage.get(root);
|
|
80
|
-
}
|
|
81
|
-
delete(root) {
|
|
82
|
-
this.configStorage.delete(root);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
const config = new Configuration();
|
|
86
|
-
|
|
87
|
-
class TreeError extends Error {
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
class DragEndEvent {
|
|
91
|
-
constructor(source, endpoints) {
|
|
92
|
-
this._source = source;
|
|
93
|
-
this._oldParent = endpoints.oldParent;
|
|
94
|
-
this._oldIndex = endpoints.oldIndex;
|
|
95
|
-
this._newParent = endpoints.newParent;
|
|
96
|
-
this._newIndex = endpoints.newIndex;
|
|
97
|
-
}
|
|
98
|
-
type() {
|
|
99
|
-
return "drag end";
|
|
100
|
-
}
|
|
101
|
-
source() {
|
|
102
|
-
return this._source;
|
|
103
|
-
}
|
|
104
|
-
newIndex() {
|
|
105
|
-
return this._newIndex;
|
|
106
|
-
}
|
|
107
|
-
newParent() {
|
|
108
|
-
return this._newParent;
|
|
109
|
-
}
|
|
110
|
-
oldIndex() {
|
|
111
|
-
return this._oldIndex;
|
|
112
|
-
}
|
|
113
|
-
oldParent() {
|
|
114
|
-
return this._oldParent;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
class DragStartEvent {
|
|
119
|
-
constructor(source) {
|
|
120
|
-
this._source = source;
|
|
121
|
-
}
|
|
122
|
-
type() {
|
|
123
|
-
return "drag start";
|
|
124
|
-
}
|
|
125
|
-
source() {
|
|
126
|
-
return this._source;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
95
|
function assert(condition) {
|
|
131
96
|
if (condition) {
|
|
132
97
|
return;
|
|
@@ -179,119 +144,20 @@ class DragState {
|
|
|
179
144
|
}
|
|
180
145
|
const dragState = new DragState();
|
|
181
146
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
type() {
|
|
189
|
-
return "drag end";
|
|
190
|
-
}
|
|
191
|
-
source() {
|
|
192
|
-
return this._source;
|
|
193
|
-
}
|
|
194
|
-
index() {
|
|
195
|
-
return this._index;
|
|
196
|
-
}
|
|
197
|
-
parent() {
|
|
198
|
-
return this._parent;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
class DragAndDrop {
|
|
203
|
-
constructor() {
|
|
204
|
-
this.dragAborted$ = new Subject();
|
|
205
|
-
}
|
|
206
|
-
dragStart(treeBranch, event) {
|
|
207
|
-
if (!this.draggingAllowed(treeBranch)) {
|
|
208
|
-
event.preventDefault();
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
treeBranch.dispatch(new DragStartEvent(treeBranch));
|
|
212
|
-
this.setDragEffects(treeBranch, event);
|
|
213
|
-
this.watchForDragend(treeBranch, event);
|
|
214
|
-
// We have to do a setTimeout because DOM changes are not allowed during a
|
|
215
|
-
// dragstart event.
|
|
216
|
-
setTimeout(() => {
|
|
217
|
-
dragState.starting(treeBranch);
|
|
218
|
-
treeBranch.prune();
|
|
219
|
-
dragState.dragging();
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
drop(parent, index) {
|
|
223
|
-
const treeBranch = dragState.getDragData();
|
|
224
|
-
if (treeBranch === undefined) {
|
|
225
|
-
throw new TreeError("Cannot get dragged branch");
|
|
226
|
-
}
|
|
227
|
-
this.graftDraggedBranch(treeBranch, parent, index);
|
|
228
|
-
treeBranch.dispatch(new DropEvent(treeBranch, parent, index));
|
|
229
|
-
}
|
|
230
|
-
getDragImageOffsets(event, element) {
|
|
231
|
-
const bounds = element.getBoundingClientRect();
|
|
232
|
-
const xOffset = event.clientX - bounds.left;
|
|
233
|
-
const yOffset = event.clientY - bounds.top;
|
|
234
|
-
return [xOffset, yOffset];
|
|
235
|
-
}
|
|
236
|
-
setDragEffects(treeBranch, event) {
|
|
237
|
-
const dataTransfer = event.dataTransfer;
|
|
238
|
-
if (!(dataTransfer instanceof DataTransfer)) {
|
|
239
|
-
throw new Error("bad drag event");
|
|
240
|
-
}
|
|
241
|
-
const nativeElement = treeBranch.getContents().location.nativeElement;
|
|
242
|
-
const [xOffset, yOffset] = this.getDragImageOffsets(event, nativeElement);
|
|
243
|
-
dataTransfer.setDragImage(nativeElement, xOffset, yOffset);
|
|
244
|
-
}
|
|
245
|
-
watchForDragend(treeBranch, event) {
|
|
246
|
-
const oldParent = treeBranch.parent();
|
|
247
|
-
const oldIndex = treeBranch.index();
|
|
248
|
-
if (oldParent === undefined || oldIndex === undefined) {
|
|
249
|
-
throw new Error("branch must have a parent");
|
|
250
|
-
}
|
|
251
|
-
event.target?.addEventListener("dragend", (dragend) => {
|
|
252
|
-
if (dragState.state() !== DragStates.Dropped) {
|
|
253
|
-
//The drag ended but a drop never occurred, so put the dragged branch back where it started.
|
|
254
|
-
this.dragAborted$.next(dragend);
|
|
255
|
-
this.graftDraggedBranch(treeBranch, oldParent, oldIndex);
|
|
256
|
-
}
|
|
257
|
-
dragState.restart();
|
|
258
|
-
const newParent = treeBranch.parent();
|
|
259
|
-
assert(newParent !== undefined);
|
|
260
|
-
const newIndex = treeBranch.index();
|
|
261
|
-
assert(newIndex !== undefined);
|
|
262
|
-
treeBranch.dispatch(new DragEndEvent(treeBranch, {
|
|
263
|
-
oldParent,
|
|
264
|
-
oldIndex,
|
|
265
|
-
newParent,
|
|
266
|
-
newIndex
|
|
267
|
-
}));
|
|
268
|
-
}, { once: true });
|
|
269
|
-
}
|
|
270
|
-
draggingAllowed(treeBranch) {
|
|
271
|
-
const allowDragging = config.getConfig(treeBranch.root())?.allowDragging ??
|
|
272
|
-
(() => true);
|
|
273
|
-
return allowDragging(treeBranch);
|
|
274
|
-
}
|
|
275
|
-
graftDraggedBranch(treeBranch, parent, index) {
|
|
276
|
-
treeBranch.graftTo(parent, index);
|
|
277
|
-
treeBranch.getContents().location.nativeElement.style.display = "block";
|
|
278
|
-
dragState.dropped();
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
const dragAndDrop = new DragAndDrop();
|
|
282
|
-
|
|
147
|
+
/**
|
|
148
|
+
* Works just like Angular's built-in `(dragover)` event binding, but is much
|
|
149
|
+
* more performant. It throttles the event to a configurable rate (default once
|
|
150
|
+
* every 25ms) and runs outside of Angular's change detection.
|
|
151
|
+
*/
|
|
283
152
|
class DragoverNoChangeDetectDirective {
|
|
284
153
|
constructor(ngZone, el) {
|
|
285
154
|
this.ngZone = ngZone;
|
|
286
155
|
this.el = el;
|
|
287
156
|
this.dragoverNoChangeDetect = new EventEmitter();
|
|
288
|
-
this.dragoverEventThrottle = 25;
|
|
289
157
|
}
|
|
290
158
|
ngOnInit() {
|
|
291
159
|
this.ngZone.runOutsideAngular(() => {
|
|
292
|
-
this.eventSubscription = fromEvent(this.el.nativeElement, "dragover")
|
|
293
|
-
.pipe(throttleTime(this.dragoverEventThrottle))
|
|
294
|
-
.subscribe(($event) => {
|
|
160
|
+
this.eventSubscription = fromEvent(this.el.nativeElement, "dragover").subscribe(($event) => {
|
|
295
161
|
this.dragoverNoChangeDetect.emit($event);
|
|
296
162
|
});
|
|
297
163
|
});
|
|
@@ -303,16 +169,14 @@ class DragoverNoChangeDetectDirective {
|
|
|
303
169
|
}
|
|
304
170
|
}
|
|
305
171
|
DragoverNoChangeDetectDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: DragoverNoChangeDetectDirective, deps: [{ token: i0.NgZone }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
306
|
-
DragoverNoChangeDetectDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.12", type: DragoverNoChangeDetectDirective, isStandalone: true, selector: "[dragoverNoChangeDetect]",
|
|
172
|
+
DragoverNoChangeDetectDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.12", type: DragoverNoChangeDetectDirective, isStandalone: true, selector: "[dragoverNoChangeDetect]", outputs: { dragoverNoChangeDetect: "dragoverNoChangeDetect" }, ngImport: i0 });
|
|
307
173
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: DragoverNoChangeDetectDirective, decorators: [{
|
|
308
174
|
type: Directive,
|
|
309
175
|
args: [{
|
|
310
176
|
standalone: true,
|
|
311
177
|
selector: "[dragoverNoChangeDetect]"
|
|
312
178
|
}]
|
|
313
|
-
}], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.ElementRef }]; }, propDecorators: {
|
|
314
|
-
type: Input
|
|
315
|
-
}], dragoverNoChangeDetect: [{
|
|
179
|
+
}], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.ElementRef }]; }, propDecorators: { dragoverNoChangeDetect: [{
|
|
316
180
|
type: Output
|
|
317
181
|
}] } });
|
|
318
182
|
|
|
@@ -336,10 +200,10 @@ class DropzoneComponent {
|
|
|
336
200
|
}
|
|
337
201
|
}
|
|
338
202
|
DropzoneComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: DropzoneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
339
|
-
DropzoneComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", 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:
|
|
203
|
+
DropzoneComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", 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"] }] });
|
|
340
204
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: DropzoneComponent, decorators: [{
|
|
341
205
|
type: Component,
|
|
342
|
-
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:
|
|
206
|
+
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"] }]
|
|
343
207
|
}], propDecorators: { placement: [{
|
|
344
208
|
type: Input
|
|
345
209
|
}], dropped: [{
|
|
@@ -359,22 +223,14 @@ class BranchComponent {
|
|
|
359
223
|
this.showLateralDropzone = false;
|
|
360
224
|
}
|
|
361
225
|
ngAfterViewInit() {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
365
|
-
if (this.contentToHost === undefined) {
|
|
366
|
-
throw new TreeError("'content' is a required input");
|
|
367
|
-
}
|
|
226
|
+
assert(this.contentContainer !== undefined);
|
|
227
|
+
assert(this.contentToHost !== undefined);
|
|
368
228
|
this.hostedContent = this.contentContainer.createComponent(this.contentToHost);
|
|
369
229
|
this.contentCreated.emit(this.hostedContent.instance);
|
|
370
|
-
|
|
371
|
-
throw new Error("querylist not defined");
|
|
372
|
-
}
|
|
230
|
+
assert(this.dropzones !== undefined);
|
|
373
231
|
const inner = this.dropzones.get(0);
|
|
374
232
|
const lateral = this.dropzones.get(1);
|
|
375
|
-
|
|
376
|
-
throw new Error("dropzones not defined");
|
|
377
|
-
}
|
|
233
|
+
assert(inner !== undefined && lateral !== undefined);
|
|
378
234
|
merge(inner.dropped.pipe(map(() => "inner")), lateral.dropped.pipe(map(() => "lateral"))).subscribe(this.dropped);
|
|
379
235
|
this.hostedContent.changeDetectorRef.detectChanges();
|
|
380
236
|
}
|
|
@@ -403,7 +259,7 @@ class BranchComponent {
|
|
|
403
259
|
}
|
|
404
260
|
}
|
|
405
261
|
BranchComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: BranchComponent, deps: [{ token: i0.ApplicationRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
406
|
-
BranchComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", 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]",
|
|
262
|
+
BranchComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", 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"] }] });
|
|
407
263
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: BranchComponent, decorators: [{
|
|
408
264
|
type: Component,
|
|
409
265
|
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"] }]
|
|
@@ -426,6 +282,162 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
|
|
|
426
282
|
type: Output
|
|
427
283
|
}] } });
|
|
428
284
|
|
|
285
|
+
class Configuration {
|
|
286
|
+
constructor() {
|
|
287
|
+
this.configStorage = new Map();
|
|
288
|
+
this.configStorage = new Map();
|
|
289
|
+
}
|
|
290
|
+
setConfig(root, options) {
|
|
291
|
+
this.configStorage.set(root, options);
|
|
292
|
+
}
|
|
293
|
+
getConfig(root) {
|
|
294
|
+
return this.configStorage.get(root);
|
|
295
|
+
}
|
|
296
|
+
delete(root) {
|
|
297
|
+
this.configStorage.delete(root);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const config = new Configuration();
|
|
301
|
+
|
|
302
|
+
class TreeError extends Error {
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/** Emitted when a drag-and-drop operation has completed */
|
|
306
|
+
class DragEndEvent {
|
|
307
|
+
constructor(source, endpoints) {
|
|
308
|
+
this._source = source;
|
|
309
|
+
this._oldParent = endpoints.oldParent;
|
|
310
|
+
this._oldIndex = endpoints.oldIndex;
|
|
311
|
+
this._newParent = endpoints.newParent;
|
|
312
|
+
this._newIndex = endpoints.newIndex;
|
|
313
|
+
}
|
|
314
|
+
/** @returns The new index of the dropped branch */
|
|
315
|
+
newIndex() {
|
|
316
|
+
return this._newIndex;
|
|
317
|
+
}
|
|
318
|
+
/** @returns The new parent of the dropped branch */
|
|
319
|
+
newParent() {
|
|
320
|
+
return this._newParent;
|
|
321
|
+
}
|
|
322
|
+
/** @returns The index of the dropped branch before it was dragged */
|
|
323
|
+
oldIndex() {
|
|
324
|
+
return this._oldIndex;
|
|
325
|
+
}
|
|
326
|
+
/** @returns The parent of the dropped branch before it was dragged */
|
|
327
|
+
oldParent() {
|
|
328
|
+
return this._oldParent;
|
|
329
|
+
}
|
|
330
|
+
source() {
|
|
331
|
+
return this._source;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** Emitted when a TreeBranch begins being dragged */
|
|
336
|
+
class DragStartEvent {
|
|
337
|
+
constructor(source) {
|
|
338
|
+
this._source = source;
|
|
339
|
+
}
|
|
340
|
+
source() {
|
|
341
|
+
return this._source;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** Emitted when a TreeBranch is dropped into a valid Dropzone */
|
|
346
|
+
class DropEvent {
|
|
347
|
+
constructor(source, parent, index) {
|
|
348
|
+
this._source = source;
|
|
349
|
+
this._parent = parent;
|
|
350
|
+
this._index = index;
|
|
351
|
+
}
|
|
352
|
+
source() {
|
|
353
|
+
return this._source;
|
|
354
|
+
}
|
|
355
|
+
index() {
|
|
356
|
+
return this._index;
|
|
357
|
+
}
|
|
358
|
+
parent() {
|
|
359
|
+
return this._parent;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
class DragAndDrop {
|
|
364
|
+
constructor() {
|
|
365
|
+
this.dragAborted$ = new Subject();
|
|
366
|
+
}
|
|
367
|
+
dragStart(treeBranch, event) {
|
|
368
|
+
if (!this.draggingAllowed(treeBranch)) {
|
|
369
|
+
event.preventDefault();
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
treeBranch.dispatch(new DragStartEvent(treeBranch));
|
|
373
|
+
this.setDragEffects(treeBranch, event);
|
|
374
|
+
this.watchForDragend(treeBranch, event);
|
|
375
|
+
// We have to do a setTimeout because DOM changes are not allowed during a
|
|
376
|
+
// dragstart event.
|
|
377
|
+
setTimeout(() => {
|
|
378
|
+
dragState.starting(treeBranch);
|
|
379
|
+
treeBranch.prune();
|
|
380
|
+
dragState.dragging();
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
drop(parent, index) {
|
|
384
|
+
const treeBranch = dragState.getDragData();
|
|
385
|
+
if (treeBranch === undefined) {
|
|
386
|
+
throw new TreeError("Cannot get dragged branch");
|
|
387
|
+
}
|
|
388
|
+
this.graftDraggedBranch(treeBranch, parent, index);
|
|
389
|
+
treeBranch.dispatch(new DropEvent(treeBranch, parent, index));
|
|
390
|
+
}
|
|
391
|
+
getDragImageOffsets(event, element) {
|
|
392
|
+
const bounds = element.getBoundingClientRect();
|
|
393
|
+
const xOffset = event.clientX - bounds.left;
|
|
394
|
+
const yOffset = event.clientY - bounds.top;
|
|
395
|
+
return [xOffset, yOffset];
|
|
396
|
+
}
|
|
397
|
+
setDragEffects(treeBranch, event) {
|
|
398
|
+
const dataTransfer = event.dataTransfer;
|
|
399
|
+
assert(dataTransfer instanceof DataTransfer);
|
|
400
|
+
const nativeElement = treeBranch.getNativeElement();
|
|
401
|
+
const [xOffset, yOffset] = this.getDragImageOffsets(event, nativeElement);
|
|
402
|
+
dataTransfer.setDragImage(nativeElement, xOffset, yOffset);
|
|
403
|
+
}
|
|
404
|
+
watchForDragend(treeBranch, event) {
|
|
405
|
+
const oldParent = treeBranch.parent();
|
|
406
|
+
const oldIndex = treeBranch.index();
|
|
407
|
+
assert(oldParent !== undefined && oldIndex !== undefined);
|
|
408
|
+
event.target?.addEventListener("dragend", (dragend) => {
|
|
409
|
+
if (dragState.state() !== DragStates.Dropped) {
|
|
410
|
+
//The drag ended but a drop never occurred, so put the dragged branch back where it started.
|
|
411
|
+
this.dragAborted$.next(dragend);
|
|
412
|
+
this.graftDraggedBranch(treeBranch, oldParent, oldIndex);
|
|
413
|
+
}
|
|
414
|
+
dragState.restart();
|
|
415
|
+
const newParent = treeBranch.parent();
|
|
416
|
+
assert(newParent !== undefined);
|
|
417
|
+
const newIndex = treeBranch.index();
|
|
418
|
+
assert(newIndex !== undefined);
|
|
419
|
+
treeBranch.dispatch(new DragEndEvent(treeBranch, {
|
|
420
|
+
oldParent,
|
|
421
|
+
oldIndex,
|
|
422
|
+
newParent,
|
|
423
|
+
newIndex
|
|
424
|
+
}));
|
|
425
|
+
}, { once: true });
|
|
426
|
+
}
|
|
427
|
+
draggingAllowed(treeBranch) {
|
|
428
|
+
const allowDragging = config.getConfig(treeBranch.root())?.dragAndDrop?.allowDragging ??
|
|
429
|
+
(() => true);
|
|
430
|
+
return allowDragging(treeBranch);
|
|
431
|
+
}
|
|
432
|
+
graftDraggedBranch(treeBranch, parent, index) {
|
|
433
|
+
treeBranch.graftTo(parent, index);
|
|
434
|
+
treeBranch.getNativeElement().style.display = "block";
|
|
435
|
+
dragState.dropped();
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
const dragAndDrop = new DragAndDrop();
|
|
439
|
+
|
|
440
|
+
/** Emits when a branch is grafted to another tree node */
|
|
429
441
|
class GraftEvent {
|
|
430
442
|
constructor(source, relationship) {
|
|
431
443
|
this._source = source;
|
|
@@ -436,9 +448,6 @@ class GraftEvent {
|
|
|
436
448
|
child() {
|
|
437
449
|
return this._child;
|
|
438
450
|
}
|
|
439
|
-
type() {
|
|
440
|
-
return "graft";
|
|
441
|
-
}
|
|
442
451
|
index() {
|
|
443
452
|
return this._index;
|
|
444
453
|
}
|
|
@@ -450,6 +459,7 @@ class GraftEvent {
|
|
|
450
459
|
}
|
|
451
460
|
}
|
|
452
461
|
|
|
462
|
+
/** Emitted when a branch is pruned from its parent branch */
|
|
453
463
|
class PruneEvent {
|
|
454
464
|
constructor(source, relationship) {
|
|
455
465
|
this._source = source;
|
|
@@ -460,9 +470,6 @@ class PruneEvent {
|
|
|
460
470
|
child() {
|
|
461
471
|
return this._child;
|
|
462
472
|
}
|
|
463
|
-
type() {
|
|
464
|
-
return "prune";
|
|
465
|
-
}
|
|
466
473
|
index() {
|
|
467
474
|
return this._index;
|
|
468
475
|
}
|
|
@@ -476,6 +483,7 @@ class PruneEvent {
|
|
|
476
483
|
|
|
477
484
|
class TreeNodeBase {
|
|
478
485
|
constructor() {
|
|
486
|
+
this.destroyed = false;
|
|
479
487
|
this._branches = [];
|
|
480
488
|
this.events$ = new Subject();
|
|
481
489
|
this.subscriptions = [
|
|
@@ -490,17 +498,14 @@ class TreeNodeBase {
|
|
|
490
498
|
branches() {
|
|
491
499
|
return [...this._branches];
|
|
492
500
|
}
|
|
493
|
-
deleteBranch(index) {
|
|
494
|
-
if (index === undefined) {
|
|
495
|
-
this._branches.pop();
|
|
496
|
-
return;
|
|
497
|
-
}
|
|
498
|
-
this._branches.splice(index, 1);
|
|
499
|
-
}
|
|
500
501
|
destroy() {
|
|
502
|
+
this.branches().forEach((branch) => {
|
|
503
|
+
branch.destroy();
|
|
504
|
+
});
|
|
501
505
|
this.subscriptions.forEach((sub) => {
|
|
502
506
|
sub.unsubscribe();
|
|
503
507
|
});
|
|
508
|
+
this.destroyed = true;
|
|
504
509
|
}
|
|
505
510
|
dispatch(event) {
|
|
506
511
|
this.events$.next(event);
|
|
@@ -511,6 +516,9 @@ class TreeNodeBase {
|
|
|
511
516
|
getBranch(index) {
|
|
512
517
|
return this._branches[index];
|
|
513
518
|
}
|
|
519
|
+
isDestroyed() {
|
|
520
|
+
return this.destroyed;
|
|
521
|
+
}
|
|
514
522
|
plot() {
|
|
515
523
|
return new Map(this.branches().map((branch, index) => [index, branch.plot()]));
|
|
516
524
|
}
|
|
@@ -521,7 +529,7 @@ class TreeNodeBase {
|
|
|
521
529
|
}
|
|
522
530
|
deregisterChildRelationship(child) {
|
|
523
531
|
const index = this.branches().findIndex((branch) => branch === child);
|
|
524
|
-
this.
|
|
532
|
+
this._branches.splice(index, 1);
|
|
525
533
|
}
|
|
526
534
|
graftsToSelf() {
|
|
527
535
|
return this.events().pipe(filter((event) => event instanceof GraftEvent), filter((event) => event.parent().events() === this.events$));
|
|
@@ -538,6 +546,16 @@ class TreeNodeBase {
|
|
|
538
546
|
}
|
|
539
547
|
}
|
|
540
548
|
|
|
549
|
+
/** Emitted when a node is destroyed */
|
|
550
|
+
class DestructionEvent {
|
|
551
|
+
constructor(source) {
|
|
552
|
+
this._source = source;
|
|
553
|
+
}
|
|
554
|
+
source() {
|
|
555
|
+
return this._source;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
541
559
|
class RootComponent {
|
|
542
560
|
constructor() {
|
|
543
561
|
this.branchesContainer = undefined;
|
|
@@ -548,9 +566,7 @@ class RootComponent {
|
|
|
548
566
|
}
|
|
549
567
|
ngAfterViewInit() {
|
|
550
568
|
this.afterViewInit.emit();
|
|
551
|
-
|
|
552
|
-
throw new Error("dropzone is not defined");
|
|
553
|
-
}
|
|
569
|
+
assert(this.dropzone !== undefined);
|
|
554
570
|
this.dropzone.dropped.subscribe(this.dropped);
|
|
555
571
|
}
|
|
556
572
|
}
|
|
@@ -571,71 +587,225 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
|
|
|
571
587
|
type: Output
|
|
572
588
|
}] } });
|
|
573
589
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
590
|
+
/**
|
|
591
|
+
* A wrapper around the BranchComponent that helps instantiate it and handles its events.
|
|
592
|
+
*/
|
|
593
|
+
class RootController {
|
|
594
|
+
constructor(treeRoot, viewContainerRef) {
|
|
595
|
+
this.treeRoot = treeRoot;
|
|
596
|
+
this.rootComponentRef = viewContainerRef.createComponent(RootComponent);
|
|
580
597
|
const viewInitSub = this.rootComponentRef.instance.afterViewInit.subscribe(() => {
|
|
581
598
|
const dropzone = this.rootComponentRef.instance.dropzone;
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
}
|
|
585
|
-
dropzoneRenderer.registerDropzone(dropzone, this);
|
|
599
|
+
assert(dropzone !== undefined);
|
|
600
|
+
dropzoneRenderer.registerDropzone(dropzone, this.treeRoot);
|
|
586
601
|
});
|
|
587
602
|
const droppedSub = this.rootComponentRef.instance.dropped.subscribe(() => {
|
|
588
|
-
dropzoneRenderer.handleDrop(this, "inner");
|
|
603
|
+
dropzoneRenderer.handleDrop(this.treeRoot, "inner");
|
|
589
604
|
});
|
|
590
605
|
this.instanceSubscriptions = [viewInitSub, droppedSub];
|
|
606
|
+
}
|
|
607
|
+
destroy() {
|
|
608
|
+
this.instanceSubscriptions.forEach((sub) => {
|
|
609
|
+
sub.unsubscribe();
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
detectChanges() {
|
|
591
613
|
this.rootComponentRef.changeDetectorRef.detectChanges();
|
|
592
614
|
}
|
|
615
|
+
getBranchesContainer() {
|
|
616
|
+
return this.rootComponentRef.instance.branchesContainer;
|
|
617
|
+
}
|
|
618
|
+
getComponentInstance() {
|
|
619
|
+
return this.rootComponentRef.instance;
|
|
620
|
+
}
|
|
621
|
+
getHostView() {
|
|
622
|
+
return this.rootComponentRef.hostView;
|
|
623
|
+
}
|
|
624
|
+
getNativeElement() {
|
|
625
|
+
return this.rootComponentRef.location.nativeElement;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Represents the base of the tree. It renders a very simple container for child
|
|
631
|
+
* branches. It has methods for creating and accessing those branches. It emits
|
|
632
|
+
* events when things happen in the tree.
|
|
633
|
+
*/
|
|
634
|
+
class TreeRoot {
|
|
635
|
+
constructor(viewContainerRef) {
|
|
636
|
+
this.viewContainerRef = viewContainerRef;
|
|
637
|
+
this.treeNodeBase = new TreeNodeBase();
|
|
638
|
+
this.rootController = new RootController(this, viewContainerRef);
|
|
639
|
+
this.detectChanges();
|
|
640
|
+
}
|
|
641
|
+
/** @returns All child branches as an array of TreeBranch instances */
|
|
593
642
|
branches() {
|
|
594
643
|
return this.treeNodeBase.branches();
|
|
595
644
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
645
|
+
/**
|
|
646
|
+
* Recursively destroys all branches of the tree, as well as itself.
|
|
647
|
+
*
|
|
648
|
+
* @remarks
|
|
649
|
+
* This releases all resources held or consumed by the tree.
|
|
650
|
+
*
|
|
651
|
+
* It is important to call this method when a tree is discarded, otherwise
|
|
652
|
+
* the tree will remain in memory and continue to consume resources.
|
|
653
|
+
*/
|
|
599
654
|
destroy() {
|
|
655
|
+
if (this.isDestroyed()) {
|
|
656
|
+
throw new TreeError("Cannot destroy a destroyed tree root");
|
|
657
|
+
}
|
|
600
658
|
dropzoneRenderer.clearTreeFromRegistry(this);
|
|
601
|
-
this.branches().forEach((branch) => {
|
|
602
|
-
branch.destroy();
|
|
603
|
-
});
|
|
604
659
|
this.treeNodeBase.destroy();
|
|
605
|
-
this.
|
|
606
|
-
sub.unsubscribe();
|
|
607
|
-
});
|
|
660
|
+
this.rootController.destroy();
|
|
608
661
|
this.viewContainerRef.clear();
|
|
609
662
|
config.delete(this);
|
|
610
|
-
|
|
663
|
+
this.dispatch(new DestructionEvent(this));
|
|
664
|
+
}
|
|
665
|
+
/** Run Angular change detection on the root of the tree */
|
|
666
|
+
detectChanges() {
|
|
667
|
+
this.rootController.detectChanges();
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Emits the specified TreeEvent.
|
|
671
|
+
*
|
|
672
|
+
* @remarks
|
|
673
|
+
* Caution: It is not recommended to manually emit TreeEvents that are already
|
|
674
|
+
* provided by the library. For example, it is not recommended to emit a
|
|
675
|
+
* `GraftEvent`, `DestructionEvent`, etc. These events may be used by the tree,
|
|
676
|
+
* and emitting them manually may cause unexpected behavior. Instead, we
|
|
677
|
+
* recommend implementing the TreeEvent interface with your own custom events
|
|
678
|
+
* and dispatching those.
|
|
679
|
+
*
|
|
680
|
+
* @param event - The TreeEvent that will be emitted.
|
|
681
|
+
*/
|
|
611
682
|
dispatch(event) {
|
|
612
683
|
this.treeNodeBase.dispatch(event);
|
|
613
684
|
}
|
|
685
|
+
/**
|
|
686
|
+
* @returns
|
|
687
|
+
* An observable that emits TreeEvents whenever an event is dispatched
|
|
688
|
+
* in the root or any of its descendant branches.
|
|
689
|
+
*/
|
|
614
690
|
events() {
|
|
615
691
|
return this.treeNodeBase.events();
|
|
616
692
|
}
|
|
693
|
+
/**
|
|
694
|
+
* @returns
|
|
695
|
+
* The child branch at the specified index, or undefined if there is
|
|
696
|
+
* no child branch at the specified index.
|
|
697
|
+
*/
|
|
617
698
|
getBranch(index) {
|
|
618
699
|
return this.treeNodeBase.getBranch(index);
|
|
619
700
|
}
|
|
620
|
-
|
|
621
|
-
|
|
701
|
+
/** @returns The ViewContainerRef in which child branches are rendered */
|
|
702
|
+
getBranchesContainer() {
|
|
703
|
+
if (this.isDestroyed()) {
|
|
704
|
+
throw new TreeError("Cannot get branches container from a destroyed tree root");
|
|
705
|
+
}
|
|
706
|
+
return this.rootController.getBranchesContainer();
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Retrieves the RootComponent.
|
|
710
|
+
*
|
|
711
|
+
* @remarks
|
|
712
|
+
* The RootComponent holds the BranchesContainer, as well as a single Dropzone
|
|
713
|
+
* for drag-and-drop operations.
|
|
714
|
+
*
|
|
715
|
+
* @returns The instance of RootComponent that is rendered by this class.
|
|
716
|
+
*/
|
|
717
|
+
getComponentInstance() {
|
|
718
|
+
if (this.isDestroyed()) {
|
|
719
|
+
throw new TreeError("Cannot get component instance from a destroyed tree root");
|
|
720
|
+
}
|
|
721
|
+
return this.rootController.getComponentInstance();
|
|
722
|
+
}
|
|
723
|
+
/** @returns The Host View in which the RootComponent is rendered */
|
|
724
|
+
getHostView() {
|
|
725
|
+
if (this.isDestroyed()) {
|
|
726
|
+
throw new TreeError("Cannot get component host view from a destroyed tree root");
|
|
727
|
+
}
|
|
728
|
+
return this.rootController.getHostView();
|
|
622
729
|
}
|
|
730
|
+
/** @returns The RootComponent as a native HTML Element */
|
|
731
|
+
getNativeElement() {
|
|
732
|
+
if (this.isDestroyed()) {
|
|
733
|
+
throw new TreeError("Cannot get native element from a destroyed tree root");
|
|
734
|
+
}
|
|
735
|
+
return this.rootController.getNativeElement();
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Appends a new child branch to this branch. The child branch will render
|
|
739
|
+
* the specified component according to the (optional) configuration parameter.
|
|
740
|
+
*
|
|
741
|
+
* @param component - The component to render in the new child branch.
|
|
742
|
+
* @param options - Configuration options for the new child branch.
|
|
743
|
+
*
|
|
744
|
+
* @returns
|
|
745
|
+
* The newly-created child branch.
|
|
746
|
+
*/
|
|
623
747
|
grow(component, options) {
|
|
748
|
+
if (this.isDestroyed()) {
|
|
749
|
+
throw new TreeError("Cannot grow a branch on a destroyed tree root");
|
|
750
|
+
}
|
|
624
751
|
return new TreeBranch(this, { component, ...options });
|
|
625
752
|
}
|
|
753
|
+
/** @returns `true` if the tree is destroyed, `false` otherwise */
|
|
754
|
+
isDestroyed() {
|
|
755
|
+
return this.treeNodeBase.isDestroyed();
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Provides a model describing the shape of the tree.
|
|
759
|
+
*
|
|
760
|
+
* @returns A multi-dimensional Map which describes the shape of the tree.
|
|
761
|
+
*
|
|
762
|
+
* @example
|
|
763
|
+
* For example, an empty tree will return an empty Map. A tree with a single
|
|
764
|
+
* branch will return a Map with a single entry, where the key is the index
|
|
765
|
+
* of the branch (zero) and the value is an empty Map. A Tree like this:
|
|
766
|
+
*
|
|
767
|
+
* ```
|
|
768
|
+
* ---Branch-------Branch
|
|
769
|
+
* /
|
|
770
|
+
* Root-------Branch
|
|
771
|
+
* \
|
|
772
|
+
* ---Branch
|
|
773
|
+
* ```
|
|
774
|
+
* Will return a Map of matching shape:
|
|
775
|
+
* ```
|
|
776
|
+
* Map {
|
|
777
|
+
* 0: Map { 0: Map {}},
|
|
778
|
+
* 1: Map {},
|
|
779
|
+
* 2: Map {}
|
|
780
|
+
* }
|
|
781
|
+
* ```
|
|
782
|
+
*/
|
|
626
783
|
plot() {
|
|
627
784
|
return this.treeNodeBase.plot();
|
|
628
785
|
}
|
|
786
|
+
/** @returns Itself */
|
|
629
787
|
root() {
|
|
630
788
|
return this;
|
|
631
789
|
}
|
|
790
|
+
/**
|
|
791
|
+
* Traverses the tree in depth-first pre-order, executing the provided
|
|
792
|
+
* callback function on each node. Traversal includes the Root.
|
|
793
|
+
*
|
|
794
|
+
* @param callback - A function to execute on each node.
|
|
795
|
+
*/
|
|
632
796
|
traverse(callback) {
|
|
633
797
|
callback(this);
|
|
634
798
|
this.treeNodeBase.traverse(callback);
|
|
635
799
|
}
|
|
636
800
|
}
|
|
637
801
|
|
|
802
|
+
/** Responsible for the creation of new trees. */
|
|
638
803
|
class TreeService {
|
|
804
|
+
/**
|
|
805
|
+
* Creates a new, empty tree structure inside the provided container.
|
|
806
|
+
*
|
|
807
|
+
* @returns A `TreeRoot` representing the base of the new tree.
|
|
808
|
+
*/
|
|
639
809
|
createEmptyTree(container, options = {}) {
|
|
640
810
|
container.clear();
|
|
641
811
|
const root = new TreeRoot(container);
|
|
@@ -650,29 +820,126 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
|
|
|
650
820
|
args: [{ providedIn: "root" }]
|
|
651
821
|
}] });
|
|
652
822
|
|
|
823
|
+
/**
|
|
824
|
+
* A wrapper around the BranchComponent that helps instantiate it and handles its events.
|
|
825
|
+
*/
|
|
826
|
+
class BranchController {
|
|
827
|
+
constructor(treeBranch, parentBranchesContainer) {
|
|
828
|
+
this.treeBranch = treeBranch;
|
|
829
|
+
this.outputBindingSubscriptions = [];
|
|
830
|
+
this.branchComponentRef = createComponent(BranchComponent, {
|
|
831
|
+
environmentInjector: parentBranchesContainer.injector.get(EnvironmentInjector)
|
|
832
|
+
});
|
|
833
|
+
this.branchComponentRef.instance.contentToHost =
|
|
834
|
+
this.treeBranch.branchOptions.component;
|
|
835
|
+
this.instanceSubscriptions = this.getInstanceSubscriptions(this.branchComponentRef.instance);
|
|
836
|
+
}
|
|
837
|
+
destroy() {
|
|
838
|
+
this.instanceSubscriptions.forEach((sub) => {
|
|
839
|
+
sub.unsubscribe();
|
|
840
|
+
});
|
|
841
|
+
this.outputBindingSubscriptions.forEach((sub) => {
|
|
842
|
+
sub.unsubscribe();
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
detectChanges() {
|
|
846
|
+
this.branchComponentRef.changeDetectorRef.detectChanges();
|
|
847
|
+
}
|
|
848
|
+
getBranchesContainer() {
|
|
849
|
+
return this.branchComponentRef.instance.branchesContainer;
|
|
850
|
+
}
|
|
851
|
+
getComponentInstance() {
|
|
852
|
+
return this.branchComponentRef.instance;
|
|
853
|
+
}
|
|
854
|
+
getHostView() {
|
|
855
|
+
return this.branchComponentRef.hostView;
|
|
856
|
+
}
|
|
857
|
+
getNativeElement() {
|
|
858
|
+
return this.branchComponentRef.location.nativeElement;
|
|
859
|
+
}
|
|
860
|
+
getUserlandComponentRef() {
|
|
861
|
+
return this.branchComponentRef.instance.getHostedContent();
|
|
862
|
+
}
|
|
863
|
+
getContentCreatedSub(instance) {
|
|
864
|
+
return instance.contentCreated.subscribe((userlandComponentInstance) => {
|
|
865
|
+
const component = userlandComponentInstance;
|
|
866
|
+
Object.entries(this.treeBranch.branchOptions.inputBindings ?? {}).forEach(([key, value]) => {
|
|
867
|
+
component[key] = value;
|
|
868
|
+
});
|
|
869
|
+
Object.entries(this.treeBranch.branchOptions.outputBindings ?? {}).forEach(([key, value]) => {
|
|
870
|
+
this.outputBindingSubscriptions.push(component[key].subscribe(value));
|
|
871
|
+
});
|
|
872
|
+
component.treeBranch = this.treeBranch;
|
|
873
|
+
const dropzones = instance.dropzones;
|
|
874
|
+
assert(dropzones !== undefined);
|
|
875
|
+
dropzoneRenderer.registerDropzones(dropzones, this.treeBranch);
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
getInstanceSubscriptions(instance) {
|
|
879
|
+
const droppedSub = instance.dropped.subscribe((placement) => {
|
|
880
|
+
dropzoneRenderer.handleDrop(this.treeBranch, placement);
|
|
881
|
+
});
|
|
882
|
+
return [
|
|
883
|
+
this.getContentCreatedSub(instance),
|
|
884
|
+
this.getShowLowerZonesSub(instance),
|
|
885
|
+
this.getShowUpperZonesSub(instance),
|
|
886
|
+
droppedSub
|
|
887
|
+
];
|
|
888
|
+
}
|
|
889
|
+
getShowLowerZonesSub(instance) {
|
|
890
|
+
return instance.showDropzones
|
|
891
|
+
.pipe(filter((direction) => direction === "lower"))
|
|
892
|
+
.subscribe(() => {
|
|
893
|
+
const currentDropzoneDisplayed = dropzoneRenderer.getCurrentDisplay();
|
|
894
|
+
if (currentDropzoneDisplayed?.treeBranch === this.treeBranch &&
|
|
895
|
+
currentDropzoneDisplayed.direction === "lower") {
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
dropzoneRenderer.showLowerZones(this.treeBranch);
|
|
899
|
+
instance.triggerChangeDetection();
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
getShowUpperZonesSub(instance) {
|
|
903
|
+
return instance.showDropzones
|
|
904
|
+
.pipe(filter((direction) => direction === "upper"))
|
|
905
|
+
.subscribe(() => {
|
|
906
|
+
const currentDropzoneDisplayed = dropzoneRenderer.getCurrentDisplay();
|
|
907
|
+
if (currentDropzoneDisplayed?.treeBranch === this.treeBranch &&
|
|
908
|
+
currentDropzoneDisplayed.direction === "upper") {
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
dropzoneRenderer.showUpperZones(this.treeBranch);
|
|
912
|
+
instance.triggerChangeDetection();
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
/** Represents a standard node in a tree. Renders a BranchComponent.
|
|
918
|
+
*
|
|
919
|
+
* @remarks
|
|
920
|
+
* This class renders a branch component, which does the following:
|
|
921
|
+
* 1. Renders a component provided by the user
|
|
922
|
+
* 2. Provides a container in which child branches may be rendered
|
|
923
|
+
* 3. Contains two Dropzones: one for dropping branches below this branch (as a
|
|
924
|
+
* sibling), and one for dropping branches as a first child of this branch.
|
|
925
|
+
*/
|
|
653
926
|
class TreeBranch {
|
|
654
927
|
constructor(parent, branchOptions) {
|
|
655
928
|
this.branchOptions = branchOptions;
|
|
656
929
|
this.detachedView = null;
|
|
657
930
|
this.treeNodeBase = new TreeNodeBase();
|
|
658
|
-
|
|
659
|
-
const parentBranchesContainer = parent.getContents().instance.branchesContainer;
|
|
931
|
+
const parentBranchesContainer = parent.getBranchesContainer();
|
|
660
932
|
assert(parentBranchesContainer !== undefined);
|
|
661
|
-
this.
|
|
662
|
-
environmentInjector: parentBranchesContainer.injector.get(EnvironmentInjector)
|
|
663
|
-
});
|
|
664
|
-
this.contents.instance.contentToHost = this.userlandComponent;
|
|
933
|
+
this.branchController = new BranchController(this, parentBranchesContainer);
|
|
665
934
|
this.setIndentation(parent);
|
|
666
|
-
this.outputBindingSubscriptions = [];
|
|
667
|
-
this.instanceSubscriptions = this.getInstanceSubscriptions();
|
|
668
935
|
if (parent instanceof TreeBranch &&
|
|
669
|
-
parent.branchOptions.
|
|
936
|
+
parent.branchOptions.defaultCollapsed === true) {
|
|
670
937
|
treeCollapser.storePrecollapsedNode(parent, this);
|
|
671
|
-
this.detachedView = this.
|
|
938
|
+
this.detachedView = this.branchController.getHostView();
|
|
672
939
|
}
|
|
673
940
|
else {
|
|
674
|
-
parentBranchesContainer.insert(this.
|
|
675
|
-
this.
|
|
941
|
+
parentBranchesContainer.insert(this.branchController.getHostView());
|
|
942
|
+
this.detectChanges();
|
|
676
943
|
this._parent = parent;
|
|
677
944
|
this.dispatch(new GraftEvent(this, {
|
|
678
945
|
parent: this._parent,
|
|
@@ -681,50 +948,127 @@ class TreeBranch {
|
|
|
681
948
|
}));
|
|
682
949
|
}
|
|
683
950
|
}
|
|
951
|
+
/** @returns All child branches as an array of TreeBranch instances, in order. */
|
|
684
952
|
branches() {
|
|
685
953
|
return this.treeNodeBase.branches();
|
|
686
954
|
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
955
|
+
/**
|
|
956
|
+
* Recursively destroys all descendant branches, as well as itself. This
|
|
957
|
+
* releases all resources held or consumed by this branch and its descendants.
|
|
958
|
+
*
|
|
959
|
+
* @remarks
|
|
960
|
+
* It is important to call this method when a branch is discarded, otherwise
|
|
961
|
+
* the branch will remain in memory and continue to consume resources.
|
|
962
|
+
*/
|
|
690
963
|
destroy() {
|
|
691
|
-
if (
|
|
692
|
-
|
|
693
|
-
dropzoneRenderer.clearTreeFromRegistry(this);
|
|
694
|
-
}
|
|
695
|
-
this.branches().forEach((branch) => {
|
|
696
|
-
branch.destroy();
|
|
697
|
-
});
|
|
698
|
-
const parent = this._parent;
|
|
699
|
-
const index = this.index();
|
|
700
|
-
if (index !== undefined && parent !== undefined) {
|
|
701
|
-
const container = parent.getContents().instance.branchesContainer;
|
|
702
|
-
assert(container !== undefined);
|
|
703
|
-
container.remove(index);
|
|
704
|
-
parent.deleteBranch(index);
|
|
964
|
+
if (this.isDestroyed()) {
|
|
965
|
+
throw new TreeError("Cannot destroy a destroyed tree branch");
|
|
705
966
|
}
|
|
967
|
+
this.prune();
|
|
968
|
+
treeCollapser.expand(this);
|
|
969
|
+
dropzoneRenderer.clearTreeFromRegistry(this);
|
|
970
|
+
this.branchController.getHostView().destroy();
|
|
706
971
|
this.treeNodeBase.destroy();
|
|
707
|
-
this.
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
}
|
|
972
|
+
this.branchController.destroy();
|
|
973
|
+
this.dispatch(new DestructionEvent(this));
|
|
974
|
+
}
|
|
975
|
+
/** Run Angular change detection on this branch */
|
|
976
|
+
detectChanges() {
|
|
977
|
+
this.branchController.detectChanges();
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* Emits the specified TreeEvent.
|
|
981
|
+
*
|
|
982
|
+
* @remarks
|
|
983
|
+
* Caution: It is not recommended to manually emit TreeEvents that are already
|
|
984
|
+
* provided by the library. For example, it is not recommended to emit a
|
|
985
|
+
* `GraftEvent`, `DestructionEvent`, etc. These events may be used by the tree,
|
|
986
|
+
* and emitting them manually may cause unexpected behavior. Instead, we
|
|
987
|
+
* recommend implementing the TreeEvent interface with your own custom events
|
|
988
|
+
* and dispatching those.
|
|
989
|
+
*
|
|
990
|
+
* @param event - The TreeEvent that will be emitted.
|
|
991
|
+
*/
|
|
714
992
|
dispatch(event) {
|
|
715
993
|
this.treeNodeBase.dispatch(event);
|
|
716
994
|
this._parent?.dispatch(event);
|
|
717
995
|
}
|
|
996
|
+
/**
|
|
997
|
+
* @returns
|
|
998
|
+
* An observable that emits TreeEvents whenever an event is dispatched
|
|
999
|
+
* in this branch or any of its descendant branches.
|
|
1000
|
+
*/
|
|
718
1001
|
events() {
|
|
719
1002
|
return this.treeNodeBase.events();
|
|
720
1003
|
}
|
|
1004
|
+
/**
|
|
1005
|
+
* @param index - The index of the child branch to retrieve.
|
|
1006
|
+
*
|
|
1007
|
+
* @returns
|
|
1008
|
+
* The child branch at the specified index, or undefined if there is
|
|
1009
|
+
* no child branch at the specified index.
|
|
1010
|
+
*/
|
|
721
1011
|
getBranch(index) {
|
|
722
1012
|
return this.treeNodeBase.getBranch(index);
|
|
723
1013
|
}
|
|
724
|
-
|
|
725
|
-
|
|
1014
|
+
/** @returns The ViewContainerRef in which child branches are rendered */
|
|
1015
|
+
getBranchesContainer() {
|
|
1016
|
+
if (this.isDestroyed()) {
|
|
1017
|
+
throw new TreeError("Cannot get branches container from a destroyed tree branch");
|
|
1018
|
+
}
|
|
1019
|
+
return this.branchController.getBranchesContainer();
|
|
1020
|
+
}
|
|
1021
|
+
/** @returns The instance of BranchComponent that is rendered by this class. */
|
|
1022
|
+
getComponentInstance() {
|
|
1023
|
+
if (this.isDestroyed()) {
|
|
1024
|
+
throw new TreeError("Cannot get component instance from a destroyed tree branch");
|
|
1025
|
+
}
|
|
1026
|
+
return this.branchController.getComponentInstance();
|
|
1027
|
+
}
|
|
1028
|
+
/** @returns The Host View in which the BranchComponent is rendered */
|
|
1029
|
+
getHostView() {
|
|
1030
|
+
if (this.isDestroyed()) {
|
|
1031
|
+
throw new TreeError("Cannot get component host view from a destroyed tree branch");
|
|
1032
|
+
}
|
|
1033
|
+
return this.branchController.getHostView();
|
|
726
1034
|
}
|
|
1035
|
+
/** @returns The BranchComponent as a native HTML Element */
|
|
1036
|
+
getNativeElement() {
|
|
1037
|
+
if (this.isDestroyed()) {
|
|
1038
|
+
throw new TreeError("Cannot get native element from a destroyed tree branch");
|
|
1039
|
+
}
|
|
1040
|
+
return this.branchController.getNativeElement();
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* @returns
|
|
1044
|
+
* A ComponentRef containing the instance of the user-provided
|
|
1045
|
+
* component which is rendered by this branch.
|
|
1046
|
+
*/
|
|
1047
|
+
getUserlandComponentRef() {
|
|
1048
|
+
if (this.isDestroyed()) {
|
|
1049
|
+
throw new TreeError("Cannot get userland component from a destroyed tree branch");
|
|
1050
|
+
}
|
|
1051
|
+
return this.branchController.getUserlandComponentRef();
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Attaches a branch to a new parent node.
|
|
1055
|
+
*
|
|
1056
|
+
* @remarks
|
|
1057
|
+
* If not already pruned, this method prunes (removes) this branch from its
|
|
1058
|
+
* current position in the tree; then grafts (reattaches) it as a child of the
|
|
1059
|
+
* specified parent branch at the specified index. If no index is specified,
|
|
1060
|
+
* the branch is appended as the last child of the parent. This causes this
|
|
1061
|
+
* branch's associated BranchComponent to be re-rendered in the DOM at the
|
|
1062
|
+
* new location.
|
|
1063
|
+
*
|
|
1064
|
+
* @param newParent - The new parent branch unto which this branch will be grafted.
|
|
1065
|
+
* @param index - The index at which this branch will be grafted. If not specified,
|
|
1066
|
+
* this branch will be appended as the last child of the new parent.
|
|
1067
|
+
*
|
|
1068
|
+
* @returns The index at which this branch was grafted.
|
|
1069
|
+
*/
|
|
727
1070
|
graftTo(newParent, index) {
|
|
1071
|
+
this.checkGraftLocationValidity(newParent, index);
|
|
728
1072
|
const ownIndex = this.index();
|
|
729
1073
|
if (ownIndex !== undefined) {
|
|
730
1074
|
this.prune();
|
|
@@ -739,9 +1083,35 @@ class TreeBranch {
|
|
|
739
1083
|
}));
|
|
740
1084
|
return newIndex;
|
|
741
1085
|
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Appends a new child branch to this branch. The child branch will render
|
|
1088
|
+
* the specified component according to the (optional) configuration parameter.
|
|
1089
|
+
*
|
|
1090
|
+
* @param component - The component to render in the new child branch.
|
|
1091
|
+
* @param options - Configuration options for the new child branch.
|
|
1092
|
+
*
|
|
1093
|
+
* @returns
|
|
1094
|
+
* The newly-created child branch.
|
|
1095
|
+
*/
|
|
742
1096
|
grow(component, options) {
|
|
1097
|
+
if (this.isDestroyed()) {
|
|
1098
|
+
throw new TreeError("Cannot grow a branch on a destroyed tree branch");
|
|
1099
|
+
}
|
|
743
1100
|
return new TreeBranch(this, { component, ...options });
|
|
744
1101
|
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Determines this branch's index in relation to its sibling branches.
|
|
1104
|
+
*
|
|
1105
|
+
* @remarks
|
|
1106
|
+
* For example, if it is the first child of its parent, this method will return
|
|
1107
|
+
* 0. If it is the second child of its parent, this method will return 1.
|
|
1108
|
+
*
|
|
1109
|
+
* If this branch has no parent, (eg, if this branch has been pruned) this
|
|
1110
|
+
* method will return undefined.
|
|
1111
|
+
*
|
|
1112
|
+
* @returns
|
|
1113
|
+
* The index of this branch in relation to its sibling branches, or undefined.
|
|
1114
|
+
*/
|
|
745
1115
|
index() {
|
|
746
1116
|
if (!this._parent) {
|
|
747
1117
|
return undefined;
|
|
@@ -752,15 +1122,76 @@ class TreeBranch {
|
|
|
752
1122
|
assert(index >= 0);
|
|
753
1123
|
return index;
|
|
754
1124
|
}
|
|
1125
|
+
/** @returns `true` if the branch is destroyed, `false` otherwise */
|
|
1126
|
+
isDestroyed() {
|
|
1127
|
+
return this.treeNodeBase.isDestroyed();
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* @returns
|
|
1131
|
+
* The data that was passed into the `branchOptions`' `meta` property
|
|
1132
|
+
* at construction.
|
|
1133
|
+
*/
|
|
755
1134
|
meta() {
|
|
756
1135
|
return this.branchOptions.meta ?? {};
|
|
757
1136
|
}
|
|
1137
|
+
/**
|
|
1138
|
+
* @returns
|
|
1139
|
+
* This branch's parent node (which may be a TreeBranch or TreeRoot).
|
|
1140
|
+
* If this branch has no parent, (eg, if this branch has been pruned) this
|
|
1141
|
+
* method will return undefined.
|
|
1142
|
+
*/
|
|
758
1143
|
parent() {
|
|
759
1144
|
return this._parent;
|
|
760
1145
|
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Provides a model describing this branch's descendants.
|
|
1148
|
+
*
|
|
1149
|
+
* @returns
|
|
1150
|
+
* A multi-dimensional Map which describes the shape of this branch's
|
|
1151
|
+
* descendants.
|
|
1152
|
+
*
|
|
1153
|
+
* @example
|
|
1154
|
+
* A branch with no children will return an empty Map. A branch with
|
|
1155
|
+
* a single child will return a Map with a single entry, where the key is the index
|
|
1156
|
+
* of the branch (zero) and the value is an empty Map. A Tree like this:
|
|
1157
|
+
*
|
|
1158
|
+
* ```
|
|
1159
|
+
* ---Branch-------Branch
|
|
1160
|
+
* /
|
|
1161
|
+
* Branch-------Branch
|
|
1162
|
+
* \
|
|
1163
|
+
* ---Branch
|
|
1164
|
+
* ```
|
|
1165
|
+
* Will return a Map of matching shape:
|
|
1166
|
+
* ```
|
|
1167
|
+
* Map {
|
|
1168
|
+
* 0: Map { 0: Map {}},
|
|
1169
|
+
* 1: Map {},
|
|
1170
|
+
* 2: Map {}
|
|
1171
|
+
* }
|
|
1172
|
+
* ```
|
|
1173
|
+
*/
|
|
761
1174
|
plot() {
|
|
762
1175
|
return this.treeNodeBase.plot();
|
|
763
1176
|
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Calculates the branch's position in the tree relative to the Root.
|
|
1179
|
+
*
|
|
1180
|
+
* @remarks
|
|
1181
|
+
* The position is described as an array of numbers, where each number
|
|
1182
|
+
* represents the index of the branch at that level of the tree.
|
|
1183
|
+
*
|
|
1184
|
+
* For example, if this branch is the first child of the Root, this method
|
|
1185
|
+
* will return [0]. If this branch is the second child of the first child
|
|
1186
|
+
* of the Root, this method will return [0, 1].
|
|
1187
|
+
*
|
|
1188
|
+
* If the branch is not related to a TreeRoot, (such as when it has been
|
|
1189
|
+
* pruned,) this method will throw an error.
|
|
1190
|
+
*
|
|
1191
|
+
* @returns
|
|
1192
|
+
* An array of numbers which describe the branch's position in the tree
|
|
1193
|
+
* relative to the Root.
|
|
1194
|
+
*/
|
|
764
1195
|
position() {
|
|
765
1196
|
const index = this.index();
|
|
766
1197
|
if (index === undefined) {
|
|
@@ -772,12 +1203,28 @@ class TreeBranch {
|
|
|
772
1203
|
}
|
|
773
1204
|
return [index];
|
|
774
1205
|
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Removes a branch from its tree without destroying it.
|
|
1208
|
+
*
|
|
1209
|
+
* @remarks
|
|
1210
|
+
* Removes this branch from its parent and detaches its associated
|
|
1211
|
+
* BranchComponent from the DOM. This puts the branch in a "pruned" state,
|
|
1212
|
+
* which may affect the behavior of other methods.
|
|
1213
|
+
*
|
|
1214
|
+
* A pruned branch can be reattached to any other node using the `graftTo` method.
|
|
1215
|
+
*
|
|
1216
|
+
* @returns
|
|
1217
|
+
* Itself, or undefined if it is already in a pruned state.
|
|
1218
|
+
*/
|
|
775
1219
|
prune() {
|
|
1220
|
+
if (this.isDestroyed()) {
|
|
1221
|
+
throw new TreeError("Cannot prune a destroyed tree branch");
|
|
1222
|
+
}
|
|
776
1223
|
const parent = this._parent;
|
|
777
1224
|
const index = this.index();
|
|
778
1225
|
if (index === undefined || parent === undefined)
|
|
779
1226
|
return;
|
|
780
|
-
const container = parent.
|
|
1227
|
+
const container = parent.getBranchesContainer();
|
|
781
1228
|
assert(container !== undefined);
|
|
782
1229
|
this.detachedView = container.detach(index);
|
|
783
1230
|
assert(this.detachedView !== null);
|
|
@@ -790,83 +1237,56 @@ class TreeBranch {
|
|
|
790
1237
|
this._parent = undefined;
|
|
791
1238
|
return this;
|
|
792
1239
|
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Get the root of the tree to which this Branch is attached.
|
|
1242
|
+
*
|
|
1243
|
+
* @returns
|
|
1244
|
+
* The TreeRoot of the tree this branch is in. If this branch is
|
|
1245
|
+
* does not have a root (such as when it has been pruned) this method will
|
|
1246
|
+
* return undefined.
|
|
1247
|
+
*/
|
|
793
1248
|
root() {
|
|
794
1249
|
const parent = this.parent();
|
|
795
|
-
if (parent === undefined) {
|
|
796
|
-
return undefined;
|
|
797
|
-
}
|
|
798
1250
|
if (parent instanceof TreeBranch) {
|
|
799
1251
|
return parent.root();
|
|
800
1252
|
}
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
1253
|
+
assert(parent instanceof TreeRoot || parent === undefined);
|
|
1254
|
+
return parent;
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Traverses this branch's descendants in depth-first pre-order, executing
|
|
1258
|
+
* the provided callback function on each node. Traversal includes this branch.
|
|
1259
|
+
*
|
|
1260
|
+
* @param callback - A function to execute on each node.
|
|
1261
|
+
*/
|
|
806
1262
|
traverse(callback) {
|
|
807
1263
|
callback(this);
|
|
808
1264
|
this.treeNodeBase.traverse(callback);
|
|
809
1265
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
dropzoneRenderer.registerDropzones(dropzones, this);
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
getInstanceSubscriptions() {
|
|
828
|
-
const droppedSub = this.contents.instance.dropped.subscribe((placement) => {
|
|
829
|
-
dropzoneRenderer.handleDrop(this, placement);
|
|
830
|
-
});
|
|
831
|
-
return [
|
|
832
|
-
this.getContentCreatedSub(),
|
|
833
|
-
this.getShowLowerZonesSub(),
|
|
834
|
-
this.getShowUpperZonesSub(),
|
|
835
|
-
droppedSub
|
|
836
|
-
];
|
|
837
|
-
}
|
|
838
|
-
getShowLowerZonesSub() {
|
|
839
|
-
const instance = this.contents.instance;
|
|
840
|
-
return instance.showDropzones
|
|
841
|
-
.pipe(filter((direction) => direction === "lower"))
|
|
842
|
-
.subscribe(() => {
|
|
843
|
-
const currentDropzoneDisplayed = dropzoneRenderer.getCurrentDisplay();
|
|
844
|
-
if (currentDropzoneDisplayed?.treeBranch === this &&
|
|
845
|
-
currentDropzoneDisplayed.direction === "lower") {
|
|
846
|
-
return;
|
|
1266
|
+
checkGraftLocationValidity(newParent, index) {
|
|
1267
|
+
if (this.isDestroyed()) {
|
|
1268
|
+
throw new TreeError("Cannot graft a destroyed tree branch");
|
|
1269
|
+
}
|
|
1270
|
+
if (newParent.isDestroyed()) {
|
|
1271
|
+
throw new TreeError("Cannot graft to a destroyed tree branch");
|
|
1272
|
+
}
|
|
1273
|
+
if (typeof index === "number" &&
|
|
1274
|
+
this.indexIsOutOfRange(newParent, index)) {
|
|
1275
|
+
throw new TreeError(`Cannot graft branch at index ${index} of the parent. Out of range.`);
|
|
1276
|
+
}
|
|
1277
|
+
this.traverse((node) => {
|
|
1278
|
+
if (node === newParent) {
|
|
1279
|
+
throw new TreeError("Cannot graft a branch to itself or any of its own descendants");
|
|
847
1280
|
}
|
|
848
|
-
dropzoneRenderer.showLowerZones(this);
|
|
849
|
-
instance.triggerChangeDetection();
|
|
850
1281
|
});
|
|
851
1282
|
}
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
return instance.showDropzones
|
|
855
|
-
.pipe(filter((direction) => direction === "upper"))
|
|
856
|
-
.subscribe(() => {
|
|
857
|
-
const currentDropzoneDisplayed = dropzoneRenderer.getCurrentDisplay();
|
|
858
|
-
if (currentDropzoneDisplayed?.treeBranch === this &&
|
|
859
|
-
currentDropzoneDisplayed.direction === "upper") {
|
|
860
|
-
return;
|
|
861
|
-
}
|
|
862
|
-
dropzoneRenderer.showUpperZones(this);
|
|
863
|
-
instance.triggerChangeDetection();
|
|
864
|
-
});
|
|
1283
|
+
indexIsOutOfRange(parent, index) {
|
|
1284
|
+
return index < 0 || index > parent.branches().length;
|
|
865
1285
|
}
|
|
866
1286
|
reattachView(index) {
|
|
867
1287
|
assert(this._parent !== undefined);
|
|
868
1288
|
assert(this.detachedView !== null);
|
|
869
|
-
const container = this._parent.
|
|
1289
|
+
const container = this._parent.getBranchesContainer();
|
|
870
1290
|
assert(container !== undefined);
|
|
871
1291
|
this.detachedView.reattach();
|
|
872
1292
|
container.insert(this.detachedView, index);
|
|
@@ -876,7 +1296,8 @@ class TreeBranch {
|
|
|
876
1296
|
const root = parent.root();
|
|
877
1297
|
assert(root !== undefined);
|
|
878
1298
|
const options = config.getConfig(root);
|
|
879
|
-
const branchesContainerEl = this.
|
|
1299
|
+
const branchesContainerEl = this.branchController
|
|
1300
|
+
.getNativeElement()
|
|
880
1301
|
.getElementsByClassName("branches-container")
|
|
881
1302
|
.item(0);
|
|
882
1303
|
assert(branchesContainerEl instanceof HTMLElement);
|
|
@@ -916,7 +1337,7 @@ class DropzoneRenderer {
|
|
|
916
1337
|
if (this.currentDisplay === null)
|
|
917
1338
|
return;
|
|
918
1339
|
for (const branch of this.registry.values()) {
|
|
919
|
-
const instance = branch.
|
|
1340
|
+
const instance = branch.getComponentInstance();
|
|
920
1341
|
instance.showInnerDropzone = false;
|
|
921
1342
|
if (instance instanceof BranchComponent) {
|
|
922
1343
|
instance.showLateralDropzone = false;
|
|
@@ -1017,7 +1438,7 @@ class DropzoneRenderer {
|
|
|
1017
1438
|
return true;
|
|
1018
1439
|
}
|
|
1019
1440
|
if (treeNode instanceof TreeBranch) {
|
|
1020
|
-
const allowNesting = config.getConfig(treeNode.root())?.allowNesting ??
|
|
1441
|
+
const allowNesting = config.getConfig(treeNode.root())?.dragAndDrop?.allowNesting ??
|
|
1021
1442
|
(() => true);
|
|
1022
1443
|
return allowNesting(treeNode);
|
|
1023
1444
|
}
|
|
@@ -1027,11 +1448,13 @@ class DropzoneRenderer {
|
|
|
1027
1448
|
const sourceNode = dragState.getDragData();
|
|
1028
1449
|
assert(sourceNode instanceof TreeBranch);
|
|
1029
1450
|
if (parent instanceof TreeRoot) {
|
|
1030
|
-
const allowDrop = config.getConfig(parent)?.allowDrop ??
|
|
1451
|
+
const allowDrop = config.getConfig(parent)?.dragAndDrop?.allowDrop ??
|
|
1452
|
+
(() => true);
|
|
1031
1453
|
return allowDrop(sourceNode, parent, index);
|
|
1032
1454
|
}
|
|
1033
1455
|
if (parent instanceof TreeBranch) {
|
|
1034
|
-
const allowDrop = config.getConfig(parent.root())?.allowDrop ??
|
|
1456
|
+
const allowDrop = config.getConfig(parent.root())?.dragAndDrop?.allowDrop ??
|
|
1457
|
+
(() => true);
|
|
1035
1458
|
return allowDrop(sourceNode, parent, index);
|
|
1036
1459
|
}
|
|
1037
1460
|
throw new Error("unsupported treeNode type");
|
|
@@ -1039,31 +1462,48 @@ class DropzoneRenderer {
|
|
|
1039
1462
|
showInnerZone(treeNode) {
|
|
1040
1463
|
if (!this.nestingAllowed(treeNode) || !this.dropAllowed(treeNode, 0))
|
|
1041
1464
|
return;
|
|
1042
|
-
treeNode.
|
|
1465
|
+
treeNode.getComponentInstance().showInnerDropzone = true;
|
|
1043
1466
|
}
|
|
1044
1467
|
showLateralZone(treeBranch) {
|
|
1045
1468
|
const index = treeBranch.index();
|
|
1046
1469
|
assert(index !== undefined);
|
|
1047
1470
|
if (!this.dropAllowed(treeBranch.parent(), index + 1))
|
|
1048
1471
|
return;
|
|
1049
|
-
treeBranch.
|
|
1472
|
+
treeBranch.getComponentInstance().showLateralDropzone = true;
|
|
1050
1473
|
}
|
|
1051
1474
|
}
|
|
1052
1475
|
const dropzoneRenderer = new DropzoneRenderer();
|
|
1053
1476
|
|
|
1054
1477
|
class TreeDragAndDropService {
|
|
1478
|
+
/** Hides all Dropzones */
|
|
1055
1479
|
clearDropzones() {
|
|
1056
1480
|
dropzoneRenderer.clearCurrentDisplay();
|
|
1057
1481
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1482
|
+
/**
|
|
1483
|
+
* @returns An object that indicates which dropzones are currently being displayed.
|
|
1484
|
+
* If no dropzones are being displayed, then null is returned.
|
|
1485
|
+
*/
|
|
1061
1486
|
getCurrentlyDisplayedDropzoneFamily() {
|
|
1062
1487
|
return dropzoneRenderer.getCurrentDisplay();
|
|
1063
1488
|
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Causes the dropzone of the TreeRoot to be displayed.
|
|
1491
|
+
*
|
|
1492
|
+
* @remarks
|
|
1493
|
+
* This is a useful function when you want to show the dropzone of a TreeRoot
|
|
1494
|
+
* that has no child branches.
|
|
1495
|
+
*
|
|
1496
|
+
* @param root - The TreeRoot whose dropzone you want to show.
|
|
1497
|
+
*/
|
|
1064
1498
|
showRootDropzone(root) {
|
|
1065
1499
|
dropzoneRenderer.showLowerZones(root);
|
|
1066
1500
|
}
|
|
1501
|
+
/**
|
|
1502
|
+
* @returns An observable that emits a number whenever the drag state changes.
|
|
1503
|
+
*
|
|
1504
|
+
* @remarks
|
|
1505
|
+
* See the `DragStates` enum for a list of possible states.
|
|
1506
|
+
*/
|
|
1067
1507
|
state() {
|
|
1068
1508
|
return dragState.events();
|
|
1069
1509
|
}
|
|
@@ -1074,19 +1514,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
|
|
|
1074
1514
|
type: Injectable
|
|
1075
1515
|
}] });
|
|
1076
1516
|
|
|
1517
|
+
/** Makes an TreeBranch draggable when the host element is dragged */
|
|
1077
1518
|
class DraggableDirective {
|
|
1078
|
-
constructor(
|
|
1079
|
-
this.dragAndDropService = dragAndDropService;
|
|
1519
|
+
constructor(renderer, hostElement) {
|
|
1080
1520
|
renderer.setAttribute(hostElement.nativeElement, "draggable", "true");
|
|
1081
1521
|
renderer.setStyle(hostElement.nativeElement, "cursor", "grab");
|
|
1082
1522
|
}
|
|
1083
1523
|
onDragstart(event) {
|
|
1084
1524
|
if (this.limbleTreeDraggable === undefined)
|
|
1085
1525
|
return;
|
|
1086
|
-
|
|
1526
|
+
dragAndDrop.dragStart(this.limbleTreeDraggable, event);
|
|
1087
1527
|
}
|
|
1088
1528
|
}
|
|
1089
|
-
DraggableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: DraggableDirective, deps: [{ token:
|
|
1529
|
+
DraggableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: DraggableDirective, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1090
1530
|
DraggableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.12", type: DraggableDirective, isStandalone: true, selector: "[limbleTreeDraggable]", inputs: { limbleTreeDraggable: "limbleTreeDraggable" }, host: { listeners: { "dragstart": "onDragstart($event)" } }, ngImport: i0 });
|
|
1091
1531
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: DraggableDirective, decorators: [{
|
|
1092
1532
|
type: Directive,
|
|
@@ -1094,13 +1534,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
|
|
|
1094
1534
|
selector: "[limbleTreeDraggable]",
|
|
1095
1535
|
standalone: true
|
|
1096
1536
|
}]
|
|
1097
|
-
}], ctorParameters: function () { return [{ type:
|
|
1537
|
+
}], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ElementRef }]; }, propDecorators: { limbleTreeDraggable: [{
|
|
1098
1538
|
type: Input
|
|
1099
1539
|
}], onDragstart: [{
|
|
1100
1540
|
type: HostListener,
|
|
1101
1541
|
args: ["dragstart", ["$event"]]
|
|
1102
1542
|
}] } });
|
|
1103
1543
|
|
|
1544
|
+
/**
|
|
1545
|
+
* An Angular module containing all of the entities which provide Drag-And-Drop
|
|
1546
|
+
* functionality.
|
|
1547
|
+
*/
|
|
1104
1548
|
class TreeDragAndDropModule {
|
|
1105
1549
|
}
|
|
1106
1550
|
TreeDragAndDropModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeDragAndDropModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
@@ -1132,32 +1576,34 @@ class LegacyTree {
|
|
|
1132
1576
|
upgradeOptions(legacyOptions) {
|
|
1133
1577
|
return {
|
|
1134
1578
|
indentation: legacyOptions.indent,
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1579
|
+
dragAndDrop: {
|
|
1580
|
+
allowNesting: (branch) => {
|
|
1581
|
+
if (legacyOptions.listMode === true) {
|
|
1582
|
+
return false;
|
|
1583
|
+
}
|
|
1584
|
+
if (legacyOptions.allowNesting === undefined) {
|
|
1585
|
+
return true;
|
|
1586
|
+
}
|
|
1587
|
+
if (typeof legacyOptions.allowNesting === "boolean") {
|
|
1588
|
+
return legacyOptions.allowNesting;
|
|
1589
|
+
}
|
|
1590
|
+
return legacyOptions.allowNesting(branch);
|
|
1591
|
+
},
|
|
1592
|
+
allowDragging: (branch) => {
|
|
1593
|
+
if (legacyOptions.allowDragging === undefined) {
|
|
1594
|
+
return true;
|
|
1595
|
+
}
|
|
1596
|
+
if (typeof legacyOptions.allowDragging === "boolean") {
|
|
1597
|
+
return legacyOptions.allowDragging;
|
|
1598
|
+
}
|
|
1599
|
+
return legacyOptions.allowDragging(branch);
|
|
1600
|
+
},
|
|
1601
|
+
allowDrop: (source, parent, index) => {
|
|
1602
|
+
if (legacyOptions.allowDrop === undefined) {
|
|
1603
|
+
return true;
|
|
1604
|
+
}
|
|
1605
|
+
return legacyOptions.allowDrop(source, parent, index);
|
|
1138
1606
|
}
|
|
1139
|
-
if (legacyOptions.allowNesting === undefined) {
|
|
1140
|
-
return true;
|
|
1141
|
-
}
|
|
1142
|
-
if (typeof legacyOptions.allowNesting === "boolean") {
|
|
1143
|
-
return legacyOptions.allowNesting;
|
|
1144
|
-
}
|
|
1145
|
-
return legacyOptions.allowNesting(branch);
|
|
1146
|
-
},
|
|
1147
|
-
allowDragging: (branch) => {
|
|
1148
|
-
if (legacyOptions.allowDragging === undefined) {
|
|
1149
|
-
return true;
|
|
1150
|
-
}
|
|
1151
|
-
if (typeof legacyOptions.allowDragging === "boolean") {
|
|
1152
|
-
return legacyOptions.allowDragging;
|
|
1153
|
-
}
|
|
1154
|
-
return legacyOptions.allowDragging(branch);
|
|
1155
|
-
},
|
|
1156
|
-
allowDrop: (source, parent, index) => {
|
|
1157
|
-
if (legacyOptions.allowDrop === undefined) {
|
|
1158
|
-
return true;
|
|
1159
|
-
}
|
|
1160
|
-
return legacyOptions.allowDrop(source, parent, index);
|
|
1161
1607
|
}
|
|
1162
1608
|
};
|
|
1163
1609
|
}
|
|
@@ -1170,9 +1616,6 @@ class LegacyTree {
|
|
|
1170
1616
|
options.defaultComponent?.bindings ??
|
|
1171
1617
|
{});
|
|
1172
1618
|
const nodeData = node;
|
|
1173
|
-
delete nodeData.nodes;
|
|
1174
|
-
delete nodeData.collapsed;
|
|
1175
|
-
delete nodeData.component;
|
|
1176
1619
|
const branch = parent.grow(component, {
|
|
1177
1620
|
inputBindings: bindings,
|
|
1178
1621
|
meta: { nodeData }
|
|
@@ -1273,6 +1716,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
|
|
|
1273
1716
|
}]
|
|
1274
1717
|
}] });
|
|
1275
1718
|
|
|
1719
|
+
/**
|
|
1720
|
+
* Import this Angular module into your application to gain access to the
|
|
1721
|
+
* components, directives, and services provided by Limble Tree.
|
|
1722
|
+
*/
|
|
1276
1723
|
class LimbleTreeModule {
|
|
1277
1724
|
}
|
|
1278
1725
|
LimbleTreeModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LimbleTreeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
@@ -1296,5 +1743,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
|
|
|
1296
1743
|
* Generated bundle index. Do not edit.
|
|
1297
1744
|
*/
|
|
1298
1745
|
|
|
1299
|
-
export { DragEndEvent, DragStartEvent, DraggableDirective, DragoverNoChangeDetectDirective, DropEvent, GraftEvent, LegacyTree, LimbleTreeLegacyModule, LimbleTreeModule, LimbleTreeRootComponent, PruneEvent, TreeBranch, TreeCollapseModule, TreeCollapseService, TreeDragAndDropModule, TreeDragAndDropService, TreeError, TreeRoot, TreeService
|
|
1746
|
+
export { DestructionEvent, DragEndEvent, DragStartEvent, DraggableDirective, DragoverNoChangeDetectDirective, DropEvent, GraftEvent, LegacyTree, LimbleTreeLegacyModule, LimbleTreeModule, LimbleTreeRootComponent, PruneEvent, TreeBranch, TreeCollapseModule, TreeCollapseService, TreeDragAndDropModule, TreeDragAndDropService, TreeError, TreeRoot, TreeService };
|
|
1300
1747
|
//# sourceMappingURL=limble-limble-tree.mjs.map
|