@limble/limble-tree 0.13.0 → 1.0.0-alpha.2
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 +418 -96
- package/esm2020/lib/components/branch/branch.component.mjs +79 -0
- package/esm2020/lib/components/dropzone/dropzone.component.mjs +35 -0
- package/esm2020/lib/components/host-component.interface.mjs +2 -0
- package/esm2020/lib/components/node-component.interface.mjs +2 -0
- package/esm2020/lib/components/root/root.component.mjs +36 -0
- package/esm2020/lib/core/branch-options.interface.mjs +2 -0
- package/esm2020/lib/core/configuration/configuration.mjs +17 -0
- package/esm2020/lib/core/configuration/tree-options.interface.mjs +2 -0
- package/esm2020/lib/core/index.mjs +6 -0
- package/esm2020/lib/core/relationship.interface.mjs +2 -0
- package/esm2020/lib/core/tree-branch/branch-controller.mjs +99 -0
- package/esm2020/lib/core/tree-branch/tree-branch.mjs +224 -0
- package/esm2020/lib/core/tree-node-base.mjs +69 -0
- package/esm2020/lib/core/tree-root/root-controller.mjs +42 -0
- package/esm2020/lib/core/tree-root/tree-root.mjs +85 -0
- package/esm2020/lib/core/tree-service/tree.service.mjs +19 -0
- package/esm2020/lib/errors/index.mjs +2 -0
- package/esm2020/lib/errors/tree-error.mjs +3 -0
- package/esm2020/lib/events/drag/drag-end-event.mjs +28 -0
- package/esm2020/lib/events/drag/drag-start-event.mjs +12 -0
- package/esm2020/lib/events/drag/drop-event.mjs +20 -0
- package/esm2020/lib/events/drag/index.mjs +4 -0
- package/esm2020/lib/events/general/destruction-event.mjs +12 -0
- package/esm2020/lib/events/general/index.mjs +2 -0
- package/esm2020/lib/events/index.mjs +4 -0
- package/esm2020/lib/events/relational/graft-event.mjs +24 -0
- package/esm2020/lib/events/relational/index.mjs +4 -0
- package/esm2020/lib/events/relational/prune-event.mjs +24 -0
- package/esm2020/lib/events/relational/relational-tree-event.interface.mjs +2 -0
- package/esm2020/lib/extras/collapse/collapse.mjs +33 -0
- package/esm2020/lib/extras/collapse/collapse.module.mjs +15 -0
- package/esm2020/lib/extras/collapse/collapse.service.mjs +20 -0
- package/esm2020/lib/extras/collapse/index.mjs +3 -0
- package/esm2020/lib/extras/drag-and-drop/drag-and-drop.mjs +85 -0
- package/esm2020/lib/extras/drag-and-drop/drag-and-drop.module.mjs +19 -0
- package/esm2020/lib/extras/drag-and-drop/drag-and-drop.service.mjs +28 -0
- package/esm2020/lib/extras/drag-and-drop/drag-state.mjs +47 -0
- package/esm2020/lib/extras/drag-and-drop/draggable.directive.mjs +30 -0
- package/esm2020/lib/extras/drag-and-drop/dragover-no-change-detect.mjs +40 -0
- package/esm2020/lib/extras/drag-and-drop/dropzone-renderer.mjs +178 -0
- package/esm2020/lib/extras/drag-and-drop/index.mjs +5 -0
- package/esm2020/lib/legacy/index.mjs +7 -0
- package/esm2020/lib/legacy/legacy-component-obj.interface.mjs +2 -0
- package/esm2020/lib/legacy/legacy-tree-data.interface.mjs +2 -0
- package/esm2020/lib/legacy/legacy-tree-options.interface.mjs +2 -0
- package/esm2020/lib/legacy/legacy-tree.mjs +73 -0
- package/esm2020/lib/legacy/limble-tree-legacy.module.mjs +20 -0
- package/esm2020/lib/legacy/limble-tree-root/limble-tree-root.component.mjs +78 -0
- package/esm2020/lib/limble-tree.module.mjs +21 -47
- package/esm2020/lib/structure/branchable.interface.mjs +2 -0
- package/esm2020/lib/structure/component-container.interface.mjs +2 -0
- package/esm2020/lib/structure/event-conduit.interface.mjs +2 -0
- package/esm2020/lib/structure/graftable.interface.mjs +2 -0
- package/esm2020/lib/structure/index.mjs +10 -0
- package/esm2020/lib/structure/tree-branch-node.interface.mjs +2 -0
- package/esm2020/lib/structure/tree-event.interface.mjs +2 -0
- package/esm2020/lib/structure/tree-node.interface.mjs +2 -0
- package/esm2020/lib/structure/tree-plot.mjs +2 -0
- package/esm2020/lib/structure/tree-relationship.interface.mjs +2 -0
- package/esm2020/limble-limble-tree.mjs +4 -4
- package/esm2020/public-api.mjs +12 -6
- package/esm2020/shared/assert.mjs +7 -0
- package/fesm2015/limble-limble-tree.mjs +1404 -2226
- package/fesm2015/limble-limble-tree.mjs.map +1 -1
- package/fesm2020/limble-limble-tree.mjs +1396 -2132
- package/fesm2020/limble-limble-tree.mjs.map +1 -1
- package/index.d.ts +5 -5
- package/lib/components/branch/branch.component.d.ts +26 -0
- package/lib/components/dropzone/dropzone.component.d.ts +13 -0
- package/lib/components/host-component.interface.d.ts +6 -0
- package/lib/components/node-component.interface.d.ts +5 -0
- package/lib/components/root/root.component.d.ts +14 -0
- package/lib/core/branch-options.interface.d.ts +14 -0
- package/lib/core/configuration/configuration.d.ts +11 -0
- package/lib/core/configuration/tree-options.interface.d.ts +32 -0
- package/lib/core/index.d.ts +5 -0
- package/lib/core/relationship.interface.d.ts +5 -0
- package/lib/core/tree-branch/branch-controller.d.ts +25 -0
- package/lib/core/tree-branch/tree-branch.d.ts +44 -0
- package/lib/core/tree-node-base.d.ts +25 -0
- package/lib/core/tree-root/root-controller.d.ts +19 -0
- package/lib/core/tree-root/tree-root.d.ts +30 -0
- package/lib/core/tree-service/tree.service.d.ts +9 -0
- package/lib/errors/index.d.ts +1 -0
- package/lib/errors/tree-error.d.ts +2 -0
- package/lib/events/drag/drag-end-event.d.ts +24 -0
- package/lib/events/drag/drag-start-event.d.ts +8 -0
- package/lib/events/drag/drop-event.d.ts +13 -0
- package/lib/events/drag/index.d.ts +3 -0
- 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 +3 -0
- package/lib/events/relational/graft-event.d.ts +15 -0
- package/lib/events/relational/index.d.ts +3 -0
- package/lib/events/relational/prune-event.d.ts +15 -0
- package/lib/events/relational/relational-tree-event.interface.d.ts +6 -0
- package/lib/extras/collapse/collapse.d.ts +11 -0
- package/lib/extras/collapse/collapse.module.d.ts +6 -0
- package/lib/extras/collapse/collapse.service.d.ts +9 -0
- package/lib/extras/collapse/index.d.ts +2 -0
- package/lib/extras/drag-and-drop/drag-and-drop.d.ts +16 -0
- package/lib/extras/drag-and-drop/drag-and-drop.module.d.ts +8 -0
- package/lib/extras/drag-and-drop/drag-and-drop.service.d.ts +16 -0
- package/lib/extras/drag-and-drop/drag-state.d.ts +23 -0
- package/lib/extras/drag-and-drop/draggable.directive.d.ts +12 -0
- package/lib/{custom-event-bindings/dragover-no-change-detect.directive.d.ts → extras/drag-and-drop/dragover-no-change-detect.d.ts} +14 -14
- package/lib/extras/drag-and-drop/dropzone-renderer.d.ts +28 -0
- package/lib/extras/drag-and-drop/index.d.ts +4 -0
- package/lib/legacy/index.d.ts +6 -0
- package/lib/legacy/legacy-component-obj.interface.d.ts +13 -0
- package/lib/legacy/legacy-tree-data.interface.d.ts +18 -0
- package/lib/legacy/legacy-tree-options.interface.d.ts +34 -0
- package/lib/legacy/legacy-tree.d.ts +14 -0
- package/lib/legacy/limble-tree-legacy.module.d.ts +8 -0
- package/lib/legacy/limble-tree-root/limble-tree-root.component.d.ts +28 -0
- package/lib/limble-tree.module.d.ts +9 -14
- package/lib/structure/branchable.interface.d.ts +4 -0
- package/lib/structure/component-container.interface.d.ts +8 -0
- package/lib/structure/event-conduit.interface.d.ts +6 -0
- package/lib/structure/graftable.interface.d.ts +6 -0
- package/lib/structure/index.d.ts +9 -0
- package/lib/structure/tree-branch-node.interface.d.ts +5 -0
- package/lib/structure/tree-event.interface.d.ts +5 -0
- package/lib/structure/tree-node.interface.d.ts +11 -0
- package/lib/structure/tree-plot.d.ts +1 -0
- package/lib/structure/tree-relationship.interface.d.ts +7 -0
- package/package.json +6 -14
- package/public-api.d.ts +8 -3
- package/shared/assert.d.ts +1 -0
- package/esm2020/lib/classes/Branch.mjs +0 -153
- package/esm2020/lib/classes/DropZone.mjs +0 -71
- package/esm2020/lib/classes/DropZoneLocation.mjs +0 -16
- package/esm2020/lib/custom-event-bindings/dragleave-no-change-detect.directive.mjs +0 -33
- package/esm2020/lib/custom-event-bindings/dragover-no-change-detect.directive.mjs +0 -39
- package/esm2020/lib/drop-zone/drop-zone.component.mjs +0 -75
- package/esm2020/lib/limble-tree-branch/limble-tree-branch.component.mjs +0 -110
- package/esm2020/lib/limble-tree-node/limble-tree-node.component.mjs +0 -467
- package/esm2020/lib/limble-tree-placeholder/limble-tree-placeholder.component.mjs +0 -70
- package/esm2020/lib/limble-tree-root/drop-zone.service.mjs +0 -376
- package/esm2020/lib/limble-tree-root/limble-tree-root.component.mjs +0 -172
- package/esm2020/lib/limble-tree-root/tree-construction-status.service.mjs +0 -33
- package/esm2020/lib/limble-tree-root/tree.service.mjs +0 -297
- package/esm2020/lib/singletons/component-creator.service.mjs +0 -19
- package/esm2020/lib/singletons/drag-state.service.mjs +0 -63
- package/esm2020/lib/singletons/global-events.service.mjs +0 -136
- package/esm2020/lib/util.mjs +0 -74
- package/lib/classes/Branch.d.ts +0 -26
- package/lib/classes/DropZone.d.ts +0 -27
- package/lib/classes/DropZoneLocation.d.ts +0 -9
- package/lib/custom-event-bindings/dragleave-no-change-detect.directive.d.ts +0 -13
- package/lib/drop-zone/drop-zone.component.d.ts +0 -18
- package/lib/limble-tree-branch/limble-tree-branch.component.d.ts +0 -28
- package/lib/limble-tree-node/limble-tree-node.component.d.ts +0 -53
- package/lib/limble-tree-placeholder/limble-tree-placeholder.component.d.ts +0 -21
- package/lib/limble-tree-root/drop-zone.service.d.ts +0 -62
- package/lib/limble-tree-root/limble-tree-root.component.d.ts +0 -37
- package/lib/limble-tree-root/tree-construction-status.service.d.ts +0 -15
- package/lib/limble-tree-root/tree.service.d.ts +0 -132
- package/lib/singletons/component-creator.service.d.ts +0 -9
- package/lib/singletons/drag-state.service.d.ts +0 -35
- package/lib/singletons/global-events.service.d.ts +0 -13
- package/lib/util.d.ts +0 -13
|
@@ -1,2162 +1,1426 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable,
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import * as i2 from '@angular/common';
|
|
2
|
+
import { Injectable, NgModule, EventEmitter, Directive, Input, Output, Component, NgZone, ViewContainerRef, ViewChild, ViewChildren, createComponent, EnvironmentInjector, HostListener } from '@angular/core';
|
|
3
|
+
import { BehaviorSubject, Subject, fromEvent, merge, map, filter, first } from 'rxjs';
|
|
4
|
+
import * as i1 from '@angular/common';
|
|
6
5
|
import { CommonModule } from '@angular/common';
|
|
6
|
+
import { throttleTime } from 'rxjs/operators';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
cursor = cursor.parentNode;
|
|
39
|
-
}
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
function isNestingAllowed(options, nodeData) {
|
|
43
|
-
return (options !== undefined &&
|
|
44
|
-
(options.allowNesting === true ||
|
|
45
|
-
(typeof options.allowNesting === "function" &&
|
|
46
|
-
nodeData !== undefined &&
|
|
47
|
-
options.allowNesting(nodeData) === true)));
|
|
48
|
-
}
|
|
49
|
-
function isDraggingAllowed(options, nodeData) {
|
|
50
|
-
return (options !== undefined &&
|
|
51
|
-
(options.allowDragging === true ||
|
|
52
|
-
(typeof options.allowDragging === "function" &&
|
|
53
|
-
nodeData !== undefined &&
|
|
54
|
-
options.allowDragging(nodeData) === true)));
|
|
55
|
-
}
|
|
56
|
-
function isFirefox() {
|
|
57
|
-
return navigator.userAgent.includes("Firefox");
|
|
58
|
-
}
|
|
59
|
-
/** Because drop zones can disappear when the mouse moves, sometimes
|
|
60
|
-
* moving the mouse just a little bit inside the tree causes the tree to
|
|
61
|
-
* shrink such that the mouse is no longer over the tree. In this case,
|
|
62
|
-
* a dragleave event may not fire, and we can't clear the drop zones. This
|
|
63
|
-
* function is used to catch this edge case.
|
|
64
|
-
*/
|
|
65
|
-
function suddenTreeExit(event) {
|
|
66
|
-
if (event.target === null || !(event.target instanceof Element)) {
|
|
67
|
-
throw new Error("failed to get event target element");
|
|
68
|
-
}
|
|
69
|
-
const treeEventHost = event.target.closest(".tree-event-host");
|
|
70
|
-
if (treeEventHost === null) {
|
|
71
|
-
console.log(event.target);
|
|
72
|
-
throw new Error("failed to find treeEventHost");
|
|
73
|
-
}
|
|
74
|
-
const rect = treeEventHost.getBoundingClientRect();
|
|
75
|
-
const clientY = event.clientY;
|
|
76
|
-
if (clientY > rect.bottom || clientY < rect.top) {
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
return false;
|
|
8
|
+
class TreeCollapser {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.tempStorage = new Map();
|
|
11
|
+
}
|
|
12
|
+
collapse(treeBranch) {
|
|
13
|
+
if (treeBranch.branches().length === 0)
|
|
14
|
+
return;
|
|
15
|
+
const branches = [];
|
|
16
|
+
this.tempStorage.set(treeBranch, branches);
|
|
17
|
+
treeBranch.branches().forEach((branch) => {
|
|
18
|
+
branch.prune();
|
|
19
|
+
branches.push(branch);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
expand(treeBranch) {
|
|
23
|
+
const branches = this.tempStorage.get(treeBranch);
|
|
24
|
+
if (branches === undefined)
|
|
25
|
+
return;
|
|
26
|
+
branches.forEach((branch) => {
|
|
27
|
+
branch.graftTo(treeBranch);
|
|
28
|
+
});
|
|
29
|
+
this.tempStorage.delete(treeBranch);
|
|
30
|
+
treeBranch.detectChanges();
|
|
31
|
+
}
|
|
32
|
+
isCollapsed(treeBranch) {
|
|
33
|
+
return this.tempStorage.has(treeBranch);
|
|
34
|
+
}
|
|
35
|
+
storePrecollapsedNode(parent, branch) {
|
|
36
|
+
this.tempStorage.set(parent, (this.tempStorage.get(parent) ?? []).concat(branch));
|
|
37
|
+
}
|
|
80
38
|
}
|
|
39
|
+
const treeCollapser = new TreeCollapser();
|
|
81
40
|
|
|
82
|
-
class
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
setInsertIndex(index) {
|
|
94
|
-
this.insertIndex = index;
|
|
95
|
-
}
|
|
41
|
+
class TreeCollapseService {
|
|
42
|
+
collapse(treeBranch) {
|
|
43
|
+
treeCollapser.collapse(treeBranch);
|
|
44
|
+
}
|
|
45
|
+
expand(treeBranch) {
|
|
46
|
+
treeCollapser.expand(treeBranch);
|
|
47
|
+
}
|
|
48
|
+
isCollapsed(treeBranch) {
|
|
49
|
+
return treeCollapser.isCollapsed(treeBranch);
|
|
50
|
+
}
|
|
96
51
|
}
|
|
52
|
+
TreeCollapseService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeCollapseService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
53
|
+
TreeCollapseService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeCollapseService });
|
|
54
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeCollapseService, decorators: [{
|
|
55
|
+
type: Injectable
|
|
56
|
+
}] });
|
|
97
57
|
|
|
98
|
-
class
|
|
99
|
-
constructor(parentCoordinates, insertIndex) {
|
|
100
|
-
this.location = new DropZoneLocation(parentCoordinates, insertIndex);
|
|
101
|
-
this.rendered = false;
|
|
102
|
-
this.visible = false;
|
|
103
|
-
this.active = false;
|
|
104
|
-
this.commChannel = new Subject();
|
|
105
|
-
}
|
|
106
|
-
static dropZoneLocationsAreEqual(valueA, valueB) {
|
|
107
|
-
return arraysAreEqual(valueA.getFullInsertCoordinates(), valueB.getFullInsertCoordinates());
|
|
108
|
-
}
|
|
109
|
-
isRendered(set = undefined) {
|
|
110
|
-
if (set !== undefined) {
|
|
111
|
-
this.rendered = set;
|
|
112
|
-
if (this.commChannel !== undefined) {
|
|
113
|
-
this.commChannel.next("checkRendered");
|
|
114
|
-
}
|
|
115
|
-
if (this.rendered === false) {
|
|
116
|
-
this.isVisible(false);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return this.rendered;
|
|
120
|
-
}
|
|
121
|
-
isVisible(set = undefined) {
|
|
122
|
-
if (set !== undefined) {
|
|
123
|
-
this.visible = set;
|
|
124
|
-
if (this.commChannel !== undefined) {
|
|
125
|
-
this.commChannel.next("checkVisible");
|
|
126
|
-
}
|
|
127
|
-
if (this.visible === false) {
|
|
128
|
-
this.isActive(false);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return this.visible;
|
|
132
|
-
}
|
|
133
|
-
isActive(set = undefined) {
|
|
134
|
-
if (set !== undefined) {
|
|
135
|
-
this.active = set;
|
|
136
|
-
if (this.commChannel !== undefined) {
|
|
137
|
-
this.commChannel.next("checkActive");
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
return this.active;
|
|
141
|
-
}
|
|
142
|
-
getLocation() {
|
|
143
|
-
return this.location;
|
|
144
|
-
}
|
|
145
|
-
getFamily() {
|
|
146
|
-
return this.family;
|
|
147
|
-
}
|
|
148
|
-
setFamily(family) {
|
|
149
|
-
this.family = family;
|
|
150
|
-
}
|
|
151
|
-
getCommChannel() {
|
|
152
|
-
return this.commChannel;
|
|
153
|
-
}
|
|
154
|
-
getFullInsertCoordinates() {
|
|
155
|
-
return this.location.getFullInsertCoordinates();
|
|
156
|
-
}
|
|
157
|
-
setHost(host) {
|
|
158
|
-
this.host = host;
|
|
159
|
-
return this.host;
|
|
160
|
-
}
|
|
161
|
-
getHost() {
|
|
162
|
-
return this.host;
|
|
163
|
-
}
|
|
58
|
+
class TreeCollapseModule {
|
|
164
59
|
}
|
|
60
|
+
TreeCollapseModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeCollapseModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
61
|
+
TreeCollapseModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.12", ngImport: i0, type: TreeCollapseModule });
|
|
62
|
+
TreeCollapseModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeCollapseModule, providers: [TreeCollapseService] });
|
|
63
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeCollapseModule, decorators: [{
|
|
64
|
+
type: NgModule,
|
|
65
|
+
args: [{
|
|
66
|
+
providers: [TreeCollapseService]
|
|
67
|
+
}]
|
|
68
|
+
}] });
|
|
165
69
|
|
|
166
|
-
class
|
|
167
|
-
constructor() {
|
|
168
|
-
this.
|
|
169
|
-
this.
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
this.
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if (this.state !== "dragging") {
|
|
183
|
-
throw new Error("Can only call `droppable` when state is `dragging`");
|
|
184
|
-
}
|
|
185
|
-
this.state = "droppable";
|
|
186
|
-
this.state$.next(this.state);
|
|
187
|
-
}
|
|
188
|
-
/** Called to indicate that there is no longer a valid active drop zone. Drop is no longer possible. */
|
|
189
|
-
notDroppable() {
|
|
190
|
-
if (this.state !== "droppable") {
|
|
191
|
-
throw new Error("Can only call `notDroppable` when state is `droppable`");
|
|
192
|
-
}
|
|
193
|
-
this.state = "dragging";
|
|
194
|
-
this.state$.next(this.state);
|
|
195
|
-
}
|
|
196
|
-
/** Called to indicate that a drop into a valid drop zone has occurred. Returns the item that was dropped. */
|
|
197
|
-
capture() {
|
|
198
|
-
if (this.state !== "droppable") {
|
|
199
|
-
throw new Error("Can only move to `captured` state from `droppable` state");
|
|
200
|
-
}
|
|
201
|
-
this.state = "captured";
|
|
202
|
-
this.state$.next(this.state);
|
|
203
|
-
return this._tempData?.branch;
|
|
204
|
-
}
|
|
205
|
-
/** Called to reset the service for future drags */
|
|
206
|
-
release() {
|
|
207
|
-
this._tempData = undefined;
|
|
208
|
-
this.state = "idle";
|
|
209
|
-
this.state$.next(this.state);
|
|
210
|
-
}
|
|
211
|
-
/** gets the current thing being dragged, if any. */
|
|
212
|
-
getData() {
|
|
213
|
-
return this._tempData;
|
|
214
|
-
}
|
|
215
|
-
/** gets the current state */
|
|
216
|
-
getState() {
|
|
217
|
-
return this.state;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
DragStateService.ɵfac = function DragStateService_Factory(t) { return new (t || DragStateService)(); };
|
|
221
|
-
DragStateService.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: DragStateService, factory: DragStateService.ɵfac });
|
|
222
|
-
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DragStateService, [{
|
|
223
|
-
type: Injectable
|
|
224
|
-
}], function () { return []; }, null); })();
|
|
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();
|
|
225
86
|
|
|
226
|
-
class
|
|
227
|
-
|
|
228
|
-
this.beingBuilt = 0;
|
|
229
|
-
this.isReady = false;
|
|
230
|
-
this.stable$ = new BehaviorSubject(this.treeIsStable());
|
|
231
|
-
}
|
|
232
|
-
constructing() {
|
|
233
|
-
this.beingBuilt++;
|
|
234
|
-
this.emit();
|
|
235
|
-
}
|
|
236
|
-
doneConstructing() {
|
|
237
|
-
this.beingBuilt--;
|
|
238
|
-
this.emit();
|
|
239
|
-
}
|
|
240
|
-
treeIsStable() {
|
|
241
|
-
return this.isReady === true && this.beingBuilt === 0;
|
|
242
|
-
}
|
|
243
|
-
ready(val) {
|
|
244
|
-
this.isReady = val;
|
|
245
|
-
}
|
|
246
|
-
emit() {
|
|
247
|
-
this.stable$.next(this.treeIsStable());
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
TreeConstructionStatus.ɵfac = function TreeConstructionStatus_Factory(t) { return new (t || TreeConstructionStatus)(); };
|
|
251
|
-
TreeConstructionStatus.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: TreeConstructionStatus, factory: TreeConstructionStatus.ɵfac });
|
|
252
|
-
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TreeConstructionStatus, [{
|
|
253
|
-
type: Injectable
|
|
254
|
-
}], function () { return []; }, null); })();
|
|
87
|
+
class TreeError extends Error {
|
|
88
|
+
}
|
|
255
89
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
this.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
this.
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
.pipe(debounce(() => {
|
|
284
|
-
if (treeIsStable === true) {
|
|
285
|
-
//If tree is stable, continue right away
|
|
286
|
-
return Promise.resolve();
|
|
287
|
-
}
|
|
288
|
-
//If tree is not stable, wait for it to become so.
|
|
289
|
-
return treeIsStable$;
|
|
290
|
-
}))
|
|
291
|
-
.subscribe(() => {
|
|
292
|
-
setTimeout(() => {
|
|
293
|
-
this.updateDropZones();
|
|
294
|
-
});
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
addDropZone(newDropZone) {
|
|
298
|
-
this.dropZoneArchive.add(newDropZone);
|
|
299
|
-
}
|
|
300
|
-
/** hides all drop zones */
|
|
301
|
-
clearVisibleZones() {
|
|
302
|
-
if (this.visibleFamily !== null) {
|
|
303
|
-
for (const member of this.visibleFamily.members) {
|
|
304
|
-
member.isVisible(false);
|
|
305
|
-
}
|
|
306
|
-
this.visibleFamily = null;
|
|
307
|
-
}
|
|
308
|
-
this.setActiveDropZone(null);
|
|
309
|
-
}
|
|
310
|
-
getActiveDropZone() {
|
|
311
|
-
return this.activeDropZone;
|
|
312
|
-
}
|
|
313
|
-
getDropZone(coordinates) {
|
|
314
|
-
const parent = [...coordinates];
|
|
315
|
-
parent.pop();
|
|
316
|
-
const index = coordinates[coordinates.length - 1];
|
|
317
|
-
const location = new DropZoneLocation(parent, index);
|
|
318
|
-
return this.dropZoneInventory.find((dropZone) => DropZone.dropZoneLocationsAreEqual(dropZone, location));
|
|
319
|
-
}
|
|
320
|
-
init(tree, treeOptions) {
|
|
321
|
-
this.tree = tree;
|
|
322
|
-
this.treeOptions = treeOptions;
|
|
323
|
-
this.update();
|
|
324
|
-
}
|
|
325
|
-
removeDropZone(dropZone) {
|
|
326
|
-
this.dropZoneArchive.delete(dropZone);
|
|
327
|
-
}
|
|
328
|
-
/** hides all drop zones, deletes all the family assignments,
|
|
329
|
-
* and empties the dropZoneInventory
|
|
330
|
-
*/
|
|
331
|
-
reset() {
|
|
332
|
-
this.clearVisibleZones();
|
|
333
|
-
this.dropZoneFamilies.length = 0;
|
|
334
|
-
this.dropZoneInventory.length = 0;
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* Restores the service to its initial state: hides all drop zones,
|
|
338
|
-
* deletes all the family assignments, and empties the dropZoneInventory
|
|
339
|
-
* and dropZoneArchive.
|
|
340
|
-
*/
|
|
341
|
-
restart() {
|
|
342
|
-
this.reset();
|
|
343
|
-
this.dropZoneArchive.clear();
|
|
344
|
-
}
|
|
345
|
-
restoreFamilies() {
|
|
346
|
-
if (this.tempFamilies.length === 2) {
|
|
347
|
-
this.dropZoneFamilies.pop();
|
|
348
|
-
this.dropZoneFamilies.push(this.tempFamilies[0]);
|
|
349
|
-
for (const member of this.tempFamilies[0].members) {
|
|
350
|
-
member.setFamily(this.tempFamilies[0]);
|
|
351
|
-
}
|
|
352
|
-
if (this.tempFamilies[1] !== null) {
|
|
353
|
-
this.dropZoneFamilies.push(this.tempFamilies[1]);
|
|
354
|
-
for (const member of this.tempFamilies[1].members) {
|
|
355
|
-
member.setFamily(this.tempFamilies[1]);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
this.tempFamilies = [];
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Shows the drop zone family of the drop zone indicated by `coordinates`.
|
|
363
|
-
*/
|
|
364
|
-
showDropZoneFamily(
|
|
365
|
-
/** Note: this drop zone may not exist in the dropZoneInventory; we have to search the inventory based on its location */
|
|
366
|
-
dropZone, options = { joinFamilies: false, activateLowestInsteadOfFounder: false }) {
|
|
367
|
-
if (this.activeDropZone !== null &&
|
|
368
|
-
DropZone.dropZoneLocationsAreEqual(this.activeDropZone, dropZone)) {
|
|
369
|
-
//Already showing the family with the appropriate active drop zone
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
if (this.visibleFamily !== null || this.activeDropZone !== null) {
|
|
373
|
-
this.clearVisibleZones();
|
|
374
|
-
}
|
|
375
|
-
const target = this.dropZoneInventory.find((zone) => DropZone.dropZoneLocationsAreEqual(zone, dropZone));
|
|
376
|
-
if (target === undefined) {
|
|
377
|
-
throw new Error(`Could not find drop zone to show. location: ${JSON.stringify(dropZone.getLocation())}`);
|
|
378
|
-
}
|
|
379
|
-
const family = target.getFamily();
|
|
380
|
-
if (options.joinFamilies === true) {
|
|
381
|
-
const location1 = dropZone.getLocation();
|
|
382
|
-
const location2 = new DropZoneLocation([...location1.parentCoordinates], location1.insertIndex + 1);
|
|
383
|
-
const target2 = this.dropZoneInventory.find((zone) => DropZone.dropZoneLocationsAreEqual(zone, location2));
|
|
384
|
-
if (target2 === undefined) {
|
|
385
|
-
throw new Error("Could not find drop zone to show");
|
|
386
|
-
}
|
|
387
|
-
const family2 = target2.getFamily();
|
|
388
|
-
if (family === undefined || family2 === undefined) {
|
|
389
|
-
throw new Error("No family");
|
|
390
|
-
}
|
|
391
|
-
const newFamily = {
|
|
392
|
-
founder: family.founder,
|
|
393
|
-
members: [...family.members]
|
|
394
|
-
};
|
|
395
|
-
this.showDropZone(family.founder, true);
|
|
396
|
-
for (const member of family.members.sort(sortFamily)) {
|
|
397
|
-
member.setFamily(newFamily);
|
|
398
|
-
if (member !== family.founder) {
|
|
399
|
-
if (this.activeDropZone === null) {
|
|
400
|
-
//Failed to activate a zone so far, so activate this one instead
|
|
401
|
-
this.showDropZone(member, true);
|
|
402
|
-
}
|
|
403
|
-
else {
|
|
404
|
-
this.showDropZone(member);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
for (const member of family2.members) {
|
|
409
|
-
member.setFamily(newFamily);
|
|
410
|
-
if (member.getLocation().parentCoordinates.length <
|
|
411
|
-
target2.getLocation().parentCoordinates.length) {
|
|
412
|
-
newFamily.members.push(member);
|
|
413
|
-
this.showDropZone(member);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
//Temporarily store the old families
|
|
417
|
-
this.tempFamilies = [family, family2];
|
|
418
|
-
//Remove the old families
|
|
419
|
-
const familyIndex = this.dropZoneFamilies.indexOf(family);
|
|
420
|
-
this.dropZoneFamilies.splice(familyIndex, 1);
|
|
421
|
-
const family2Index = this.dropZoneFamilies.indexOf(family2);
|
|
422
|
-
this.dropZoneFamilies.splice(family2Index, 1);
|
|
423
|
-
//Add the new family
|
|
424
|
-
this.dropZoneFamilies.push(newFamily);
|
|
425
|
-
this.visibleFamily = newFamily;
|
|
426
|
-
}
|
|
427
|
-
else {
|
|
428
|
-
if (family === undefined) {
|
|
429
|
-
throw new Error("No family");
|
|
430
|
-
}
|
|
431
|
-
this.visibleFamily = family;
|
|
432
|
-
this.showDropZone(family.founder, true);
|
|
433
|
-
if (family.members.length > 1) {
|
|
434
|
-
for (const member of family.members.sort(sortFamily)) {
|
|
435
|
-
if (member !== family.founder) {
|
|
436
|
-
if (this.activeDropZone === null) {
|
|
437
|
-
//Failed to activate a zone so far, so activate this one instead
|
|
438
|
-
this.showDropZone(member, true);
|
|
439
|
-
}
|
|
440
|
-
else {
|
|
441
|
-
this.showDropZone(member);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
if (options.activateLowestInsteadOfFounder === true &&
|
|
448
|
-
this.visibleFamily.members.length > 1) {
|
|
449
|
-
const lowestMember = [...this.visibleFamily.members]
|
|
450
|
-
.sort(sortFamily)
|
|
451
|
-
.pop();
|
|
452
|
-
if (lowestMember === undefined) {
|
|
453
|
-
throw new Error("Could not get lowest member");
|
|
454
|
-
}
|
|
455
|
-
this.swapActiveDropZone(lowestMember);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
swapActiveDropZone(newActiveDropZone) {
|
|
459
|
-
if (this.visibleFamily === null) {
|
|
460
|
-
throw new Error("No visible family available for swapping");
|
|
461
|
-
}
|
|
462
|
-
const index = this.visibleFamily.members.findIndex((dropZone) => dropZone === newActiveDropZone);
|
|
463
|
-
if (index === -1) {
|
|
464
|
-
throw new Error("failed to swap active drop zone");
|
|
465
|
-
}
|
|
466
|
-
this.setActiveDropZone(newActiveDropZone);
|
|
467
|
-
}
|
|
468
|
-
update() {
|
|
469
|
-
this.update$.next(null);
|
|
470
|
-
}
|
|
471
|
-
assignFamilies() {
|
|
472
|
-
const orphanZones = [...this.dropZoneInventory];
|
|
473
|
-
const deepestMembers = orphanZones
|
|
474
|
-
.filter((zone) => {
|
|
475
|
-
const location = zone.getLocation();
|
|
476
|
-
return (location.insertIndex === 0 &&
|
|
477
|
-
location.parentCoordinates.length > 0);
|
|
478
|
-
})
|
|
479
|
-
.sort((valueA, valueB) => {
|
|
480
|
-
const aCoordinates = valueA.getFullInsertCoordinates();
|
|
481
|
-
const bCoordinates = valueB.getFullInsertCoordinates();
|
|
482
|
-
const length = Math.max(aCoordinates.length, bCoordinates.length);
|
|
483
|
-
for (let index = 0; index < length; index++) {
|
|
484
|
-
if ((aCoordinates[index] ?? -1) > (bCoordinates[index] ?? -1)) {
|
|
485
|
-
return -1;
|
|
486
|
-
}
|
|
487
|
-
else if ((aCoordinates[index] ?? -1) < (bCoordinates[index] ?? -1)) {
|
|
488
|
-
return 1;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
return 0;
|
|
492
|
-
});
|
|
493
|
-
for (const dropZone of deepestMembers) {
|
|
494
|
-
if (!orphanZones.includes(dropZone)) {
|
|
495
|
-
continue;
|
|
496
|
-
}
|
|
497
|
-
const family = {
|
|
498
|
-
founder: dropZone,
|
|
499
|
-
members: []
|
|
500
|
-
};
|
|
501
|
-
dropZone.setFamily(family);
|
|
502
|
-
//See if there are any orphans that belong to this family and claim them.
|
|
503
|
-
const cursor = [...dropZone.getFullInsertCoordinates()];
|
|
504
|
-
while (cursor.length > 0) {
|
|
505
|
-
const familyMemberIndex = orphanZones.findIndex((zone) => arraysAreEqual(zone.getFullInsertCoordinates(), cursor));
|
|
506
|
-
if (familyMemberIndex !== -1) {
|
|
507
|
-
const familyMember = orphanZones.splice(familyMemberIndex, 1)[0];
|
|
508
|
-
family.members.push(familyMember);
|
|
509
|
-
familyMember.setFamily(family);
|
|
510
|
-
}
|
|
511
|
-
cursor.pop();
|
|
512
|
-
cursor[cursor.length - 1]++;
|
|
513
|
-
}
|
|
514
|
-
this.dropZoneFamilies.push(family);
|
|
515
|
-
}
|
|
516
|
-
for (const dropZone of orphanZones.filter((zone) => zone.getFullInsertCoordinates().length === 1)) {
|
|
517
|
-
const family = {
|
|
518
|
-
founder: dropZone,
|
|
519
|
-
members: [dropZone]
|
|
520
|
-
};
|
|
521
|
-
dropZone.setFamily(family);
|
|
522
|
-
this.dropZoneFamilies.push(family);
|
|
523
|
-
orphanZones.splice(orphanZones.indexOf(dropZone), 1);
|
|
524
|
-
}
|
|
525
|
-
if (orphanZones.length !== 0) {
|
|
526
|
-
let orphans = "";
|
|
527
|
-
for (const zone of orphanZones) {
|
|
528
|
-
orphans += `${JSON.stringify(zone.getLocation())}, `;
|
|
529
|
-
}
|
|
530
|
-
orphans = orphans.slice(0, orphans.length - 2);
|
|
531
|
-
throw new Error(`Some zones were not assigned to a family. The orphan zones have the following locations: ${orphans}`);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
buildInventory() {
|
|
535
|
-
//We do this funky string array because it is faster than doing direct array comparisons
|
|
536
|
-
const inventoryCoordinates = [];
|
|
537
|
-
for (const dropZone of this.dropZoneArchive) {
|
|
538
|
-
const coordinates = dropZone.getFullInsertCoordinates().join(",");
|
|
539
|
-
if (inventoryCoordinates.includes(coordinates)) {
|
|
540
|
-
dropZone.isRendered(false);
|
|
541
|
-
}
|
|
542
|
-
else {
|
|
543
|
-
this.dropZoneInventory.push(dropZone);
|
|
544
|
-
inventoryCoordinates.push(coordinates);
|
|
545
|
-
dropZone.isRendered(true);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
setActiveDropZone(dropZone) {
|
|
550
|
-
if (this.activeDropZone !== null) {
|
|
551
|
-
this.activeDropZone.isActive(false);
|
|
552
|
-
}
|
|
553
|
-
this.activeDropZone = dropZone;
|
|
554
|
-
if (this.activeDropZone !== null &&
|
|
555
|
-
this.dragStateService.getState() !== "droppable") {
|
|
556
|
-
this.dragStateService.droppable();
|
|
557
|
-
}
|
|
558
|
-
else if (this.activeDropZone === null &&
|
|
559
|
-
this.dragStateService.getState() === "droppable") {
|
|
560
|
-
this.dragStateService.notDroppable();
|
|
561
|
-
}
|
|
562
|
-
if (this.activeDropZone !== null) {
|
|
563
|
-
this.activeDropZone.isActive(true);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
showDropZone(dropZone, active = false) {
|
|
567
|
-
if (this.tree === undefined) {
|
|
568
|
-
throw new Error("DropZoneService not initialized");
|
|
569
|
-
}
|
|
570
|
-
if (!this.zoneIsAllowed(dropZone)) {
|
|
571
|
-
//User settings indicate to skip this drop zone
|
|
572
|
-
return false;
|
|
573
|
-
}
|
|
574
|
-
const parent = this.tree.findByCoordinates(dropZone.getLocation().parentCoordinates);
|
|
575
|
-
if (parent === undefined) {
|
|
576
|
-
throw new Error("Bad family member");
|
|
577
|
-
}
|
|
578
|
-
dropZone.isVisible(true);
|
|
579
|
-
if (active === true) {
|
|
580
|
-
this.setActiveDropZone(dropZone);
|
|
581
|
-
}
|
|
582
|
-
return true;
|
|
583
|
-
}
|
|
584
|
-
updateDropZones() {
|
|
585
|
-
this.reset();
|
|
586
|
-
this.buildInventory();
|
|
587
|
-
this.assignFamilies();
|
|
588
|
-
}
|
|
589
|
-
zoneIsAllowed(dropZone) {
|
|
590
|
-
if (this.treeOptions === undefined || this.tree === undefined) {
|
|
591
|
-
throw new Error("dropZoneService not initialized");
|
|
592
|
-
}
|
|
593
|
-
const data = this.dragStateService.getData();
|
|
594
|
-
if (data === undefined) {
|
|
595
|
-
throw new Error("Can't get dragged node");
|
|
596
|
-
}
|
|
597
|
-
const parentCoordinates = dropZone.getLocation().parentCoordinates;
|
|
598
|
-
const dropZoneParent = this.tree.findByCoordinates(parentCoordinates);
|
|
599
|
-
if (dropZoneParent === undefined) {
|
|
600
|
-
throw new Error("Could not get drop zone parent");
|
|
601
|
-
}
|
|
602
|
-
if (parentCoordinates.length > 0 &&
|
|
603
|
-
!isNestingAllowed(this.treeOptions, dropZoneParent.data)) {
|
|
604
|
-
return false;
|
|
605
|
-
}
|
|
606
|
-
const dropZoneIndex = dropZone.getLocation().insertIndex;
|
|
607
|
-
if (dropZoneIndex === undefined) {
|
|
608
|
-
throw new Error("Could not get drop zone index");
|
|
609
|
-
}
|
|
610
|
-
const draggedNode = data.branch;
|
|
611
|
-
if (!this.treeOptions.allowDrop(draggedNode.data, dropZoneParent.data, dropZoneIndex)) {
|
|
612
|
-
return false;
|
|
613
|
-
}
|
|
614
|
-
return true;
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
DropZoneService.ɵfac = function DropZoneService_Factory(t) { return new (t || DropZoneService)(i0.ɵɵinject(DragStateService), i0.ɵɵinject(TreeConstructionStatus)); };
|
|
618
|
-
DropZoneService.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: DropZoneService, factory: DropZoneService.ɵfac });
|
|
619
|
-
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DropZoneService, [{
|
|
620
|
-
type: Injectable
|
|
621
|
-
}], function () { return [{ type: DragStateService }, { type: TreeConstructionStatus }]; }, null); })();
|
|
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
|
+
}
|
|
622
117
|
|
|
623
|
-
class
|
|
624
|
-
constructor(
|
|
625
|
-
this.
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
return this.parent;
|
|
634
|
-
}
|
|
635
|
-
setParent(parent) {
|
|
636
|
-
this.parent = parent;
|
|
637
|
-
}
|
|
638
|
-
findByCoordinates(relativeCoordinates) {
|
|
639
|
-
let cursor = this;
|
|
640
|
-
for (const index of relativeCoordinates.values()) {
|
|
641
|
-
cursor = cursor.getChild(index);
|
|
642
|
-
if (cursor === undefined) {
|
|
643
|
-
return undefined;
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
return cursor;
|
|
647
|
-
}
|
|
648
|
-
getCoordinates() {
|
|
649
|
-
const coordinates = [];
|
|
650
|
-
let cursor = this;
|
|
651
|
-
while (cursor.parent !== null) {
|
|
652
|
-
const cursorIndex = cursor.getIndex();
|
|
653
|
-
if (cursorIndex === undefined || cursorIndex === null) {
|
|
654
|
-
throw new Error("Could not get cursor index");
|
|
655
|
-
}
|
|
656
|
-
coordinates.unshift(cursorIndex);
|
|
657
|
-
cursor = cursor.parent;
|
|
658
|
-
}
|
|
659
|
-
return coordinates;
|
|
660
|
-
}
|
|
661
|
-
getChild(index) {
|
|
662
|
-
return this.children[index];
|
|
663
|
-
}
|
|
664
|
-
getChildren() {
|
|
665
|
-
return this.children;
|
|
666
|
-
}
|
|
667
|
-
clearChildren() {
|
|
668
|
-
for (const child of this.children) {
|
|
669
|
-
child.setParent(null);
|
|
670
|
-
}
|
|
671
|
-
this.children.length = 0;
|
|
672
|
-
}
|
|
673
|
-
getIndex() {
|
|
674
|
-
if (this.parent === null) {
|
|
675
|
-
return null;
|
|
676
|
-
}
|
|
677
|
-
const index = this.parent.children.findIndex((branch) => branch === this);
|
|
678
|
-
if (index === -1) {
|
|
679
|
-
return undefined;
|
|
680
|
-
}
|
|
681
|
-
return index;
|
|
682
|
-
}
|
|
683
|
-
getDescendant(relativeCoordinates) {
|
|
684
|
-
let cursor = this;
|
|
685
|
-
for (const index of relativeCoordinates) {
|
|
686
|
-
cursor = cursor.children[index];
|
|
687
|
-
if (cursor === undefined) {
|
|
688
|
-
return undefined;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
return cursor;
|
|
692
|
-
}
|
|
693
|
-
findDescendant(predicate) {
|
|
694
|
-
if (predicate(this.data) === true) {
|
|
695
|
-
return this;
|
|
696
|
-
}
|
|
697
|
-
if (this.children.length > 0) {
|
|
698
|
-
for (const child of this.children) {
|
|
699
|
-
const foundDeeper = child.findDescendant(predicate);
|
|
700
|
-
if (foundDeeper !== undefined) {
|
|
701
|
-
return foundDeeper;
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
return undefined;
|
|
706
|
-
}
|
|
707
|
-
getAncestors() {
|
|
708
|
-
const result = [];
|
|
709
|
-
let cursor = this;
|
|
710
|
-
while (cursor.parent !== null) {
|
|
711
|
-
result.push(cursor.parent);
|
|
712
|
-
cursor = cursor.parent;
|
|
713
|
-
}
|
|
714
|
-
return result;
|
|
715
|
-
}
|
|
716
|
-
appendChild(child) {
|
|
717
|
-
if (child.getParent() !== null) {
|
|
718
|
-
child.remove();
|
|
719
|
-
}
|
|
720
|
-
child.setParent(this);
|
|
721
|
-
this.children.push(child);
|
|
722
|
-
return child;
|
|
723
|
-
}
|
|
724
|
-
insertChild(child, index) {
|
|
725
|
-
const isOwnChild = this.children.indexOf(child);
|
|
726
|
-
if (isOwnChild === -1) {
|
|
727
|
-
if (child.getParent() !== null) {
|
|
728
|
-
child.remove();
|
|
729
|
-
}
|
|
730
|
-
child.setParent(this);
|
|
731
|
-
this.children.splice(index, 0, child);
|
|
732
|
-
}
|
|
733
|
-
else {
|
|
734
|
-
if (index > isOwnChild) {
|
|
735
|
-
//Insert first, then remove
|
|
736
|
-
this.children.splice(index, 0, child);
|
|
737
|
-
this.removeChild(isOwnChild);
|
|
738
|
-
child.setParent(this);
|
|
739
|
-
}
|
|
740
|
-
else {
|
|
741
|
-
//remove first, then insert
|
|
742
|
-
child.remove();
|
|
743
|
-
this.children.splice(index, 0, child);
|
|
744
|
-
child.setParent(this);
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
return child;
|
|
748
|
-
}
|
|
749
|
-
removeChild(index) {
|
|
750
|
-
const target = this.children.splice(index, 1)[0];
|
|
751
|
-
target.setParent(null);
|
|
752
|
-
return target;
|
|
753
|
-
}
|
|
754
|
-
remove() {
|
|
755
|
-
const index = this.getIndex();
|
|
756
|
-
if (this.parent === null || index === undefined || index === null) {
|
|
757
|
-
throw new Error("can't remove root");
|
|
758
|
-
}
|
|
759
|
-
return this.parent.removeChild(index);
|
|
760
|
-
}
|
|
761
|
-
copy() {
|
|
762
|
-
const copy = this.copyHelper();
|
|
763
|
-
copy.setParent(null);
|
|
764
|
-
return copy;
|
|
765
|
-
}
|
|
766
|
-
copyHelper() {
|
|
767
|
-
const copy = new Branch(this.data);
|
|
768
|
-
for (const child of this.children) {
|
|
769
|
-
const newChild = copy.appendChild(child.copyHelper());
|
|
770
|
-
newChild.parent = copy;
|
|
771
|
-
}
|
|
772
|
-
return copy;
|
|
773
|
-
}
|
|
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
|
+
}
|
|
774
128
|
}
|
|
775
129
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
i0.ɵɵelementEnd();
|
|
783
|
-
} if (rf & 2) {
|
|
784
|
-
const ctx_r0 = i0.ɵɵnextContext();
|
|
785
|
-
i0.ɵɵadvance(1);
|
|
786
|
-
i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction2(1, _c0$3, ctx_r0.active, !ctx_r0.active));
|
|
787
|
-
} }
|
|
788
|
-
class DropZoneComponent {
|
|
789
|
-
constructor(dropZoneService, changeDetectorRef) {
|
|
790
|
-
this.dropZoneService = dropZoneService;
|
|
791
|
-
this.changeDetectorRef = changeDetectorRef;
|
|
792
|
-
this.visible = false;
|
|
793
|
-
this.active = false;
|
|
794
|
-
}
|
|
795
|
-
dragenterHandler() {
|
|
796
|
-
if (this.dropZone === undefined || this.active === true) {
|
|
797
|
-
return;
|
|
798
|
-
}
|
|
799
|
-
this.dropZoneService.swapActiveDropZone(this.dropZone);
|
|
800
|
-
}
|
|
801
|
-
ngOnInit() {
|
|
802
|
-
if (this.dropZone === undefined) {
|
|
803
|
-
throw new Error("No drop zone object at component initialization");
|
|
804
|
-
}
|
|
805
|
-
this.commSubscription = this.dropZone
|
|
806
|
-
.getCommChannel()
|
|
807
|
-
.subscribe((message) => {
|
|
808
|
-
switch (message) {
|
|
809
|
-
case "checkVisible": {
|
|
810
|
-
this.visible = this.dropZone?.isVisible() ?? false;
|
|
811
|
-
break;
|
|
812
|
-
}
|
|
813
|
-
case "checkActive": {
|
|
814
|
-
this.active = this.dropZone?.isActive() ?? false;
|
|
815
|
-
break;
|
|
816
|
-
}
|
|
817
|
-
case "checkRendered": {
|
|
818
|
-
//Do nothing. This message is for other subscribers
|
|
819
|
-
break;
|
|
820
|
-
}
|
|
821
|
-
default: {
|
|
822
|
-
throw new Error("unhandled comm message");
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
this.changeDetectorRef.detectChanges();
|
|
826
|
-
});
|
|
827
|
-
}
|
|
828
|
-
ngOnDestroy() {
|
|
829
|
-
if (this.commSubscription !== undefined) {
|
|
830
|
-
this.commSubscription.unsubscribe();
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
DropZoneComponent.ɵfac = function DropZoneComponent_Factory(t) { return new (t || DropZoneComponent)(i0.ɵɵdirectiveInject(DropZoneService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
835
|
-
DropZoneComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DropZoneComponent, selectors: [["drop-zone"]], inputs: { dropZone: "dropZone" }, decls: 1, vars: 1, consts: [["class", "dropZoneContainer", 3, "dragenter", 4, "ngIf"], [1, "dropZoneContainer", 3, "dragenter"], [3, "ngClass"]], template: function DropZoneComponent_Template(rf, ctx) { if (rf & 1) {
|
|
836
|
-
i0.ɵɵtemplate(0, DropZoneComponent_div_0_Template, 2, 4, "div", 0);
|
|
837
|
-
} if (rf & 2) {
|
|
838
|
-
i0.ɵɵproperty("ngIf", ctx.visible);
|
|
839
|
-
} }, dependencies: [i2.NgClass, i2.NgIf], styles: [".active[_ngcontent-%COMP%]{margin:10px 0;width:calc(100% - 20px);height:105px;border-radius:5px;background:#f0f9ff;border:2px dashed #bed2db;box-sizing:border-box}.related[_ngcontent-%COMP%]{margin:10px 0;width:calc(100% - 20px);height:30px;border-radius:5px;background:#fff6f0;border:1px dashed #dbccbe;box-sizing:border-box;opacity:.8}.dropZoneContainer[_ngcontent-%COMP%]{position:relative}"], changeDetection: 0 });
|
|
840
|
-
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DropZoneComponent, [{
|
|
841
|
-
type: Component,
|
|
842
|
-
args: [{ selector: "drop-zone", changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"dropZoneContainer\" (dragenter)=\"dragenterHandler()\" *ngIf=\"visible\">\n <div [ngClass]=\"{ active: active, related: !active }\"></div>\n</div>\n", styles: [".active{margin:10px 0;width:calc(100% - 20px);height:105px;border-radius:5px;background:#f0f9ff;border:2px dashed #bed2db;box-sizing:border-box}.related{margin:10px 0;width:calc(100% - 20px);height:30px;border-radius:5px;background:#fff6f0;border:1px dashed #dbccbe;box-sizing:border-box;opacity:.8}.dropZoneContainer{position:relative}\n"] }]
|
|
843
|
-
}], function () { return [{ type: DropZoneService }, { type: i0.ChangeDetectorRef }]; }, { dropZone: [{
|
|
844
|
-
type: Input
|
|
845
|
-
}] }); })();
|
|
130
|
+
function assert(condition) {
|
|
131
|
+
if (condition) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
throw new Error("Assertion Failed!");
|
|
135
|
+
}
|
|
846
136
|
|
|
847
|
-
|
|
848
|
-
function
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
} }
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
this.
|
|
858
|
-
this.
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
this.
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
this.
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
this.
|
|
868
|
-
this.
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
this.
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
}
|
|
892
|
-
ngOnDestroy() {
|
|
893
|
-
if (this.dropZoneInside !== undefined) {
|
|
894
|
-
this.dropZoneService.removeDropZone(this.dropZoneInside);
|
|
895
|
-
}
|
|
896
|
-
this.treeService.cleanupSignal$.next(true);
|
|
897
|
-
}
|
|
898
|
-
addDropZoneInside() {
|
|
899
|
-
if (this.branch === undefined) {
|
|
900
|
-
throw new Error("failed to register drop zone inside");
|
|
901
|
-
}
|
|
902
|
-
this.dropZoneInside = new DropZone([...this.branch.getCoordinates()], 0);
|
|
903
|
-
this.dropZoneService.addDropZone(this.dropZoneInside);
|
|
904
|
-
}
|
|
905
|
-
reRender() {
|
|
906
|
-
if (this.children === undefined || this.branch === undefined) {
|
|
907
|
-
throw new Error("Failed to render limble tree branch");
|
|
908
|
-
}
|
|
909
|
-
this.treeService.renderBranch(this.children, this.branch);
|
|
910
|
-
}
|
|
911
|
-
setDropZoneHost() {
|
|
912
|
-
if (this.children === undefined || this.dropZoneInside === undefined) {
|
|
913
|
-
throw new Error("Failed to add drop zone host");
|
|
914
|
-
}
|
|
915
|
-
this.dropZoneInside.setHost(this.children);
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
LimbleTreeBranchComponent.ɵfac = function LimbleTreeBranchComponent_Factory(t) { return new (t || LimbleTreeBranchComponent)(i0.ɵɵdirectiveInject(TreeService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(DropZoneService), i0.ɵɵdirectiveInject(TreeConstructionStatus), i0.ɵɵdirectiveInject(i0.NgZone)); };
|
|
919
|
-
LimbleTreeBranchComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: LimbleTreeBranchComponent, selectors: [["limble-tree-branch"]], viewQuery: function LimbleTreeBranchComponent_Query(rf, ctx) { if (rf & 1) {
|
|
920
|
-
i0.ɵɵviewQuery(_c0$2, 5, ViewContainerRef);
|
|
921
|
-
} if (rf & 2) {
|
|
922
|
-
let _t;
|
|
923
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.children = _t.first);
|
|
924
|
-
} }, inputs: { branch: "branch" }, decls: 5, vars: 4, consts: [[3, "dropZone", 4, "ngIf"], [1, "limble-child-nodes", 3, "hidden"], ["children", ""], [3, "dropZone"]], template: function LimbleTreeBranchComponent_Template(rf, ctx) { if (rf & 1) {
|
|
925
|
-
i0.ɵɵelementStart(0, "div");
|
|
926
|
-
i0.ɵɵtemplate(1, LimbleTreeBranchComponent_drop_zone_1_Template, 1, 1, "drop-zone", 0);
|
|
927
|
-
i0.ɵɵelementStart(2, "span", 1);
|
|
928
|
-
i0.ɵɵtemplate(3, LimbleTreeBranchComponent_ng_template_3_Template, 0, 0, "ng-template", null, 2, i0.ɵɵtemplateRefExtractor);
|
|
929
|
-
i0.ɵɵelementEnd()();
|
|
930
|
-
} if (rf & 2) {
|
|
931
|
-
i0.ɵɵstyleProp("margin-left", ctx.indent, "px");
|
|
932
|
-
i0.ɵɵadvance(1);
|
|
933
|
-
i0.ɵɵproperty("ngIf", ctx.renderDropZoneInside);
|
|
934
|
-
i0.ɵɵadvance(1);
|
|
935
|
-
i0.ɵɵproperty("hidden", ctx.branch && ctx.branch.data.collapsed);
|
|
936
|
-
} }, dependencies: [i2.NgIf, DropZoneComponent] });
|
|
937
|
-
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(LimbleTreeBranchComponent, [{
|
|
938
|
-
type: Component,
|
|
939
|
-
args: [{ selector: "limble-tree-branch", template: "<div [style.marginLeft.px]=\"indent\">\n <drop-zone\n *ngIf=\"renderDropZoneInside\"\n [dropZone]=\"dropZoneInside\"\n ></drop-zone>\n <span [hidden]=\"branch && branch.data.collapsed\" class=\"limble-child-nodes\">\n <ng-template #children></ng-template>\n </span>\n</div>\n" }]
|
|
940
|
-
}], function () { return [{ type: TreeService }, { type: i0.ChangeDetectorRef }, { type: DropZoneService }, { type: TreeConstructionStatus }, { type: i0.NgZone }]; }, { branch: [{
|
|
941
|
-
type: Input
|
|
942
|
-
}], children: [{
|
|
943
|
-
type: ViewChild,
|
|
944
|
-
args: ["children", { read: ViewContainerRef }]
|
|
945
|
-
}] }); })();
|
|
137
|
+
var DragStates;
|
|
138
|
+
(function (DragStates) {
|
|
139
|
+
DragStates[DragStates["Idle"] = 0] = "Idle";
|
|
140
|
+
DragStates[DragStates["Starting"] = 1] = "Starting";
|
|
141
|
+
DragStates[DragStates["Dragging"] = 2] = "Dragging";
|
|
142
|
+
DragStates[DragStates["Dropped"] = 3] = "Dropped";
|
|
143
|
+
})(DragStates || (DragStates = {}));
|
|
144
|
+
class DragState {
|
|
145
|
+
constructor() {
|
|
146
|
+
this._state = DragStates.Idle;
|
|
147
|
+
this.state$ = new BehaviorSubject(DragStates.Idle);
|
|
148
|
+
this.state$.subscribe((state) => {
|
|
149
|
+
this._state = state;
|
|
150
|
+
});
|
|
151
|
+
this.dragData = undefined;
|
|
152
|
+
}
|
|
153
|
+
getDragData() {
|
|
154
|
+
return this.dragData;
|
|
155
|
+
}
|
|
156
|
+
starting(treeBranch) {
|
|
157
|
+
assert(this._state === DragStates.Idle);
|
|
158
|
+
this.dragData = treeBranch;
|
|
159
|
+
this.state$.next(DragStates.Starting);
|
|
160
|
+
}
|
|
161
|
+
dragging() {
|
|
162
|
+
assert(this._state === DragStates.Starting);
|
|
163
|
+
this.state$.next(DragStates.Dragging);
|
|
164
|
+
}
|
|
165
|
+
dropped() {
|
|
166
|
+
assert(this._state === DragStates.Dragging);
|
|
167
|
+
this.state$.next(DragStates.Dropped);
|
|
168
|
+
}
|
|
169
|
+
restart() {
|
|
170
|
+
this.dragData = undefined;
|
|
171
|
+
this.state$.next(DragStates.Idle);
|
|
172
|
+
}
|
|
173
|
+
events() {
|
|
174
|
+
return this.state$;
|
|
175
|
+
}
|
|
176
|
+
state() {
|
|
177
|
+
return this._state;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const dragState = new DragState();
|
|
946
181
|
|
|
947
|
-
class
|
|
948
|
-
constructor(
|
|
949
|
-
this.
|
|
950
|
-
this.
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
182
|
+
class DropEvent {
|
|
183
|
+
constructor(source, parent, index) {
|
|
184
|
+
this._source = source;
|
|
185
|
+
this._parent = parent;
|
|
186
|
+
this._index = index;
|
|
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
|
+
}
|
|
963
201
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
//Outside of scrollable div
|
|
1041
|
-
return false;
|
|
1042
|
-
}
|
|
1043
|
-
scrollAreaSize = Math.max(viewPortHeight * 0.1, 100);
|
|
1044
|
-
edgeTop = scrollAreaSize;
|
|
1045
|
-
edgeBottom = viewPortHeight - scrollAreaSize;
|
|
1046
|
-
isInTopScrollArea = relativeY < edgeTop;
|
|
1047
|
-
isInBottomScrollArea = relativeY > edgeBottom;
|
|
1048
|
-
return isInTopScrollArea || isInBottomScrollArea;
|
|
1049
|
-
}))
|
|
1050
|
-
.subscribe(() => {
|
|
1051
|
-
if (scrollableDiv === null) {
|
|
1052
|
-
return;
|
|
1053
|
-
}
|
|
1054
|
-
const height = scrollableDiv.scrollHeight;
|
|
1055
|
-
const maxScrollY = height - viewPortHeight;
|
|
1056
|
-
const currentScrollY = scrollableDiv.scrollTop;
|
|
1057
|
-
const canScrollUp = currentScrollY > 0;
|
|
1058
|
-
const canScrollDown = currentScrollY < maxScrollY;
|
|
1059
|
-
let nextScrollY;
|
|
1060
|
-
const maxStep = 75;
|
|
1061
|
-
if (isInTopScrollArea && canScrollUp) {
|
|
1062
|
-
const intensity = (edgeTop - relativeY) / scrollAreaSize;
|
|
1063
|
-
nextScrollY = currentScrollY - maxStep * intensity;
|
|
1064
|
-
}
|
|
1065
|
-
else if (isInBottomScrollArea && canScrollDown) {
|
|
1066
|
-
const intensity = (relativeY - edgeBottom) / scrollAreaSize;
|
|
1067
|
-
nextScrollY = currentScrollY + maxStep * intensity;
|
|
1068
|
-
}
|
|
1069
|
-
else {
|
|
1070
|
-
return;
|
|
1071
|
-
}
|
|
1072
|
-
nextScrollY = Math.max(0, Math.min(maxScrollY, nextScrollY));
|
|
1073
|
-
if (nextScrollY !== currentScrollY) {
|
|
1074
|
-
scrollableDiv.scrollTo({ top: nextScrollY });
|
|
1075
|
-
this.scrolling = true;
|
|
1076
|
-
clearTimeout(timer);
|
|
1077
|
-
timer = setTimeout(() => {
|
|
1078
|
-
this.scrolling = false;
|
|
1079
|
-
}, 100);
|
|
1080
|
-
}
|
|
1081
|
-
});
|
|
1082
|
-
});
|
|
1083
|
-
}
|
|
1084
|
-
removeScrolling() {
|
|
1085
|
-
if (this.globalDragSubscription !== undefined) {
|
|
1086
|
-
this.globalDragSubscription.unsubscribe();
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
GlobalEventsService.ɵfac = function GlobalEventsService_Factory(t) { return new (t || GlobalEventsService)(i0.ɵɵinject(i0.NgZone)); };
|
|
1091
|
-
GlobalEventsService.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: GlobalEventsService, factory: GlobalEventsService.ɵfac });
|
|
1092
|
-
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(GlobalEventsService, [{
|
|
1093
|
-
type: Injectable
|
|
1094
|
-
}], function () { return [{ type: i0.NgZone }]; }, null); })();
|
|
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
|
+
assert(dataTransfer instanceof DataTransfer);
|
|
239
|
+
const nativeElement = treeBranch.getNativeElement();
|
|
240
|
+
const [xOffset, yOffset] = this.getDragImageOffsets(event, nativeElement);
|
|
241
|
+
dataTransfer.setDragImage(nativeElement, xOffset, yOffset);
|
|
242
|
+
}
|
|
243
|
+
watchForDragend(treeBranch, event) {
|
|
244
|
+
const oldParent = treeBranch.parent();
|
|
245
|
+
const oldIndex = treeBranch.index();
|
|
246
|
+
assert(oldParent !== undefined && oldIndex !== undefined);
|
|
247
|
+
event.target?.addEventListener("dragend", (dragend) => {
|
|
248
|
+
if (dragState.state() !== DragStates.Dropped) {
|
|
249
|
+
//The drag ended but a drop never occurred, so put the dragged branch back where it started.
|
|
250
|
+
this.dragAborted$.next(dragend);
|
|
251
|
+
this.graftDraggedBranch(treeBranch, oldParent, oldIndex);
|
|
252
|
+
}
|
|
253
|
+
dragState.restart();
|
|
254
|
+
const newParent = treeBranch.parent();
|
|
255
|
+
assert(newParent !== undefined);
|
|
256
|
+
const newIndex = treeBranch.index();
|
|
257
|
+
assert(newIndex !== undefined);
|
|
258
|
+
treeBranch.dispatch(new DragEndEvent(treeBranch, {
|
|
259
|
+
oldParent,
|
|
260
|
+
oldIndex,
|
|
261
|
+
newParent,
|
|
262
|
+
newIndex
|
|
263
|
+
}));
|
|
264
|
+
}, { once: true });
|
|
265
|
+
}
|
|
266
|
+
draggingAllowed(treeBranch) {
|
|
267
|
+
const allowDragging = config.getConfig(treeBranch.root())?.dragAndDrop?.allowDragging ??
|
|
268
|
+
(() => true);
|
|
269
|
+
return allowDragging(treeBranch);
|
|
270
|
+
}
|
|
271
|
+
graftDraggedBranch(treeBranch, parent, index) {
|
|
272
|
+
treeBranch.graftTo(parent, index);
|
|
273
|
+
treeBranch.getNativeElement().style.display = "block";
|
|
274
|
+
dragState.dropped();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const dragAndDrop = new DragAndDrop();
|
|
1095
278
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
} }
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
this.treeService.treeOptions.listMode !== true) {
|
|
1132
|
-
this.renderInnerBranch = true;
|
|
1133
|
-
}
|
|
1134
|
-
else {
|
|
1135
|
-
this.renderInnerBranch = false;
|
|
1136
|
-
}
|
|
1137
|
-
this.renderDropZoneBelow = false;
|
|
1138
|
-
this.renderDropZoneAbove = false;
|
|
1139
|
-
this.treeChangeSubscription = this.treeService.changes$
|
|
1140
|
-
.pipe(
|
|
1141
|
-
//The first one is the initial tree render, which we can ignore
|
|
1142
|
-
skip(1))
|
|
1143
|
-
.subscribe(() => {
|
|
1144
|
-
this.treeChangeHandler();
|
|
1145
|
-
});
|
|
1146
|
-
}
|
|
1147
|
-
treeChangeHandler() {
|
|
1148
|
-
if (this.branch !== undefined &&
|
|
1149
|
-
this.currentBranchCoordinates !== undefined &&
|
|
1150
|
-
!arraysAreEqual(this.branch.getCoordinates(), this.currentBranchCoordinates)) {
|
|
1151
|
-
this.updateDropZones();
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
ngOnInit() {
|
|
1155
|
-
if (this.treeService.treeOptions?.allowDragging === false) {
|
|
1156
|
-
return;
|
|
1157
|
-
}
|
|
1158
|
-
const parent = this.branch?.getParent();
|
|
1159
|
-
if (parent?.data !== null) {
|
|
1160
|
-
const parentData = parent?.data;
|
|
1161
|
-
if (!isNestingAllowed(this.treeService.treeOptions, parentData)) {
|
|
1162
|
-
this.renderInnerBranch = false;
|
|
1163
|
-
return;
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
this.registerDropZones();
|
|
1167
|
-
this.currentBranchCoordinates = this.branch?.getCoordinates();
|
|
1168
|
-
this.ngZone.runOutsideAngular(() => {
|
|
1169
|
-
if (this.dropZoneAbove === undefined ||
|
|
1170
|
-
this.dropZoneBelow === undefined) {
|
|
1171
|
-
throw new Error("Zones not registered");
|
|
1172
|
-
}
|
|
1173
|
-
merge(this.dropZoneAbove.getCommChannel(), this.dropZoneBelow.getCommChannel())
|
|
1174
|
-
.pipe(filter((message) => message === "checkRendered"))
|
|
1175
|
-
.subscribe(() => {
|
|
1176
|
-
if (this.dropZoneAbove === undefined ||
|
|
1177
|
-
this.dropZoneBelow === undefined ||
|
|
1178
|
-
this.branch === undefined) {
|
|
1179
|
-
throw new Error("Zones not registered");
|
|
1180
|
-
}
|
|
1181
|
-
this.renderDropZoneAbove = this.dropZoneAbove.isRendered();
|
|
1182
|
-
this.renderDropZoneBelow = this.dropZoneBelow.isRendered();
|
|
1183
|
-
});
|
|
1184
|
-
});
|
|
1185
|
-
}
|
|
1186
|
-
ngAfterViewInit() {
|
|
1187
|
-
this.renderNode();
|
|
1188
|
-
this.setDropZoneHosts();
|
|
1189
|
-
this.checkForHandle();
|
|
1190
|
-
this.treeConstructionStatus.doneConstructing();
|
|
1191
|
-
this.changeDetectorRef.detectChanges();
|
|
1192
|
-
}
|
|
1193
|
-
ngOnDestroy() {
|
|
1194
|
-
this.treeChangeSubscription.unsubscribe();
|
|
1195
|
-
if (this.dropZoneAbove !== undefined) {
|
|
1196
|
-
this.dropZoneService.removeDropZone(this.dropZoneAbove);
|
|
1197
|
-
}
|
|
1198
|
-
if (this.dropZoneBelow !== undefined) {
|
|
1199
|
-
this.dropZoneService.removeDropZone(this.dropZoneBelow);
|
|
1200
|
-
}
|
|
1201
|
-
this.treeService.cleanupSignal$.next(true);
|
|
1202
|
-
}
|
|
1203
|
-
dragstartHandler(event) {
|
|
1204
|
-
event.stopPropagation();
|
|
1205
|
-
if (event.dataTransfer === null ||
|
|
1206
|
-
this.branch === undefined ||
|
|
1207
|
-
this.parentHost === undefined) {
|
|
1208
|
-
throw new Error("failed to run dragstartHandler");
|
|
1209
|
-
}
|
|
1210
|
-
const draggedElement = event.target;
|
|
1211
|
-
if (draggedElement.parentElement?.tagName !== "LIMBLE-TREE-NODE") {
|
|
1212
|
-
//Don't drag stuff that isn't part of the tree
|
|
1213
|
-
event.preventDefault();
|
|
1214
|
-
return;
|
|
1215
|
-
}
|
|
1216
|
-
event.dataTransfer.effectAllowed = "move";
|
|
1217
|
-
this.dragStateService.dragging(this.branch, this.parentHost);
|
|
1218
|
-
const treeElement = draggedElement.closest("limble-tree-root");
|
|
1219
|
-
if (treeElement === null) {
|
|
1220
|
-
throw new Error("could not get root of tree");
|
|
1221
|
-
}
|
|
1222
|
-
this.ngZone.runOutsideAngular(() => {
|
|
1223
|
-
//We have to use a setTimeout due to a bug in chrome: https://stackoverflow.com/a/20733870/8796651
|
|
1224
|
-
setTimeout(() => {
|
|
1225
|
-
draggedElement.classList.add("dragging");
|
|
1226
|
-
if (this.treeService.treeData?.length === 1 &&
|
|
1227
|
-
this.branch?.getCoordinates().length === 1) {
|
|
1228
|
-
//We are dragging the only element in the tree, so we have to use the placeholder system
|
|
1229
|
-
this.treeService.placeholder$.next(true);
|
|
1230
|
-
}
|
|
1231
|
-
});
|
|
1232
|
-
//We use this weird subscription/timeout combo in order to avoid a strange bug where the dragleave event
|
|
1233
|
-
//does not fire if the user drags out of the tree too quickly. This issue would make the drop zone
|
|
1234
|
-
//remain in the UI, potentially causing drop zones to appear in multiple trees at a time. This subscription
|
|
1235
|
-
//waits for the dragover event on the tree to fire before rendering any drop zones. If the dragover
|
|
1236
|
-
//event does not fire within a half second, we know the mouse left the tree too quickly, and we won't
|
|
1237
|
-
//render the drop zone at all.
|
|
1238
|
-
const dragSubscription = fromEvent(treeElement, "dragover")
|
|
1239
|
-
.pipe(first())
|
|
1240
|
-
.subscribe((dragoverEvent) => {
|
|
1241
|
-
dragoverEvent.stopPropagation();
|
|
1242
|
-
if (this.branch === undefined) {
|
|
1243
|
-
throw new Error("Could not show surrounding drop zones");
|
|
1244
|
-
}
|
|
1245
|
-
const parent = this.branch.getParent();
|
|
1246
|
-
let parentData;
|
|
1247
|
-
let parentNestingAllowed = true;
|
|
1248
|
-
if (parent?.data !== null) {
|
|
1249
|
-
parentData = parent?.data;
|
|
1250
|
-
parentNestingAllowed = isNestingAllowed(this.treeService.treeOptions, parentData);
|
|
1251
|
-
}
|
|
1252
|
-
if (this.dropZoneAbove !== undefined && parentNestingAllowed) {
|
|
1253
|
-
this.dropZoneService.showDropZoneFamily(this.dropZoneAbove, {
|
|
1254
|
-
joinFamilies: true
|
|
1255
|
-
});
|
|
1256
|
-
}
|
|
1257
|
-
});
|
|
1258
|
-
setTimeout(() => {
|
|
1259
|
-
if (!dragSubscription.closed) {
|
|
1260
|
-
dragSubscription.unsubscribe();
|
|
1261
|
-
}
|
|
1262
|
-
}, 500);
|
|
1263
|
-
});
|
|
1264
|
-
}
|
|
1265
|
-
dragendHandler(event) {
|
|
1266
|
-
event?.stopPropagation();
|
|
1267
|
-
if (this.draggableDiv === undefined) {
|
|
1268
|
-
throw new Error("could not get draggable div");
|
|
1269
|
-
}
|
|
1270
|
-
this.draggableDiv.nativeElement.classList.remove("dragging");
|
|
1271
|
-
if (this.dragStateService.getState() === "captured") {
|
|
1272
|
-
if (this.treeService.captured === false) {
|
|
1273
|
-
//Dropped in a different tree. Remove the one in this tree
|
|
1274
|
-
if (this.branch === undefined) {
|
|
1275
|
-
throw new Error("could not get branch in dragendHandler");
|
|
1276
|
-
}
|
|
1277
|
-
this.treeService.cleanupSignal$.next(true);
|
|
1278
|
-
this.treeService.captured = false;
|
|
1279
|
-
}
|
|
1280
|
-
this.dragStateService.release();
|
|
1281
|
-
}
|
|
1282
|
-
else {
|
|
1283
|
-
//Wasn't dropped into a valid tree, so reset for next drag and
|
|
1284
|
-
//don't do anything else.
|
|
1285
|
-
this.dragStateService.release();
|
|
1286
|
-
this.dropZoneService.clearVisibleZones();
|
|
1287
|
-
this.dropZoneService.restoreFamilies();
|
|
1288
|
-
if (this.treeService.treeData?.length === 1 &&
|
|
1289
|
-
this.branch?.getCoordinates().length === 1) {
|
|
1290
|
-
//We were dragging the only element in the tree, so we have to
|
|
1291
|
-
//remove the placeholder that we added in the dragstart
|
|
1292
|
-
this.treeService.placeholder$.next(false);
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
dragoverHandler(event) {
|
|
1297
|
-
if (this.globalEventsService.scrolling === true) {
|
|
1298
|
-
return;
|
|
1299
|
-
}
|
|
1300
|
-
if (this.branch === undefined) {
|
|
1301
|
-
throw new Error("Can't get current branch during dragover event");
|
|
1302
|
-
}
|
|
1303
|
-
const data = this.dragStateService.getData();
|
|
1304
|
-
if (data === undefined) {
|
|
1305
|
-
//They might be dragging something that isn't a node. Just ignore it.
|
|
1306
|
-
return;
|
|
1307
|
-
}
|
|
1308
|
-
const sourceBranch = data.branch;
|
|
1309
|
-
//If trying to drop on self, return.
|
|
1310
|
-
if (sourceBranch === this.branch ||
|
|
1311
|
-
this.branch.getAncestors().includes(sourceBranch)) {
|
|
1312
|
-
return;
|
|
1313
|
-
}
|
|
1314
|
-
const target = event.currentTarget.closest(".node-host-container");
|
|
1315
|
-
if (!(target instanceof HTMLElement)) {
|
|
1316
|
-
throw new Error("Failed to find node host container while dragging");
|
|
1317
|
-
}
|
|
1318
|
-
let topLine;
|
|
1319
|
-
let bottomLine;
|
|
1320
|
-
if (this.innerBranch?.renderDropZoneInside === false) {
|
|
1321
|
-
topLine = target.offsetHeight / 2 - 6;
|
|
1322
|
-
bottomLine = topLine;
|
|
1323
|
-
}
|
|
1324
|
-
else {
|
|
1325
|
-
topLine = target.offsetHeight / 3 - 3; //an imaginary line 1/3 of the way down from the top of the element;
|
|
1326
|
-
bottomLine = topLine * 2; //an imaginary line 1/3 of the way up from the bottom of the element;
|
|
1327
|
-
}
|
|
1328
|
-
const parent = this.branch.getParent();
|
|
1329
|
-
let parentData;
|
|
1330
|
-
let parentNestingAllowed = true;
|
|
1331
|
-
if (parent?.data !== null) {
|
|
1332
|
-
parentData = parent?.data;
|
|
1333
|
-
parentNestingAllowed = isNestingAllowed(this.treeService.treeOptions, parentData);
|
|
1334
|
-
}
|
|
1335
|
-
/** The y-coordinates of the mouse in relation to the node it is hovering over */
|
|
1336
|
-
const offsetY = event.clientY - target.getBoundingClientRect().top;
|
|
1337
|
-
const activeDropZone = this.dropZoneService.getActiveDropZone();
|
|
1338
|
-
if (offsetY < topLine &&
|
|
1339
|
-
this.dropZoneAbove !== undefined &&
|
|
1340
|
-
parentNestingAllowed &&
|
|
1341
|
-
(activeDropZone === null ||
|
|
1342
|
-
!DropZone.dropZoneLocationsAreEqual(activeDropZone, this.dropZoneAbove))) {
|
|
1343
|
-
const index = this.branch.getIndex();
|
|
1344
|
-
if (index === undefined || index === null) {
|
|
1345
|
-
throw new Error("can't get branch index");
|
|
1346
|
-
}
|
|
1347
|
-
this.dropZoneService.showDropZoneFamily(this.dropZoneAbove, {
|
|
1348
|
-
activateLowestInsteadOfFounder: true
|
|
1349
|
-
});
|
|
1350
|
-
if (suddenTreeExit(event)) {
|
|
1351
|
-
this.dropZoneService.clearVisibleZones();
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
else if (offsetY < bottomLine &&
|
|
1355
|
-
offsetY > topLine &&
|
|
1356
|
-
this.innerBranch?.renderDropZoneInside === true &&
|
|
1357
|
-
this.innerBranch?.dropZoneInside !== undefined &&
|
|
1358
|
-
(activeDropZone === null ||
|
|
1359
|
-
!DropZone.dropZoneLocationsAreEqual(activeDropZone, this.innerBranch.dropZoneInside))) {
|
|
1360
|
-
this.dropZoneService.showDropZoneFamily(this.innerBranch.dropZoneInside);
|
|
1361
|
-
if (suddenTreeExit(event)) {
|
|
1362
|
-
this.dropZoneService.clearVisibleZones();
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
else if (offsetY >= bottomLine &&
|
|
1366
|
-
this.dropZoneBelow !== undefined &&
|
|
1367
|
-
parentNestingAllowed &&
|
|
1368
|
-
(activeDropZone === null ||
|
|
1369
|
-
!DropZone.dropZoneLocationsAreEqual(activeDropZone, this.dropZoneBelow)) &&
|
|
1370
|
-
this.branch.getChildren().length === 0) {
|
|
1371
|
-
const index = this.branch.getIndex();
|
|
1372
|
-
if (index === undefined || index === null) {
|
|
1373
|
-
throw new Error("can't get branch index");
|
|
1374
|
-
}
|
|
1375
|
-
this.dropZoneService.showDropZoneFamily(this.dropZoneBelow);
|
|
1376
|
-
if (suddenTreeExit(event)) {
|
|
1377
|
-
this.dropZoneService.clearVisibleZones();
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
renderNode() {
|
|
1382
|
-
if (this.nodeHost === undefined || this.branch === undefined) {
|
|
1383
|
-
throw new Error("Failed to render tree node");
|
|
1384
|
-
}
|
|
1385
|
-
let component = this.branch.data.component;
|
|
1386
|
-
if (component === undefined) {
|
|
1387
|
-
component = this.treeService.treeOptions?.defaultComponent;
|
|
1388
|
-
}
|
|
1389
|
-
if (component === undefined) {
|
|
1390
|
-
throw new Error("limbleTree requires a component to render");
|
|
1391
|
-
}
|
|
1392
|
-
const componentRef = this.componentCreatorService.appendComponent(component.class, this.nodeHost);
|
|
1393
|
-
componentRef.instance.nodeData = this.branch.data;
|
|
1394
|
-
for (const binding in component.bindings) {
|
|
1395
|
-
componentRef.instance[binding] = component.bindings[binding];
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
registerDropZones() {
|
|
1399
|
-
this.addDropZoneAbove();
|
|
1400
|
-
this.addDropZoneBelow();
|
|
1401
|
-
}
|
|
1402
|
-
addDropZoneAbove() {
|
|
1403
|
-
if (this.branch === undefined) {
|
|
1404
|
-
throw new Error("failed to register drop zone above");
|
|
1405
|
-
}
|
|
1406
|
-
const parent = this.branch.getParent();
|
|
1407
|
-
const currentCoordinates = this.branch.getCoordinates();
|
|
1408
|
-
const index = currentCoordinates[currentCoordinates.length - 1];
|
|
1409
|
-
this.dropZoneAbove = new DropZone([...(parent?.getCoordinates() ?? [])], index);
|
|
1410
|
-
this.dropZoneService.addDropZone(this.dropZoneAbove);
|
|
1411
|
-
}
|
|
1412
|
-
addDropZoneBelow() {
|
|
1413
|
-
if (this.branch === undefined) {
|
|
1414
|
-
throw new Error("failed to register drop zone below");
|
|
1415
|
-
}
|
|
1416
|
-
const parent = this.branch.getParent();
|
|
1417
|
-
const currentCoordinates = this.branch.getCoordinates();
|
|
1418
|
-
const index = currentCoordinates[currentCoordinates.length - 1];
|
|
1419
|
-
this.dropZoneBelow = new DropZone([...(parent?.getCoordinates() ?? [])], index + 1);
|
|
1420
|
-
this.dropZoneService.addDropZone(this.dropZoneBelow);
|
|
1421
|
-
}
|
|
1422
|
-
updateDropZones() {
|
|
1423
|
-
this.currentBranchCoordinates = this.branch?.getCoordinates();
|
|
1424
|
-
this.updateDropZoneAbove();
|
|
1425
|
-
this.updateDropZoneBelow();
|
|
1426
|
-
this.updateDropZoneInside();
|
|
1427
|
-
this.setDropZoneHosts();
|
|
1428
|
-
}
|
|
1429
|
-
updateDropZoneAbove() {
|
|
1430
|
-
if (this.branch === undefined || this.dropZoneAbove === undefined) {
|
|
1431
|
-
throw new Error("failed to update drop zone above");
|
|
1432
|
-
}
|
|
1433
|
-
const parent = this.branch.getParent();
|
|
1434
|
-
const currentCoordinates = this.branch.getCoordinates();
|
|
1435
|
-
const index = currentCoordinates[currentCoordinates.length - 1];
|
|
1436
|
-
const location = this.dropZoneAbove.getLocation();
|
|
1437
|
-
location.setParentCoordinates([...(parent?.getCoordinates() ?? [])]);
|
|
1438
|
-
location.setInsertIndex(index);
|
|
1439
|
-
}
|
|
1440
|
-
updateDropZoneBelow() {
|
|
1441
|
-
if (this.branch === undefined || this.dropZoneBelow === undefined) {
|
|
1442
|
-
throw new Error("failed to update drop zone below");
|
|
1443
|
-
}
|
|
1444
|
-
const parent = this.branch.getParent();
|
|
1445
|
-
const currentCoordinates = this.branch.getCoordinates();
|
|
1446
|
-
const index = currentCoordinates[currentCoordinates.length - 1];
|
|
1447
|
-
const location = this.dropZoneBelow.getLocation();
|
|
1448
|
-
location.setParentCoordinates([...(parent?.getCoordinates() ?? [])]);
|
|
1449
|
-
location.setInsertIndex(index + 1);
|
|
1450
|
-
}
|
|
1451
|
-
updateDropZoneInside() {
|
|
1452
|
-
if (this.innerBranch?.dropZoneInside === undefined) {
|
|
1453
|
-
return;
|
|
1454
|
-
}
|
|
1455
|
-
if (this.branch === undefined) {
|
|
1456
|
-
throw new Error("failed to update drop zone inside");
|
|
1457
|
-
}
|
|
1458
|
-
const location = this.innerBranch.dropZoneInside.getLocation();
|
|
1459
|
-
location.setParentCoordinates([...this.branch.getCoordinates()]);
|
|
1460
|
-
}
|
|
1461
|
-
setDropZoneHosts() {
|
|
1462
|
-
if (this.dropZoneAbove === undefined ||
|
|
1463
|
-
this.dropZoneBelow === undefined) {
|
|
1464
|
-
return;
|
|
1465
|
-
}
|
|
1466
|
-
this.dropZoneAbove.setHost(this.parentHost);
|
|
1467
|
-
this.dropZoneBelow.setHost(this.parentHost);
|
|
1468
|
-
}
|
|
1469
|
-
checkForHandle() {
|
|
1470
|
-
if (this.nodeHostContainer === undefined ||
|
|
1471
|
-
this.draggableDiv === undefined) {
|
|
1472
|
-
return;
|
|
1473
|
-
}
|
|
1474
|
-
const nodeHostContainerElement = this.nodeHostContainer.nativeElement;
|
|
1475
|
-
const handle = nodeHostContainerElement.querySelector(".limble-tree-handle");
|
|
1476
|
-
const draggableDivElement = this.draggableDiv.nativeElement;
|
|
1477
|
-
if (!isDraggingAllowed(this.treeService.treeOptions, this.branch?.data)) {
|
|
1478
|
-
draggableDivElement.setAttribute("draggable", "false");
|
|
1479
|
-
}
|
|
1480
|
-
else if (handle === null) {
|
|
1481
|
-
draggableDivElement.setAttribute("draggable", "true");
|
|
1482
|
-
}
|
|
1483
|
-
else {
|
|
1484
|
-
handle.addEventListener("mousedown", () => {
|
|
1485
|
-
draggableDivElement.setAttribute("draggable", "true");
|
|
1486
|
-
//For some reason mouseup doesn't fire after a drag, so we use this observable sequence instead.
|
|
1487
|
-
const dragging = this.dragStateService.state$.pipe(filter((state) => state === "dragging"), first());
|
|
1488
|
-
this.dragStateService.state$
|
|
1489
|
-
.pipe(skipUntil(dragging), filter((state) => state === "idle"), first())
|
|
1490
|
-
.subscribe(() => {
|
|
1491
|
-
draggableDivElement.setAttribute("draggable", "false");
|
|
1492
|
-
});
|
|
1493
|
-
});
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
LimbleTreeNodeComponent.ɵfac = function LimbleTreeNodeComponent_Factory(t) { return new (t || LimbleTreeNodeComponent)(i0.ɵɵdirectiveInject(ComponentCreatorService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(DragStateService), i0.ɵɵdirectiveInject(DropZoneService), i0.ɵɵdirectiveInject(TreeService), i0.ɵɵdirectiveInject(GlobalEventsService), i0.ɵɵdirectiveInject(i0.NgZone), i0.ɵɵdirectiveInject(TreeConstructionStatus)); };
|
|
1498
|
-
LimbleTreeNodeComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: LimbleTreeNodeComponent, selectors: [["limble-tree-node"]], viewQuery: function LimbleTreeNodeComponent_Query(rf, ctx) { if (rf & 1) {
|
|
1499
|
-
i0.ɵɵviewQuery(_c0$1, 5, ViewContainerRef);
|
|
1500
|
-
i0.ɵɵviewQuery(_c1, 5, ElementRef);
|
|
1501
|
-
i0.ɵɵviewQuery(_c2, 5, ElementRef);
|
|
1502
|
-
i0.ɵɵviewQuery(_c3, 5, LimbleTreeBranchComponent);
|
|
1503
|
-
} if (rf & 2) {
|
|
1504
|
-
let _t;
|
|
1505
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.nodeHost = _t.first);
|
|
1506
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.draggableDiv = _t.first);
|
|
1507
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.nodeHostContainer = _t.first);
|
|
1508
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.innerBranch = _t.first);
|
|
1509
|
-
} }, inputs: { branch: "branch", parentHost: "parentHost" }, decls: 9, vars: 4, consts: [[3, "dropZone", 4, "ngIf"], [1, "limble-parent-container", 3, "dragstart", "dragend"], ["draggableDiv", ""], [1, "node-host-container", 3, "dragoverEventThrottle", "dragoverNoChangeDetect"], ["nodeHostContainer", ""], ["nodeHost", ""], [3, "branch", 4, "ngIf"], [3, "dropZone"], [3, "branch"], ["innerBranch", ""]], template: function LimbleTreeNodeComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1510
|
-
i0.ɵɵtemplate(0, LimbleTreeNodeComponent_drop_zone_0_Template, 1, 1, "drop-zone", 0);
|
|
1511
|
-
i0.ɵɵelementStart(1, "div", 1, 2);
|
|
1512
|
-
i0.ɵɵlistener("dragstart", function LimbleTreeNodeComponent_Template_div_dragstart_1_listener($event) { return ctx.dragstartHandler($event); })("dragend", function LimbleTreeNodeComponent_Template_div_dragend_1_listener($event) { return ctx.dragendHandler($event); });
|
|
1513
|
-
i0.ɵɵelementStart(3, "div", 3, 4);
|
|
1514
|
-
i0.ɵɵlistener("dragoverNoChangeDetect", function LimbleTreeNodeComponent_Template_div_dragoverNoChangeDetect_3_listener($event) { return ctx.dragoverHandler($event); });
|
|
1515
|
-
i0.ɵɵtemplate(5, LimbleTreeNodeComponent_ng_template_5_Template, 0, 0, "ng-template", null, 5, i0.ɵɵtemplateRefExtractor);
|
|
1516
|
-
i0.ɵɵelementEnd();
|
|
1517
|
-
i0.ɵɵtemplate(7, LimbleTreeNodeComponent_limble_tree_branch_7_Template, 2, 1, "limble-tree-branch", 6);
|
|
1518
|
-
i0.ɵɵelementEnd();
|
|
1519
|
-
i0.ɵɵtemplate(8, LimbleTreeNodeComponent_drop_zone_8_Template, 1, 1, "drop-zone", 0);
|
|
1520
|
-
} if (rf & 2) {
|
|
1521
|
-
i0.ɵɵproperty("ngIf", ctx.renderDropZoneAbove === true);
|
|
1522
|
-
i0.ɵɵadvance(3);
|
|
1523
|
-
i0.ɵɵproperty("dragoverEventThrottle", 10);
|
|
1524
|
-
i0.ɵɵadvance(4);
|
|
1525
|
-
i0.ɵɵproperty("ngIf", ctx.branch !== undefined && ctx.renderInnerBranch === true);
|
|
1526
|
-
i0.ɵɵadvance(1);
|
|
1527
|
-
i0.ɵɵproperty("ngIf", ctx.renderDropZoneBelow === true);
|
|
1528
|
-
} }, styles: [".dragging[_ngcontent-%COMP%]{position:absolute;transition:transform .01s;transform:translate(-9999px)}"] });
|
|
1529
|
-
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(LimbleTreeNodeComponent, [{
|
|
1530
|
-
type: Component,
|
|
1531
|
-
args: [{ selector: "limble-tree-node", template: "<drop-zone\n *ngIf=\"renderDropZoneAbove === true\"\n [dropZone]=\"dropZoneAbove\"\n></drop-zone>\n<div\n (dragstart)=\"dragstartHandler($event)\"\n (dragend)=\"dragendHandler($event)\"\n class=\"limble-parent-container\"\n #draggableDiv\n>\n <div\n class=\"node-host-container\"\n (dragoverNoChangeDetect)=\"dragoverHandler($event)\"\n [dragoverEventThrottle]=\"10\"\n #nodeHostContainer\n >\n <ng-template #nodeHost></ng-template>\n </div>\n <limble-tree-branch\n *ngIf=\"branch !== undefined && renderInnerBranch === true\"\n [branch]=\"branch\"\n #innerBranch\n ></limble-tree-branch>\n</div>\n<drop-zone\n *ngIf=\"renderDropZoneBelow === true\"\n [dropZone]=\"dropZoneBelow\"\n></drop-zone>\n", styles: [".dragging{position:absolute;transition:transform .01s;transform:translate(-9999px)}\n"] }]
|
|
1532
|
-
}], function () { return [{ type: ComponentCreatorService }, { type: i0.ChangeDetectorRef }, { type: DragStateService }, { type: DropZoneService }, { type: TreeService }, { type: GlobalEventsService }, { type: i0.NgZone }, { type: TreeConstructionStatus }]; }, { branch: [{
|
|
1533
|
-
type: Input
|
|
1534
|
-
}], nodeHost: [{
|
|
1535
|
-
type: ViewChild,
|
|
1536
|
-
args: ["nodeHost", { read: ViewContainerRef }]
|
|
1537
|
-
}], draggableDiv: [{
|
|
1538
|
-
type: ViewChild,
|
|
1539
|
-
args: ["draggableDiv", { read: ElementRef }]
|
|
1540
|
-
}], nodeHostContainer: [{
|
|
1541
|
-
type: ViewChild,
|
|
1542
|
-
args: ["nodeHostContainer", { read: ElementRef }]
|
|
1543
|
-
}], parentHost: [{
|
|
1544
|
-
type: Input
|
|
1545
|
-
}], innerBranch: [{
|
|
1546
|
-
type: ViewChild,
|
|
1547
|
-
args: ["innerBranch", { read: LimbleTreeBranchComponent }]
|
|
1548
|
-
}] }); })();
|
|
279
|
+
class DragoverNoChangeDetectDirective {
|
|
280
|
+
constructor(ngZone, el) {
|
|
281
|
+
this.ngZone = ngZone;
|
|
282
|
+
this.el = el;
|
|
283
|
+
this.dragoverNoChangeDetect = new EventEmitter();
|
|
284
|
+
this.dragoverEventThrottle = 25;
|
|
285
|
+
}
|
|
286
|
+
ngOnInit() {
|
|
287
|
+
this.ngZone.runOutsideAngular(() => {
|
|
288
|
+
this.eventSubscription = fromEvent(this.el.nativeElement, "dragover")
|
|
289
|
+
.pipe(throttleTime(this.dragoverEventThrottle))
|
|
290
|
+
.subscribe(($event) => {
|
|
291
|
+
this.dragoverNoChangeDetect.emit($event);
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
ngOnDestroy() {
|
|
296
|
+
if (this.eventSubscription !== undefined) {
|
|
297
|
+
this.eventSubscription.unsubscribe();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
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 });
|
|
302
|
+
DragoverNoChangeDetectDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.12", type: DragoverNoChangeDetectDirective, isStandalone: true, selector: "[dragoverNoChangeDetect]", inputs: { dragoverEventThrottle: "dragoverEventThrottle" }, outputs: { dragoverNoChangeDetect: "dragoverNoChangeDetect" }, ngImport: i0 });
|
|
303
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: DragoverNoChangeDetectDirective, decorators: [{
|
|
304
|
+
type: Directive,
|
|
305
|
+
args: [{
|
|
306
|
+
standalone: true,
|
|
307
|
+
selector: "[dragoverNoChangeDetect]"
|
|
308
|
+
}]
|
|
309
|
+
}], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.ElementRef }]; }, propDecorators: { dragoverEventThrottle: [{
|
|
310
|
+
type: Input
|
|
311
|
+
}], dragoverNoChangeDetect: [{
|
|
312
|
+
type: Output
|
|
313
|
+
}] } });
|
|
1549
314
|
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
this.
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
this.
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
}),
|
|
1580
|
-
//We use this timed debounce to throttle chained destruction of components
|
|
1581
|
-
debounceTime(5))
|
|
1582
|
-
.subscribe(() => {
|
|
1583
|
-
this.cleanup(rebuild);
|
|
1584
|
-
rebuild = false;
|
|
1585
|
-
});
|
|
1586
|
-
this.placeholder$ = new BehaviorSubject(false);
|
|
1587
|
-
this.placeholder$.subscribe((value) => {
|
|
1588
|
-
this.placeholder = value;
|
|
1589
|
-
});
|
|
1590
|
-
}
|
|
1591
|
-
drop(source, targetCoordinates) {
|
|
1592
|
-
//prep
|
|
1593
|
-
const sourceParent = source.getParent();
|
|
1594
|
-
if (sourceParent === null) {
|
|
1595
|
-
throw new Error("can't drop root of tree");
|
|
1596
|
-
}
|
|
1597
|
-
const sourceIndex = source.getIndex();
|
|
1598
|
-
if (sourceIndex === undefined || sourceIndex === null) {
|
|
1599
|
-
throw new Error("Cannot move the hidden root node");
|
|
1600
|
-
}
|
|
1601
|
-
let targetParentCoordinates;
|
|
1602
|
-
let newIndex;
|
|
1603
|
-
if (this.placeholder === true) {
|
|
1604
|
-
targetParentCoordinates = [];
|
|
1605
|
-
newIndex = 0;
|
|
1606
|
-
}
|
|
1607
|
-
else {
|
|
1608
|
-
targetParentCoordinates = [...targetCoordinates];
|
|
1609
|
-
newIndex = targetParentCoordinates.pop();
|
|
1610
|
-
}
|
|
1611
|
-
if (newIndex === undefined) {
|
|
1612
|
-
throw new Error("target coordinates are empty");
|
|
1613
|
-
}
|
|
1614
|
-
const targetParent = this.treeModel.getDescendant(targetParentCoordinates);
|
|
1615
|
-
if (targetParent === undefined) {
|
|
1616
|
-
throw new Error("could not get to target");
|
|
1617
|
-
}
|
|
1618
|
-
const target = this.dropZoneService.getDropZone(targetCoordinates);
|
|
1619
|
-
const targetIndex = target?.getLocation().insertIndex;
|
|
1620
|
-
const targetHost = target?.getHost();
|
|
1621
|
-
const sourceHost = this.dragStateService.getData()?.parentContainer;
|
|
1622
|
-
if (this.placeholder === true) {
|
|
1623
|
-
this.placeholder$.next(false);
|
|
1624
|
-
}
|
|
1625
|
-
//Change the treeModel
|
|
1626
|
-
targetParent.insertChild(source, newIndex);
|
|
1627
|
-
//Prepare to update the view
|
|
1628
|
-
if (targetHost === undefined ||
|
|
1629
|
-
sourceHost === undefined ||
|
|
1630
|
-
targetIndex === undefined) {
|
|
1631
|
-
//Hitting this means there is a bug, but not a fatal one.
|
|
1632
|
-
//Just render the whole tree again.
|
|
1633
|
-
console.warn("Could not perform a precise update. Re-rendering the entire tree instead");
|
|
1634
|
-
this.render();
|
|
1635
|
-
this.changes$.next(null);
|
|
1636
|
-
return;
|
|
1637
|
-
}
|
|
1638
|
-
//Update the view
|
|
1639
|
-
const nodesInSource = sourceHost.length;
|
|
1640
|
-
const componentRef = this.componentCreatorService.appendComponent(LimbleTreeNodeComponent, targetHost, newIndex);
|
|
1641
|
-
componentRef.instance.branch = source;
|
|
1642
|
-
componentRef.instance.parentHost = targetHost;
|
|
1643
|
-
if (targetIndex < sourceIndex &&
|
|
1644
|
-
sourceHost.length > nodesInSource &&
|
|
1645
|
-
arraysAreEqual(sourceParent.getCoordinates(), targetParentCoordinates)) {
|
|
1646
|
-
sourceHost.remove(sourceIndex + 1);
|
|
1647
|
-
}
|
|
1648
|
-
else {
|
|
1649
|
-
sourceHost.remove(sourceIndex);
|
|
1650
|
-
}
|
|
1651
|
-
//Update the tree data
|
|
1652
|
-
this.rebuildTreeData();
|
|
1653
|
-
//Publish drop data
|
|
1654
|
-
this.drops$.next({
|
|
1655
|
-
target: source.data,
|
|
1656
|
-
oldParent: sourceParent.data,
|
|
1657
|
-
oldIndex: sourceIndex,
|
|
1658
|
-
newParent: targetParent.data,
|
|
1659
|
-
newIndex: newIndex
|
|
1660
|
-
});
|
|
1661
|
-
this.cleanupSignal$.next(false);
|
|
1662
|
-
}
|
|
1663
|
-
/** Initializes the service and renders the tree.
|
|
1664
|
-
* @param host - The ViewContainerRef into which the tree will be rendered.
|
|
1665
|
-
* @param data - The data array that was passed in to LimbleTreeRoot, which is
|
|
1666
|
-
* the users' representation of the tree
|
|
1667
|
-
* @param options - The options object that was passed in to LimbleTreeRoot
|
|
1668
|
-
*/
|
|
1669
|
-
init(host, data, options, itemsPerPage, page) {
|
|
1670
|
-
this.host = host;
|
|
1671
|
-
this.originalData = data;
|
|
1672
|
-
this.treeOptions = this.processOptions(options, itemsPerPage, page);
|
|
1673
|
-
if (this.treeOptions.listMode === true) {
|
|
1674
|
-
let start = this.treeOptions.itemsPerPage * (this.treeOptions.page - 1);
|
|
1675
|
-
if (isNaN(start)) {
|
|
1676
|
-
//This catches the case where itemsPerPage was not passed by the user,
|
|
1677
|
-
//causing `start` to equal infinity*0, which is NaN.
|
|
1678
|
-
start = 0;
|
|
1679
|
-
}
|
|
1680
|
-
const end = start + this.treeOptions.itemsPerPage;
|
|
1681
|
-
this.treeData = this.originalData.slice(start, end);
|
|
1682
|
-
}
|
|
1683
|
-
else {
|
|
1684
|
-
this.treeData = [...this.originalData];
|
|
1685
|
-
}
|
|
1686
|
-
this.render();
|
|
1687
|
-
}
|
|
1688
|
-
cleanup(rebuild = false) {
|
|
1689
|
-
if (rebuild) {
|
|
1690
|
-
this.rebuildTreeData();
|
|
1691
|
-
}
|
|
1692
|
-
if (this.treeData?.length === 0) {
|
|
1693
|
-
//We do a full render here because it isn't actually any slower
|
|
1694
|
-
//when there are no nodes, and it is a little more straightforward
|
|
1695
|
-
this.render();
|
|
1696
|
-
}
|
|
1697
|
-
else {
|
|
1698
|
-
this.changes$.next(null);
|
|
1699
|
-
this.dropZoneService.update();
|
|
1700
|
-
}
|
|
1701
|
-
}
|
|
1702
|
-
/** Renders the entire tree from root to leaves */
|
|
1703
|
-
render() {
|
|
1704
|
-
if (this.host === undefined ||
|
|
1705
|
-
this.treeData === undefined ||
|
|
1706
|
-
this.treeOptions === undefined) {
|
|
1707
|
-
throw new Error("TreeModel not initialized");
|
|
1708
|
-
}
|
|
1709
|
-
this.treeConstructionStatus.ready(false);
|
|
1710
|
-
this.host.clear();
|
|
1711
|
-
this.dropZoneService.restart();
|
|
1712
|
-
this.placeholder$.next(false);
|
|
1713
|
-
this.treeModel = new Branch(null);
|
|
1714
|
-
if (this.treeData.length === 0) {
|
|
1715
|
-
//Tree is empty, but we have to to have something there so other trees' items can be dropped into it
|
|
1716
|
-
this.placeholder$.next(true);
|
|
1717
|
-
}
|
|
1718
|
-
else {
|
|
1719
|
-
for (const node of this.treeData) {
|
|
1720
|
-
const branch = new Branch(node);
|
|
1721
|
-
this.treeModel.appendChild(branch);
|
|
1722
|
-
}
|
|
1723
|
-
for (const branch of this.treeModel.getChildren()) {
|
|
1724
|
-
const componentRef = this.componentCreatorService.appendComponent(LimbleTreeNodeComponent, this.host);
|
|
1725
|
-
componentRef.instance.branch = branch;
|
|
1726
|
-
componentRef.instance.parentHost = this.host;
|
|
1727
|
-
//The LimbleTreeNodeComponent will (indirectly) call the `renderBranch` method of this service to render
|
|
1728
|
-
//its own children
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
this.treeConstructionStatus.ready(true);
|
|
1732
|
-
this.changes$.next(null);
|
|
1733
|
-
this.dropZoneService.init(this.treeModel, this.treeOptions);
|
|
1734
|
-
}
|
|
1735
|
-
/** Renders a branch of the tree and all of its descendants */
|
|
1736
|
-
renderBranch(host, branch) {
|
|
1737
|
-
if (this.treeModel === undefined) {
|
|
1738
|
-
throw new Error("TreeModel not initialized");
|
|
1739
|
-
}
|
|
1740
|
-
host.clear();
|
|
1741
|
-
branch.clearChildren();
|
|
1742
|
-
for (const node of branch.data?.nodes ?? []) {
|
|
1743
|
-
const newBranch = new Branch(node);
|
|
1744
|
-
branch.appendChild(newBranch);
|
|
1745
|
-
const componentRef = this.componentCreatorService.appendComponent(LimbleTreeNodeComponent, host);
|
|
1746
|
-
componentRef.instance.branch = newBranch;
|
|
1747
|
-
componentRef.instance.parentHost = host;
|
|
1748
|
-
//The LimbleTreeNodeComponent will (indirectly) call the `renderBranch` method of this service to render
|
|
1749
|
-
//its own children
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
processOptions(options = {}, itemsPerPage = Infinity, page = 1) {
|
|
1753
|
-
if (options.listMode === true &&
|
|
1754
|
-
options.allowNesting !== undefined &&
|
|
1755
|
-
options.allowNesting !== false) {
|
|
1756
|
-
console.warn("The value of `allowNesting` will be ignored; it must be false when `listMode` is true");
|
|
1757
|
-
}
|
|
1758
|
-
const result = {
|
|
1759
|
-
defaultComponent: options.defaultComponent,
|
|
1760
|
-
indent: options.indent ?? INDENT,
|
|
1761
|
-
allowNesting: options.listMode !== true && (options.allowNesting ?? true),
|
|
1762
|
-
allowDragging: options.allowDragging ?? true,
|
|
1763
|
-
allowDrop: options.allowDrop ?? (() => true),
|
|
1764
|
-
listMode: options.listMode ?? false,
|
|
1765
|
-
itemsPerPage: options.listMode ? itemsPerPage : undefined,
|
|
1766
|
-
page: options.listMode ? page : undefined
|
|
1767
|
-
};
|
|
1768
|
-
return result;
|
|
1769
|
-
}
|
|
1770
|
-
rebuildTreeData() {
|
|
1771
|
-
if (this.originalData === undefined ||
|
|
1772
|
-
this.treeData === undefined ||
|
|
1773
|
-
this.treeOptions === undefined ||
|
|
1774
|
-
this.host === undefined) {
|
|
1775
|
-
throw new Error("Tree data not initialized");
|
|
1776
|
-
}
|
|
1777
|
-
this.treeData = [];
|
|
1778
|
-
for (const branch of this.treeModel.getChildren()) {
|
|
1779
|
-
this.treeData.push(this.rebuildBranch(branch));
|
|
1780
|
-
}
|
|
1781
|
-
if (this.treeOptions.listMode === true &&
|
|
1782
|
-
this.treeOptions.itemsPerPage < Infinity) {
|
|
1783
|
-
const itemsPerPage = this.treeOptions.itemsPerPage;
|
|
1784
|
-
const start = itemsPerPage * (this.treeOptions.page - 1);
|
|
1785
|
-
this.originalData.splice(start, itemsPerPage, ...this.treeData);
|
|
1786
|
-
if (this.treeData.length !== itemsPerPage) {
|
|
1787
|
-
let action = false;
|
|
1788
|
-
if (this.treeData.length < itemsPerPage &&
|
|
1789
|
-
start + itemsPerPage <= this.originalData.length) {
|
|
1790
|
-
//The current page does not have enough nodes. Add some to the view from the next page.
|
|
1791
|
-
const count = itemsPerPage - this.treeData.length;
|
|
1792
|
-
for (let index = itemsPerPage - 1; index < itemsPerPage + count - 1; index++) {
|
|
1793
|
-
const branch = new Branch(this.originalData[start + index]);
|
|
1794
|
-
this.treeModel.appendChild(branch);
|
|
1795
|
-
const componentRef = this.componentCreatorService.appendComponent(LimbleTreeNodeComponent, this.host);
|
|
1796
|
-
componentRef.instance.branch = branch;
|
|
1797
|
-
componentRef.instance.parentHost = this.host;
|
|
1798
|
-
}
|
|
1799
|
-
action = true;
|
|
1800
|
-
}
|
|
1801
|
-
else if (this.treeData.length > itemsPerPage) {
|
|
1802
|
-
//The current page has too many nodes. Remove some of them from the view.
|
|
1803
|
-
const count = this.treeData.length - itemsPerPage;
|
|
1804
|
-
for (let index = itemsPerPage + count - 1; index >= itemsPerPage; index--) {
|
|
1805
|
-
this.treeModel.removeChild(index);
|
|
1806
|
-
this.host.remove(index);
|
|
1807
|
-
}
|
|
1808
|
-
action = true;
|
|
1809
|
-
}
|
|
1810
|
-
if (action === true) {
|
|
1811
|
-
const end = start + itemsPerPage;
|
|
1812
|
-
this.treeData = this.originalData.slice(start, end);
|
|
1813
|
-
}
|
|
1814
|
-
}
|
|
1815
|
-
}
|
|
1816
|
-
else {
|
|
1817
|
-
this.originalData.length = 0;
|
|
1818
|
-
this.originalData.push(...this.treeData);
|
|
1819
|
-
}
|
|
1820
|
-
}
|
|
1821
|
-
rebuildBranch(branch) {
|
|
1822
|
-
const temp = branch.data;
|
|
1823
|
-
temp.nodes = [];
|
|
1824
|
-
for (const child of branch.getChildren()) {
|
|
1825
|
-
temp.nodes.push(this.rebuildBranch(child));
|
|
1826
|
-
}
|
|
1827
|
-
return temp;
|
|
1828
|
-
}
|
|
1829
|
-
}
|
|
1830
|
-
TreeService.ɵfac = function TreeService_Factory(t) { return new (t || TreeService)(i0.ɵɵinject(ComponentCreatorService), i0.ɵɵinject(DropZoneService), i0.ɵɵinject(DragStateService), i0.ɵɵinject(TreeConstructionStatus)); };
|
|
1831
|
-
TreeService.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: TreeService, factory: TreeService.ɵfac });
|
|
1832
|
-
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TreeService, [{
|
|
1833
|
-
type: Injectable
|
|
1834
|
-
}], function () { return [{ type: ComponentCreatorService }, { type: DropZoneService }, { type: DragStateService }, { type: TreeConstructionStatus }]; }, null); })();
|
|
315
|
+
class DropzoneComponent {
|
|
316
|
+
constructor() {
|
|
317
|
+
this.dropped = new EventEmitter();
|
|
318
|
+
this.active = false;
|
|
319
|
+
}
|
|
320
|
+
dragenterHandler() {
|
|
321
|
+
this.active = true;
|
|
322
|
+
}
|
|
323
|
+
dragleaveHandler() {
|
|
324
|
+
this.active = false;
|
|
325
|
+
}
|
|
326
|
+
dragoverHandler(event) {
|
|
327
|
+
event.preventDefault();
|
|
328
|
+
event.dataTransfer.dropEffect = "move";
|
|
329
|
+
}
|
|
330
|
+
dropHandler(event) {
|
|
331
|
+
this.dropped.emit(event);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
DropzoneComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: DropzoneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
335
|
+
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:20px;margin:8px 0;transition:height .2s ease-out;animation:animation .2s ease-out}.dropzone.active{border-color:#289e49;border-width:2px;background-color:#d0e8d6;height:48px}@keyframes animation{0%{height:0px;opacity:0}to{height:20px;opacity:1}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: DragoverNoChangeDetectDirective, selector: "[dragoverNoChangeDetect]", inputs: ["dragoverEventThrottle"], outputs: ["dragoverNoChangeDetect"] }] });
|
|
336
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: DropzoneComponent, decorators: [{
|
|
337
|
+
type: Component,
|
|
338
|
+
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:20px;margin:8px 0;transition:height .2s ease-out;animation:animation .2s ease-out}.dropzone.active{border-color:#289e49;border-width:2px;background-color:#d0e8d6;height:48px}@keyframes animation{0%{height:0px;opacity:0}to{height:20px;opacity:1}}\n"] }]
|
|
339
|
+
}], propDecorators: { placement: [{
|
|
340
|
+
type: Input
|
|
341
|
+
}], dropped: [{
|
|
342
|
+
type: Output
|
|
343
|
+
}] } });
|
|
1835
344
|
|
|
1836
|
-
class
|
|
1837
|
-
constructor(
|
|
1838
|
-
this.
|
|
1839
|
-
this.
|
|
1840
|
-
this.
|
|
1841
|
-
this.
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
this.
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
(
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
345
|
+
class BranchComponent {
|
|
346
|
+
constructor(appRef) {
|
|
347
|
+
this.appRef = appRef;
|
|
348
|
+
this.branchesContainer = undefined;
|
|
349
|
+
this.contentContainer = undefined;
|
|
350
|
+
this.dropzones = undefined;
|
|
351
|
+
this.contentCreated = new EventEmitter();
|
|
352
|
+
this.showDropzones = new EventEmitter();
|
|
353
|
+
this.dropped = new EventEmitter();
|
|
354
|
+
this.showInnerDropzone = false;
|
|
355
|
+
this.showLateralDropzone = false;
|
|
356
|
+
}
|
|
357
|
+
ngAfterViewInit() {
|
|
358
|
+
assert(this.contentContainer !== undefined);
|
|
359
|
+
assert(this.contentToHost !== undefined);
|
|
360
|
+
this.hostedContent = this.contentContainer.createComponent(this.contentToHost);
|
|
361
|
+
this.contentCreated.emit(this.hostedContent.instance);
|
|
362
|
+
assert(this.dropzones !== undefined);
|
|
363
|
+
const inner = this.dropzones.get(0);
|
|
364
|
+
const lateral = this.dropzones.get(1);
|
|
365
|
+
assert(inner !== undefined && lateral !== undefined);
|
|
366
|
+
merge(inner.dropped.pipe(map(() => "inner")), lateral.dropped.pipe(map(() => "lateral"))).subscribe(this.dropped);
|
|
367
|
+
this.hostedContent.changeDetectorRef.detectChanges();
|
|
368
|
+
}
|
|
369
|
+
getHostedContent() {
|
|
370
|
+
return this.hostedContent;
|
|
371
|
+
}
|
|
372
|
+
triggerChangeDetection() {
|
|
373
|
+
if (!NgZone.isInAngularZone()) {
|
|
374
|
+
this.appRef.tick();
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
dragoverHandler(event) {
|
|
378
|
+
const elementHeight = event.currentTarget.getBoundingClientRect().height;
|
|
379
|
+
if (event.offsetY < elementHeight / 2) {
|
|
380
|
+
this.showDropzones.emit("upper");
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
this.showDropzones.emit("lower");
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
ngOnDestroy() {
|
|
387
|
+
//I'm not 100% sure why, but we have to remove any reference to the
|
|
388
|
+
//componentRef otherwise Angular will never release it for garbage
|
|
389
|
+
//collection.
|
|
390
|
+
this.hostedContent = undefined;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
BranchComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: BranchComponent, deps: [{ token: i0.ApplicationRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
394
|
+
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]", inputs: ["dragoverEventThrottle"], outputs: ["dragoverNoChangeDetect"] }] });
|
|
395
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: BranchComponent, decorators: [{
|
|
396
|
+
type: Component,
|
|
397
|
+
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"] }]
|
|
398
|
+
}], ctorParameters: function () { return [{ type: i0.ApplicationRef }]; }, propDecorators: { branchesContainer: [{
|
|
399
|
+
type: ViewChild,
|
|
400
|
+
args: ["branchesContainer", { read: ViewContainerRef }]
|
|
401
|
+
}], contentContainer: [{
|
|
402
|
+
type: ViewChild,
|
|
403
|
+
args: ["contentContainer", { read: ViewContainerRef }]
|
|
404
|
+
}], dropzones: [{
|
|
405
|
+
type: ViewChildren,
|
|
406
|
+
args: [DropzoneComponent]
|
|
407
|
+
}], contentToHost: [{
|
|
408
|
+
type: Input
|
|
409
|
+
}], contentCreated: [{
|
|
410
|
+
type: Output
|
|
411
|
+
}], showDropzones: [{
|
|
412
|
+
type: Output
|
|
413
|
+
}], dropped: [{
|
|
414
|
+
type: Output
|
|
415
|
+
}] } });
|
|
1870
416
|
|
|
1871
|
-
class
|
|
1872
|
-
constructor(
|
|
1873
|
-
this.
|
|
1874
|
-
this.
|
|
1875
|
-
this.
|
|
1876
|
-
this.
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
}
|
|
1893
|
-
|
|
1894
|
-
this.dropZone = new DropZone([], 0);
|
|
1895
|
-
this.dropZoneService.addDropZone(this.dropZone);
|
|
1896
|
-
}
|
|
1897
|
-
ngAfterViewInit() {
|
|
1898
|
-
if (this.dropZone === undefined) {
|
|
1899
|
-
throw new Error("placeholder drop zone is not defined");
|
|
1900
|
-
}
|
|
1901
|
-
this.dropZone.setHost(this.treeService.host);
|
|
1902
|
-
this.treeConstructionStatus.doneConstructing();
|
|
1903
|
-
this.changeDetectorRef.detectChanges();
|
|
1904
|
-
}
|
|
1905
|
-
dragoverHandler() {
|
|
1906
|
-
if (this.dropZone === undefined) {
|
|
1907
|
-
return;
|
|
1908
|
-
}
|
|
1909
|
-
this.dropZoneService.showDropZoneFamily(this.dropZone);
|
|
1910
|
-
}
|
|
1911
|
-
ngOnDestroy() {
|
|
1912
|
-
this.placeholderSubscription.unsubscribe();
|
|
1913
|
-
if (this.dropZone === undefined) {
|
|
1914
|
-
throw new Error("could not remove placeholder drop zone");
|
|
1915
|
-
}
|
|
1916
|
-
this.dropZoneService.removeDropZone(this.dropZone);
|
|
1917
|
-
}
|
|
1918
|
-
}
|
|
1919
|
-
LimbleTreePlaceholderComponent.ɵfac = function LimbleTreePlaceholderComponent_Factory(t) { return new (t || LimbleTreePlaceholderComponent)(i0.ɵɵdirectiveInject(DropZoneService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(TreeService), i0.ɵɵdirectiveInject(TreeConstructionStatus)); };
|
|
1920
|
-
LimbleTreePlaceholderComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: LimbleTreePlaceholderComponent, selectors: [["limble-tree-placeholder"]], decls: 2, vars: 1, consts: [[3, "dropZone"], [1, "placeholder", 3, "dragoverNoChangeDetect"]], template: function LimbleTreePlaceholderComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1921
|
-
i0.ɵɵelement(0, "drop-zone", 0);
|
|
1922
|
-
i0.ɵɵelementStart(1, "div", 1);
|
|
1923
|
-
i0.ɵɵlistener("dragoverNoChangeDetect", function LimbleTreePlaceholderComponent_Template_div_dragoverNoChangeDetect_1_listener() { return ctx.dragoverHandler(); });
|
|
1924
|
-
i0.ɵɵelementEnd();
|
|
1925
|
-
} if (rf & 2) {
|
|
1926
|
-
i0.ɵɵproperty("dropZone", ctx.dropZone);
|
|
1927
|
-
} }, dependencies: [DropZoneComponent, DragoverNoChangeDetectDirective], styles: [".placeholder[_ngcontent-%COMP%]{width:100%;height:20px}"], changeDetection: 0 });
|
|
1928
|
-
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(LimbleTreePlaceholderComponent, [{
|
|
1929
|
-
type: Component,
|
|
1930
|
-
args: [{ selector: "limble-tree-placeholder", changeDetection: ChangeDetectionStrategy.OnPush, template: "<drop-zone [dropZone]=\"dropZone\"></drop-zone>\n<div class=\"placeholder\" (dragoverNoChangeDetect)=\"dragoverHandler()\"></div>\n", styles: [".placeholder{width:100%;height:20px}\n"] }]
|
|
1931
|
-
}], function () { return [{ type: DropZoneService }, { type: i0.ChangeDetectorRef }, { type: TreeService }, { type: TreeConstructionStatus }]; }, null); })();
|
|
417
|
+
class GraftEvent {
|
|
418
|
+
constructor(source, relationship) {
|
|
419
|
+
this._source = source;
|
|
420
|
+
this._child = relationship.child;
|
|
421
|
+
this._parent = relationship.parent;
|
|
422
|
+
this._index = relationship.index;
|
|
423
|
+
}
|
|
424
|
+
child() {
|
|
425
|
+
return this._child;
|
|
426
|
+
}
|
|
427
|
+
type() {
|
|
428
|
+
return "graft";
|
|
429
|
+
}
|
|
430
|
+
index() {
|
|
431
|
+
return this._index;
|
|
432
|
+
}
|
|
433
|
+
parent() {
|
|
434
|
+
return this._parent;
|
|
435
|
+
}
|
|
436
|
+
source() {
|
|
437
|
+
return this._source;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
1932
440
|
|
|
1933
|
-
class
|
|
1934
|
-
constructor(
|
|
1935
|
-
this.
|
|
1936
|
-
this.
|
|
1937
|
-
this.
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
}
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
args: [{
|
|
1957
|
-
selector: "[dragleaveNoChangeDetect]"
|
|
1958
|
-
}]
|
|
1959
|
-
}], function () { return [{ type: i0.NgZone }, { type: i0.ElementRef }]; }, { dragleaveNoChangeDetect: [{
|
|
1960
|
-
type: Output
|
|
1961
|
-
}] }); })();
|
|
441
|
+
class PruneEvent {
|
|
442
|
+
constructor(source, relationship) {
|
|
443
|
+
this._source = source;
|
|
444
|
+
this._child = relationship.child;
|
|
445
|
+
this._parent = relationship.parent;
|
|
446
|
+
this._index = relationship.index;
|
|
447
|
+
}
|
|
448
|
+
child() {
|
|
449
|
+
return this._child;
|
|
450
|
+
}
|
|
451
|
+
type() {
|
|
452
|
+
return "prune";
|
|
453
|
+
}
|
|
454
|
+
index() {
|
|
455
|
+
return this._index;
|
|
456
|
+
}
|
|
457
|
+
parent() {
|
|
458
|
+
return this._parent;
|
|
459
|
+
}
|
|
460
|
+
source() {
|
|
461
|
+
return this._source;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
1962
464
|
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
this.
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
}
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
}
|
|
2040
|
-
event.stopPropagation();
|
|
2041
|
-
event.preventDefault();
|
|
2042
|
-
event.dataTransfer.dropEffect = "move";
|
|
2043
|
-
}
|
|
2044
|
-
dragleaveHandler(event) {
|
|
2045
|
-
const currentTarget = event.currentTarget;
|
|
2046
|
-
const relatedTarget = event.relatedTarget;
|
|
2047
|
-
if (!(currentTarget instanceof Node) ||
|
|
2048
|
-
!(relatedTarget instanceof Node) ||
|
|
2049
|
-
isElementDescendant(currentTarget, relatedTarget) !== false) {
|
|
2050
|
-
//event came from deeper in the tree. Ignore it.
|
|
2051
|
-
return;
|
|
2052
|
-
}
|
|
2053
|
-
//Mouse has left the tree, so clear the drop zones
|
|
2054
|
-
this.dropZoneService.clearVisibleZones();
|
|
2055
|
-
this.changeDetectorRef.detectChanges();
|
|
2056
|
-
}
|
|
2057
|
-
dropHandler(event) {
|
|
2058
|
-
event.stopPropagation();
|
|
2059
|
-
if (this.dragStateService.getState() !== "droppable") {
|
|
2060
|
-
return;
|
|
2061
|
-
}
|
|
2062
|
-
const sourceBranch = this.dragStateService.capture();
|
|
2063
|
-
if (sourceBranch === undefined) {
|
|
2064
|
-
throw new Error("failed to get current branch in dragendHandler");
|
|
2065
|
-
}
|
|
2066
|
-
const dropZone = this.dropZoneService.getActiveDropZone();
|
|
2067
|
-
if (dropZone === null) {
|
|
2068
|
-
throw new Error("failed to get active drop zone at drop handler");
|
|
2069
|
-
}
|
|
2070
|
-
this.treeService.captured = true;
|
|
2071
|
-
this.dragStateService.state$
|
|
2072
|
-
.pipe(first((message) => message === "idle"))
|
|
2073
|
-
.subscribe(() => {
|
|
2074
|
-
this.treeService.captured = false;
|
|
2075
|
-
});
|
|
2076
|
-
this.dropZoneService.clearVisibleZones();
|
|
2077
|
-
this.treeService.drop(sourceBranch, dropZone.getFullInsertCoordinates());
|
|
2078
|
-
}
|
|
2079
|
-
ngOnDestroy() {
|
|
2080
|
-
this.changesSubscription.unsubscribe();
|
|
2081
|
-
this.dropSubscription.unsubscribe();
|
|
2082
|
-
}
|
|
2083
|
-
}
|
|
2084
|
-
LimbleTreeRootComponent.ɵfac = function LimbleTreeRootComponent_Factory(t) { return new (t || LimbleTreeRootComponent)(i0.ɵɵdirectiveInject(TreeService), i0.ɵɵdirectiveInject(DropZoneService), i0.ɵɵdirectiveInject(DragStateService), i0.ɵɵdirectiveInject(GlobalEventsService), i0.ɵɵdirectiveInject(i0.NgZone), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.ElementRef)); };
|
|
2085
|
-
LimbleTreeRootComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: LimbleTreeRootComponent, selectors: [["limble-tree-root"]], viewQuery: function LimbleTreeRootComponent_Query(rf, ctx) { if (rf & 1) {
|
|
2086
|
-
i0.ɵɵviewQuery(_c0, 5, ViewContainerRef);
|
|
2087
|
-
} if (rf & 2) {
|
|
2088
|
-
let _t;
|
|
2089
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.host = _t.first);
|
|
2090
|
-
} }, inputs: { data: "data", options: "options", itemsPerPage: "itemsPerPage", page: "page" }, outputs: { treeChange: "treeChange", treeDrop: "treeDrop" }, features: [i0.ɵɵProvidersFeature([TreeService, DropZoneService, TreeConstructionStatus]), i0.ɵɵNgOnChangesFeature], decls: 4, vars: 1, consts: [[1, "tree-event-host", 3, "dragoverNoChangeDetect", "dragleaveNoChangeDetect", "drop"], [4, "ngIf"], ["host", ""]], template: function LimbleTreeRootComponent_Template(rf, ctx) { if (rf & 1) {
|
|
2091
|
-
i0.ɵɵelementStart(0, "div", 0);
|
|
2092
|
-
i0.ɵɵlistener("dragoverNoChangeDetect", function LimbleTreeRootComponent_Template_div_dragoverNoChangeDetect_0_listener($event) { return ctx.dragoverHandler($event); })("dragleaveNoChangeDetect", function LimbleTreeRootComponent_Template_div_dragleaveNoChangeDetect_0_listener($event) { return ctx.dragleaveHandler($event); })("drop", function LimbleTreeRootComponent_Template_div_drop_0_listener($event) { return ctx.dropHandler($event); });
|
|
2093
|
-
i0.ɵɵtemplate(1, LimbleTreeRootComponent_limble_tree_placeholder_1_Template, 1, 0, "limble-tree-placeholder", 1);
|
|
2094
|
-
i0.ɵɵtemplate(2, LimbleTreeRootComponent_ng_template_2_Template, 0, 0, "ng-template", null, 2, i0.ɵɵtemplateRefExtractor);
|
|
2095
|
-
i0.ɵɵelementEnd();
|
|
2096
|
-
} if (rf & 2) {
|
|
2097
|
-
i0.ɵɵadvance(1);
|
|
2098
|
-
i0.ɵɵproperty("ngIf", ctx.placeholder === true);
|
|
2099
|
-
} }, dependencies: [i2.NgIf, LimbleTreePlaceholderComponent, DragoverNoChangeDetectDirective, DragleaveNoChangeDetectDirective] });
|
|
2100
|
-
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(LimbleTreeRootComponent, [{
|
|
2101
|
-
type: Component,
|
|
2102
|
-
args: [{ selector: "limble-tree-root", providers: [TreeService, DropZoneService, TreeConstructionStatus], template: "<div\n (dragoverNoChangeDetect)=\"dragoverHandler($event)\"\n (dragleaveNoChangeDetect)=\"dragleaveHandler($event)\"\n (drop)=\"dropHandler($event)\"\n class=\"tree-event-host\"\n>\n <limble-tree-placeholder\n *ngIf=\"placeholder === true\"\n ></limble-tree-placeholder>\n <ng-template #host></ng-template>\n</div>\n" }]
|
|
2103
|
-
}], function () { return [{ type: TreeService }, { type: DropZoneService }, { type: DragStateService }, { type: GlobalEventsService }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, { data: [{
|
|
2104
|
-
type: Input
|
|
2105
|
-
}], options: [{
|
|
2106
|
-
type: Input
|
|
2107
|
-
}], itemsPerPage: [{
|
|
2108
|
-
type: Input
|
|
2109
|
-
}], page: [{
|
|
2110
|
-
type: Input
|
|
2111
|
-
}], host: [{
|
|
2112
|
-
type: ViewChild,
|
|
2113
|
-
args: ["host", { read: ViewContainerRef }]
|
|
2114
|
-
}], treeChange: [{
|
|
2115
|
-
type: Output
|
|
2116
|
-
}], treeDrop: [{
|
|
2117
|
-
type: Output
|
|
2118
|
-
}] }); })();
|
|
465
|
+
class TreeNodeBase {
|
|
466
|
+
constructor() {
|
|
467
|
+
this.destroyed = false;
|
|
468
|
+
this._branches = [];
|
|
469
|
+
this.events$ = new Subject();
|
|
470
|
+
this.subscriptions = [
|
|
471
|
+
this.graftsToSelf().subscribe((event) => {
|
|
472
|
+
this.registerChildRelationship(event.child(), event.index());
|
|
473
|
+
}),
|
|
474
|
+
this.prunesToSelf().subscribe((event) => {
|
|
475
|
+
this.deregisterChildRelationship(event.child());
|
|
476
|
+
})
|
|
477
|
+
];
|
|
478
|
+
}
|
|
479
|
+
branches() {
|
|
480
|
+
return [...this._branches];
|
|
481
|
+
}
|
|
482
|
+
destroy() {
|
|
483
|
+
this.branches().forEach((branch) => {
|
|
484
|
+
branch.destroy();
|
|
485
|
+
});
|
|
486
|
+
this.subscriptions.forEach((sub) => {
|
|
487
|
+
sub.unsubscribe();
|
|
488
|
+
});
|
|
489
|
+
this.destroyed = true;
|
|
490
|
+
}
|
|
491
|
+
dispatch(event) {
|
|
492
|
+
this.events$.next(event);
|
|
493
|
+
}
|
|
494
|
+
events() {
|
|
495
|
+
return this.events$;
|
|
496
|
+
}
|
|
497
|
+
getBranch(index) {
|
|
498
|
+
return this._branches[index];
|
|
499
|
+
}
|
|
500
|
+
isDestroyed() {
|
|
501
|
+
return this.destroyed;
|
|
502
|
+
}
|
|
503
|
+
plot() {
|
|
504
|
+
return new Map(this.branches().map((branch, index) => [index, branch.plot()]));
|
|
505
|
+
}
|
|
506
|
+
traverse(callback) {
|
|
507
|
+
this.branches().forEach((branch) => {
|
|
508
|
+
branch.traverse(callback);
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
deregisterChildRelationship(child) {
|
|
512
|
+
const index = this.branches().findIndex((branch) => branch === child);
|
|
513
|
+
this._branches.splice(index, 1);
|
|
514
|
+
}
|
|
515
|
+
graftsToSelf() {
|
|
516
|
+
return this.events().pipe(filter((event) => event instanceof GraftEvent), filter((event) => event.parent().events() === this.events$));
|
|
517
|
+
}
|
|
518
|
+
prunesToSelf() {
|
|
519
|
+
return this.events().pipe(filter((event) => event instanceof PruneEvent), filter((event) => event.parent().events() === this.events$));
|
|
520
|
+
}
|
|
521
|
+
registerChildRelationship(child, index) {
|
|
522
|
+
const branches = this.branches();
|
|
523
|
+
if (index < 0 || index > branches.length) {
|
|
524
|
+
throw new TreeError(`Can't register child at index ${index}. Out of range.`);
|
|
525
|
+
}
|
|
526
|
+
this._branches.splice(index, 0, child);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
class DestructionEvent {
|
|
531
|
+
constructor(source) {
|
|
532
|
+
this._source = source;
|
|
533
|
+
}
|
|
534
|
+
type() {
|
|
535
|
+
return "destruction";
|
|
536
|
+
}
|
|
537
|
+
source() {
|
|
538
|
+
return this._source;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
2119
541
|
|
|
2120
|
-
class
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
542
|
+
class RootComponent {
|
|
543
|
+
constructor() {
|
|
544
|
+
this.branchesContainer = undefined;
|
|
545
|
+
this.dropzone = undefined;
|
|
546
|
+
this.afterViewInit = new EventEmitter();
|
|
547
|
+
this.dropped = new EventEmitter();
|
|
548
|
+
this.showInnerDropzone = false;
|
|
549
|
+
}
|
|
550
|
+
ngAfterViewInit() {
|
|
551
|
+
this.afterViewInit.emit();
|
|
552
|
+
assert(this.dropzone !== undefined);
|
|
553
|
+
this.dropzone.dropped.subscribe(this.dropped);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
RootComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RootComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
557
|
+
RootComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", 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"] }] });
|
|
558
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RootComponent, decorators: [{
|
|
559
|
+
type: Component,
|
|
560
|
+
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"] }]
|
|
561
|
+
}], propDecorators: { branchesContainer: [{
|
|
562
|
+
type: ViewChild,
|
|
563
|
+
args: ["branchesContainer", { read: ViewContainerRef }]
|
|
564
|
+
}], dropzone: [{
|
|
565
|
+
type: ViewChild,
|
|
566
|
+
args: [DropzoneComponent]
|
|
567
|
+
}], afterViewInit: [{
|
|
568
|
+
type: Output
|
|
569
|
+
}], dropped: [{
|
|
570
|
+
type: Output
|
|
571
|
+
}] } });
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* A wrapper around the BranchComponent that helps instantiate it and handles its events.
|
|
575
|
+
*/
|
|
576
|
+
class RootController {
|
|
577
|
+
constructor(treeRoot, viewContainerRef) {
|
|
578
|
+
this.treeRoot = treeRoot;
|
|
579
|
+
this.rootComponentRef = viewContainerRef.createComponent(RootComponent);
|
|
580
|
+
const viewInitSub = this.rootComponentRef.instance.afterViewInit.subscribe(() => {
|
|
581
|
+
const dropzone = this.rootComponentRef.instance.dropzone;
|
|
582
|
+
assert(dropzone !== undefined);
|
|
583
|
+
dropzoneRenderer.registerDropzone(dropzone, this.treeRoot);
|
|
584
|
+
});
|
|
585
|
+
const droppedSub = this.rootComponentRef.instance.dropped.subscribe(() => {
|
|
586
|
+
dropzoneRenderer.handleDrop(this.treeRoot, "inner");
|
|
587
|
+
});
|
|
588
|
+
this.instanceSubscriptions = [viewInitSub, droppedSub];
|
|
589
|
+
}
|
|
590
|
+
destroy() {
|
|
591
|
+
this.instanceSubscriptions.forEach((sub) => {
|
|
592
|
+
sub.unsubscribe();
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
detectChanges() {
|
|
596
|
+
this.rootComponentRef.changeDetectorRef.detectChanges();
|
|
597
|
+
}
|
|
598
|
+
getBranchesContainer() {
|
|
599
|
+
return this.rootComponentRef.instance.branchesContainer;
|
|
600
|
+
}
|
|
601
|
+
getComponentInstance() {
|
|
602
|
+
return this.rootComponentRef.instance;
|
|
603
|
+
}
|
|
604
|
+
getHostView() {
|
|
605
|
+
return this.rootComponentRef.hostView;
|
|
606
|
+
}
|
|
607
|
+
getNativeElement() {
|
|
608
|
+
return this.rootComponentRef.location.nativeElement;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
class TreeRoot {
|
|
613
|
+
constructor(viewContainerRef) {
|
|
614
|
+
this.viewContainerRef = viewContainerRef;
|
|
615
|
+
this.treeNodeBase = new TreeNodeBase();
|
|
616
|
+
this.rootController = new RootController(this, viewContainerRef);
|
|
617
|
+
this.detectChanges();
|
|
618
|
+
}
|
|
619
|
+
branches() {
|
|
620
|
+
return this.treeNodeBase.branches();
|
|
621
|
+
}
|
|
622
|
+
destroy() {
|
|
623
|
+
if (this.isDestroyed()) {
|
|
624
|
+
throw new TreeError("Cannot destroy a destroyed tree root");
|
|
625
|
+
}
|
|
626
|
+
dropzoneRenderer.clearTreeFromRegistry(this);
|
|
627
|
+
this.treeNodeBase.destroy();
|
|
628
|
+
this.rootController.destroy();
|
|
629
|
+
this.viewContainerRef.clear();
|
|
630
|
+
config.delete(this);
|
|
631
|
+
this.dispatch(new DestructionEvent(this));
|
|
632
|
+
}
|
|
633
|
+
detectChanges() {
|
|
634
|
+
this.rootController.detectChanges();
|
|
635
|
+
}
|
|
636
|
+
dispatch(event) {
|
|
637
|
+
this.treeNodeBase.dispatch(event);
|
|
638
|
+
}
|
|
639
|
+
events() {
|
|
640
|
+
return this.treeNodeBase.events();
|
|
641
|
+
}
|
|
642
|
+
getBranch(index) {
|
|
643
|
+
return this.treeNodeBase.getBranch(index);
|
|
644
|
+
}
|
|
645
|
+
getBranchesContainer() {
|
|
646
|
+
if (this.isDestroyed()) {
|
|
647
|
+
throw new TreeError("Cannot get branches container from a destroyed tree root");
|
|
648
|
+
}
|
|
649
|
+
return this.rootController.getBranchesContainer();
|
|
650
|
+
}
|
|
651
|
+
getComponentInstance() {
|
|
652
|
+
if (this.isDestroyed()) {
|
|
653
|
+
throw new TreeError("Cannot get component instance from a destroyed tree root");
|
|
654
|
+
}
|
|
655
|
+
return this.rootController.getComponentInstance();
|
|
656
|
+
}
|
|
657
|
+
getHostView() {
|
|
658
|
+
if (this.isDestroyed()) {
|
|
659
|
+
throw new TreeError("Cannot get component host view from a destroyed tree root");
|
|
660
|
+
}
|
|
661
|
+
return this.rootController.getHostView();
|
|
662
|
+
}
|
|
663
|
+
getNativeElement() {
|
|
664
|
+
if (this.isDestroyed()) {
|
|
665
|
+
throw new TreeError("Cannot get native element from a destroyed tree root");
|
|
666
|
+
}
|
|
667
|
+
return this.rootController.getNativeElement();
|
|
668
|
+
}
|
|
669
|
+
grow(component, options) {
|
|
670
|
+
if (this.isDestroyed()) {
|
|
671
|
+
throw new TreeError("Cannot grow a branch on a destroyed tree root");
|
|
672
|
+
}
|
|
673
|
+
return new TreeBranch(this, { component, ...options });
|
|
674
|
+
}
|
|
675
|
+
isDestroyed() {
|
|
676
|
+
return this.treeNodeBase.isDestroyed();
|
|
677
|
+
}
|
|
678
|
+
plot() {
|
|
679
|
+
return this.treeNodeBase.plot();
|
|
680
|
+
}
|
|
681
|
+
root() {
|
|
682
|
+
return this;
|
|
683
|
+
}
|
|
684
|
+
traverse(callback) {
|
|
685
|
+
callback(this);
|
|
686
|
+
this.treeNodeBase.traverse(callback);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
class TreeService {
|
|
691
|
+
createEmptyTree(container, options = {}) {
|
|
692
|
+
container.clear();
|
|
693
|
+
const root = new TreeRoot(container);
|
|
694
|
+
config.setConfig(root, options);
|
|
695
|
+
return root;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
TreeService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
699
|
+
TreeService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeService, providedIn: "root" });
|
|
700
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeService, decorators: [{
|
|
701
|
+
type: Injectable,
|
|
702
|
+
args: [{ providedIn: "root" }]
|
|
703
|
+
}] });
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* A wrapper around the BranchComponent that helps instantiate it and handles its events.
|
|
707
|
+
*/
|
|
708
|
+
class BranchController {
|
|
709
|
+
constructor(treeBranch, parentBranchesContainer) {
|
|
710
|
+
this.treeBranch = treeBranch;
|
|
711
|
+
this.outputBindingSubscriptions = [];
|
|
712
|
+
this.branchComponentRef = createComponent(BranchComponent, {
|
|
713
|
+
environmentInjector: parentBranchesContainer.injector.get(EnvironmentInjector)
|
|
714
|
+
});
|
|
715
|
+
this.branchComponentRef.instance.contentToHost =
|
|
716
|
+
this.treeBranch.branchOptions.component;
|
|
717
|
+
this.instanceSubscriptions = this.getInstanceSubscriptions(this.branchComponentRef.instance);
|
|
718
|
+
}
|
|
719
|
+
destroy() {
|
|
720
|
+
this.instanceSubscriptions.forEach((sub) => {
|
|
721
|
+
sub.unsubscribe();
|
|
722
|
+
});
|
|
723
|
+
this.outputBindingSubscriptions.forEach((sub) => {
|
|
724
|
+
sub.unsubscribe();
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
detectChanges() {
|
|
728
|
+
this.branchComponentRef.changeDetectorRef.detectChanges();
|
|
729
|
+
}
|
|
730
|
+
getBranchesContainer() {
|
|
731
|
+
return this.branchComponentRef.instance.branchesContainer;
|
|
732
|
+
}
|
|
733
|
+
getComponentInstance() {
|
|
734
|
+
return this.branchComponentRef.instance;
|
|
735
|
+
}
|
|
736
|
+
getHostView() {
|
|
737
|
+
return this.branchComponentRef.hostView;
|
|
738
|
+
}
|
|
739
|
+
getNativeElement() {
|
|
740
|
+
return this.branchComponentRef.location.nativeElement;
|
|
741
|
+
}
|
|
742
|
+
getUserlandComponentRef() {
|
|
743
|
+
return this.branchComponentRef.instance.getHostedContent();
|
|
744
|
+
}
|
|
745
|
+
getContentCreatedSub(instance) {
|
|
746
|
+
return instance.contentCreated.subscribe((userlandComponentInstance) => {
|
|
747
|
+
const component = userlandComponentInstance;
|
|
748
|
+
Object.entries(this.treeBranch.branchOptions.inputBindings ?? {}).forEach(([key, value]) => {
|
|
749
|
+
component[key] = value;
|
|
750
|
+
});
|
|
751
|
+
Object.entries(this.treeBranch.branchOptions.outputBindings ?? {}).forEach(([key, value]) => {
|
|
752
|
+
this.outputBindingSubscriptions.push(component[key].subscribe(value));
|
|
753
|
+
});
|
|
754
|
+
component.treeBranch = this.treeBranch;
|
|
755
|
+
const dropzones = instance.dropzones;
|
|
756
|
+
assert(dropzones !== undefined);
|
|
757
|
+
dropzoneRenderer.registerDropzones(dropzones, this.treeBranch);
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
getInstanceSubscriptions(instance) {
|
|
761
|
+
const droppedSub = instance.dropped.subscribe((placement) => {
|
|
762
|
+
dropzoneRenderer.handleDrop(this.treeBranch, placement);
|
|
763
|
+
});
|
|
764
|
+
return [
|
|
765
|
+
this.getContentCreatedSub(instance),
|
|
766
|
+
this.getShowLowerZonesSub(instance),
|
|
767
|
+
this.getShowUpperZonesSub(instance),
|
|
768
|
+
droppedSub
|
|
769
|
+
];
|
|
770
|
+
}
|
|
771
|
+
getShowLowerZonesSub(instance) {
|
|
772
|
+
return instance.showDropzones
|
|
773
|
+
.pipe(filter((direction) => direction === "lower"))
|
|
774
|
+
.subscribe(() => {
|
|
775
|
+
const currentDropzoneDisplayed = dropzoneRenderer.getCurrentDisplay();
|
|
776
|
+
if (currentDropzoneDisplayed?.treeBranch === this.treeBranch &&
|
|
777
|
+
currentDropzoneDisplayed.direction === "lower") {
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
dropzoneRenderer.showLowerZones(this.treeBranch);
|
|
781
|
+
instance.triggerChangeDetection();
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
getShowUpperZonesSub(instance) {
|
|
785
|
+
return instance.showDropzones
|
|
786
|
+
.pipe(filter((direction) => direction === "upper"))
|
|
787
|
+
.subscribe(() => {
|
|
788
|
+
const currentDropzoneDisplayed = dropzoneRenderer.getCurrentDisplay();
|
|
789
|
+
if (currentDropzoneDisplayed?.treeBranch === this.treeBranch &&
|
|
790
|
+
currentDropzoneDisplayed.direction === "upper") {
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
dropzoneRenderer.showUpperZones(this.treeBranch);
|
|
794
|
+
instance.triggerChangeDetection();
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
class TreeBranch {
|
|
800
|
+
constructor(parent, branchOptions) {
|
|
801
|
+
this.branchOptions = branchOptions;
|
|
802
|
+
this.detachedView = null;
|
|
803
|
+
this.treeNodeBase = new TreeNodeBase();
|
|
804
|
+
const parentBranchesContainer = parent.getBranchesContainer();
|
|
805
|
+
assert(parentBranchesContainer !== undefined);
|
|
806
|
+
this.branchController = new BranchController(this, parentBranchesContainer);
|
|
807
|
+
this.setIndentation(parent);
|
|
808
|
+
if (parent instanceof TreeBranch &&
|
|
809
|
+
parent.branchOptions.defaultCollapsed === true) {
|
|
810
|
+
treeCollapser.storePrecollapsedNode(parent, this);
|
|
811
|
+
this.detachedView = this.branchController.getHostView();
|
|
812
|
+
}
|
|
813
|
+
else {
|
|
814
|
+
parentBranchesContainer.insert(this.branchController.getHostView());
|
|
815
|
+
this.detectChanges();
|
|
816
|
+
this._parent = parent;
|
|
817
|
+
this.dispatch(new GraftEvent(this, {
|
|
818
|
+
parent: this._parent,
|
|
819
|
+
child: this,
|
|
820
|
+
index: this._parent.branches().length
|
|
821
|
+
}));
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
branches() {
|
|
825
|
+
return this.treeNodeBase.branches();
|
|
826
|
+
}
|
|
827
|
+
destroy() {
|
|
828
|
+
if (this.isDestroyed()) {
|
|
829
|
+
throw new TreeError("Cannot destroy a destroyed tree branch");
|
|
830
|
+
}
|
|
831
|
+
this.prune();
|
|
832
|
+
treeCollapser.expand(this);
|
|
833
|
+
dropzoneRenderer.clearTreeFromRegistry(this);
|
|
834
|
+
this.branchController.getHostView().destroy();
|
|
835
|
+
this.treeNodeBase.destroy();
|
|
836
|
+
this.branchController.destroy();
|
|
837
|
+
this.dispatch(new DestructionEvent(this));
|
|
838
|
+
}
|
|
839
|
+
detectChanges() {
|
|
840
|
+
this.branchController.detectChanges();
|
|
841
|
+
}
|
|
842
|
+
dispatch(event) {
|
|
843
|
+
this.treeNodeBase.dispatch(event);
|
|
844
|
+
this._parent?.dispatch(event);
|
|
845
|
+
}
|
|
846
|
+
events() {
|
|
847
|
+
return this.treeNodeBase.events();
|
|
848
|
+
}
|
|
849
|
+
getBranch(index) {
|
|
850
|
+
return this.treeNodeBase.getBranch(index);
|
|
851
|
+
}
|
|
852
|
+
getBranchesContainer() {
|
|
853
|
+
if (this.isDestroyed()) {
|
|
854
|
+
throw new TreeError("Cannot get branches container from a destroyed tree branch");
|
|
855
|
+
}
|
|
856
|
+
return this.branchController.getBranchesContainer();
|
|
857
|
+
}
|
|
858
|
+
getComponentInstance() {
|
|
859
|
+
if (this.isDestroyed()) {
|
|
860
|
+
throw new TreeError("Cannot get component instance from a destroyed tree branch");
|
|
861
|
+
}
|
|
862
|
+
return this.branchController.getComponentInstance();
|
|
863
|
+
}
|
|
864
|
+
getHostView() {
|
|
865
|
+
if (this.isDestroyed()) {
|
|
866
|
+
throw new TreeError("Cannot get component host view from a destroyed tree branch");
|
|
867
|
+
}
|
|
868
|
+
return this.branchController.getHostView();
|
|
869
|
+
}
|
|
870
|
+
getNativeElement() {
|
|
871
|
+
if (this.isDestroyed()) {
|
|
872
|
+
throw new TreeError("Cannot get native element from a destroyed tree branch");
|
|
873
|
+
}
|
|
874
|
+
return this.branchController.getNativeElement();
|
|
875
|
+
}
|
|
876
|
+
getUserlandComponentRef() {
|
|
877
|
+
if (this.isDestroyed()) {
|
|
878
|
+
throw new TreeError("Cannot get userland component from a destroyed tree branch");
|
|
879
|
+
}
|
|
880
|
+
return this.branchController.getUserlandComponentRef();
|
|
881
|
+
}
|
|
882
|
+
graftTo(newParent, index) {
|
|
883
|
+
this.checkGraftLocationValidity(newParent, index);
|
|
884
|
+
const ownIndex = this.index();
|
|
885
|
+
if (ownIndex !== undefined) {
|
|
886
|
+
this.prune();
|
|
887
|
+
}
|
|
888
|
+
this._parent = newParent;
|
|
889
|
+
const newIndex = index ?? newParent.branches().length;
|
|
890
|
+
this.reattachView(newIndex);
|
|
891
|
+
this.dispatch(new GraftEvent(this, {
|
|
892
|
+
parent: newParent,
|
|
893
|
+
child: this,
|
|
894
|
+
index: newIndex
|
|
895
|
+
}));
|
|
896
|
+
return newIndex;
|
|
897
|
+
}
|
|
898
|
+
grow(component, options) {
|
|
899
|
+
if (this.isDestroyed()) {
|
|
900
|
+
throw new TreeError("Cannot grow a branch on a destroyed tree branch");
|
|
901
|
+
}
|
|
902
|
+
return new TreeBranch(this, { component, ...options });
|
|
903
|
+
}
|
|
904
|
+
index() {
|
|
905
|
+
if (!this._parent) {
|
|
906
|
+
return undefined;
|
|
907
|
+
}
|
|
908
|
+
const index = this._parent
|
|
909
|
+
.branches()
|
|
910
|
+
.findIndex((branch) => branch === this);
|
|
911
|
+
assert(index >= 0);
|
|
912
|
+
return index;
|
|
913
|
+
}
|
|
914
|
+
isDestroyed() {
|
|
915
|
+
return this.treeNodeBase.isDestroyed();
|
|
916
|
+
}
|
|
917
|
+
meta() {
|
|
918
|
+
return this.branchOptions.meta ?? {};
|
|
919
|
+
}
|
|
920
|
+
parent() {
|
|
921
|
+
return this._parent;
|
|
922
|
+
}
|
|
923
|
+
plot() {
|
|
924
|
+
return this.treeNodeBase.plot();
|
|
925
|
+
}
|
|
926
|
+
position() {
|
|
927
|
+
const index = this.index();
|
|
928
|
+
if (index === undefined) {
|
|
929
|
+
throw new TreeError("branch has no parent. Position cannot be determined.");
|
|
930
|
+
}
|
|
931
|
+
if (this._parent instanceof TreeBranch) {
|
|
932
|
+
const parentPosition = this._parent.position();
|
|
933
|
+
return [...parentPosition, index];
|
|
934
|
+
}
|
|
935
|
+
return [index];
|
|
936
|
+
}
|
|
937
|
+
prune() {
|
|
938
|
+
if (this.isDestroyed()) {
|
|
939
|
+
throw new TreeError("Cannot prune a destroyed tree branch");
|
|
940
|
+
}
|
|
941
|
+
const parent = this._parent;
|
|
942
|
+
const index = this.index();
|
|
943
|
+
if (index === undefined || parent === undefined)
|
|
944
|
+
return;
|
|
945
|
+
const container = parent.getBranchesContainer();
|
|
946
|
+
assert(container !== undefined);
|
|
947
|
+
this.detachedView = container.detach(index);
|
|
948
|
+
assert(this.detachedView !== null);
|
|
949
|
+
this.detachedView.detach();
|
|
950
|
+
this.dispatch(new PruneEvent(this, {
|
|
951
|
+
parent: parent,
|
|
952
|
+
child: this,
|
|
953
|
+
index: index
|
|
954
|
+
}));
|
|
955
|
+
this._parent = undefined;
|
|
956
|
+
return this;
|
|
957
|
+
}
|
|
958
|
+
root() {
|
|
959
|
+
const parent = this.parent();
|
|
960
|
+
if (parent instanceof TreeBranch) {
|
|
961
|
+
return parent.root();
|
|
962
|
+
}
|
|
963
|
+
assert(parent instanceof TreeRoot || parent === undefined);
|
|
964
|
+
return parent;
|
|
965
|
+
}
|
|
966
|
+
traverse(callback) {
|
|
967
|
+
callback(this);
|
|
968
|
+
this.treeNodeBase.traverse(callback);
|
|
969
|
+
}
|
|
970
|
+
checkGraftLocationValidity(newParent, index) {
|
|
971
|
+
if (this.isDestroyed()) {
|
|
972
|
+
throw new TreeError("Cannot graft a destroyed tree branch");
|
|
973
|
+
}
|
|
974
|
+
if (newParent.isDestroyed()) {
|
|
975
|
+
throw new TreeError("Cannot graft to a destroyed tree branch");
|
|
976
|
+
}
|
|
977
|
+
if (typeof index === "number" &&
|
|
978
|
+
this.indexIsOutOfRange(newParent, index)) {
|
|
979
|
+
throw new TreeError(`Cannot graft branch at index ${index} of the parent. Out of range.`);
|
|
980
|
+
}
|
|
981
|
+
this.traverse((node) => {
|
|
982
|
+
if (node === newParent) {
|
|
983
|
+
throw new TreeError("Cannot graft a branch to itself or any of its own descendants");
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
indexIsOutOfRange(parent, index) {
|
|
988
|
+
return index < 0 || index > parent.branches().length;
|
|
989
|
+
}
|
|
990
|
+
reattachView(index) {
|
|
991
|
+
assert(this._parent !== undefined);
|
|
992
|
+
assert(this.detachedView !== null);
|
|
993
|
+
const container = this._parent.getBranchesContainer();
|
|
994
|
+
assert(container !== undefined);
|
|
995
|
+
this.detachedView.reattach();
|
|
996
|
+
container.insert(this.detachedView, index);
|
|
997
|
+
this.detachedView = null;
|
|
998
|
+
}
|
|
999
|
+
setIndentation(parent) {
|
|
1000
|
+
const root = parent.root();
|
|
1001
|
+
assert(root !== undefined);
|
|
1002
|
+
const options = config.getConfig(root);
|
|
1003
|
+
const branchesContainerEl = this.branchController
|
|
1004
|
+
.getNativeElement()
|
|
1005
|
+
.getElementsByClassName("branches-container")
|
|
1006
|
+
.item(0);
|
|
1007
|
+
assert(branchesContainerEl instanceof HTMLElement);
|
|
1008
|
+
branchesContainerEl.style.marginLeft = `${options?.indentation ?? 16}px`;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
class DropzoneRenderer {
|
|
1013
|
+
constructor() {
|
|
1014
|
+
this.registry = new Map();
|
|
1015
|
+
this.currentDisplay = null;
|
|
1016
|
+
dragAndDrop.dragAborted$.subscribe(() => {
|
|
1017
|
+
this.clearCurrentDisplay();
|
|
1018
|
+
});
|
|
1019
|
+
dragState
|
|
1020
|
+
.events()
|
|
1021
|
+
.pipe(filter((event) => event === DragStates.Starting))
|
|
1022
|
+
.subscribe(() => {
|
|
1023
|
+
const branch = dragState.getDragData();
|
|
1024
|
+
assert(branch !== undefined);
|
|
1025
|
+
let cursor = branch.parent()?.getBranch((branch.index() ?? 0) - 1);
|
|
1026
|
+
let final = branch.parent();
|
|
1027
|
+
while (cursor !== undefined) {
|
|
1028
|
+
final = cursor;
|
|
1029
|
+
cursor = cursor.branches().at(-1);
|
|
1030
|
+
}
|
|
1031
|
+
branch
|
|
1032
|
+
.events()
|
|
1033
|
+
.pipe(filter((event) => event instanceof PruneEvent), first())
|
|
1034
|
+
.subscribe(() => {
|
|
1035
|
+
assert(final instanceof TreeBranch || final instanceof TreeRoot);
|
|
1036
|
+
this.showLowerZones(final);
|
|
1037
|
+
});
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
clearCurrentDisplay() {
|
|
1041
|
+
if (this.currentDisplay === null)
|
|
1042
|
+
return;
|
|
1043
|
+
for (const branch of this.registry.values()) {
|
|
1044
|
+
const instance = branch.getComponentInstance();
|
|
1045
|
+
instance.showInnerDropzone = false;
|
|
1046
|
+
if (instance instanceof BranchComponent) {
|
|
1047
|
+
instance.showLateralDropzone = false;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
this.currentDisplay = null;
|
|
1051
|
+
}
|
|
1052
|
+
clearTreeFromRegistry(tree) {
|
|
1053
|
+
const nodes = [];
|
|
1054
|
+
tree.traverse((node) => nodes.push(node));
|
|
1055
|
+
for (const [dropzoneComponent, treeNode] of this.registry) {
|
|
1056
|
+
if (nodes.includes(treeNode)) {
|
|
1057
|
+
this.registry.delete(dropzoneComponent);
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
getCurrentDisplay() {
|
|
1062
|
+
if (this.currentDisplay === null)
|
|
1063
|
+
return null;
|
|
1064
|
+
return { ...this.currentDisplay };
|
|
1065
|
+
}
|
|
1066
|
+
getDropzoneLocation(dropzone) {
|
|
1067
|
+
const branch = this.registry.get(dropzone);
|
|
1068
|
+
const placement = dropzone.placement;
|
|
1069
|
+
if (branch === undefined) {
|
|
1070
|
+
throw new Error("dropzone not found in registry");
|
|
1071
|
+
}
|
|
1072
|
+
if (placement === undefined) {
|
|
1073
|
+
throw new Error("dropzone has an undefined placement");
|
|
1074
|
+
}
|
|
1075
|
+
return [branch, placement];
|
|
1076
|
+
}
|
|
1077
|
+
handleDrop(treeNode, placement) {
|
|
1078
|
+
if (placement === "inner") {
|
|
1079
|
+
dragAndDrop.drop(treeNode, 0);
|
|
1080
|
+
}
|
|
1081
|
+
else if (treeNode instanceof TreeBranch && placement === "lateral") {
|
|
1082
|
+
const currentParent = treeNode.parent();
|
|
1083
|
+
const index = treeNode.index();
|
|
1084
|
+
if (currentParent === undefined || index === undefined) {
|
|
1085
|
+
throw new Error("branch must have a parent");
|
|
1086
|
+
}
|
|
1087
|
+
dragAndDrop.drop(currentParent, index + 1);
|
|
1088
|
+
}
|
|
1089
|
+
this.clearCurrentDisplay();
|
|
1090
|
+
}
|
|
1091
|
+
registerDropzone(dropzone, treeNode) {
|
|
1092
|
+
this.registry.set(dropzone, treeNode);
|
|
1093
|
+
}
|
|
1094
|
+
registerDropzones(dropzones, treeBranch) {
|
|
1095
|
+
for (const dropzone of dropzones) {
|
|
1096
|
+
this.registry.set(dropzone, treeBranch);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
showLowerZones(treeNode) {
|
|
1100
|
+
this.clearCurrentDisplay();
|
|
1101
|
+
this.showInnerZone(treeNode);
|
|
1102
|
+
if (treeNode.branches().length === 0) {
|
|
1103
|
+
this.loopThroughLowerZones(treeNode);
|
|
1104
|
+
}
|
|
1105
|
+
this.currentDisplay = { treeBranch: treeNode, direction: "lower" };
|
|
1106
|
+
}
|
|
1107
|
+
showUpperZones(treeBranch) {
|
|
1108
|
+
this.clearCurrentDisplay();
|
|
1109
|
+
this.loopThroughUpperZones(treeBranch);
|
|
1110
|
+
this.currentDisplay = { treeBranch, direction: "upper" };
|
|
1111
|
+
}
|
|
1112
|
+
loopThroughLowerZones(treeNode) {
|
|
1113
|
+
let cursor = treeNode;
|
|
1114
|
+
while (cursor instanceof TreeBranch) {
|
|
1115
|
+
this.showLateralZone(cursor);
|
|
1116
|
+
const parent = cursor.parent();
|
|
1117
|
+
const index = cursor.index();
|
|
1118
|
+
assert(parent !== undefined && index !== undefined);
|
|
1119
|
+
if (parent.branches().length > index + 1) {
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
cursor = cursor.parent();
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
loopThroughUpperZones(treeBranch) {
|
|
1126
|
+
let cursor = treeBranch
|
|
1127
|
+
.parent()
|
|
1128
|
+
?.getBranch((treeBranch.index() ?? 0) - 1);
|
|
1129
|
+
let final = treeBranch.parent();
|
|
1130
|
+
while (cursor !== undefined) {
|
|
1131
|
+
this.showLateralZone(cursor);
|
|
1132
|
+
final = cursor;
|
|
1133
|
+
cursor = cursor.branches().at(-1);
|
|
1134
|
+
}
|
|
1135
|
+
if (final !== undefined &&
|
|
1136
|
+
(final instanceof TreeRoot || final instanceof TreeBranch)) {
|
|
1137
|
+
this.showInnerZone(final);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
nestingAllowed(treeNode) {
|
|
1141
|
+
if (treeNode instanceof TreeRoot) {
|
|
1142
|
+
return true;
|
|
1143
|
+
}
|
|
1144
|
+
if (treeNode instanceof TreeBranch) {
|
|
1145
|
+
const allowNesting = config.getConfig(treeNode.root())?.dragAndDrop?.allowNesting ??
|
|
1146
|
+
(() => true);
|
|
1147
|
+
return allowNesting(treeNode);
|
|
1148
|
+
}
|
|
1149
|
+
throw new Error("unsupported treeNode type");
|
|
1150
|
+
}
|
|
1151
|
+
dropAllowed(parent, index) {
|
|
1152
|
+
const sourceNode = dragState.getDragData();
|
|
1153
|
+
assert(sourceNode instanceof TreeBranch);
|
|
1154
|
+
if (parent instanceof TreeRoot) {
|
|
1155
|
+
const allowDrop = config.getConfig(parent)?.dragAndDrop?.allowDrop ??
|
|
1156
|
+
(() => true);
|
|
1157
|
+
return allowDrop(sourceNode, parent, index);
|
|
1158
|
+
}
|
|
1159
|
+
if (parent instanceof TreeBranch) {
|
|
1160
|
+
const allowDrop = config.getConfig(parent.root())?.dragAndDrop?.allowDrop ??
|
|
1161
|
+
(() => true);
|
|
1162
|
+
return allowDrop(sourceNode, parent, index);
|
|
1163
|
+
}
|
|
1164
|
+
throw new Error("unsupported treeNode type");
|
|
1165
|
+
}
|
|
1166
|
+
showInnerZone(treeNode) {
|
|
1167
|
+
if (!this.nestingAllowed(treeNode) || !this.dropAllowed(treeNode, 0))
|
|
1168
|
+
return;
|
|
1169
|
+
treeNode.getComponentInstance().showInnerDropzone = true;
|
|
1170
|
+
}
|
|
1171
|
+
showLateralZone(treeBranch) {
|
|
1172
|
+
const index = treeBranch.index();
|
|
1173
|
+
assert(index !== undefined);
|
|
1174
|
+
if (!this.dropAllowed(treeBranch.parent(), index + 1))
|
|
1175
|
+
return;
|
|
1176
|
+
treeBranch.getComponentInstance().showLateralDropzone = true;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
const dropzoneRenderer = new DropzoneRenderer();
|
|
1180
|
+
|
|
1181
|
+
class TreeDragAndDropService {
|
|
1182
|
+
clearDropzones() {
|
|
1183
|
+
dropzoneRenderer.clearCurrentDisplay();
|
|
1184
|
+
}
|
|
1185
|
+
dragStart(treeBranch, event) {
|
|
1186
|
+
dragAndDrop.dragStart(treeBranch, event);
|
|
1187
|
+
}
|
|
1188
|
+
getCurrentlyDisplayedDropzoneFamily() {
|
|
1189
|
+
return dropzoneRenderer.getCurrentDisplay();
|
|
1190
|
+
}
|
|
1191
|
+
showRootDropzone(root) {
|
|
1192
|
+
dropzoneRenderer.showLowerZones(root);
|
|
1193
|
+
}
|
|
1194
|
+
state() {
|
|
1195
|
+
return dragState.events();
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
TreeDragAndDropService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeDragAndDropService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1199
|
+
TreeDragAndDropService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeDragAndDropService });
|
|
1200
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeDragAndDropService, decorators: [{
|
|
1201
|
+
type: Injectable
|
|
1202
|
+
}] });
|
|
1203
|
+
|
|
1204
|
+
class DraggableDirective {
|
|
1205
|
+
constructor(dragAndDropService, renderer, hostElement) {
|
|
1206
|
+
this.dragAndDropService = dragAndDropService;
|
|
1207
|
+
renderer.setAttribute(hostElement.nativeElement, "draggable", "true");
|
|
1208
|
+
renderer.setStyle(hostElement.nativeElement, "cursor", "grab");
|
|
1209
|
+
}
|
|
1210
|
+
onDragstart(event) {
|
|
1211
|
+
if (this.limbleTreeDraggable === undefined)
|
|
1212
|
+
return;
|
|
1213
|
+
this.dragAndDropService.dragStart(this.limbleTreeDraggable, event);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
DraggableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: DraggableDirective, deps: [{ token: TreeDragAndDropService }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1217
|
+
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 });
|
|
1218
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: DraggableDirective, decorators: [{
|
|
1219
|
+
type: Directive,
|
|
1220
|
+
args: [{
|
|
1221
|
+
selector: "[limbleTreeDraggable]",
|
|
1222
|
+
standalone: true
|
|
1223
|
+
}]
|
|
1224
|
+
}], ctorParameters: function () { return [{ type: TreeDragAndDropService }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; }, propDecorators: { limbleTreeDraggable: [{
|
|
1225
|
+
type: Input
|
|
1226
|
+
}], onDragstart: [{
|
|
1227
|
+
type: HostListener,
|
|
1228
|
+
args: ["dragstart", ["$event"]]
|
|
1229
|
+
}] } });
|
|
1230
|
+
|
|
1231
|
+
class TreeDragAndDropModule {
|
|
1232
|
+
}
|
|
1233
|
+
TreeDragAndDropModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeDragAndDropModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1234
|
+
TreeDragAndDropModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.12", ngImport: i0, type: TreeDragAndDropModule, imports: [DraggableDirective, DragoverNoChangeDetectDirective], exports: [DraggableDirective, DragoverNoChangeDetectDirective] });
|
|
1235
|
+
TreeDragAndDropModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeDragAndDropModule, providers: [TreeDragAndDropService] });
|
|
1236
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TreeDragAndDropModule, decorators: [{
|
|
1237
|
+
type: NgModule,
|
|
1238
|
+
args: [{
|
|
1239
|
+
imports: [DraggableDirective, DragoverNoChangeDetectDirective],
|
|
1240
|
+
providers: [TreeDragAndDropService],
|
|
1241
|
+
exports: [DraggableDirective, DragoverNoChangeDetectDirective]
|
|
1242
|
+
}]
|
|
1243
|
+
}] });
|
|
1244
|
+
|
|
1245
|
+
/**
|
|
1246
|
+
* A shim to help with the transition from v0 to v1.
|
|
1247
|
+
* @deprecated
|
|
1248
|
+
*/
|
|
1249
|
+
class LegacyTree {
|
|
1250
|
+
/** Creates a v1 tree structure from a v0 data array and v0 tree options. */
|
|
1251
|
+
createTreeFromLegacyArray(container, data, treeOptions = {}) {
|
|
1252
|
+
const root = new TreeRoot(container);
|
|
1253
|
+
config.setConfig(root, this.upgradeOptions(treeOptions));
|
|
1254
|
+
for (const node of data) {
|
|
1255
|
+
this.renderTreeNode(root, node, treeOptions);
|
|
1256
|
+
}
|
|
1257
|
+
return root;
|
|
1258
|
+
}
|
|
1259
|
+
upgradeOptions(legacyOptions) {
|
|
1260
|
+
return {
|
|
1261
|
+
indentation: legacyOptions.indent,
|
|
1262
|
+
dragAndDrop: {
|
|
1263
|
+
allowNesting: (branch) => {
|
|
1264
|
+
if (legacyOptions.listMode === true) {
|
|
1265
|
+
return false;
|
|
1266
|
+
}
|
|
1267
|
+
if (legacyOptions.allowNesting === undefined) {
|
|
1268
|
+
return true;
|
|
1269
|
+
}
|
|
1270
|
+
if (typeof legacyOptions.allowNesting === "boolean") {
|
|
1271
|
+
return legacyOptions.allowNesting;
|
|
1272
|
+
}
|
|
1273
|
+
return legacyOptions.allowNesting(branch);
|
|
1274
|
+
},
|
|
1275
|
+
allowDragging: (branch) => {
|
|
1276
|
+
if (legacyOptions.allowDragging === undefined) {
|
|
1277
|
+
return true;
|
|
1278
|
+
}
|
|
1279
|
+
if (typeof legacyOptions.allowDragging === "boolean") {
|
|
1280
|
+
return legacyOptions.allowDragging;
|
|
1281
|
+
}
|
|
1282
|
+
return legacyOptions.allowDragging(branch);
|
|
1283
|
+
},
|
|
1284
|
+
allowDrop: (source, parent, index) => {
|
|
1285
|
+
if (legacyOptions.allowDrop === undefined) {
|
|
1286
|
+
return true;
|
|
1287
|
+
}
|
|
1288
|
+
return legacyOptions.allowDrop(source, parent, index);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
renderTreeNode(parent, node, options) {
|
|
1294
|
+
const component = node.component?.class ?? options.defaultComponent?.class;
|
|
1295
|
+
if (component === undefined) {
|
|
1296
|
+
throw new TreeError("A component must be provided");
|
|
1297
|
+
}
|
|
1298
|
+
const bindings = (node.component?.bindings ??
|
|
1299
|
+
options.defaultComponent?.bindings ??
|
|
1300
|
+
{});
|
|
1301
|
+
const nodeData = node;
|
|
1302
|
+
const branch = parent.grow(component, {
|
|
1303
|
+
inputBindings: bindings,
|
|
1304
|
+
meta: { nodeData }
|
|
1305
|
+
});
|
|
1306
|
+
for (const childNode of node.nodes ?? []) {
|
|
1307
|
+
this.renderTreeNode(branch, childNode, options);
|
|
1308
|
+
}
|
|
1309
|
+
if (node.collapsed === true) {
|
|
1310
|
+
treeCollapser.collapse(branch);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
/** @deprecated */
|
|
1316
|
+
class LimbleTreeRootComponent {
|
|
1317
|
+
constructor() {
|
|
1318
|
+
this.itemsPerPage = Infinity;
|
|
1319
|
+
this.page = 1;
|
|
1320
|
+
this.treeChange = new EventEmitter();
|
|
1321
|
+
this.treeDrop = new EventEmitter();
|
|
1322
|
+
this.legacyTree = new LegacyTree();
|
|
1323
|
+
}
|
|
1324
|
+
ngAfterViewInit() {
|
|
1325
|
+
this.update();
|
|
1326
|
+
}
|
|
1327
|
+
ngOnChanges() {
|
|
1328
|
+
if (this.host !== undefined && this.data !== undefined) {
|
|
1329
|
+
this.update();
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
ngOnDestroy() {
|
|
1333
|
+
this.dropSubscription?.unsubscribe();
|
|
1334
|
+
this.root?.destroy();
|
|
1335
|
+
}
|
|
1336
|
+
getRoot() {
|
|
1337
|
+
return this.root;
|
|
1338
|
+
}
|
|
1339
|
+
update() {
|
|
1340
|
+
if (this.data === undefined) {
|
|
1341
|
+
throw new TreeError("LimbleTreeRootComponent's `data` input is required");
|
|
1342
|
+
}
|
|
1343
|
+
if (this.host === undefined) {
|
|
1344
|
+
throw new TreeError("LimbleTreeRootComponent's `host` property is not defined");
|
|
1345
|
+
}
|
|
1346
|
+
this.root?.destroy();
|
|
1347
|
+
this.dropSubscription?.unsubscribe();
|
|
1348
|
+
const dataSlice = this.paginatedData();
|
|
1349
|
+
this.root = this.legacyTree.createTreeFromLegacyArray(this.host, dataSlice, this.options);
|
|
1350
|
+
this.dropSubscription = this.root
|
|
1351
|
+
.events()
|
|
1352
|
+
.pipe(filter((event) => event instanceof DragEndEvent))
|
|
1353
|
+
.subscribe(this.treeDrop);
|
|
1354
|
+
this.treeChange.emit(this.root);
|
|
1355
|
+
}
|
|
1356
|
+
paginatedData() {
|
|
1357
|
+
assert(this.data !== undefined);
|
|
1358
|
+
if (this.options?.listMode !== true) {
|
|
1359
|
+
return this.data;
|
|
1360
|
+
}
|
|
1361
|
+
return this.data.slice((this.page - 1) * this.itemsPerPage, this.page * this.itemsPerPage);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
LimbleTreeRootComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LimbleTreeRootComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1365
|
+
LimbleTreeRootComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", 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" });
|
|
1366
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LimbleTreeRootComponent, decorators: [{
|
|
1367
|
+
type: Component,
|
|
1368
|
+
args: [{ selector: "limble-tree-root", standalone: true, template: "<div #host></div>\n" }]
|
|
1369
|
+
}], ctorParameters: function () { return []; }, propDecorators: { data: [{
|
|
1370
|
+
type: Input
|
|
1371
|
+
}], options: [{
|
|
1372
|
+
type: Input
|
|
1373
|
+
}], itemsPerPage: [{
|
|
1374
|
+
type: Input
|
|
1375
|
+
}], page: [{
|
|
1376
|
+
type: Input
|
|
1377
|
+
}], host: [{
|
|
1378
|
+
type: ViewChild,
|
|
1379
|
+
args: ["host", { read: ViewContainerRef }]
|
|
1380
|
+
}], treeChange: [{
|
|
1381
|
+
type: Output
|
|
1382
|
+
}], treeDrop: [{
|
|
1383
|
+
type: Output
|
|
1384
|
+
}] } });
|
|
1385
|
+
|
|
1386
|
+
/** @deprecated */
|
|
1387
|
+
class LimbleTreeLegacyModule {
|
|
1388
|
+
}
|
|
1389
|
+
LimbleTreeLegacyModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LimbleTreeLegacyModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1390
|
+
LimbleTreeLegacyModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.12", ngImport: i0, type: LimbleTreeLegacyModule, imports: [LimbleTreeRootComponent], exports: [LimbleTreeRootComponent] });
|
|
1391
|
+
LimbleTreeLegacyModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LimbleTreeLegacyModule, providers: [LegacyTree], imports: [LimbleTreeRootComponent] });
|
|
1392
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LimbleTreeLegacyModule, decorators: [{
|
|
1393
|
+
type: NgModule,
|
|
1394
|
+
args: [{
|
|
1395
|
+
declarations: [],
|
|
1396
|
+
imports: [LimbleTreeRootComponent],
|
|
1397
|
+
providers: [LegacyTree],
|
|
1398
|
+
exports: [LimbleTreeRootComponent]
|
|
1399
|
+
}]
|
|
1400
|
+
}] });
|
|
1401
|
+
|
|
1402
|
+
class LimbleTreeModule {
|
|
1403
|
+
}
|
|
1404
|
+
LimbleTreeModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LimbleTreeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1405
|
+
LimbleTreeModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.12", ngImport: i0, type: LimbleTreeModule, imports: [LimbleTreeLegacyModule, TreeCollapseModule, TreeDragAndDropModule], exports: [LimbleTreeLegacyModule, TreeCollapseModule, TreeDragAndDropModule] });
|
|
1406
|
+
LimbleTreeModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LimbleTreeModule, providers: [TreeService], imports: [LimbleTreeLegacyModule, TreeCollapseModule, TreeDragAndDropModule, LimbleTreeLegacyModule, TreeCollapseModule, TreeDragAndDropModule] });
|
|
1407
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LimbleTreeModule, decorators: [{
|
|
1408
|
+
type: NgModule,
|
|
1409
|
+
args: [{
|
|
1410
|
+
declarations: [],
|
|
1411
|
+
imports: [LimbleTreeLegacyModule, TreeCollapseModule, TreeDragAndDropModule],
|
|
1412
|
+
providers: [TreeService],
|
|
1413
|
+
exports: [LimbleTreeLegacyModule, TreeCollapseModule, TreeDragAndDropModule]
|
|
1414
|
+
}]
|
|
1415
|
+
}] });
|
|
2152
1416
|
|
|
2153
|
-
/*
|
|
2154
|
-
* Public API Surface of limble-tree
|
|
1417
|
+
/*
|
|
1418
|
+
* Public API Surface of limble-tree
|
|
2155
1419
|
*/
|
|
2156
1420
|
|
|
2157
|
-
/**
|
|
2158
|
-
* Generated bundle index. Do not edit.
|
|
1421
|
+
/**
|
|
1422
|
+
* Generated bundle index. Do not edit.
|
|
2159
1423
|
*/
|
|
2160
1424
|
|
|
2161
|
-
export { LimbleTreeModule, LimbleTreeRootComponent };
|
|
1425
|
+
export { DestructionEvent, DragEndEvent, DragStartEvent, DraggableDirective, DragoverNoChangeDetectDirective, DropEvent, GraftEvent, LegacyTree, LimbleTreeLegacyModule, LimbleTreeModule, LimbleTreeRootComponent, PruneEvent, TreeBranch, TreeCollapseModule, TreeCollapseService, TreeDragAndDropModule, TreeDragAndDropService, TreeError, TreeRoot, TreeService, config };
|
|
2162
1426
|
//# sourceMappingURL=limble-limble-tree.mjs.map
|