@acorex/components 21.0.0-next.40 → 21.0.0-next.42
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/accordion/index.d.ts +1 -0
- package/button-group/index.d.ts +4 -6
- package/chips/index.d.ts +8 -3
- package/dialog/index.d.ts +1 -1
- package/fesm2022/acorex-components-accordion.mjs +21 -16
- package/fesm2022/acorex-components-accordion.mjs.map +1 -1
- package/fesm2022/acorex-components-action-sheet.mjs +12 -12
- package/fesm2022/acorex-components-action-sheet.mjs.map +1 -1
- package/fesm2022/acorex-components-alert.mjs +13 -13
- package/fesm2022/acorex-components-alert.mjs.map +1 -1
- package/fesm2022/acorex-components-aspect-ratio.mjs +3 -3
- package/fesm2022/acorex-components-aspect-ratio.mjs.map +1 -1
- package/fesm2022/acorex-components-audio-wave.mjs +10 -11
- package/fesm2022/acorex-components-audio-wave.mjs.map +1 -1
- package/fesm2022/acorex-components-autocomplete.mjs +7 -7
- package/fesm2022/acorex-components-autocomplete.mjs.map +1 -1
- package/fesm2022/acorex-components-avatar.mjs +12 -12
- package/fesm2022/acorex-components-avatar.mjs.map +1 -1
- package/fesm2022/acorex-components-badge.mjs +9 -9
- package/fesm2022/acorex-components-badge.mjs.map +1 -1
- package/fesm2022/acorex-components-bottom-navigation.mjs +11 -11
- package/fesm2022/acorex-components-bottom-navigation.mjs.map +1 -1
- package/fesm2022/acorex-components-breadcrumbs.mjs +11 -11
- package/fesm2022/acorex-components-breadcrumbs.mjs.map +1 -1
- package/fesm2022/acorex-components-button-group.mjs +19 -23
- package/fesm2022/acorex-components-button-group.mjs.map +1 -1
- package/fesm2022/acorex-components-button.mjs +18 -18
- package/fesm2022/acorex-components-button.mjs.map +1 -1
- package/fesm2022/acorex-components-calendar.mjs +17 -17
- package/fesm2022/acorex-components-calendar.mjs.map +1 -1
- package/fesm2022/acorex-components-check-box.mjs +10 -10
- package/fesm2022/acorex-components-check-box.mjs.map +1 -1
- package/fesm2022/acorex-components-chips.mjs +14 -12
- package/fesm2022/acorex-components-chips.mjs.map +1 -1
- package/fesm2022/acorex-components-circular-progress.mjs +10 -12
- package/fesm2022/acorex-components-circular-progress.mjs.map +1 -1
- package/fesm2022/acorex-components-code-editor.mjs +10 -10
- package/fesm2022/acorex-components-code-editor.mjs.map +1 -1
- package/fesm2022/acorex-components-collapse.mjs +13 -13
- package/fesm2022/acorex-components-collapse.mjs.map +1 -1
- package/fesm2022/acorex-components-color-box.mjs +9 -9
- package/fesm2022/acorex-components-color-box.mjs.map +1 -1
- package/fesm2022/acorex-components-color-palette.mjs +30 -30
- package/fesm2022/acorex-components-color-palette.mjs.map +1 -1
- package/fesm2022/acorex-components-command.mjs +9 -9
- package/fesm2022/acorex-components-command.mjs.map +1 -1
- package/fesm2022/acorex-components-comment.mjs +32 -32
- package/fesm2022/acorex-components-comment.mjs.map +1 -1
- package/fesm2022/acorex-components-conversation.mjs +51 -51
- package/fesm2022/acorex-components-conversation.mjs.map +1 -1
- package/fesm2022/acorex-components-conversation2.mjs +184 -184
- package/fesm2022/acorex-components-conversation2.mjs.map +1 -1
- package/fesm2022/acorex-components-cron-job.mjs +46 -46
- package/fesm2022/acorex-components-cron-job.mjs.map +1 -1
- package/fesm2022/acorex-components-data-list.mjs +3 -3
- package/fesm2022/acorex-components-data-list.mjs.map +1 -1
- package/fesm2022/acorex-components-data-pager.mjs +33 -33
- package/fesm2022/acorex-components-data-pager.mjs.map +1 -1
- package/fesm2022/acorex-components-data-table.mjs +43 -43
- package/fesm2022/acorex-components-data-table.mjs.map +1 -1
- package/fesm2022/acorex-components-datetime-box.mjs +9 -9
- package/fesm2022/acorex-components-datetime-box.mjs.map +1 -1
- package/fesm2022/acorex-components-datetime-input.mjs +9 -9
- package/fesm2022/acorex-components-datetime-input.mjs.map +1 -1
- package/fesm2022/acorex-components-datetime-picker.mjs +9 -9
- package/fesm2022/acorex-components-datetime-picker.mjs.map +1 -1
- package/fesm2022/acorex-components-decorators.mjs +36 -43
- package/fesm2022/acorex-components-decorators.mjs.map +1 -1
- package/fesm2022/acorex-components-dialog.mjs +14 -15
- package/fesm2022/acorex-components-dialog.mjs.map +1 -1
- package/fesm2022/acorex-components-drawer-legacy.mjs +13 -13
- package/fesm2022/acorex-components-drawer-legacy.mjs.map +1 -1
- package/fesm2022/acorex-components-drawer.mjs +16 -15
- package/fesm2022/acorex-components-drawer.mjs.map +1 -1
- package/fesm2022/acorex-components-dropdown-button.mjs +9 -9
- package/fesm2022/acorex-components-dropdown-button.mjs.map +1 -1
- package/fesm2022/acorex-components-dropdown.mjs +16 -18
- package/fesm2022/acorex-components-dropdown.mjs.map +1 -1
- package/fesm2022/acorex-components-editor.mjs +11 -11
- package/fesm2022/acorex-components-editor.mjs.map +1 -1
- package/fesm2022/acorex-components-file-explorer.mjs +25 -25
- package/fesm2022/acorex-components-file-explorer.mjs.map +1 -1
- package/fesm2022/acorex-components-flow-chart.mjs +16 -16
- package/fesm2022/acorex-components-flow-chart.mjs.map +1 -1
- package/fesm2022/acorex-components-form.mjs +24 -32
- package/fesm2022/acorex-components-form.mjs.map +1 -1
- package/fesm2022/acorex-components-grid-layout-builder.mjs +13 -12
- package/fesm2022/acorex-components-grid-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-components-image-editor.mjs +44 -44
- package/fesm2022/acorex-components-image-editor.mjs.map +1 -1
- package/fesm2022/acorex-components-image.mjs +9 -9
- package/fesm2022/acorex-components-image.mjs.map +1 -1
- package/fesm2022/acorex-components-json-viewer.mjs +8 -8
- package/fesm2022/acorex-components-json-viewer.mjs.map +1 -1
- package/fesm2022/acorex-components-kanban.mjs +6 -8
- package/fesm2022/acorex-components-kanban.mjs.map +1 -1
- package/fesm2022/acorex-components-kbd.mjs +11 -29
- package/fesm2022/acorex-components-kbd.mjs.map +1 -1
- package/fesm2022/acorex-components-label.mjs +9 -9
- package/fesm2022/acorex-components-label.mjs.map +1 -1
- package/fesm2022/acorex-components-list.mjs +9 -9
- package/fesm2022/acorex-components-list.mjs.map +1 -1
- package/fesm2022/acorex-components-loading-dialog.mjs +12 -12
- package/fesm2022/acorex-components-loading-dialog.mjs.map +1 -1
- package/fesm2022/acorex-components-loading.mjs +23 -23
- package/fesm2022/acorex-components-loading.mjs.map +1 -1
- package/fesm2022/acorex-components-map.mjs +14 -14
- package/fesm2022/acorex-components-map.mjs.map +1 -1
- package/fesm2022/acorex-components-media-viewer.mjs +41 -41
- package/fesm2022/acorex-components-media-viewer.mjs.map +1 -1
- package/fesm2022/acorex-components-menu.mjs +21 -21
- package/fesm2022/acorex-components-menu.mjs.map +1 -1
- package/fesm2022/{acorex-components-modal-acorex-components-modal-CjHPRiZD.mjs → acorex-components-modal-acorex-components-modal-iYSPzoLn.mjs} +22 -22
- package/fesm2022/acorex-components-modal-acorex-components-modal-iYSPzoLn.mjs.map +1 -0
- package/fesm2022/acorex-components-modal-modal-content.component-sZWKhYM-.mjs +212 -0
- package/fesm2022/acorex-components-modal-modal-content.component-sZWKhYM-.mjs.map +1 -0
- package/fesm2022/acorex-components-modal.mjs +1 -1
- package/fesm2022/acorex-components-navbar.mjs +9 -9
- package/fesm2022/acorex-components-navbar.mjs.map +1 -1
- package/fesm2022/acorex-components-notification.mjs +23 -16
- package/fesm2022/acorex-components-notification.mjs.map +1 -1
- package/fesm2022/acorex-components-number-box-legacy.mjs +9 -9
- package/fesm2022/acorex-components-number-box-legacy.mjs.map +1 -1
- package/fesm2022/acorex-components-number-box.mjs +15 -14
- package/fesm2022/acorex-components-number-box.mjs.map +1 -1
- package/fesm2022/acorex-components-otp.mjs +9 -9
- package/fesm2022/acorex-components-otp.mjs.map +1 -1
- package/fesm2022/acorex-components-page.mjs +10 -10
- package/fesm2022/acorex-components-page.mjs.map +1 -1
- package/fesm2022/acorex-components-paint.mjs +39 -34
- package/fesm2022/acorex-components-paint.mjs.map +1 -1
- package/fesm2022/acorex-components-password-box.mjs +12 -12
- package/fesm2022/acorex-components-password-box.mjs.map +1 -1
- package/fesm2022/acorex-components-pdf-reader.mjs +8 -8
- package/fesm2022/acorex-components-pdf-reader.mjs.map +1 -1
- package/fesm2022/acorex-components-phone-box.mjs +9 -9
- package/fesm2022/acorex-components-phone-box.mjs.map +1 -1
- package/fesm2022/acorex-components-picker.mjs +15 -15
- package/fesm2022/acorex-components-picker.mjs.map +1 -1
- package/fesm2022/acorex-components-popover.mjs +11 -11
- package/fesm2022/acorex-components-popover.mjs.map +1 -1
- package/fesm2022/acorex-components-popup.mjs +13 -13
- package/fesm2022/acorex-components-popup.mjs.map +1 -1
- package/fesm2022/acorex-components-progress-bar.mjs +9 -11
- package/fesm2022/acorex-components-progress-bar.mjs.map +1 -1
- package/fesm2022/acorex-components-qrcode.mjs +7 -7
- package/fesm2022/acorex-components-qrcode.mjs.map +1 -1
- package/fesm2022/acorex-components-query-builder.mjs +8 -8
- package/fesm2022/acorex-components-query-builder.mjs.map +1 -1
- package/fesm2022/acorex-components-radio.mjs +7 -7
- package/fesm2022/acorex-components-radio.mjs.map +1 -1
- package/fesm2022/acorex-components-rail-navigation.mjs +36 -38
- package/fesm2022/acorex-components-rail-navigation.mjs.map +1 -1
- package/fesm2022/acorex-components-range-slider.mjs +10 -10
- package/fesm2022/acorex-components-range-slider.mjs.map +1 -1
- package/fesm2022/acorex-components-rate-picker.mjs +35 -20
- package/fesm2022/acorex-components-rate-picker.mjs.map +1 -1
- package/fesm2022/acorex-components-rest-api-generator.mjs +22 -22
- package/fesm2022/acorex-components-rest-api-generator.mjs.map +1 -1
- package/fesm2022/acorex-components-result.mjs +8 -8
- package/fesm2022/acorex-components-result.mjs.map +1 -1
- package/fesm2022/acorex-components-routing-progress.mjs +8 -8
- package/fesm2022/acorex-components-routing-progress.mjs.map +1 -1
- package/fesm2022/acorex-components-rrule.mjs +9 -9
- package/fesm2022/acorex-components-rrule.mjs.map +1 -1
- package/fesm2022/acorex-components-scheduler-picker.mjs +56 -56
- package/fesm2022/acorex-components-scheduler-picker.mjs.map +1 -1
- package/fesm2022/acorex-components-scheduler.mjs +43 -43
- package/fesm2022/acorex-components-scheduler.mjs.map +1 -1
- package/fesm2022/acorex-components-scss.mjs +4 -4
- package/fesm2022/acorex-components-scss.mjs.map +1 -1
- package/fesm2022/acorex-components-search-box.mjs +10 -16
- package/fesm2022/acorex-components-search-box.mjs.map +1 -1
- package/fesm2022/acorex-components-select-box.mjs +9 -11
- package/fesm2022/acorex-components-select-box.mjs.map +1 -1
- package/fesm2022/acorex-components-selection-list-2.mjs +11 -11
- package/fesm2022/acorex-components-selection-list-2.mjs.map +1 -1
- package/fesm2022/acorex-components-selection-list.mjs +9 -9
- package/fesm2022/acorex-components-selection-list.mjs.map +1 -1
- package/fesm2022/acorex-components-side-menu.mjs +14 -14
- package/fesm2022/acorex-components-side-menu.mjs.map +1 -1
- package/fesm2022/acorex-components-skeleton.mjs +8 -8
- package/fesm2022/acorex-components-skeleton.mjs.map +1 -1
- package/fesm2022/acorex-components-slider.mjs +10 -10
- package/fesm2022/acorex-components-slider.mjs.map +1 -1
- package/fesm2022/acorex-components-sliding-item.mjs +14 -14
- package/fesm2022/acorex-components-sliding-item.mjs.map +1 -1
- package/fesm2022/acorex-components-step-wizard.mjs +14 -14
- package/fesm2022/acorex-components-step-wizard.mjs.map +1 -1
- package/fesm2022/acorex-components-switch.mjs +14 -14
- package/fesm2022/acorex-components-switch.mjs.map +1 -1
- package/fesm2022/acorex-components-tabs.mjs +15 -15
- package/fesm2022/acorex-components-tabs.mjs.map +1 -1
- package/fesm2022/acorex-components-tag-box.mjs +9 -9
- package/fesm2022/acorex-components-tag-box.mjs.map +1 -1
- package/fesm2022/acorex-components-tag.mjs +9 -9
- package/fesm2022/acorex-components-tag.mjs.map +1 -1
- package/fesm2022/acorex-components-text-area.mjs +9 -9
- package/fesm2022/acorex-components-text-area.mjs.map +1 -1
- package/fesm2022/acorex-components-text-box.mjs +12 -12
- package/fesm2022/acorex-components-text-box.mjs.map +1 -1
- package/fesm2022/acorex-components-time-duration.mjs +7 -7
- package/fesm2022/acorex-components-time-duration.mjs.map +1 -1
- package/fesm2022/acorex-components-time-line.mjs +12 -12
- package/fesm2022/acorex-components-time-line.mjs.map +1 -1
- package/fesm2022/acorex-components-toast.mjs +14 -14
- package/fesm2022/acorex-components-toast.mjs.map +1 -1
- package/fesm2022/acorex-components-toolbar.mjs +8 -8
- package/fesm2022/acorex-components-toolbar.mjs.map +1 -1
- package/fesm2022/acorex-components-tooltip.mjs +11 -11
- package/fesm2022/acorex-components-tooltip.mjs.map +1 -1
- package/fesm2022/acorex-components-tree-view-legacy.mjs +10 -10
- package/fesm2022/acorex-components-tree-view-legacy.mjs.map +1 -1
- package/fesm2022/acorex-components-tree-view.mjs +872 -464
- package/fesm2022/acorex-components-tree-view.mjs.map +1 -1
- package/fesm2022/acorex-components-uploader.mjs +16 -16
- package/fesm2022/acorex-components-uploader.mjs.map +1 -1
- package/fesm2022/acorex-components-video-player.mjs +7 -7
- package/fesm2022/acorex-components-video-player.mjs.map +1 -1
- package/fesm2022/acorex-components-wysiwyg.mjs +44 -44
- package/fesm2022/acorex-components-wysiwyg.mjs.map +1 -1
- package/fesm2022/acorex-components.mjs.map +1 -1
- package/grid-layout-builder/index.d.ts +2 -1
- package/kbd/index.d.ts +7 -13
- package/loading/index.d.ts +1 -1
- package/notification/index.d.ts +2 -0
- package/number-box/index.d.ts +1 -1
- package/package.json +21 -21
- package/paint/index.d.ts +6 -1
- package/rate-picker/index.d.ts +15 -5
- package/tree-view/index.d.ts +292 -68
- package/wysiwyg/index.d.ts +1 -0
- package/fesm2022/acorex-components-modal-acorex-components-modal-CjHPRiZD.mjs.map +0 -1
- package/fesm2022/acorex-components-modal-modal-content.component-j-bS0WGj.mjs +0 -214
- package/fesm2022/acorex-components-modal-modal-content.component-j-bS0WGj.mjs.map +0 -1
|
@@ -4,6 +4,7 @@ import { AXBadgeComponent } from '@acorex/components/badge';
|
|
|
4
4
|
import { AXButtonComponent } from '@acorex/components/button';
|
|
5
5
|
import { AXCheckBoxComponent } from '@acorex/components/check-box';
|
|
6
6
|
import { AXDecoratorIconComponent } from '@acorex/components/decorators';
|
|
7
|
+
import { AXTooltipDirective } from '@acorex/components/tooltip';
|
|
7
8
|
import { AXPlatform } from '@acorex/core/platform';
|
|
8
9
|
import * as i1 from '@angular/common';
|
|
9
10
|
import { CommonModule, NgTemplateOutlet } from '@angular/common';
|
|
@@ -27,12 +28,13 @@ class AXTreeViewService {
|
|
|
27
28
|
/**
|
|
28
29
|
* Find a node by ID in the tree
|
|
29
30
|
*/
|
|
30
|
-
findNodeById(nodes, id) {
|
|
31
|
+
findNodeById(nodes, id, idField = 'id') {
|
|
31
32
|
for (const node of nodes) {
|
|
32
|
-
if (node
|
|
33
|
+
if (node[idField] === id)
|
|
33
34
|
return node;
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
const children = node['children'];
|
|
36
|
+
if (children) {
|
|
37
|
+
const found = this.findNodeById(children, id, idField);
|
|
36
38
|
if (found)
|
|
37
39
|
return found;
|
|
38
40
|
}
|
|
@@ -42,13 +44,15 @@ class AXTreeViewService {
|
|
|
42
44
|
/**
|
|
43
45
|
* Find parent node of a given node
|
|
44
46
|
*/
|
|
45
|
-
findParentNode(nodes, targetNode) {
|
|
47
|
+
findParentNode(nodes, targetNode, idField = 'id', childrenField = 'children') {
|
|
48
|
+
const targetId = targetNode[idField];
|
|
46
49
|
for (const node of nodes) {
|
|
47
|
-
|
|
50
|
+
const children = node[childrenField];
|
|
51
|
+
if (children?.some((child) => child[idField] === targetId)) {
|
|
48
52
|
return node;
|
|
49
53
|
}
|
|
50
|
-
if (
|
|
51
|
-
const found = this.findParentNode(
|
|
54
|
+
if (children) {
|
|
55
|
+
const found = this.findParentNode(children, targetNode, idField, childrenField);
|
|
52
56
|
if (found)
|
|
53
57
|
return found;
|
|
54
58
|
}
|
|
@@ -59,8 +63,10 @@ class AXTreeViewService {
|
|
|
59
63
|
* Check if targetNode is a descendant of ancestorNode (or the same node)
|
|
60
64
|
* Prevents circular references by checking if target exists in ancestor's children tree
|
|
61
65
|
*/
|
|
62
|
-
isValidDropTarget(movedNode, targetNode) {
|
|
63
|
-
|
|
66
|
+
isValidDropTarget(movedNode, targetNode, idField = 'id', childrenField = 'children') {
|
|
67
|
+
const movedId = movedNode[idField];
|
|
68
|
+
const targetId = targetNode[idField];
|
|
69
|
+
if (movedId === targetId || this.isNodeDescendantOf(targetNode, movedNode, idField, childrenField)) {
|
|
64
70
|
return false;
|
|
65
71
|
}
|
|
66
72
|
return true;
|
|
@@ -68,18 +74,22 @@ class AXTreeViewService {
|
|
|
68
74
|
/**
|
|
69
75
|
* Check if targetNode is a descendant of ancestorNode
|
|
70
76
|
*/
|
|
71
|
-
isNodeDescendantOf(targetNode, ancestorNode) {
|
|
72
|
-
|
|
77
|
+
isNodeDescendantOf(targetNode, ancestorNode, idField = 'id', childrenField = 'children') {
|
|
78
|
+
const targetId = targetNode[idField];
|
|
79
|
+
const ancestorId = ancestorNode[idField];
|
|
80
|
+
if (targetId === ancestorId) {
|
|
73
81
|
return true;
|
|
74
82
|
}
|
|
75
|
-
|
|
83
|
+
const children = ancestorNode[childrenField];
|
|
84
|
+
if (!children || children.length === 0) {
|
|
76
85
|
return false;
|
|
77
86
|
}
|
|
78
|
-
for (const child of
|
|
79
|
-
|
|
87
|
+
for (const child of children) {
|
|
88
|
+
const childId = child[idField];
|
|
89
|
+
if (childId === targetId) {
|
|
80
90
|
return true;
|
|
81
91
|
}
|
|
82
|
-
if (this.isNodeDescendantOf(targetNode, child)) {
|
|
92
|
+
if (this.isNodeDescendantOf(targetNode, child, idField, childrenField)) {
|
|
83
93
|
return true;
|
|
84
94
|
}
|
|
85
95
|
}
|
|
@@ -88,14 +98,18 @@ class AXTreeViewService {
|
|
|
88
98
|
/**
|
|
89
99
|
* Build a flat list of all visible focusable nodes
|
|
90
100
|
*/
|
|
91
|
-
buildFlatNodeList(nodes) {
|
|
101
|
+
buildFlatNodeList(nodes, hiddenField = 'hidden', disabledField = 'disabled', expandedField = 'expanded', childrenField = 'children') {
|
|
92
102
|
const flatList = [];
|
|
93
103
|
const traverse = (nodeList, level, parent) => {
|
|
94
104
|
for (const node of nodeList) {
|
|
95
|
-
|
|
105
|
+
const hidden = node[hiddenField];
|
|
106
|
+
const disabled = node[disabledField];
|
|
107
|
+
if (hidden !== true && !disabled) {
|
|
96
108
|
flatList.push({ node, level, parent });
|
|
97
|
-
|
|
98
|
-
|
|
109
|
+
const expanded = node[expandedField];
|
|
110
|
+
const children = node[childrenField];
|
|
111
|
+
if (expanded && children) {
|
|
112
|
+
traverse(children, level + 1, node);
|
|
99
113
|
}
|
|
100
114
|
}
|
|
101
115
|
}
|
|
@@ -107,39 +121,44 @@ class AXTreeViewService {
|
|
|
107
121
|
/**
|
|
108
122
|
* Check if node has children
|
|
109
123
|
*/
|
|
110
|
-
hasChildren(node) {
|
|
111
|
-
|
|
124
|
+
hasChildren(node, childrenField = 'children') {
|
|
125
|
+
const children = node[childrenField];
|
|
126
|
+
return Boolean(children?.length);
|
|
112
127
|
}
|
|
113
128
|
/**
|
|
114
129
|
* Check if node can be lazy loaded
|
|
115
130
|
*/
|
|
116
|
-
canLazyLoad(node, isLazyDataSource) {
|
|
117
|
-
|
|
131
|
+
canLazyLoad(node, isLazyDataSource, childrenCountField = 'childrenCount', childrenField = 'children') {
|
|
132
|
+
const childrenCount = node[childrenCountField];
|
|
133
|
+
return isLazyDataSource && Boolean(childrenCount && childrenCount > 0 && !this.hasChildren(node, childrenField));
|
|
118
134
|
}
|
|
119
135
|
// ==================== Selection Management ====================
|
|
120
136
|
/**
|
|
121
137
|
* Recursively select/deselect all children
|
|
122
138
|
*/
|
|
123
|
-
selectAllChildren(children, selected) {
|
|
139
|
+
selectAllChildren(children, selected, selectedField = 'selected', indeterminateField = 'indeterminate', childrenField = 'children') {
|
|
124
140
|
for (const child of children) {
|
|
125
|
-
child
|
|
126
|
-
child
|
|
127
|
-
|
|
128
|
-
|
|
141
|
+
child[selectedField] = selected;
|
|
142
|
+
child[indeterminateField] = false;
|
|
143
|
+
const childChildren = child[childrenField];
|
|
144
|
+
if (childChildren) {
|
|
145
|
+
this.selectAllChildren(childChildren, selected, selectedField, indeterminateField, childrenField);
|
|
129
146
|
}
|
|
130
147
|
}
|
|
131
148
|
}
|
|
132
149
|
/**
|
|
133
150
|
* Get selection state of children
|
|
134
151
|
*/
|
|
135
|
-
getChildrenSelectionState(children) {
|
|
152
|
+
getChildrenSelectionState(children, selectedField = 'selected', indeterminateField = 'indeterminate') {
|
|
136
153
|
let selectedCount = 0;
|
|
137
154
|
let indeterminateCount = 0;
|
|
138
155
|
for (const child of children) {
|
|
139
|
-
|
|
156
|
+
const selected = child[selectedField];
|
|
157
|
+
const indeterminate = child[indeterminateField];
|
|
158
|
+
if (selected && !indeterminate) {
|
|
140
159
|
selectedCount++;
|
|
141
160
|
}
|
|
142
|
-
if (
|
|
161
|
+
if (indeterminate) {
|
|
143
162
|
indeterminateCount++;
|
|
144
163
|
}
|
|
145
164
|
}
|
|
@@ -151,65 +170,69 @@ class AXTreeViewService {
|
|
|
151
170
|
/**
|
|
152
171
|
* Update parent node states based on children selection (with intermediate state support)
|
|
153
172
|
*/
|
|
154
|
-
updateParentStates(nodes, changedNode, intermediateState) {
|
|
155
|
-
const parent = this.findParentNode(nodes, changedNode);
|
|
156
|
-
|
|
173
|
+
updateParentStates(nodes, changedNode, intermediateState, idField = 'id', childrenField = 'children', selectedField = 'selected', indeterminateField = 'indeterminate') {
|
|
174
|
+
const parent = this.findParentNode(nodes, changedNode, idField, childrenField);
|
|
175
|
+
const parentChildren = parent?.[childrenField];
|
|
176
|
+
if (!parent || !parentChildren)
|
|
157
177
|
return;
|
|
158
|
-
const { allSelected, someSelected } = this.getChildrenSelectionState(
|
|
178
|
+
const { allSelected, someSelected } = this.getChildrenSelectionState(parentChildren, selectedField, indeterminateField);
|
|
159
179
|
if (allSelected) {
|
|
160
|
-
parent
|
|
161
|
-
parent
|
|
180
|
+
parent[selectedField] = true;
|
|
181
|
+
parent[indeterminateField] = false;
|
|
162
182
|
}
|
|
163
183
|
else if (someSelected) {
|
|
164
184
|
if (intermediateState) {
|
|
165
|
-
parent
|
|
166
|
-
parent
|
|
185
|
+
parent[selectedField] = true;
|
|
186
|
+
parent[indeterminateField] = true;
|
|
167
187
|
}
|
|
168
188
|
else {
|
|
169
|
-
parent
|
|
170
|
-
parent
|
|
189
|
+
parent[selectedField] = false;
|
|
190
|
+
parent[indeterminateField] = false;
|
|
171
191
|
}
|
|
172
192
|
}
|
|
173
193
|
else {
|
|
174
|
-
parent
|
|
175
|
-
parent
|
|
194
|
+
parent[selectedField] = false;
|
|
195
|
+
parent[indeterminateField] = false;
|
|
176
196
|
}
|
|
177
|
-
this.updateParentStates(nodes, parent, intermediateState);
|
|
197
|
+
this.updateParentStates(nodes, parent, intermediateState, idField, childrenField, selectedField, indeterminateField);
|
|
178
198
|
}
|
|
179
199
|
/**
|
|
180
200
|
* Recursively deselect all nodes
|
|
181
201
|
*/
|
|
182
|
-
deselectAllNodes(nodes) {
|
|
202
|
+
deselectAllNodes(nodes, selectedField = 'selected', indeterminateField = 'indeterminate', childrenField = 'children') {
|
|
183
203
|
for (const node of nodes) {
|
|
184
|
-
node
|
|
185
|
-
node
|
|
186
|
-
|
|
187
|
-
|
|
204
|
+
node[selectedField] = false;
|
|
205
|
+
node[indeterminateField] = false;
|
|
206
|
+
const children = node[childrenField];
|
|
207
|
+
if (children) {
|
|
208
|
+
this.deselectAllNodes(children, selectedField, indeterminateField, childrenField);
|
|
188
209
|
}
|
|
189
210
|
}
|
|
190
211
|
}
|
|
191
212
|
/**
|
|
192
213
|
* Recursively set selection state for all nodes
|
|
193
214
|
*/
|
|
194
|
-
setAllSelection(nodes, selected) {
|
|
215
|
+
setAllSelection(nodes, selected, selectedField = 'selected', indeterminateField = 'indeterminate', childrenField = 'children') {
|
|
195
216
|
for (const node of nodes) {
|
|
196
|
-
node
|
|
197
|
-
node
|
|
198
|
-
|
|
199
|
-
|
|
217
|
+
node[selectedField] = selected;
|
|
218
|
+
node[indeterminateField] = false;
|
|
219
|
+
const children = node[childrenField];
|
|
220
|
+
if (children) {
|
|
221
|
+
this.setAllSelection(children, selected, selectedField, indeterminateField, childrenField);
|
|
200
222
|
}
|
|
201
223
|
}
|
|
202
224
|
}
|
|
203
225
|
/**
|
|
204
226
|
* Recursively count selected nodes
|
|
205
227
|
*/
|
|
206
|
-
countSelected(nodes) {
|
|
228
|
+
countSelected(nodes, selectedField = 'selected', childrenField = 'children') {
|
|
207
229
|
let count = 0;
|
|
208
230
|
for (const node of nodes) {
|
|
209
|
-
if (node
|
|
231
|
+
if (node[selectedField])
|
|
210
232
|
count++;
|
|
211
|
-
|
|
212
|
-
|
|
233
|
+
const children = node[childrenField];
|
|
234
|
+
if (children) {
|
|
235
|
+
count += this.countSelected(children, selectedField, childrenField);
|
|
213
236
|
}
|
|
214
237
|
}
|
|
215
238
|
return count;
|
|
@@ -217,53 +240,61 @@ class AXTreeViewService {
|
|
|
217
240
|
/**
|
|
218
241
|
* Recursively collect selected nodes
|
|
219
242
|
*/
|
|
220
|
-
collectSelected(nodes, result) {
|
|
243
|
+
collectSelected(nodes, result, selectedField = 'selected', childrenField = 'children') {
|
|
221
244
|
for (const node of nodes) {
|
|
222
|
-
if (node
|
|
245
|
+
if (node[selectedField])
|
|
223
246
|
result.push(node);
|
|
224
|
-
|
|
225
|
-
|
|
247
|
+
const children = node[childrenField];
|
|
248
|
+
if (children) {
|
|
249
|
+
this.collectSelected(children, result, selectedField, childrenField);
|
|
226
250
|
}
|
|
227
251
|
}
|
|
228
252
|
}
|
|
229
253
|
/**
|
|
230
254
|
* Recursively remove selected nodes
|
|
231
255
|
*/
|
|
232
|
-
removeSelected(nodes) {
|
|
256
|
+
removeSelected(nodes, selectedField = 'selected', indeterminateField = 'indeterminate', childrenField = 'children') {
|
|
233
257
|
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
234
|
-
|
|
258
|
+
const node = nodes[i];
|
|
259
|
+
const selected = node[selectedField];
|
|
260
|
+
const indeterminate = node[indeterminateField];
|
|
261
|
+
if (selected && !indeterminate) {
|
|
235
262
|
nodes.splice(i, 1);
|
|
236
263
|
}
|
|
237
|
-
else
|
|
238
|
-
|
|
264
|
+
else {
|
|
265
|
+
const children = node[childrenField];
|
|
266
|
+
if (children) {
|
|
267
|
+
this.removeSelected(children, selectedField, indeterminateField, childrenField);
|
|
268
|
+
}
|
|
239
269
|
}
|
|
240
270
|
}
|
|
241
271
|
}
|
|
242
272
|
/**
|
|
243
273
|
* Recursively update all parent states in the tree (used after deletion)
|
|
244
274
|
*/
|
|
245
|
-
updateAllParentStates(nodes, intermediateState) {
|
|
275
|
+
updateAllParentStates(nodes, intermediateState, childrenField = 'children', selectedField = 'selected', indeterminateField = 'indeterminate') {
|
|
246
276
|
for (const node of nodes) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
277
|
+
const children = node[childrenField];
|
|
278
|
+
if (children && children.length > 0) {
|
|
279
|
+
this.updateAllParentStates(children, intermediateState, childrenField, selectedField, indeterminateField);
|
|
280
|
+
const { allSelected, someSelected } = this.getChildrenSelectionState(children, selectedField, indeterminateField);
|
|
250
281
|
if (allSelected) {
|
|
251
|
-
node
|
|
252
|
-
node
|
|
282
|
+
node[selectedField] = true;
|
|
283
|
+
node[indeterminateField] = false;
|
|
253
284
|
}
|
|
254
285
|
else if (someSelected) {
|
|
255
286
|
if (intermediateState) {
|
|
256
|
-
node
|
|
257
|
-
node
|
|
287
|
+
node[selectedField] = true;
|
|
288
|
+
node[indeterminateField] = true;
|
|
258
289
|
}
|
|
259
290
|
else {
|
|
260
|
-
node
|
|
261
|
-
node
|
|
291
|
+
node[selectedField] = false;
|
|
292
|
+
node[indeterminateField] = false;
|
|
262
293
|
}
|
|
263
294
|
}
|
|
264
295
|
else {
|
|
265
|
-
node
|
|
266
|
-
node
|
|
296
|
+
node[selectedField] = false;
|
|
297
|
+
node[indeterminateField] = false;
|
|
267
298
|
}
|
|
268
299
|
}
|
|
269
300
|
}
|
|
@@ -272,17 +303,18 @@ class AXTreeViewService {
|
|
|
272
303
|
/**
|
|
273
304
|
* Recursively set expanded state (with lazy loading)
|
|
274
305
|
*/
|
|
275
|
-
async setExpandedState(nodes, expanded, isLazyDataSource, loadNodeChildren) {
|
|
306
|
+
async setExpandedState(nodes, expanded, isLazyDataSource, loadNodeChildren, expandedField = 'expanded', childrenField = 'children', childrenCountField = 'childrenCount') {
|
|
276
307
|
for (const node of nodes) {
|
|
277
|
-
const hasChildren = this.hasChildren(node);
|
|
278
|
-
const canLazyLoad = this.canLazyLoad(node, isLazyDataSource);
|
|
308
|
+
const hasChildren = this.hasChildren(node, childrenField);
|
|
309
|
+
const canLazyLoad = this.canLazyLoad(node, isLazyDataSource, childrenCountField, childrenField);
|
|
279
310
|
if (hasChildren || canLazyLoad) {
|
|
280
311
|
if (expanded && canLazyLoad) {
|
|
281
312
|
await loadNodeChildren(node);
|
|
282
313
|
}
|
|
283
|
-
node
|
|
284
|
-
|
|
285
|
-
|
|
314
|
+
node[expandedField] = expanded;
|
|
315
|
+
const children = node[childrenField];
|
|
316
|
+
if (children) {
|
|
317
|
+
await this.setExpandedState(children, expanded, isLazyDataSource, loadNodeChildren, expandedField, childrenField, childrenCountField);
|
|
286
318
|
}
|
|
287
319
|
}
|
|
288
320
|
}
|
|
@@ -291,23 +323,24 @@ class AXTreeViewService {
|
|
|
291
323
|
/**
|
|
292
324
|
* Get array reference by drop list ID
|
|
293
325
|
*/
|
|
294
|
-
getArrayByListId(nodes, listId) {
|
|
326
|
+
getArrayByListId(nodes, listId, idField = 'id', childrenField = 'children') {
|
|
295
327
|
if (listId === AXTreeViewService.ROOT_LIST_ID) {
|
|
296
328
|
return nodes;
|
|
297
329
|
}
|
|
298
330
|
if (listId.startsWith(AXTreeViewService.NODE_DROP_PREFIX)) {
|
|
299
331
|
const nodeId = listId.replace(AXTreeViewService.NODE_DROP_PREFIX, '');
|
|
300
|
-
const node = this.findNodeById(nodes, nodeId);
|
|
332
|
+
const node = this.findNodeById(nodes, nodeId, idField);
|
|
301
333
|
return node ? [node] : null;
|
|
302
334
|
}
|
|
303
335
|
const nodeId = listId.replace(AXTreeViewService.LIST_PREFIX, '');
|
|
304
|
-
const node = this.findNodeById(nodes, nodeId);
|
|
305
|
-
|
|
336
|
+
const node = this.findNodeById(nodes, nodeId, idField);
|
|
337
|
+
const children = node?.[childrenField];
|
|
338
|
+
return children ?? null;
|
|
306
339
|
}
|
|
307
340
|
/**
|
|
308
341
|
* Find parent node by list ID
|
|
309
342
|
*/
|
|
310
|
-
findParentByListId(nodes, listId) {
|
|
343
|
+
findParentByListId(nodes, listId, idField = 'id') {
|
|
311
344
|
if (listId === AXTreeViewService.ROOT_LIST_ID) {
|
|
312
345
|
return undefined;
|
|
313
346
|
}
|
|
@@ -315,13 +348,16 @@ class AXTreeViewService {
|
|
|
315
348
|
? AXTreeViewService.NODE_DROP_PREFIX
|
|
316
349
|
: AXTreeViewService.LIST_PREFIX;
|
|
317
350
|
const nodeId = listId.replace(prefix, '');
|
|
318
|
-
return this.findNodeById(nodes, nodeId) ?? undefined;
|
|
351
|
+
return this.findNodeById(nodes, nodeId, idField) ?? undefined;
|
|
319
352
|
}
|
|
320
353
|
/**
|
|
321
354
|
* Generate unique list ID for each node
|
|
322
355
|
*/
|
|
323
|
-
getListId(node) {
|
|
324
|
-
|
|
356
|
+
getListId(node, idField = 'id') {
|
|
357
|
+
if (!node)
|
|
358
|
+
return AXTreeViewService.ROOT_LIST_ID;
|
|
359
|
+
const nodeId = node[idField];
|
|
360
|
+
return `${AXTreeViewService.LIST_PREFIX}${nodeId}`;
|
|
325
361
|
}
|
|
326
362
|
/**
|
|
327
363
|
* Get root list ID constant
|
|
@@ -345,13 +381,14 @@ class AXTreeViewService {
|
|
|
345
381
|
/**
|
|
346
382
|
* Get all nodes in a flat array
|
|
347
383
|
*/
|
|
348
|
-
getAllNodes(nodes) {
|
|
384
|
+
getAllNodes(nodes, childrenField = 'children') {
|
|
349
385
|
const allNodes = [];
|
|
350
386
|
const traverse = (nodeList) => {
|
|
351
387
|
for (const node of nodeList) {
|
|
352
388
|
allNodes.push(node);
|
|
353
|
-
|
|
354
|
-
|
|
389
|
+
const children = node[childrenField];
|
|
390
|
+
if (children) {
|
|
391
|
+
traverse(children);
|
|
355
392
|
}
|
|
356
393
|
}
|
|
357
394
|
};
|
|
@@ -361,16 +398,16 @@ class AXTreeViewService {
|
|
|
361
398
|
/**
|
|
362
399
|
* Get the path to a node (array of parent nodes from root to node)
|
|
363
400
|
*/
|
|
364
|
-
getNodePath(nodes, nodeId) {
|
|
401
|
+
getNodePath(nodes, nodeId, idField = 'id', childrenField = 'children') {
|
|
365
402
|
const path = [];
|
|
366
|
-
const node = this.findNodeById(nodes, nodeId);
|
|
403
|
+
const node = this.findNodeById(nodes, nodeId, idField);
|
|
367
404
|
if (!node) {
|
|
368
405
|
return path;
|
|
369
406
|
}
|
|
370
407
|
let current = node;
|
|
371
408
|
while (current) {
|
|
372
409
|
path.unshift(current);
|
|
373
|
-
const parent = this.findParentNode(nodes, current);
|
|
410
|
+
const parent = this.findParentNode(nodes, current, idField, childrenField);
|
|
374
411
|
current = parent ?? null;
|
|
375
412
|
}
|
|
376
413
|
return path;
|
|
@@ -378,70 +415,255 @@ class AXTreeViewService {
|
|
|
378
415
|
/**
|
|
379
416
|
* Get the level/depth of a node (0 = root level)
|
|
380
417
|
*/
|
|
381
|
-
getNodeLevel(nodes, nodeId) {
|
|
382
|
-
const path = this.getNodePath(nodes, nodeId);
|
|
418
|
+
getNodeLevel(nodes, nodeId, idField = 'id', childrenField = 'children') {
|
|
419
|
+
const path = this.getNodePath(nodes, nodeId, idField, childrenField);
|
|
383
420
|
return path.length > 0 ? path.length - 1 : -1;
|
|
384
421
|
}
|
|
385
422
|
/**
|
|
386
423
|
* Get sibling nodes of a given node
|
|
387
424
|
*/
|
|
388
|
-
getSiblings(nodes, nodeId) {
|
|
389
|
-
const node = this.findNodeById(nodes, nodeId);
|
|
425
|
+
getSiblings(nodes, nodeId, idField = 'id', childrenField = 'children') {
|
|
426
|
+
const node = this.findNodeById(nodes, nodeId, idField);
|
|
390
427
|
if (!node) {
|
|
391
428
|
return [];
|
|
392
429
|
}
|
|
393
|
-
const parent = this.findParentNode(nodes, node);
|
|
394
|
-
const siblingsArray = parent?.
|
|
395
|
-
return siblingsArray.filter((n) => n
|
|
430
|
+
const parent = this.findParentNode(nodes, node, idField, childrenField);
|
|
431
|
+
const siblingsArray = parent?.[childrenField] ?? nodes;
|
|
432
|
+
return siblingsArray.filter((n) => n[idField] !== nodeId);
|
|
396
433
|
}
|
|
397
434
|
/**
|
|
398
435
|
* Clone a node (creates a deep copy)
|
|
399
436
|
*/
|
|
400
|
-
cloneNode(node) {
|
|
437
|
+
cloneNode(node, idField = 'id', titleField = 'title', tooltipField = 'tooltip', iconField = 'icon', expandedField = 'expanded', selectedField = 'selected', indeterminateField = 'indeterminate', disabledField = 'disabled', hiddenField = 'hidden', childrenCountField = 'childrenCount', dataField = 'data', childrenField = 'children') {
|
|
401
438
|
const cloned = {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
439
|
+
[idField]: `${node[idField]}-clone-${Date.now()}`,
|
|
440
|
+
[titleField]: node[titleField],
|
|
441
|
+
[tooltipField]: node[tooltipField],
|
|
442
|
+
[iconField]: node[iconField],
|
|
443
|
+
[expandedField]: node[expandedField],
|
|
444
|
+
[selectedField]: false, // Cloned nodes are not selected by default
|
|
445
|
+
[indeterminateField]: false,
|
|
446
|
+
[disabledField]: node[disabledField],
|
|
447
|
+
[hiddenField]: node[hiddenField],
|
|
448
|
+
[childrenCountField]: node[childrenCountField],
|
|
449
|
+
[dataField]: node[dataField] ? JSON.parse(JSON.stringify(node[dataField])) : undefined,
|
|
413
450
|
};
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
cloned
|
|
451
|
+
const children = node[childrenField];
|
|
452
|
+
if (children && children.length > 0) {
|
|
453
|
+
cloned[childrenField] = children.map((child) => this.cloneNode(child, idField, titleField, tooltipField, iconField, expandedField, selectedField, indeterminateField, disabledField, hiddenField, childrenCountField, dataField, childrenField));
|
|
454
|
+
cloned[childrenCountField] = cloned[childrenField].length;
|
|
417
455
|
}
|
|
418
456
|
return cloned;
|
|
419
457
|
}
|
|
458
|
+
// ==================== Node Manipulation ====================
|
|
459
|
+
/**
|
|
460
|
+
* Move a node to a new parent in the tree
|
|
461
|
+
* @param nodes - Root nodes array
|
|
462
|
+
* @param nodeId - The ID of the node to move
|
|
463
|
+
* @param newParentId - The ID of the new parent (undefined for root level)
|
|
464
|
+
* @param index - Optional index to insert at (default: append to end)
|
|
465
|
+
* @param idField - Field name for node ID
|
|
466
|
+
* @param childrenField - Field name for children array
|
|
467
|
+
* @param childrenCountField - Field name for children count
|
|
468
|
+
* @param expandedField - Field name for expanded state
|
|
469
|
+
* @returns Object with success status, moved node, previous parent, new parent, and indices
|
|
470
|
+
*/
|
|
471
|
+
moveNode(nodes, nodeId, newParentId, index, idField = 'id', childrenField = 'children', childrenCountField = 'childrenCount', expandedField = 'expanded') {
|
|
472
|
+
const node = this.findNodeById(nodes, nodeId, idField);
|
|
473
|
+
if (!node) {
|
|
474
|
+
return { success: false, previousIndex: -1, currentIndex: -1 };
|
|
475
|
+
}
|
|
476
|
+
// Find current parent
|
|
477
|
+
const currentParent = this.findParentNode(nodes, node, idField, childrenField);
|
|
478
|
+
const currentParentChildren = currentParent
|
|
479
|
+
? currentParent[childrenField]
|
|
480
|
+
: undefined;
|
|
481
|
+
const currentArray = currentParentChildren ?? nodes;
|
|
482
|
+
// Find and remove from current location
|
|
483
|
+
const currentIndex = currentArray.findIndex((n) => n[idField] === nodeId);
|
|
484
|
+
if (currentIndex === -1) {
|
|
485
|
+
return { success: false, previousIndex: -1, currentIndex: -1 };
|
|
486
|
+
}
|
|
487
|
+
const movedNode = currentArray.splice(currentIndex, 1)[0];
|
|
488
|
+
// Find new parent
|
|
489
|
+
let targetArray;
|
|
490
|
+
let newParent;
|
|
491
|
+
if (newParentId) {
|
|
492
|
+
newParent = this.findNodeById(nodes, newParentId, idField);
|
|
493
|
+
if (!newParent) {
|
|
494
|
+
// Restore node if new parent not found
|
|
495
|
+
currentArray.splice(currentIndex, 0, movedNode);
|
|
496
|
+
return { success: false, previousIndex: currentIndex, currentIndex: -1 };
|
|
497
|
+
}
|
|
498
|
+
// Validate drop target
|
|
499
|
+
if (!this.isValidDropTarget(movedNode, newParent, idField, childrenField)) {
|
|
500
|
+
// Restore node if invalid drop target
|
|
501
|
+
currentArray.splice(currentIndex, 0, movedNode);
|
|
502
|
+
return { success: false, previousIndex: currentIndex, currentIndex: -1 };
|
|
503
|
+
}
|
|
504
|
+
let newParentChildren = newParent[childrenField];
|
|
505
|
+
if (!newParentChildren) {
|
|
506
|
+
newParentChildren = [];
|
|
507
|
+
newParent[childrenField] = newParentChildren;
|
|
508
|
+
}
|
|
509
|
+
targetArray = newParentChildren;
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
targetArray = nodes;
|
|
513
|
+
}
|
|
514
|
+
// Calculate new index before inserting
|
|
515
|
+
const newIndex = index !== undefined && index >= 0 && index <= targetArray.length ? index : targetArray.length;
|
|
516
|
+
// Insert at new location
|
|
517
|
+
if (index !== undefined && index >= 0 && index <= targetArray.length) {
|
|
518
|
+
targetArray.splice(index, 0, movedNode);
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
targetArray.push(movedNode);
|
|
522
|
+
}
|
|
523
|
+
// Update childrenCount
|
|
524
|
+
if (currentParent) {
|
|
525
|
+
const updatedChildren = currentParent[childrenField];
|
|
526
|
+
currentParent[childrenCountField] = updatedChildren?.length ?? 0;
|
|
527
|
+
}
|
|
528
|
+
if (newParent) {
|
|
529
|
+
const updatedChildren = newParent[childrenField];
|
|
530
|
+
newParent[childrenCountField] = updatedChildren?.length ?? 0;
|
|
531
|
+
newParent[expandedField] = true; // Auto-expand new parent
|
|
532
|
+
}
|
|
533
|
+
return {
|
|
534
|
+
success: true,
|
|
535
|
+
movedNode,
|
|
536
|
+
previousParent: currentParent,
|
|
537
|
+
newParent,
|
|
538
|
+
previousIndex: currentIndex,
|
|
539
|
+
currentIndex: newIndex,
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Edit/update a node's properties
|
|
544
|
+
* @param nodes - Root nodes array
|
|
545
|
+
* @param nodeId - The ID of the node to edit
|
|
546
|
+
* @param updates - Partial node object with properties to update
|
|
547
|
+
* @param idField - Field name for node ID
|
|
548
|
+
* @param childrenField - Field name for children array
|
|
549
|
+
* @param childrenCountField - Field name for children count
|
|
550
|
+
* @returns The updated node if found, null otherwise
|
|
551
|
+
*/
|
|
552
|
+
editNode(nodes, nodeId, updates, idField = 'id', childrenField = 'children', childrenCountField = 'childrenCount') {
|
|
553
|
+
const node = this.findNodeById(nodes, nodeId, idField);
|
|
554
|
+
if (!node) {
|
|
555
|
+
return null;
|
|
556
|
+
}
|
|
557
|
+
// Update node properties
|
|
558
|
+
Object.assign(node, updates);
|
|
559
|
+
// If children array is provided, ensure it exists and update childrenCount
|
|
560
|
+
if (updates[childrenField] !== undefined) {
|
|
561
|
+
const children = updates[childrenField];
|
|
562
|
+
node[childrenField] = children;
|
|
563
|
+
node[childrenCountField] = children?.length;
|
|
564
|
+
}
|
|
565
|
+
return node;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Add a child node to a parent node
|
|
569
|
+
* @param nodes - Root nodes array
|
|
570
|
+
* @param parentId - The ID of the parent node
|
|
571
|
+
* @param childNode - The child node to add
|
|
572
|
+
* @param index - Optional index to insert at (default: append to end)
|
|
573
|
+
* @param idField - Field name for node ID
|
|
574
|
+
* @param childrenField - Field name for children array
|
|
575
|
+
* @param childrenCountField - Field name for children count
|
|
576
|
+
* @param expandedField - Field name for expanded state
|
|
577
|
+
* @returns The parent node if found and child was added, null otherwise
|
|
578
|
+
*/
|
|
579
|
+
addChild(nodes, parentId, childNode, index, idField = 'id', childrenField = 'children', childrenCountField = 'childrenCount', expandedField = 'expanded') {
|
|
580
|
+
const parent = this.findNodeById(nodes, parentId, idField);
|
|
581
|
+
if (!parent) {
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
584
|
+
// Ensure children array exists
|
|
585
|
+
let children = parent[childrenField];
|
|
586
|
+
if (!children) {
|
|
587
|
+
children = [];
|
|
588
|
+
parent[childrenField] = children;
|
|
589
|
+
}
|
|
590
|
+
// Insert or append child
|
|
591
|
+
if (index !== undefined && index >= 0 && index <= children.length) {
|
|
592
|
+
children.splice(index, 0, childNode);
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
children.push(childNode);
|
|
596
|
+
}
|
|
597
|
+
// Update childrenCount
|
|
598
|
+
parent[childrenCountField] = children.length;
|
|
599
|
+
// Auto-expand parent if it was collapsed
|
|
600
|
+
if (!parent[expandedField]) {
|
|
601
|
+
parent[expandedField] = true;
|
|
602
|
+
}
|
|
603
|
+
return parent;
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Remove a node from the tree
|
|
607
|
+
* @param nodes - Root nodes array
|
|
608
|
+
* @param nodeId - The ID of the node to remove
|
|
609
|
+
* @param idField - Field name for node ID
|
|
610
|
+
* @param childrenField - Field name for children array
|
|
611
|
+
* @param childrenCountField - Field name for children count
|
|
612
|
+
* @returns The removed node if found, null otherwise
|
|
613
|
+
*/
|
|
614
|
+
removeNode(nodes, nodeId, idField = 'id', childrenField = 'children', childrenCountField = 'childrenCount') {
|
|
615
|
+
const node = this.findNodeById(nodes, nodeId, idField);
|
|
616
|
+
if (!node) {
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
// Find parent to remove from its children array
|
|
620
|
+
const parent = this.findParentNode(nodes, node, idField, childrenField);
|
|
621
|
+
const parentChildren = parent ? parent[childrenField] : undefined;
|
|
622
|
+
const targetArray = parentChildren ?? nodes;
|
|
623
|
+
// Find and remove the node
|
|
624
|
+
const index = targetArray.findIndex((n) => n[idField] === nodeId);
|
|
625
|
+
if (index !== -1) {
|
|
626
|
+
const removed = targetArray.splice(index, 1)[0];
|
|
627
|
+
// Update parent's childrenCount if it exists
|
|
628
|
+
if (parent) {
|
|
629
|
+
const updatedChildren = parent[childrenField];
|
|
630
|
+
parent[childrenCountField] = updatedChildren?.length ?? 0;
|
|
631
|
+
}
|
|
632
|
+
return removed;
|
|
633
|
+
}
|
|
634
|
+
return null;
|
|
635
|
+
}
|
|
420
636
|
/**
|
|
421
637
|
* Validate node structure (check for required fields and circular references)
|
|
422
638
|
*/
|
|
423
|
-
validateNode(node, visitedIds = new Set()) {
|
|
639
|
+
validateNode(node, visitedIds = new Set(), idField = 'id', titleField = 'title', childrenField = 'children', childrenCountField = 'childrenCount') {
|
|
424
640
|
const errors = [];
|
|
425
|
-
|
|
426
|
-
|
|
641
|
+
const nodeId = node[idField];
|
|
642
|
+
const nodeTitle = node[titleField];
|
|
643
|
+
if (!nodeId) {
|
|
644
|
+
errors.push(`Node must have an ${idField}`);
|
|
427
645
|
}
|
|
428
|
-
if (!
|
|
429
|
-
errors.push(
|
|
646
|
+
if (!nodeTitle) {
|
|
647
|
+
errors.push(`Node must have a ${titleField}`);
|
|
430
648
|
}
|
|
431
|
-
if (visitedIds.has(
|
|
432
|
-
errors.push(`Circular reference detected: node ${
|
|
649
|
+
if (nodeId && visitedIds.has(nodeId)) {
|
|
650
|
+
errors.push(`Circular reference detected: node ${nodeId} appears multiple times in the tree`);
|
|
433
651
|
}
|
|
434
|
-
|
|
652
|
+
const children = node[childrenField];
|
|
653
|
+
if (children) {
|
|
435
654
|
const newVisited = new Set(visitedIds);
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
655
|
+
if (nodeId) {
|
|
656
|
+
newVisited.add(nodeId);
|
|
657
|
+
}
|
|
658
|
+
for (const child of children) {
|
|
659
|
+
const childValidation = this.validateNode(child, newVisited, idField, titleField, childrenField, childrenCountField);
|
|
439
660
|
if (!childValidation.valid) {
|
|
440
|
-
errors.push(...childValidation.errors.map((e) => `Child of ${
|
|
661
|
+
errors.push(...childValidation.errors.map((e) => `Child of ${nodeId}: ${e}`));
|
|
441
662
|
}
|
|
442
663
|
}
|
|
443
|
-
|
|
444
|
-
|
|
664
|
+
const childrenCount = node[childrenCountField];
|
|
665
|
+
if (childrenCount !== undefined && childrenCount !== children.length) {
|
|
666
|
+
errors.push(`Node ${nodeId}: ${childrenCountField} (${childrenCount}) does not match ${childrenField} array length (${children.length})`);
|
|
445
667
|
}
|
|
446
668
|
}
|
|
447
669
|
return {
|
|
@@ -449,10 +671,10 @@ class AXTreeViewService {
|
|
|
449
671
|
errors,
|
|
450
672
|
};
|
|
451
673
|
}
|
|
452
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
453
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.
|
|
674
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
675
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewService }); }
|
|
454
676
|
}
|
|
455
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
677
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewService, decorators: [{
|
|
456
678
|
type: Injectable
|
|
457
679
|
}] });
|
|
458
680
|
|
|
@@ -465,36 +687,54 @@ class AXTreeViewComponent {
|
|
|
465
687
|
// ==================== Inputs ====================
|
|
466
688
|
/** Tree data source - can be static array or lazy loading function */
|
|
467
689
|
this.datasource = model.required(...(ngDevMode ? [{ debugName: "datasource" }] : []));
|
|
468
|
-
/** Selection mode: 'single' (click to select) or 'multiple' (checkbox selection) */
|
|
469
|
-
this.selectMode = input('
|
|
470
|
-
/** Whether to show checkboxes for selection (only applies to multiple mode) */
|
|
471
|
-
this.showCheckbox = input(
|
|
472
|
-
/**
|
|
473
|
-
this.
|
|
474
|
-
/**
|
|
475
|
-
this.
|
|
476
|
-
/**
|
|
477
|
-
this.
|
|
478
|
-
/**
|
|
479
|
-
this.dragMode = input('handler', ...(ngDevMode ? [{ debugName: "dragMode" }] : []));
|
|
480
|
-
/** Drag operation type: 'order-only' (reorder only), 'move' (move between parents), 'both' (allow both) */
|
|
481
|
-
this.dragOperationType = input('both', ...(ngDevMode ? [{ debugName: "dragOperationType" }] : []));
|
|
482
|
-
/** Whether to show icons */
|
|
690
|
+
/** Selection mode: 'single' (click to select) or 'multiple' (checkbox selection). Default: `'single'` */
|
|
691
|
+
this.selectMode = input('single', ...(ngDevMode ? [{ debugName: "selectMode" }] : []));
|
|
692
|
+
/** Whether to show checkboxes for selection (only applies to multiple mode). Default: `false`. When false and selectMode is not 'none', clicking on a node toggles its selection. */
|
|
693
|
+
this.showCheckbox = input(false, ...(ngDevMode ? [{ debugName: "showCheckbox" }] : []));
|
|
694
|
+
/** Selection behavior: 'all' (select anything, no special behavior), 'intermediate' (parent indeterminate state when children selected), 'leaf' (only leaf nodes selectable), 'nested' (selecting parent selects all children). Default: `'intermediate'` */
|
|
695
|
+
this.selectionBehavior = input('intermediate', ...(ngDevMode ? [{ debugName: "selectionBehavior" }] : []));
|
|
696
|
+
/** Drag area: 'handler' (drag handle), 'item' (entire item). Default: `'handler'` */
|
|
697
|
+
this.dragArea = input('handler', ...(ngDevMode ? [{ debugName: "dragArea" }] : []));
|
|
698
|
+
/** Drag behavior: 'none' (disabled), 'order-only' (reorder only), 'move' (move between parents), 'both' (allow both). Default: `'none'` */
|
|
699
|
+
this.dragBehavior = input('none', ...(ngDevMode ? [{ debugName: "dragBehavior" }] : []));
|
|
700
|
+
/** Whether to show icons. Default: `true` */
|
|
483
701
|
this.showIcons = input(true, ...(ngDevMode ? [{ debugName: "showIcons" }] : []));
|
|
484
|
-
/** Whether to show children count badge */
|
|
702
|
+
/** Whether to show children count badge. Default: `true` */
|
|
485
703
|
this.showChildrenBadge = input(true, ...(ngDevMode ? [{ debugName: "showChildrenBadge" }] : []));
|
|
486
|
-
/** Custom icon for expanded nodes */
|
|
704
|
+
/** Custom icon for expanded nodes. Default: `'fa-solid fa-chevron-down'` */
|
|
487
705
|
this.expandedIcon = input('fa-solid fa-chevron-down', ...(ngDevMode ? [{ debugName: "expandedIcon" }] : []));
|
|
488
|
-
/** Custom icon for collapsed nodes */
|
|
706
|
+
/** Custom icon for collapsed nodes. Default: `'fa-solid fa-chevron-right'` */
|
|
489
707
|
this.collapsedIcon = input('fa-solid fa-chevron-right', ...(ngDevMode ? [{ debugName: "collapsedIcon" }] : []));
|
|
490
|
-
/** Indent size in pixels for each level */
|
|
491
|
-
this.indentSize = input(
|
|
492
|
-
/**
|
|
493
|
-
this.nodeHeight = input('normal', ...(ngDevMode ? [{ debugName: "nodeHeight" }] : []));
|
|
494
|
-
/** Visual style variant */
|
|
708
|
+
/** Indent size in pixels for each level. Default: `16` */
|
|
709
|
+
this.indentSize = input(16, ...(ngDevMode ? [{ debugName: "indentSize" }] : []));
|
|
710
|
+
/** Visual style variant. Default: `'default'` */
|
|
495
711
|
this.look = input('default', ...(ngDevMode ? [{ debugName: "look" }] : []));
|
|
496
|
-
/** Custom template for tree items */
|
|
497
|
-
this.
|
|
712
|
+
/** Custom template for tree items. Default: `undefined` */
|
|
713
|
+
this.nodeTemplate = input(...(ngDevMode ? [undefined, { debugName: "nodeTemplate" }] : []));
|
|
714
|
+
/** Field name for node ID. Default: `'id'` */
|
|
715
|
+
this.idField = input('id', ...(ngDevMode ? [{ debugName: "idField" }] : []));
|
|
716
|
+
/** Field name for node title. Default: `'title'` */
|
|
717
|
+
this.titleField = input('title', ...(ngDevMode ? [{ debugName: "titleField" }] : []));
|
|
718
|
+
/** Field name for node tooltip. Default: `'tooltip'` */
|
|
719
|
+
this.tooltipField = input('tooltip', ...(ngDevMode ? [{ debugName: "tooltipField" }] : []));
|
|
720
|
+
/** Field name for node icon. Default: `'icon'` */
|
|
721
|
+
this.iconField = input('icon', ...(ngDevMode ? [{ debugName: "iconField" }] : []));
|
|
722
|
+
/** Field name for expanded state. Default: `'expanded'` */
|
|
723
|
+
this.expandedField = input('expanded', ...(ngDevMode ? [{ debugName: "expandedField" }] : []));
|
|
724
|
+
/** Field name for selected state. Default: `'selected'` */
|
|
725
|
+
this.selectedField = input('selected', ...(ngDevMode ? [{ debugName: "selectedField" }] : []));
|
|
726
|
+
/** Field name for indeterminate state. Default: `'indeterminate'` */
|
|
727
|
+
this.indeterminateField = input('indeterminate', ...(ngDevMode ? [{ debugName: "indeterminateField" }] : []));
|
|
728
|
+
/** Field name for disabled state. Default: `'disabled'` */
|
|
729
|
+
this.disabledField = input('disabled', ...(ngDevMode ? [{ debugName: "disabledField" }] : []));
|
|
730
|
+
/** Field name for hidden state. Default: `'hidden'` */
|
|
731
|
+
this.hiddenField = input('hidden', ...(ngDevMode ? [{ debugName: "hiddenField" }] : []));
|
|
732
|
+
/** Field name for children array. Default: `'children'` */
|
|
733
|
+
this.childrenField = input('children', ...(ngDevMode ? [{ debugName: "childrenField" }] : []));
|
|
734
|
+
/** Field name for children count. Default: `'childrenCount'` */
|
|
735
|
+
this.childrenCountField = input('childrenCount', ...(ngDevMode ? [{ debugName: "childrenCountField" }] : []));
|
|
736
|
+
/** Field name for custom data. Default: `'data'` */
|
|
737
|
+
this.dataField = input('data', ...(ngDevMode ? [{ debugName: "dataField" }] : []));
|
|
498
738
|
// ==================== Outputs ====================
|
|
499
739
|
/** Emitted before a drop operation - set canceled to true to prevent drop */
|
|
500
740
|
this.onBeforeDrop = output();
|
|
@@ -502,6 +742,8 @@ class AXTreeViewComponent {
|
|
|
502
742
|
this.onNodeToggle = output();
|
|
503
743
|
/** Emitted when a node is selected/deselected */
|
|
504
744
|
this.onNodeSelect = output();
|
|
745
|
+
/** Emitted when selection changes - returns all currently selected nodes */
|
|
746
|
+
this.onSelectionChange = output();
|
|
505
747
|
/** Emitted when nodes are reordered within the same parent */
|
|
506
748
|
this.onOrderChange = output();
|
|
507
749
|
/** Emitted when a node is moved to a different parent */
|
|
@@ -534,19 +776,35 @@ class AXTreeViewComponent {
|
|
|
534
776
|
this.isUpdatingFromDatasource = false;
|
|
535
777
|
/** Computed to check if datasource is a function */
|
|
536
778
|
this.isLazyDataSource = computed(() => typeof this.datasource() === 'function', ...(ngDevMode ? [{ debugName: "isLazyDataSource" }] : []));
|
|
779
|
+
/** Computed: Returns true when selection is restricted to leaf nodes only */
|
|
780
|
+
this.isLeafOnlyMode = computed(() => this.selectionBehavior() === 'leaf', ...(ngDevMode ? [{ debugName: "isLeafOnlyMode" }] : []));
|
|
781
|
+
/** Computed: Returns true when selecting a parent automatically selects all its children */
|
|
782
|
+
this.cascadesToChildren = computed(() => {
|
|
783
|
+
const behavior = this.selectionBehavior();
|
|
784
|
+
return behavior === 'nested' || behavior === 'intermediate-nested';
|
|
785
|
+
}, ...(ngDevMode ? [{ debugName: "cascadesToChildren" }] : []));
|
|
786
|
+
/** Computed: Returns true when parent nodes show indeterminate state based on children selection */
|
|
787
|
+
this.hasIntermediateState = computed(() => {
|
|
788
|
+
const behavior = this.selectionBehavior();
|
|
789
|
+
return behavior === 'intermediate' || behavior === 'intermediate-nested';
|
|
790
|
+
}, ...(ngDevMode ? [{ debugName: "hasIntermediateState" }] : []));
|
|
537
791
|
// ==================== Effects ====================
|
|
538
792
|
/** Effect to handle datasource changes */
|
|
539
|
-
this.#datasourceEffect = effect(() => {
|
|
540
|
-
if (this.isUpdatingFromDatasource)
|
|
793
|
+
this.#datasourceEffect = effect(async () => {
|
|
794
|
+
if (this.isUpdatingFromDatasource) {
|
|
541
795
|
return;
|
|
796
|
+
}
|
|
542
797
|
const ds = this.datasource();
|
|
543
798
|
if (Array.isArray(ds)) {
|
|
544
799
|
this.nodes.set([...ds]);
|
|
545
800
|
}
|
|
546
801
|
else if (typeof ds === 'function') {
|
|
547
|
-
|
|
802
|
+
try {
|
|
803
|
+
await this.loadRootItems(ds);
|
|
804
|
+
}
|
|
805
|
+
catch (error) {
|
|
548
806
|
this.handleError('Failed to load root items', error);
|
|
549
|
-
}
|
|
807
|
+
}
|
|
550
808
|
}
|
|
551
809
|
}, ...(ngDevMode ? [{ debugName: "#datasourceEffect" }] : []));
|
|
552
810
|
/** Initialize direction change listener */
|
|
@@ -556,6 +814,115 @@ class AXTreeViewComponent {
|
|
|
556
814
|
.subscribe((isRtl) => this.isRtl.set(isRtl));
|
|
557
815
|
});
|
|
558
816
|
}
|
|
817
|
+
// ==================== Node Property Helpers ====================
|
|
818
|
+
/**
|
|
819
|
+
* Get a property value from a node using the configured field name
|
|
820
|
+
*/
|
|
821
|
+
getNodeProp(node, fieldName, defaultValue) {
|
|
822
|
+
return node[fieldName] ?? defaultValue;
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Set a property value on a node using the configured field name
|
|
826
|
+
*/
|
|
827
|
+
setNodeProp(node, fieldName, value) {
|
|
828
|
+
node[fieldName] = value;
|
|
829
|
+
}
|
|
830
|
+
/**
|
|
831
|
+
* Get node ID
|
|
832
|
+
*/
|
|
833
|
+
getNodeId(node) {
|
|
834
|
+
return this.getNodeProp(node, this.idField(), '');
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Get node title
|
|
838
|
+
*/
|
|
839
|
+
getNodeTitle(node) {
|
|
840
|
+
return this.getNodeProp(node, this.titleField(), '');
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Get node tooltip
|
|
844
|
+
*/
|
|
845
|
+
getNodeTooltip(node) {
|
|
846
|
+
return this.getNodeProp(node, this.tooltipField(), undefined);
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Get node icon
|
|
850
|
+
*/
|
|
851
|
+
getNodeIcon(node) {
|
|
852
|
+
return this.getNodeProp(node, this.iconField(), undefined);
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Get node expanded state
|
|
856
|
+
*/
|
|
857
|
+
getNodeExpanded(node) {
|
|
858
|
+
return this.getNodeProp(node, this.expandedField(), false);
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Set node expanded state
|
|
862
|
+
*/
|
|
863
|
+
setNodeExpanded(node, value) {
|
|
864
|
+
this.setNodeProp(node, this.expandedField(), value);
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Get node selected state
|
|
868
|
+
*/
|
|
869
|
+
getNodeSelected(node) {
|
|
870
|
+
return this.getNodeProp(node, this.selectedField(), false);
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Set node selected state
|
|
874
|
+
*/
|
|
875
|
+
setNodeSelected(node, value) {
|
|
876
|
+
this.setNodeProp(node, this.selectedField(), value);
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Get node indeterminate state
|
|
880
|
+
*/
|
|
881
|
+
getNodeIndeterminate(node) {
|
|
882
|
+
return this.getNodeProp(node, this.indeterminateField(), false);
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Set node indeterminate state
|
|
886
|
+
*/
|
|
887
|
+
setNodeIndeterminate(node, value) {
|
|
888
|
+
this.setNodeProp(node, this.indeterminateField(), value);
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Get node disabled state
|
|
892
|
+
*/
|
|
893
|
+
getNodeDisabled(node) {
|
|
894
|
+
return this.getNodeProp(node, this.disabledField(), false);
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* Get node hidden state
|
|
898
|
+
*/
|
|
899
|
+
getNodeHidden(node) {
|
|
900
|
+
return this.getNodeProp(node, this.hiddenField(), false);
|
|
901
|
+
}
|
|
902
|
+
/**
|
|
903
|
+
* Get node children array
|
|
904
|
+
*/
|
|
905
|
+
getNodeChildren(node) {
|
|
906
|
+
return this.getNodeProp(node, this.childrenField(), undefined);
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* Set node children array
|
|
910
|
+
*/
|
|
911
|
+
setNodeChildren(node, value) {
|
|
912
|
+
this.setNodeProp(node, this.childrenField(), value);
|
|
913
|
+
}
|
|
914
|
+
/**
|
|
915
|
+
* Get node children count
|
|
916
|
+
*/
|
|
917
|
+
getNodeChildrenCount(node) {
|
|
918
|
+
return this.getNodeProp(node, this.childrenCountField(), undefined);
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Set node children count
|
|
922
|
+
*/
|
|
923
|
+
setNodeChildrenCount(node, value) {
|
|
924
|
+
this.setNodeProp(node, this.childrenCountField(), value);
|
|
925
|
+
}
|
|
559
926
|
// ==================== Effects ====================
|
|
560
927
|
/** Effect to handle datasource changes */
|
|
561
928
|
#datasourceEffect;
|
|
@@ -566,21 +933,21 @@ class AXTreeViewComponent {
|
|
|
566
933
|
* Expand all nodes in the tree (with lazy loading support)
|
|
567
934
|
*/
|
|
568
935
|
async expandAll() {
|
|
569
|
-
await this.treeService.setExpandedState(this.nodes(), true, this.isLazyDataSource(), (node) => this.loadNodeChildren(node));
|
|
936
|
+
await this.treeService.setExpandedState(this.nodes(), true, this.isLazyDataSource(), (node) => this.loadNodeChildren(node), this.expandedField(), this.childrenField(), this.childrenCountField());
|
|
570
937
|
this.refreshNodes();
|
|
571
938
|
}
|
|
572
939
|
/**
|
|
573
940
|
* Collapse all nodes in the tree
|
|
574
941
|
*/
|
|
575
942
|
collapseAll() {
|
|
576
|
-
this.treeService.setExpandedState(this.nodes(), false, this.isLazyDataSource(), (node) => this.loadNodeChildren(node));
|
|
943
|
+
this.treeService.setExpandedState(this.nodes(), false, this.isLazyDataSource(), (node) => this.loadNodeChildren(node), this.expandedField(), this.childrenField(), this.childrenCountField());
|
|
577
944
|
this.refreshNodes();
|
|
578
945
|
}
|
|
579
946
|
/**
|
|
580
947
|
* Get count of selected nodes
|
|
581
948
|
*/
|
|
582
949
|
getSelectedCount() {
|
|
583
|
-
return this.treeService.countSelected(this.nodes());
|
|
950
|
+
return this.treeService.countSelected(this.nodes(), this.selectedField(), this.childrenField());
|
|
584
951
|
}
|
|
585
952
|
/**
|
|
586
953
|
* Check if any nodes are selected
|
|
@@ -593,36 +960,62 @@ class AXTreeViewComponent {
|
|
|
593
960
|
*/
|
|
594
961
|
getSelectedNodes() {
|
|
595
962
|
const selected = [];
|
|
596
|
-
this.treeService.collectSelected(this.nodes(), selected);
|
|
963
|
+
this.treeService.collectSelected(this.nodes(), selected, this.selectedField(), this.childrenField());
|
|
597
964
|
return selected;
|
|
598
965
|
}
|
|
599
966
|
/**
|
|
600
967
|
* Delete selected nodes from the tree
|
|
601
968
|
*/
|
|
602
969
|
deleteSelected() {
|
|
603
|
-
this.treeService.removeSelected(this.nodes());
|
|
604
|
-
|
|
970
|
+
this.treeService.removeSelected(this.nodes(), this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
971
|
+
if (!this.isLeafOnlyMode()) {
|
|
972
|
+
this.treeService.updateAllParentStates(this.nodes(), this.hasIntermediateState(), this.childrenField(), this.selectedField(), this.indeterminateField());
|
|
973
|
+
}
|
|
605
974
|
this.refreshNodes();
|
|
975
|
+
this.emitSelectionChange();
|
|
606
976
|
}
|
|
607
977
|
/**
|
|
608
978
|
* Select all nodes in the tree
|
|
609
979
|
*/
|
|
610
980
|
selectAll() {
|
|
611
|
-
|
|
981
|
+
if (this.selectMode() === 'none') {
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
if (this.isLeafOnlyMode()) {
|
|
985
|
+
// Only select leaf nodes
|
|
986
|
+
const selectLeafs = (nodes) => {
|
|
987
|
+
for (const node of nodes) {
|
|
988
|
+
if (this.isLeafNode(node) && !this.getNodeDisabled(node)) {
|
|
989
|
+
this.setNodeSelected(node, true);
|
|
990
|
+
this.setNodeIndeterminate(node, false);
|
|
991
|
+
}
|
|
992
|
+
const children = this.getNodeChildren(node);
|
|
993
|
+
if (children) {
|
|
994
|
+
selectLeafs(children);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
selectLeafs(this.nodes());
|
|
999
|
+
}
|
|
1000
|
+
else {
|
|
1001
|
+
this.treeService.setAllSelection(this.nodes(), true, this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
1002
|
+
}
|
|
612
1003
|
this.refreshNodes();
|
|
1004
|
+
this.emitSelectionChange();
|
|
613
1005
|
}
|
|
614
1006
|
/**
|
|
615
1007
|
* Deselect all nodes in the tree
|
|
616
1008
|
*/
|
|
617
1009
|
deselectAll() {
|
|
618
|
-
this.treeService.setAllSelection(this.nodes(), false);
|
|
1010
|
+
this.treeService.setAllSelection(this.nodes(), false, this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
619
1011
|
this.refreshNodes();
|
|
1012
|
+
this.emitSelectionChange();
|
|
620
1013
|
}
|
|
621
1014
|
/**
|
|
622
1015
|
* Find a node by ID in the tree
|
|
623
1016
|
*/
|
|
624
1017
|
findNode(id) {
|
|
625
|
-
return this.treeService.findNodeById(this.nodes(), id);
|
|
1018
|
+
return this.treeService.findNodeById(this.nodes(), id, this.idField());
|
|
626
1019
|
}
|
|
627
1020
|
/**
|
|
628
1021
|
* Refresh the tree to trigger change detection
|
|
@@ -636,6 +1029,12 @@ class AXTreeViewComponent {
|
|
|
636
1029
|
isNodeLoading(nodeId) {
|
|
637
1030
|
return this.loadingNodes().has(nodeId);
|
|
638
1031
|
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Get loading state for a node (internal state)
|
|
1034
|
+
*/
|
|
1035
|
+
getNodeLoading(node) {
|
|
1036
|
+
return this.loadingNodes().has(this.getNodeId(node));
|
|
1037
|
+
}
|
|
639
1038
|
/**
|
|
640
1039
|
* Edit/update a node's properties
|
|
641
1040
|
* @param nodeId - The ID of the node to edit
|
|
@@ -643,22 +1042,12 @@ class AXTreeViewComponent {
|
|
|
643
1042
|
* @returns true if node was found and updated, false otherwise
|
|
644
1043
|
*/
|
|
645
1044
|
editNode(nodeId, updates) {
|
|
646
|
-
const
|
|
647
|
-
if (
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
// Update node properties
|
|
651
|
-
Object.assign(node, updates);
|
|
652
|
-
// If children array is provided, ensure it exists
|
|
653
|
-
if (updates.children !== undefined) {
|
|
654
|
-
node.children = updates.children;
|
|
655
|
-
}
|
|
656
|
-
// Update childrenCount if children array is provided
|
|
657
|
-
if (updates.children !== undefined) {
|
|
658
|
-
node.childrenCount = updates.children.length;
|
|
1045
|
+
const updated = this.treeService.editNode(this.nodes(), nodeId, updates, this.idField(), this.childrenField(), this.childrenCountField());
|
|
1046
|
+
if (updated) {
|
|
1047
|
+
this.refreshNodes();
|
|
1048
|
+
return true;
|
|
659
1049
|
}
|
|
660
|
-
|
|
661
|
-
return true;
|
|
1050
|
+
return false;
|
|
662
1051
|
}
|
|
663
1052
|
/**
|
|
664
1053
|
* Add a child node to a parent node
|
|
@@ -668,29 +1057,12 @@ class AXTreeViewComponent {
|
|
|
668
1057
|
* @returns true if parent was found and child was added, false otherwise
|
|
669
1058
|
*/
|
|
670
1059
|
addChild(parentId, childNode, index) {
|
|
671
|
-
const parent = this.
|
|
672
|
-
if (
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
// Ensure children array exists
|
|
676
|
-
if (!parent.children) {
|
|
677
|
-
parent.children = [];
|
|
678
|
-
}
|
|
679
|
-
// Insert or append child
|
|
680
|
-
if (index !== undefined && index >= 0 && index <= parent.children.length) {
|
|
681
|
-
parent.children.splice(index, 0, childNode);
|
|
682
|
-
}
|
|
683
|
-
else {
|
|
684
|
-
parent.children.push(childNode);
|
|
685
|
-
}
|
|
686
|
-
// Update childrenCount
|
|
687
|
-
parent.childrenCount = parent.children.length;
|
|
688
|
-
// Auto-expand parent if it was collapsed
|
|
689
|
-
if (!parent.expanded) {
|
|
690
|
-
parent.expanded = true;
|
|
1060
|
+
const parent = this.treeService.addChild(this.nodes(), parentId, childNode, index, this.idField(), this.childrenField(), this.childrenCountField(), this.expandedField());
|
|
1061
|
+
if (parent) {
|
|
1062
|
+
this.refreshNodes();
|
|
1063
|
+
return true;
|
|
691
1064
|
}
|
|
692
|
-
|
|
693
|
-
return true;
|
|
1065
|
+
return false;
|
|
694
1066
|
}
|
|
695
1067
|
/**
|
|
696
1068
|
* Remove a node from the tree
|
|
@@ -698,29 +1070,15 @@ class AXTreeViewComponent {
|
|
|
698
1070
|
* @returns The removed node if found, null otherwise
|
|
699
1071
|
*/
|
|
700
1072
|
removeNode(nodeId) {
|
|
701
|
-
const
|
|
702
|
-
if (
|
|
703
|
-
return null;
|
|
704
|
-
}
|
|
705
|
-
// Find parent to remove from its children array
|
|
706
|
-
const parent = this.treeService.findParentNode(this.nodes(), node);
|
|
707
|
-
const targetArray = parent?.children ?? this.nodes();
|
|
708
|
-
// Find and remove the node
|
|
709
|
-
const index = targetArray.findIndex((n) => n.id === nodeId);
|
|
710
|
-
if (index !== -1) {
|
|
711
|
-
const removed = targetArray.splice(index, 1)[0];
|
|
712
|
-
// Update parent's childrenCount if it exists
|
|
713
|
-
if (parent) {
|
|
714
|
-
parent.childrenCount = parent.children?.length ?? 0;
|
|
715
|
-
}
|
|
1073
|
+
const removed = this.treeService.removeNode(this.nodes(), nodeId, this.idField(), this.childrenField(), this.childrenCountField());
|
|
1074
|
+
if (removed) {
|
|
716
1075
|
// Update parent states if needed
|
|
717
|
-
if (this.
|
|
718
|
-
this.treeService.updateAllParentStates(this.nodes(), this.
|
|
1076
|
+
if (this.hasIntermediateState()) {
|
|
1077
|
+
this.treeService.updateAllParentStates(this.nodes(), this.hasIntermediateState(), this.childrenField(), this.selectedField(), this.indeterminateField());
|
|
719
1078
|
}
|
|
720
1079
|
this.refreshNodes();
|
|
721
|
-
return removed;
|
|
722
1080
|
}
|
|
723
|
-
return
|
|
1081
|
+
return removed;
|
|
724
1082
|
}
|
|
725
1083
|
/**
|
|
726
1084
|
* Expand a specific node
|
|
@@ -732,13 +1090,13 @@ class AXTreeViewComponent {
|
|
|
732
1090
|
if (!node) {
|
|
733
1091
|
return;
|
|
734
1092
|
}
|
|
735
|
-
const hasChildren = this.treeService.hasChildren(node);
|
|
736
|
-
const canLazyLoad = this.treeService.canLazyLoad(node, this.isLazyDataSource());
|
|
1093
|
+
const hasChildren = this.treeService.hasChildren(node, this.childrenField());
|
|
1094
|
+
const canLazyLoad = this.treeService.canLazyLoad(node, this.isLazyDataSource(), this.childrenCountField(), this.childrenField());
|
|
737
1095
|
if (hasChildren || canLazyLoad) {
|
|
738
1096
|
if (canLazyLoad) {
|
|
739
1097
|
await this.loadNodeChildren(node);
|
|
740
1098
|
}
|
|
741
|
-
node
|
|
1099
|
+
this.setNodeExpanded(node, true);
|
|
742
1100
|
this.refreshNodes();
|
|
743
1101
|
this.onNodeToggle.emit({ component: this, node, nativeEvent: new Event('expand') });
|
|
744
1102
|
}
|
|
@@ -752,8 +1110,8 @@ class AXTreeViewComponent {
|
|
|
752
1110
|
if (!node) {
|
|
753
1111
|
return;
|
|
754
1112
|
}
|
|
755
|
-
if (node
|
|
756
|
-
node
|
|
1113
|
+
if (this.getNodeExpanded(node)) {
|
|
1114
|
+
this.setNodeExpanded(node, false);
|
|
757
1115
|
this.refreshNodes();
|
|
758
1116
|
this.onNodeToggle.emit({ component: this, node, nativeEvent: new Event('collapse') });
|
|
759
1117
|
}
|
|
@@ -768,7 +1126,7 @@ class AXTreeViewComponent {
|
|
|
768
1126
|
if (!node) {
|
|
769
1127
|
return;
|
|
770
1128
|
}
|
|
771
|
-
if (node
|
|
1129
|
+
if (this.getNodeExpanded(node)) {
|
|
772
1130
|
this.collapseNode(nodeId);
|
|
773
1131
|
}
|
|
774
1132
|
else {
|
|
@@ -781,24 +1139,28 @@ class AXTreeViewComponent {
|
|
|
781
1139
|
* @returns true if node was found and selected, false otherwise
|
|
782
1140
|
*/
|
|
783
1141
|
selectNode(nodeId) {
|
|
1142
|
+
if (this.selectMode() === 'none') {
|
|
1143
|
+
return false;
|
|
1144
|
+
}
|
|
784
1145
|
const node = this.findNode(nodeId);
|
|
785
|
-
if (!node || node.
|
|
1146
|
+
if (!node || this.getNodeDisabled(node) || !this.canSelectNode(node)) {
|
|
786
1147
|
return false;
|
|
787
1148
|
}
|
|
788
1149
|
const mode = this.selectMode();
|
|
789
1150
|
if (mode === 'single') {
|
|
790
|
-
this.treeService.deselectAllNodes(this.nodes());
|
|
791
|
-
node
|
|
792
|
-
node
|
|
1151
|
+
this.treeService.deselectAllNodes(this.nodes(), this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
1152
|
+
this.setNodeSelected(node, true);
|
|
1153
|
+
this.setNodeIndeterminate(node, false);
|
|
793
1154
|
}
|
|
794
1155
|
else {
|
|
795
|
-
node
|
|
796
|
-
node
|
|
797
|
-
|
|
798
|
-
|
|
1156
|
+
this.setNodeSelected(node, true);
|
|
1157
|
+
this.setNodeIndeterminate(node, false);
|
|
1158
|
+
const children = this.getNodeChildren(node);
|
|
1159
|
+
if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
|
|
1160
|
+
this.treeService.selectAllChildren(children, true, this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
799
1161
|
}
|
|
800
|
-
if (this.
|
|
801
|
-
this.treeService.updateParentStates(this.nodes(), node, this.
|
|
1162
|
+
if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
|
|
1163
|
+
this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
|
|
802
1164
|
}
|
|
803
1165
|
}
|
|
804
1166
|
this.refreshNodes();
|
|
@@ -807,6 +1169,7 @@ class AXTreeViewComponent {
|
|
|
807
1169
|
node,
|
|
808
1170
|
isUserInteraction: false,
|
|
809
1171
|
});
|
|
1172
|
+
this.emitSelectionChange();
|
|
810
1173
|
return true;
|
|
811
1174
|
}
|
|
812
1175
|
/**
|
|
@@ -819,13 +1182,14 @@ class AXTreeViewComponent {
|
|
|
819
1182
|
if (!node) {
|
|
820
1183
|
return false;
|
|
821
1184
|
}
|
|
822
|
-
node
|
|
823
|
-
node
|
|
824
|
-
|
|
825
|
-
|
|
1185
|
+
this.setNodeSelected(node, false);
|
|
1186
|
+
this.setNodeIndeterminate(node, false);
|
|
1187
|
+
const children = this.getNodeChildren(node);
|
|
1188
|
+
if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
|
|
1189
|
+
this.treeService.selectAllChildren(children, false, this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
826
1190
|
}
|
|
827
|
-
if (this.
|
|
828
|
-
this.treeService.updateParentStates(this.nodes(), node, this.
|
|
1191
|
+
if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
|
|
1192
|
+
this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
|
|
829
1193
|
}
|
|
830
1194
|
this.refreshNodes();
|
|
831
1195
|
this.onNodeSelect.emit({
|
|
@@ -833,6 +1197,7 @@ class AXTreeViewComponent {
|
|
|
833
1197
|
node,
|
|
834
1198
|
isUserInteraction: false,
|
|
835
1199
|
});
|
|
1200
|
+
this.emitSelectionChange();
|
|
836
1201
|
return true;
|
|
837
1202
|
}
|
|
838
1203
|
/**
|
|
@@ -845,7 +1210,7 @@ class AXTreeViewComponent {
|
|
|
845
1210
|
if (!node) {
|
|
846
1211
|
return null;
|
|
847
1212
|
}
|
|
848
|
-
return this.treeService.findParentNode(this.nodes(), node) ?? null;
|
|
1213
|
+
return this.treeService.findParentNode(this.nodes(), node, this.idField(), this.childrenField()) ?? null;
|
|
849
1214
|
}
|
|
850
1215
|
/**
|
|
851
1216
|
* Get children of a node
|
|
@@ -857,7 +1222,7 @@ class AXTreeViewComponent {
|
|
|
857
1222
|
if (!node) {
|
|
858
1223
|
return null;
|
|
859
1224
|
}
|
|
860
|
-
return node
|
|
1225
|
+
return this.getNodeChildren(node) ?? [];
|
|
861
1226
|
}
|
|
862
1227
|
/**
|
|
863
1228
|
* Get all root nodes
|
|
@@ -871,17 +1236,7 @@ class AXTreeViewComponent {
|
|
|
871
1236
|
* @returns Array of all nodes in the tree
|
|
872
1237
|
*/
|
|
873
1238
|
getAllNodes() {
|
|
874
|
-
|
|
875
|
-
const traverse = (nodes) => {
|
|
876
|
-
for (const node of nodes) {
|
|
877
|
-
allNodes.push(node);
|
|
878
|
-
if (node.children) {
|
|
879
|
-
traverse(node.children);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
};
|
|
883
|
-
traverse(this.nodes());
|
|
884
|
-
return allNodes;
|
|
1239
|
+
return this.treeService.getAllNodes(this.nodes(), this.childrenField());
|
|
885
1240
|
}
|
|
886
1241
|
/**
|
|
887
1242
|
* Get the path to a node (array of parent IDs from root to node)
|
|
@@ -889,18 +1244,8 @@ class AXTreeViewComponent {
|
|
|
889
1244
|
* @returns Array of node IDs representing the path, or empty array if node not found
|
|
890
1245
|
*/
|
|
891
1246
|
getNodePath(nodeId) {
|
|
892
|
-
const
|
|
893
|
-
|
|
894
|
-
if (!node) {
|
|
895
|
-
return path;
|
|
896
|
-
}
|
|
897
|
-
let current = node;
|
|
898
|
-
while (current) {
|
|
899
|
-
path.unshift(current.id);
|
|
900
|
-
const parent = this.treeService.findParentNode(this.nodes(), current);
|
|
901
|
-
current = parent ?? null;
|
|
902
|
-
}
|
|
903
|
-
return path;
|
|
1247
|
+
const nodePath = this.treeService.getNodePath(this.nodes(), nodeId, this.idField(), this.childrenField());
|
|
1248
|
+
return nodePath.map((node) => this.getNodeId(node));
|
|
904
1249
|
}
|
|
905
1250
|
/**
|
|
906
1251
|
* Get the level/depth of a node (0 = root level)
|
|
@@ -908,8 +1253,7 @@ class AXTreeViewComponent {
|
|
|
908
1253
|
* @returns The level of the node, or -1 if node not found
|
|
909
1254
|
*/
|
|
910
1255
|
getNodeLevel(nodeId) {
|
|
911
|
-
|
|
912
|
-
return path.length > 0 ? path.length - 1 : -1;
|
|
1256
|
+
return this.treeService.getNodeLevel(this.nodes(), nodeId, this.idField(), this.childrenField());
|
|
913
1257
|
}
|
|
914
1258
|
/**
|
|
915
1259
|
* Programmatically move a node to a new parent
|
|
@@ -919,64 +1263,14 @@ class AXTreeViewComponent {
|
|
|
919
1263
|
* @returns true if move was successful, false otherwise
|
|
920
1264
|
*/
|
|
921
1265
|
moveNode(nodeId, newParentId, index) {
|
|
922
|
-
const
|
|
923
|
-
if (
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
const currentArray = currentParent?.children ?? this.nodes();
|
|
929
|
-
// Find and remove from current location
|
|
930
|
-
const currentIndex = currentArray.findIndex((n) => n.id === nodeId);
|
|
931
|
-
if (currentIndex === -1) {
|
|
932
|
-
return false;
|
|
933
|
-
}
|
|
934
|
-
const movedNode = currentArray.splice(currentIndex, 1)[0];
|
|
935
|
-
// Find new parent
|
|
936
|
-
let targetArray;
|
|
937
|
-
let newParent;
|
|
938
|
-
if (newParentId) {
|
|
939
|
-
newParent = this.findNode(newParentId);
|
|
940
|
-
if (!newParent) {
|
|
941
|
-
// Restore node if new parent not found
|
|
942
|
-
currentArray.splice(currentIndex, 0, movedNode);
|
|
943
|
-
return false;
|
|
944
|
-
}
|
|
945
|
-
// Validate drop target
|
|
946
|
-
if (!this.treeService.isValidDropTarget(movedNode, newParent)) {
|
|
947
|
-
// Restore node if invalid drop target
|
|
948
|
-
currentArray.splice(currentIndex, 0, movedNode);
|
|
949
|
-
return false;
|
|
950
|
-
}
|
|
951
|
-
if (!newParent.children) {
|
|
952
|
-
newParent.children = [];
|
|
953
|
-
}
|
|
954
|
-
targetArray = newParent.children;
|
|
955
|
-
}
|
|
956
|
-
else {
|
|
957
|
-
targetArray = this.nodes();
|
|
958
|
-
}
|
|
959
|
-
// Calculate new index before inserting
|
|
960
|
-
const newIndex = index !== undefined && index >= 0 && index <= targetArray.length ? index : targetArray.length;
|
|
961
|
-
// Insert at new location
|
|
962
|
-
if (index !== undefined && index >= 0 && index <= targetArray.length) {
|
|
963
|
-
targetArray.splice(index, 0, movedNode);
|
|
964
|
-
}
|
|
965
|
-
else {
|
|
966
|
-
targetArray.push(movedNode);
|
|
967
|
-
}
|
|
968
|
-
// Update childrenCount
|
|
969
|
-
if (currentParent) {
|
|
970
|
-
currentParent.childrenCount = currentParent.children?.length ?? 0;
|
|
971
|
-
}
|
|
972
|
-
if (newParent) {
|
|
973
|
-
newParent.childrenCount = newParent.children?.length ?? 0;
|
|
974
|
-
newParent.expanded = true; // Auto-expand new parent
|
|
1266
|
+
const result = this.treeService.moveNode(this.nodes(), nodeId, newParentId, index, this.idField(), this.childrenField(), this.childrenCountField(), this.expandedField());
|
|
1267
|
+
if (result.success && result.movedNode) {
|
|
1268
|
+
// Emit drop events
|
|
1269
|
+
this.emitDropEvents(result.movedNode, result.previousParent, result.newParent, result.previousIndex, result.currentIndex, false);
|
|
1270
|
+
this.refreshNodes();
|
|
1271
|
+
return true;
|
|
975
1272
|
}
|
|
976
|
-
|
|
977
|
-
this.emitDropEvents(movedNode, currentParent, newParent, currentIndex, newIndex, false);
|
|
978
|
-
this.refreshNodes();
|
|
979
|
-
return true;
|
|
1273
|
+
return false;
|
|
980
1274
|
}
|
|
981
1275
|
/**
|
|
982
1276
|
* Clone a node (creates a deep copy)
|
|
@@ -988,7 +1282,7 @@ class AXTreeViewComponent {
|
|
|
988
1282
|
if (!node) {
|
|
989
1283
|
return null;
|
|
990
1284
|
}
|
|
991
|
-
return this.treeService.cloneNode(node);
|
|
1285
|
+
return this.treeService.cloneNode(node, this.idField(), this.titleField(), this.tooltipField(), this.iconField(), this.expandedField(), this.selectedField(), this.indeterminateField(), this.disabledField(), this.hiddenField(), this.childrenCountField(), this.dataField(), this.childrenField());
|
|
992
1286
|
}
|
|
993
1287
|
/**
|
|
994
1288
|
* Focus a specific node by ID
|
|
@@ -997,7 +1291,7 @@ class AXTreeViewComponent {
|
|
|
997
1291
|
*/
|
|
998
1292
|
focusNode(nodeId) {
|
|
999
1293
|
const node = this.findNode(nodeId);
|
|
1000
|
-
if (!node || node
|
|
1294
|
+
if (!node || this.getNodeHidden(node) === true || this.getNodeDisabled(node)) {
|
|
1001
1295
|
return false;
|
|
1002
1296
|
}
|
|
1003
1297
|
this.focusNodeById(nodeId);
|
|
@@ -1011,11 +1305,12 @@ class AXTreeViewComponent {
|
|
|
1011
1305
|
const expanded = [];
|
|
1012
1306
|
const traverse = (nodes) => {
|
|
1013
1307
|
for (const node of nodes) {
|
|
1014
|
-
if (node
|
|
1308
|
+
if (this.getNodeExpanded(node)) {
|
|
1015
1309
|
expanded.push(node);
|
|
1016
1310
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1311
|
+
const children = this.getNodeChildren(node);
|
|
1312
|
+
if (children) {
|
|
1313
|
+
traverse(children);
|
|
1019
1314
|
}
|
|
1020
1315
|
}
|
|
1021
1316
|
};
|
|
@@ -1030,11 +1325,13 @@ class AXTreeViewComponent {
|
|
|
1030
1325
|
const collapsed = [];
|
|
1031
1326
|
const traverse = (nodes) => {
|
|
1032
1327
|
for (const node of nodes) {
|
|
1033
|
-
|
|
1328
|
+
const children = this.getNodeChildren(node);
|
|
1329
|
+
const childrenCount = this.getNodeChildrenCount(node);
|
|
1330
|
+
if (!this.getNodeExpanded(node) && (children?.length || childrenCount)) {
|
|
1034
1331
|
collapsed.push(node);
|
|
1035
1332
|
}
|
|
1036
|
-
if (
|
|
1037
|
-
traverse(
|
|
1333
|
+
if (children) {
|
|
1334
|
+
traverse(children);
|
|
1038
1335
|
}
|
|
1039
1336
|
}
|
|
1040
1337
|
};
|
|
@@ -1048,7 +1345,7 @@ class AXTreeViewComponent {
|
|
|
1048
1345
|
*/
|
|
1049
1346
|
isNodeExpanded(nodeId) {
|
|
1050
1347
|
const node = this.findNode(nodeId);
|
|
1051
|
-
return node
|
|
1348
|
+
return node ? this.getNodeExpanded(node) : false;
|
|
1052
1349
|
}
|
|
1053
1350
|
/**
|
|
1054
1351
|
* Check if a node is selected
|
|
@@ -1057,7 +1354,7 @@ class AXTreeViewComponent {
|
|
|
1057
1354
|
*/
|
|
1058
1355
|
isNodeSelected(nodeId) {
|
|
1059
1356
|
const node = this.findNode(nodeId);
|
|
1060
|
-
return node
|
|
1357
|
+
return node ? this.getNodeSelected(node) : false;
|
|
1061
1358
|
}
|
|
1062
1359
|
/**
|
|
1063
1360
|
* Check if a node has children
|
|
@@ -1066,19 +1363,21 @@ class AXTreeViewComponent {
|
|
|
1066
1363
|
*/
|
|
1067
1364
|
hasChildren(nodeId) {
|
|
1068
1365
|
const node = this.findNode(nodeId);
|
|
1069
|
-
return this.treeService.hasChildren(node ?? {
|
|
1366
|
+
return this.treeService.hasChildren(node ?? {}, this.childrenField());
|
|
1070
1367
|
}
|
|
1071
1368
|
/**
|
|
1072
1369
|
* Get template context for a node
|
|
1073
1370
|
*/
|
|
1074
1371
|
getTemplateContext(node, level = 0) {
|
|
1372
|
+
const children = this.getNodeChildren(node);
|
|
1373
|
+
const childrenCount = this.getNodeChildrenCount(node);
|
|
1075
1374
|
return {
|
|
1076
1375
|
$implicit: node,
|
|
1077
1376
|
node,
|
|
1078
1377
|
level,
|
|
1079
|
-
expanded: node
|
|
1080
|
-
childrenCount:
|
|
1081
|
-
loading: node
|
|
1378
|
+
expanded: this.getNodeExpanded(node),
|
|
1379
|
+
childrenCount: childrenCount ?? children?.length ?? 0,
|
|
1380
|
+
loading: this.getNodeLoading(node),
|
|
1082
1381
|
};
|
|
1083
1382
|
}
|
|
1084
1383
|
/**
|
|
@@ -1094,7 +1393,8 @@ class AXTreeViewComponent {
|
|
|
1094
1393
|
* Check if node should show expand toggle
|
|
1095
1394
|
*/
|
|
1096
1395
|
shouldShowExpandToggle(node) {
|
|
1097
|
-
return this.treeService.hasChildren(node
|
|
1396
|
+
return (this.treeService.hasChildren(node, this.childrenField()) ||
|
|
1397
|
+
this.treeService.canLazyLoad(node, this.isLazyDataSource(), this.childrenCountField(), this.childrenField()));
|
|
1098
1398
|
}
|
|
1099
1399
|
/**
|
|
1100
1400
|
* Check if checkboxes should be shown (only for multiple mode)
|
|
@@ -1102,11 +1402,50 @@ class AXTreeViewComponent {
|
|
|
1102
1402
|
shouldShowCheckbox() {
|
|
1103
1403
|
return this.selectMode() === 'multiple' && this.showCheckbox();
|
|
1104
1404
|
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Check if a node is a leaf (has no children)
|
|
1407
|
+
* A node is a leaf if it has no loaded children AND no childrenCount (or childrenCount is 0)
|
|
1408
|
+
*/
|
|
1409
|
+
isLeafNode(node) {
|
|
1410
|
+
const hasChildren = this.treeService.hasChildren(node, this.childrenField());
|
|
1411
|
+
const childrenCount = this.getNodeChildrenCount(node);
|
|
1412
|
+
const hasChildrenCount = childrenCount && childrenCount > 0;
|
|
1413
|
+
const canLazyLoad = this.treeService.canLazyLoad(node, this.isLazyDataSource(), this.childrenCountField(), this.childrenField());
|
|
1414
|
+
// A node is a leaf if:
|
|
1415
|
+
// 1. It has no loaded children
|
|
1416
|
+
// 2. AND it has no childrenCount (or childrenCount is 0)
|
|
1417
|
+
// 3. AND it cannot be lazy loaded
|
|
1418
|
+
return !hasChildren && !hasChildrenCount && !canLazyLoad;
|
|
1419
|
+
}
|
|
1420
|
+
/**
|
|
1421
|
+
* Check if a node can be selected (considering selectMode and isLeafOnlyMode)
|
|
1422
|
+
*/
|
|
1423
|
+
canSelectNode(node) {
|
|
1424
|
+
if (this.selectMode() === 'none') {
|
|
1425
|
+
return false;
|
|
1426
|
+
}
|
|
1427
|
+
if (this.isLeafOnlyMode()) {
|
|
1428
|
+
return this.isLeafNode(node);
|
|
1429
|
+
}
|
|
1430
|
+
return true;
|
|
1431
|
+
}
|
|
1432
|
+
/**
|
|
1433
|
+
* Check if checkbox should be shown for a specific node
|
|
1434
|
+
*/
|
|
1435
|
+
shouldShowCheckboxForNode(node) {
|
|
1436
|
+
if (!this.shouldShowCheckbox()) {
|
|
1437
|
+
return false;
|
|
1438
|
+
}
|
|
1439
|
+
if (this.isLeafOnlyMode()) {
|
|
1440
|
+
return this.isLeafNode(node);
|
|
1441
|
+
}
|
|
1442
|
+
return true;
|
|
1443
|
+
}
|
|
1105
1444
|
/**
|
|
1106
1445
|
* Generate unique list ID for each node
|
|
1107
1446
|
*/
|
|
1108
1447
|
getListId(node) {
|
|
1109
|
-
return this.treeService.getListId(node);
|
|
1448
|
+
return this.treeService.getListId(node, this.idField());
|
|
1110
1449
|
}
|
|
1111
1450
|
/**
|
|
1112
1451
|
* Check if a node is currently focused
|
|
@@ -1127,30 +1466,50 @@ class AXTreeViewComponent {
|
|
|
1127
1466
|
if (!this.shouldShowExpandToggle(node)) {
|
|
1128
1467
|
return null;
|
|
1129
1468
|
}
|
|
1130
|
-
return node
|
|
1469
|
+
return this.getNodeExpanded(node) ? 'true' : 'false';
|
|
1131
1470
|
}
|
|
1132
1471
|
/**
|
|
1133
1472
|
* Get ARIA selected state for a node
|
|
1134
1473
|
*/
|
|
1135
1474
|
getNodeAriaSelected(node) {
|
|
1475
|
+
if (this.selectMode() === 'none') {
|
|
1476
|
+
return null;
|
|
1477
|
+
}
|
|
1478
|
+
const selected = this.getNodeSelected(node);
|
|
1136
1479
|
if (this.selectMode() === 'single') {
|
|
1137
|
-
return
|
|
1480
|
+
return selected ? 'true' : 'false';
|
|
1481
|
+
}
|
|
1482
|
+
if (this.selectMode() === 'multiple') {
|
|
1483
|
+
return selected ? 'true' : 'false';
|
|
1138
1484
|
}
|
|
1139
1485
|
return null;
|
|
1140
1486
|
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Emit selection change event with all selected nodes
|
|
1489
|
+
*/
|
|
1490
|
+
emitSelectionChange() {
|
|
1491
|
+
const selectedNodes = this.getSelectedNodes();
|
|
1492
|
+
this.onSelectionChange.emit({
|
|
1493
|
+
component: this,
|
|
1494
|
+
selectedNodes,
|
|
1495
|
+
});
|
|
1496
|
+
}
|
|
1141
1497
|
// ==================== Event Handlers ====================
|
|
1142
1498
|
/**
|
|
1143
|
-
* Handle node click - for single selection mode or multiple mode
|
|
1499
|
+
* Handle node click - for single selection mode or multiple mode when showCheckbox is false
|
|
1144
1500
|
*/
|
|
1145
1501
|
onNodeClick(node, event) {
|
|
1146
|
-
if (node
|
|
1502
|
+
if (this.getNodeDisabled(node))
|
|
1503
|
+
return;
|
|
1504
|
+
if (this.selectMode() === 'none')
|
|
1505
|
+
return;
|
|
1506
|
+
if (!this.canSelectNode(node))
|
|
1147
1507
|
return;
|
|
1148
1508
|
const mode = this.selectMode();
|
|
1149
|
-
const shouldCheckOnClick = this.checkOnClick();
|
|
1150
1509
|
if (mode === 'single') {
|
|
1151
1510
|
this.handleSingleSelection(node, event);
|
|
1152
1511
|
}
|
|
1153
|
-
else if (mode === 'multiple' &&
|
|
1512
|
+
else if (mode === 'multiple' && !this.showCheckbox()) {
|
|
1154
1513
|
this.handleMultipleSelection(node, event);
|
|
1155
1514
|
}
|
|
1156
1515
|
}
|
|
@@ -1158,19 +1517,19 @@ class AXTreeViewComponent {
|
|
|
1158
1517
|
* Toggle node expansion state with lazy loading support
|
|
1159
1518
|
*/
|
|
1160
1519
|
async toggleNode(node, event) {
|
|
1161
|
-
if (node
|
|
1520
|
+
if (this.getNodeDisabled(node))
|
|
1162
1521
|
return;
|
|
1163
1522
|
if (this.isEvent(event) && typeof event.stopPropagation === 'function') {
|
|
1164
1523
|
event.stopPropagation();
|
|
1165
1524
|
}
|
|
1166
|
-
const hasChildren = this.treeService.hasChildren(node);
|
|
1167
|
-
const canLazyLoad = this.treeService.canLazyLoad(node, this.isLazyDataSource());
|
|
1525
|
+
const hasChildren = this.treeService.hasChildren(node, this.childrenField());
|
|
1526
|
+
const canLazyLoad = this.treeService.canLazyLoad(node, this.isLazyDataSource(), this.childrenCountField(), this.childrenField());
|
|
1168
1527
|
if (hasChildren || canLazyLoad) {
|
|
1169
|
-
const willExpand = !node
|
|
1528
|
+
const willExpand = !this.getNodeExpanded(node);
|
|
1170
1529
|
if (willExpand && canLazyLoad) {
|
|
1171
1530
|
await this.loadNodeChildren(node);
|
|
1172
1531
|
}
|
|
1173
|
-
node
|
|
1532
|
+
this.setNodeExpanded(node, willExpand);
|
|
1174
1533
|
this.refreshNodes();
|
|
1175
1534
|
this.onNodeToggle.emit({ component: this, node, nativeEvent: event });
|
|
1176
1535
|
}
|
|
@@ -1181,17 +1540,22 @@ class AXTreeViewComponent {
|
|
|
1181
1540
|
toggleSelection(node, event) {
|
|
1182
1541
|
if (!event.isUserInteraction)
|
|
1183
1542
|
return;
|
|
1543
|
+
if (this.selectMode() === 'none')
|
|
1544
|
+
return;
|
|
1545
|
+
if (!this.canSelectNode(node))
|
|
1546
|
+
return;
|
|
1184
1547
|
const mode = this.selectMode();
|
|
1185
1548
|
if (mode !== 'multiple')
|
|
1186
1549
|
return;
|
|
1187
1550
|
const newValue = event.value === null ? true : event.value;
|
|
1188
|
-
node
|
|
1189
|
-
node
|
|
1190
|
-
|
|
1191
|
-
|
|
1551
|
+
this.setNodeSelected(node, newValue);
|
|
1552
|
+
this.setNodeIndeterminate(node, false);
|
|
1553
|
+
const children = this.getNodeChildren(node);
|
|
1554
|
+
if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
|
|
1555
|
+
this.treeService.selectAllChildren(children, newValue, this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
1192
1556
|
}
|
|
1193
|
-
if (this.
|
|
1194
|
-
this.treeService.updateParentStates(this.nodes(), node, this.
|
|
1557
|
+
if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
|
|
1558
|
+
this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
|
|
1195
1559
|
}
|
|
1196
1560
|
this.refreshNodes();
|
|
1197
1561
|
this.onNodeSelect.emit({
|
|
@@ -1199,12 +1563,13 @@ class AXTreeViewComponent {
|
|
|
1199
1563
|
node,
|
|
1200
1564
|
isUserInteraction: event.isUserInteraction,
|
|
1201
1565
|
});
|
|
1566
|
+
this.emitSelectionChange();
|
|
1202
1567
|
}
|
|
1203
1568
|
/**
|
|
1204
1569
|
* Handle drop events for tree nodes
|
|
1205
1570
|
*/
|
|
1206
1571
|
onDrop(event, parentNode) {
|
|
1207
|
-
const targetArray = parentNode
|
|
1572
|
+
const targetArray = parentNode ? (this.getNodeChildren(parentNode) ?? []) : this.nodes();
|
|
1208
1573
|
const isReordering = event.previousContainer === event.container;
|
|
1209
1574
|
if (isReordering) {
|
|
1210
1575
|
this.handleReorder(event, targetArray, parentNode);
|
|
@@ -1225,14 +1590,18 @@ class AXTreeViewComponent {
|
|
|
1225
1590
|
if (!sourceArray)
|
|
1226
1591
|
return;
|
|
1227
1592
|
const movedNode = sourceArray[event.previousIndex];
|
|
1228
|
-
if (!this.treeService.isValidDropTarget(movedNode, targetNode))
|
|
1593
|
+
if (!this.treeService.isValidDropTarget(movedNode, targetNode, this.idField(), this.childrenField()))
|
|
1229
1594
|
return;
|
|
1230
1595
|
if (!this.emitBeforeDropEvent(movedNode, sourceListId, targetNode, event.previousIndex, 0))
|
|
1231
1596
|
return;
|
|
1232
|
-
|
|
1597
|
+
let targetChildren = this.getNodeChildren(targetNode);
|
|
1598
|
+
if (!targetChildren) {
|
|
1599
|
+
targetChildren = [];
|
|
1600
|
+
this.setNodeChildren(targetNode, targetChildren);
|
|
1601
|
+
}
|
|
1233
1602
|
sourceArray.splice(event.previousIndex, 1);
|
|
1234
|
-
|
|
1235
|
-
targetNode
|
|
1603
|
+
targetChildren.unshift(movedNode);
|
|
1604
|
+
this.setNodeExpanded(targetNode, true);
|
|
1236
1605
|
this.emitDropEvents(movedNode, this.findParentByListId(sourceListId), targetNode, event.previousIndex, 0, false);
|
|
1237
1606
|
this.refreshNodes();
|
|
1238
1607
|
}
|
|
@@ -1247,23 +1616,23 @@ class AXTreeViewComponent {
|
|
|
1247
1616
|
*/
|
|
1248
1617
|
onTreeFocus(event) {
|
|
1249
1618
|
if (event.target === event.currentTarget) {
|
|
1250
|
-
const flatList = this.treeService.buildFlatNodeList(this.nodes());
|
|
1619
|
+
const flatList = this.treeService.buildFlatNodeList(this.nodes(), this.hiddenField(), this.disabledField(), this.expandedField(), this.childrenField());
|
|
1251
1620
|
if (flatList.length > 0) {
|
|
1252
1621
|
const focusedId = this.focusedNodeId();
|
|
1253
1622
|
if (focusedId) {
|
|
1254
|
-
// Check if the focused node still exists and is
|
|
1255
|
-
const focusedNode = this.treeService.findNodeById(this.nodes(), focusedId);
|
|
1256
|
-
if (focusedNode && focusedNode
|
|
1623
|
+
// Check if the focused node still exists and is not hidden
|
|
1624
|
+
const focusedNode = this.treeService.findNodeById(this.nodes(), focusedId, this.idField());
|
|
1625
|
+
if (focusedNode && this.getNodeHidden(focusedNode) !== true) {
|
|
1257
1626
|
this.focusNodeById(focusedId);
|
|
1258
1627
|
}
|
|
1259
1628
|
else {
|
|
1260
1629
|
// Focused node no longer exists, focus first node
|
|
1261
|
-
this.focusNodeById(flatList[0].node
|
|
1630
|
+
this.focusNodeById(this.getNodeId(flatList[0].node));
|
|
1262
1631
|
}
|
|
1263
1632
|
}
|
|
1264
1633
|
else {
|
|
1265
1634
|
// No node is focused, focus first node
|
|
1266
|
-
this.focusNodeById(flatList[0].node
|
|
1635
|
+
this.focusNodeById(this.getNodeId(flatList[0].node));
|
|
1267
1636
|
}
|
|
1268
1637
|
}
|
|
1269
1638
|
}
|
|
@@ -1280,11 +1649,13 @@ class AXTreeViewComponent {
|
|
|
1280
1649
|
* Handle keyboard navigation
|
|
1281
1650
|
*/
|
|
1282
1651
|
handleKeyDown(event) {
|
|
1283
|
-
const flatList = this.treeService.buildFlatNodeList(this.nodes());
|
|
1652
|
+
const flatList = this.treeService.buildFlatNodeList(this.nodes(), this.hiddenField(), this.disabledField(), this.expandedField(), this.childrenField());
|
|
1284
1653
|
if (flatList.length === 0)
|
|
1285
1654
|
return;
|
|
1286
1655
|
const currentFocused = this.getFocusedNode();
|
|
1287
|
-
let currentIndex = currentFocused
|
|
1656
|
+
let currentIndex = currentFocused
|
|
1657
|
+
? flatList.findIndex((item) => this.getNodeId(item.node) === this.getNodeId(currentFocused))
|
|
1658
|
+
: -1;
|
|
1288
1659
|
if (currentIndex === -1 && event.target === event.currentTarget) {
|
|
1289
1660
|
currentIndex = 0;
|
|
1290
1661
|
}
|
|
@@ -1297,7 +1668,7 @@ class AXTreeViewComponent {
|
|
|
1297
1668
|
if (navigationResult.targetIndex !== null &&
|
|
1298
1669
|
navigationResult.targetIndex >= 0 &&
|
|
1299
1670
|
navigationResult.targetIndex < flatList.length) {
|
|
1300
|
-
this.focusNodeById(flatList[navigationResult.targetIndex].node
|
|
1671
|
+
this.focusNodeById(this.getNodeId(flatList[navigationResult.targetIndex].node));
|
|
1301
1672
|
}
|
|
1302
1673
|
}
|
|
1303
1674
|
}
|
|
@@ -1320,32 +1691,34 @@ class AXTreeViewComponent {
|
|
|
1320
1691
|
* Load children for a node using lazy loading
|
|
1321
1692
|
*/
|
|
1322
1693
|
async loadNodeChildren(node) {
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
if (this.treeService.hasChildren(node) || !node.childrenCount || node.childrenCount === 0) {
|
|
1694
|
+
const nodeId = this.getNodeId(node);
|
|
1695
|
+
if (!this.isLazyDataSource() || this.loadingNodes().has(nodeId))
|
|
1326
1696
|
return;
|
|
1697
|
+
if (this.treeService.hasChildren(node, this.childrenField())) {
|
|
1698
|
+
const childrenCount = this.getNodeChildrenCount(node);
|
|
1699
|
+
if (!childrenCount || childrenCount === 0) {
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1327
1702
|
}
|
|
1328
1703
|
const ds = this.datasource();
|
|
1329
1704
|
if (typeof ds !== 'function')
|
|
1330
1705
|
return;
|
|
1331
1706
|
try {
|
|
1332
|
-
|
|
1333
|
-
this.loadingNodes.update((set) => new Set(set).add(node.id));
|
|
1707
|
+
this.loadingNodes.update((set) => new Set(set).add(nodeId));
|
|
1334
1708
|
this.refreshNodes();
|
|
1335
|
-
const result = ds(
|
|
1709
|
+
const result = ds(nodeId);
|
|
1336
1710
|
const children = result instanceof Promise ? await result : result;
|
|
1337
|
-
node
|
|
1338
|
-
node
|
|
1711
|
+
this.setNodeChildren(node, children);
|
|
1712
|
+
this.setNodeChildrenCount(node, children.length);
|
|
1339
1713
|
}
|
|
1340
1714
|
catch (error) {
|
|
1341
1715
|
this.handleError('Failed to load children', error);
|
|
1342
|
-
node
|
|
1716
|
+
this.setNodeChildrenCount(node, 0);
|
|
1343
1717
|
}
|
|
1344
1718
|
finally {
|
|
1345
|
-
node.loading = false;
|
|
1346
1719
|
this.loadingNodes.update((set) => {
|
|
1347
1720
|
const newSet = new Set(set);
|
|
1348
|
-
newSet.delete(
|
|
1721
|
+
newSet.delete(nodeId);
|
|
1349
1722
|
return newSet;
|
|
1350
1723
|
});
|
|
1351
1724
|
this.refreshNodes();
|
|
@@ -1375,11 +1748,12 @@ class AXTreeViewComponent {
|
|
|
1375
1748
|
*/
|
|
1376
1749
|
ensureNewArrayReferences(nodes) {
|
|
1377
1750
|
for (const node of nodes) {
|
|
1378
|
-
|
|
1751
|
+
const children = this.getNodeChildren(node);
|
|
1752
|
+
if (children && children.length > 0) {
|
|
1379
1753
|
// Create new array reference for children
|
|
1380
|
-
node
|
|
1754
|
+
this.setNodeChildren(node, [...children]);
|
|
1381
1755
|
// Recursively process nested children
|
|
1382
|
-
this.ensureNewArrayReferences(
|
|
1756
|
+
this.ensureNewArrayReferences(children);
|
|
1383
1757
|
}
|
|
1384
1758
|
}
|
|
1385
1759
|
}
|
|
@@ -1387,9 +1761,9 @@ class AXTreeViewComponent {
|
|
|
1387
1761
|
* Handle single selection mode
|
|
1388
1762
|
*/
|
|
1389
1763
|
handleSingleSelection(node, event) {
|
|
1390
|
-
this.treeService.deselectAllNodes(this.nodes());
|
|
1391
|
-
node
|
|
1392
|
-
node
|
|
1764
|
+
this.treeService.deselectAllNodes(this.nodes(), this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
1765
|
+
this.setNodeSelected(node, true);
|
|
1766
|
+
this.setNodeIndeterminate(node, false);
|
|
1393
1767
|
this.refreshNodes();
|
|
1394
1768
|
this.onNodeSelect.emit({
|
|
1395
1769
|
component: this,
|
|
@@ -1397,19 +1771,21 @@ class AXTreeViewComponent {
|
|
|
1397
1771
|
nativeEvent: event,
|
|
1398
1772
|
isUserInteraction: true,
|
|
1399
1773
|
});
|
|
1774
|
+
this.emitSelectionChange();
|
|
1400
1775
|
}
|
|
1401
1776
|
/**
|
|
1402
|
-
* Handle multiple selection mode
|
|
1777
|
+
* Handle multiple selection mode when showCheckbox is false (click to toggle)
|
|
1403
1778
|
*/
|
|
1404
1779
|
handleMultipleSelection(node, event) {
|
|
1405
|
-
const newValue = !node
|
|
1406
|
-
node
|
|
1407
|
-
node
|
|
1408
|
-
|
|
1409
|
-
|
|
1780
|
+
const newValue = !this.getNodeSelected(node);
|
|
1781
|
+
this.setNodeSelected(node, newValue);
|
|
1782
|
+
this.setNodeIndeterminate(node, false);
|
|
1783
|
+
const children = this.getNodeChildren(node);
|
|
1784
|
+
if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
|
|
1785
|
+
this.treeService.selectAllChildren(children, newValue, this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
1410
1786
|
}
|
|
1411
|
-
if (this.
|
|
1412
|
-
this.treeService.updateParentStates(this.nodes(), node, this.
|
|
1787
|
+
if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
|
|
1788
|
+
this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
|
|
1413
1789
|
}
|
|
1414
1790
|
this.refreshNodes();
|
|
1415
1791
|
this.onNodeSelect.emit({
|
|
@@ -1418,30 +1794,33 @@ class AXTreeViewComponent {
|
|
|
1418
1794
|
nativeEvent: event,
|
|
1419
1795
|
isUserInteraction: true,
|
|
1420
1796
|
});
|
|
1797
|
+
this.emitSelectionChange();
|
|
1421
1798
|
}
|
|
1422
1799
|
/**
|
|
1423
1800
|
* Get array reference by drop list ID
|
|
1424
1801
|
*/
|
|
1425
1802
|
getArrayByListId(listId) {
|
|
1426
|
-
return this.treeService.getArrayByListId(this.nodes(), listId);
|
|
1803
|
+
return this.treeService.getArrayByListId(this.nodes(), listId, this.idField(), this.childrenField());
|
|
1427
1804
|
}
|
|
1428
1805
|
/**
|
|
1429
1806
|
* Find parent node by list ID
|
|
1430
1807
|
*/
|
|
1431
1808
|
findParentByListId(listId) {
|
|
1432
|
-
return this.treeService.findParentByListId(this.nodes(), listId);
|
|
1809
|
+
return this.treeService.findParentByListId(this.nodes(), listId, this.idField());
|
|
1433
1810
|
}
|
|
1434
1811
|
/**
|
|
1435
|
-
* Check if move operation is allowed based on
|
|
1812
|
+
* Check if move operation is allowed based on dragBehavior
|
|
1436
1813
|
*/
|
|
1437
1814
|
canMoveToParent() {
|
|
1438
|
-
|
|
1815
|
+
const behavior = this.dragBehavior();
|
|
1816
|
+
return behavior !== 'none' && behavior !== 'order-only';
|
|
1439
1817
|
}
|
|
1440
1818
|
/**
|
|
1441
|
-
* Check if reorder operation is allowed based on
|
|
1819
|
+
* Check if reorder operation is allowed based on dragBehavior
|
|
1442
1820
|
*/
|
|
1443
1821
|
canReorder() {
|
|
1444
|
-
|
|
1822
|
+
const behavior = this.dragBehavior();
|
|
1823
|
+
return behavior !== 'none' && behavior !== 'move';
|
|
1445
1824
|
}
|
|
1446
1825
|
/**
|
|
1447
1826
|
* Handle reordering within the same list */
|
|
@@ -1514,7 +1893,7 @@ class AXTreeViewComponent {
|
|
|
1514
1893
|
const focusedId = this.focusedNodeId();
|
|
1515
1894
|
if (!focusedId)
|
|
1516
1895
|
return null;
|
|
1517
|
-
return this.treeService.findNodeById(this.nodes(), focusedId);
|
|
1896
|
+
return this.treeService.findNodeById(this.nodes(), focusedId, this.idField());
|
|
1518
1897
|
}
|
|
1519
1898
|
/**
|
|
1520
1899
|
* Set focus to a node by ID
|
|
@@ -1558,14 +1937,14 @@ class AXTreeViewComponent {
|
|
|
1558
1937
|
break;
|
|
1559
1938
|
case 'ArrowLeft':
|
|
1560
1939
|
if (currentFocused) {
|
|
1561
|
-
if (currentFocused
|
|
1940
|
+
if (this.getNodeExpanded(currentFocused) && this.shouldShowExpandToggle(currentFocused)) {
|
|
1562
1941
|
this.toggleNode(currentFocused, event);
|
|
1563
1942
|
return { handled: true, shouldPreventDefault: true, targetIndex: null };
|
|
1564
1943
|
}
|
|
1565
1944
|
else {
|
|
1566
1945
|
const currentItem = flatList[currentIndex];
|
|
1567
1946
|
if (currentItem?.parent) {
|
|
1568
|
-
targetIndex = flatList.findIndex((item) => item.node
|
|
1947
|
+
targetIndex = flatList.findIndex((item) => this.getNodeId(item.node) === this.getNodeId(currentItem.parent));
|
|
1569
1948
|
}
|
|
1570
1949
|
else {
|
|
1571
1950
|
shouldPreventDefault = false;
|
|
@@ -1578,22 +1957,21 @@ class AXTreeViewComponent {
|
|
|
1578
1957
|
break;
|
|
1579
1958
|
case 'ArrowRight':
|
|
1580
1959
|
if (currentFocused) {
|
|
1581
|
-
if (!currentFocused
|
|
1960
|
+
if (!this.getNodeExpanded(currentFocused) && this.shouldShowExpandToggle(currentFocused)) {
|
|
1582
1961
|
this.toggleNode(currentFocused, event);
|
|
1583
1962
|
return { handled: true, shouldPreventDefault: true, targetIndex: null };
|
|
1584
1963
|
}
|
|
1585
|
-
else if (currentFocused
|
|
1586
|
-
this.treeService.hasChildren(currentFocused)
|
|
1587
|
-
currentFocused
|
|
1588
|
-
|
|
1589
|
-
if (children.length > 0) {
|
|
1964
|
+
else if (this.getNodeExpanded(currentFocused) &&
|
|
1965
|
+
this.treeService.hasChildren(currentFocused, this.childrenField())) {
|
|
1966
|
+
const children = this.getNodeChildren(currentFocused);
|
|
1967
|
+
if (children && children.length > 0) {
|
|
1590
1968
|
const firstChild = children[0];
|
|
1591
|
-
targetIndex = flatList.findIndex((item) => item.node
|
|
1969
|
+
targetIndex = flatList.findIndex((item) => this.getNodeId(item.node) === this.getNodeId(firstChild));
|
|
1592
1970
|
if (targetIndex === -1) {
|
|
1593
|
-
const updatedFlatList = this.treeService.buildFlatNodeList(this.nodes());
|
|
1594
|
-
targetIndex = updatedFlatList.findIndex((item) => item.node
|
|
1971
|
+
const updatedFlatList = this.treeService.buildFlatNodeList(this.nodes(), this.hiddenField(), this.disabledField(), this.expandedField(), this.childrenField());
|
|
1972
|
+
targetIndex = updatedFlatList.findIndex((item) => this.getNodeId(item.node) === this.getNodeId(firstChild));
|
|
1595
1973
|
if (targetIndex >= 0 && targetIndex < updatedFlatList.length) {
|
|
1596
|
-
this.focusNodeById(updatedFlatList[targetIndex].node
|
|
1974
|
+
this.focusNodeById(this.getNodeId(updatedFlatList[targetIndex].node));
|
|
1597
1975
|
return { handled: true, shouldPreventDefault: true, targetIndex: null };
|
|
1598
1976
|
}
|
|
1599
1977
|
}
|
|
@@ -1618,7 +1996,7 @@ class AXTreeViewComponent {
|
|
|
1618
1996
|
break;
|
|
1619
1997
|
case ' ':
|
|
1620
1998
|
case 'Space':
|
|
1621
|
-
if (currentFocused && this.selectMode()
|
|
1999
|
+
if (currentFocused && this.selectMode() !== 'none' && this.canSelectNode(currentFocused)) {
|
|
1622
2000
|
event.preventDefault();
|
|
1623
2001
|
this.handleSpaceKeySelection(currentFocused, event);
|
|
1624
2002
|
return { handled: true, shouldPreventDefault: true, targetIndex: null };
|
|
@@ -1626,7 +2004,7 @@ class AXTreeViewComponent {
|
|
|
1626
2004
|
shouldPreventDefault = false;
|
|
1627
2005
|
break;
|
|
1628
2006
|
case 'Enter':
|
|
1629
|
-
if (currentFocused) {
|
|
2007
|
+
if (currentFocused && this.canSelectNode(currentFocused)) {
|
|
1630
2008
|
event.preventDefault();
|
|
1631
2009
|
this.handleEnterKeySelection(currentFocused, event);
|
|
1632
2010
|
return { handled: true, shouldPreventDefault: true, targetIndex: null };
|
|
@@ -1635,7 +2013,7 @@ class AXTreeViewComponent {
|
|
|
1635
2013
|
break;
|
|
1636
2014
|
default:
|
|
1637
2015
|
if ((event.ctrlKey || event.metaKey) && event.key === 'Enter') {
|
|
1638
|
-
if (currentFocused && this.selectMode() === 'multiple') {
|
|
2016
|
+
if (currentFocused && this.selectMode() === 'multiple' && this.canSelectNode(currentFocused)) {
|
|
1639
2017
|
event.preventDefault();
|
|
1640
2018
|
this.handleCtrlEnterSelection(currentFocused, event);
|
|
1641
2019
|
return { handled: true, shouldPreventDefault: true, targetIndex: null };
|
|
@@ -1649,16 +2027,31 @@ class AXTreeViewComponent {
|
|
|
1649
2027
|
}
|
|
1650
2028
|
/**
|
|
1651
2029
|
* Handle Space key selection
|
|
2030
|
+
* In single mode: replaces selection (deselects all, selects this node)
|
|
2031
|
+
* In multiple mode: toggles selection
|
|
1652
2032
|
*/
|
|
1653
2033
|
handleSpaceKeySelection(node, event) {
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
if (
|
|
1658
|
-
|
|
2034
|
+
if (!this.canSelectNode(node))
|
|
2035
|
+
return;
|
|
2036
|
+
const mode = this.selectMode();
|
|
2037
|
+
if (mode === 'single') {
|
|
2038
|
+
// Single mode: replace selection
|
|
2039
|
+
this.treeService.deselectAllNodes(this.nodes(), this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
2040
|
+
this.setNodeSelected(node, true);
|
|
2041
|
+
this.setNodeIndeterminate(node, false);
|
|
1659
2042
|
}
|
|
1660
|
-
|
|
1661
|
-
|
|
2043
|
+
else {
|
|
2044
|
+
// Multiple mode: toggle selection
|
|
2045
|
+
const newValue = !this.getNodeSelected(node);
|
|
2046
|
+
this.setNodeSelected(node, newValue);
|
|
2047
|
+
this.setNodeIndeterminate(node, false);
|
|
2048
|
+
const children = this.getNodeChildren(node);
|
|
2049
|
+
if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
|
|
2050
|
+
this.treeService.selectAllChildren(children, newValue, this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
2051
|
+
}
|
|
2052
|
+
if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
|
|
2053
|
+
this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
|
|
2054
|
+
}
|
|
1662
2055
|
}
|
|
1663
2056
|
this.refreshNodes();
|
|
1664
2057
|
this.onNodeSelect.emit({
|
|
@@ -1667,21 +2060,30 @@ class AXTreeViewComponent {
|
|
|
1667
2060
|
nativeEvent: event,
|
|
1668
2061
|
isUserInteraction: true,
|
|
1669
2062
|
});
|
|
2063
|
+
this.emitSelectionChange();
|
|
1670
2064
|
}
|
|
1671
2065
|
/**
|
|
1672
2066
|
* Handle Enter key selection
|
|
2067
|
+
* In single mode: replaces selection (deselects all, selects this node)
|
|
2068
|
+
* In multiple mode: replaces selection (deselects all, selects this node and respects selectionBehavior)
|
|
1673
2069
|
*/
|
|
1674
2070
|
handleEnterKeySelection(node, event) {
|
|
2071
|
+
if (!this.canSelectNode(node))
|
|
2072
|
+
return;
|
|
1675
2073
|
const mode = this.selectMode();
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
node
|
|
2074
|
+
// Enter key always replaces selection (deselects all first)
|
|
2075
|
+
this.treeService.deselectAllNodes(this.nodes(), this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
2076
|
+
this.setNodeSelected(node, true);
|
|
2077
|
+
this.setNodeIndeterminate(node, false);
|
|
1679
2078
|
if (mode === 'multiple') {
|
|
1680
|
-
|
|
1681
|
-
|
|
2079
|
+
const children = this.getNodeChildren(node);
|
|
2080
|
+
// Respect selectionBehavior: cascade to children if enabled
|
|
2081
|
+
if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
|
|
2082
|
+
this.treeService.selectAllChildren(children, true, this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
1682
2083
|
}
|
|
1683
|
-
if
|
|
1684
|
-
|
|
2084
|
+
// Respect selectionBehavior: update parent states if intermediate mode
|
|
2085
|
+
if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
|
|
2086
|
+
this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
|
|
1685
2087
|
}
|
|
1686
2088
|
}
|
|
1687
2089
|
this.refreshNodes();
|
|
@@ -1691,19 +2093,23 @@ class AXTreeViewComponent {
|
|
|
1691
2093
|
nativeEvent: event,
|
|
1692
2094
|
isUserInteraction: true,
|
|
1693
2095
|
});
|
|
2096
|
+
this.emitSelectionChange();
|
|
1694
2097
|
}
|
|
1695
2098
|
/**
|
|
1696
2099
|
* Handle Ctrl/Cmd + Enter key selection
|
|
1697
2100
|
*/
|
|
1698
2101
|
handleCtrlEnterSelection(node, event) {
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
2102
|
+
if (!this.canSelectNode(node))
|
|
2103
|
+
return;
|
|
2104
|
+
const newValue = !this.getNodeSelected(node);
|
|
2105
|
+
this.setNodeSelected(node, newValue);
|
|
2106
|
+
this.setNodeIndeterminate(node, false);
|
|
2107
|
+
const children = this.getNodeChildren(node);
|
|
2108
|
+
if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
|
|
2109
|
+
this.treeService.selectAllChildren(children, newValue, this.selectedField(), this.indeterminateField(), this.childrenField());
|
|
1704
2110
|
}
|
|
1705
|
-
if (this.
|
|
1706
|
-
this.treeService.updateParentStates(this.nodes(), node, this.
|
|
2111
|
+
if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
|
|
2112
|
+
this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
|
|
1707
2113
|
}
|
|
1708
2114
|
this.refreshNodes();
|
|
1709
2115
|
this.onNodeSelect.emit({
|
|
@@ -1712,6 +2118,7 @@ class AXTreeViewComponent {
|
|
|
1712
2118
|
nativeEvent: event,
|
|
1713
2119
|
isUserInteraction: true,
|
|
1714
2120
|
});
|
|
2121
|
+
this.emitSelectionChange();
|
|
1715
2122
|
}
|
|
1716
2123
|
/**
|
|
1717
2124
|
* Type guard to check if value is an Event
|
|
@@ -1730,10 +2137,10 @@ class AXTreeViewComponent {
|
|
|
1730
2137
|
console.error(`${message}:`, error);
|
|
1731
2138
|
}
|
|
1732
2139
|
}
|
|
1733
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
1734
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: AXTreeViewComponent, isStandalone: true, selector: "ax-tree-view", inputs: { datasource: { classPropertyName: "datasource", publicName: "datasource", isSignal: true, isRequired: true, transformFunction: null }, selectMode: { classPropertyName: "selectMode", publicName: "selectMode", isSignal: true, isRequired: false, transformFunction: null }, showCheckbox: { classPropertyName: "showCheckbox", publicName: "showCheckbox", isSignal: true, isRequired: false, transformFunction: null }, checkChildrenOnSelect: { classPropertyName: "checkChildrenOnSelect", publicName: "checkChildrenOnSelect", isSignal: true, isRequired: false, transformFunction: null }, intermediateState: { classPropertyName: "intermediateState", publicName: "intermediateState", isSignal: true, isRequired: false, transformFunction: null }, checkOnClick: { classPropertyName: "checkOnClick", publicName: "checkOnClick", isSignal: true, isRequired: false, transformFunction: null }, dragMode: { classPropertyName: "dragMode", publicName: "dragMode", isSignal: true, isRequired: false, transformFunction: null }, dragOperationType: { classPropertyName: "dragOperationType", publicName: "dragOperationType", isSignal: true, isRequired: false, transformFunction: null }, showIcons: { classPropertyName: "showIcons", publicName: "showIcons", isSignal: true, isRequired: false, transformFunction: null }, showChildrenBadge: { classPropertyName: "showChildrenBadge", publicName: "showChildrenBadge", isSignal: true, isRequired: false, transformFunction: null }, expandedIcon: { classPropertyName: "expandedIcon", publicName: "expandedIcon", isSignal: true, isRequired: false, transformFunction: null }, collapsedIcon: { classPropertyName: "collapsedIcon", publicName: "collapsedIcon", isSignal: true, isRequired: false, transformFunction: null }, indentSize: { classPropertyName: "indentSize", publicName: "indentSize", isSignal: true, isRequired: false, transformFunction: null }, nodeHeight: { classPropertyName: "nodeHeight", publicName: "nodeHeight", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { datasource: "datasourceChange", onBeforeDrop: "onBeforeDrop", onNodeToggle: "onNodeToggle", onNodeSelect: "onNodeSelect", onOrderChange: "onOrderChange", onMoveChange: "onMoveChange", onItemsChange: "onItemsChange" }, host: { attributes: { "role": "tree", "tabindex": "0" }, listeners: { "keydown": "handleKeyDown($event)", "focus": "onTreeFocus($event)", "blur": "onTreeBlur($event)" }, properties: { "class.ax-tree-view-default": "look() === 'default'", "class.ax-tree-view-card": "look() === 'card'", "class.ax-tree-view-with-line": "look() === 'with-line'", "class.ax-tree-view-rtl": "isRtl", "style.--ax-tree-view-indent-size": "indentSize() + 'px'", "style.--ax-tree-view-line-offset": "(indentSize() / 2) + 'px'", "attr.aria-label": "\"Tree navigation\"" }, classAttribute: "ax-tree-view" }, providers: [AXTreeViewService], ngImport: i0, template: "<!-- Root drop list -->\n<div\n axFocusTrap\n [axDropList]=\"dragMode() !== 'none'\"\n [sortingDisabled]=\"false\"\n [id]=\"getListId()\"\n [attr.data-node-id]=\"null\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDrop($event)\"\n class=\"ax-tree-view-drop-list\"\n [class.ax-tree-view-card]=\"look() === 'card'\"\n [class.ax-tree-view-with-lines]=\"look() === 'with-line'\"\n [class.ax-tree-view-compact]=\"nodeHeight() === 'compact'\"\n [class.ax-tree-view-comfortable]=\"nodeHeight() === 'comfortable'\"\n role=\"group\"\n>\n @for (node of nodes(); track node.id) {\n @if (node.visible !== false) {\n <div\n [axDrag]=\"dragMode() !== 'none'\"\n [dragDisabled]=\"node.disabled\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"node.selected\"\n [class.ax-tree-view-node-disabled]=\"node.disabled\"\n [class.ax-tree-view-node-loading]=\"node.loading\"\n role=\"treeitem\"\n [attr.aria-level]=\"getNodeAriaLevel(0)\"\n [attr.aria-expanded]=\"getNodeAriaExpanded(node)\"\n [attr.aria-selected]=\"getNodeAriaSelected(node)\"\n [attr.aria-disabled]=\"node.disabled ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + node.id\"\n [attr.data-node-id]=\"node.id\"\n [attr.data-tree-node-id]=\"node.id\"\n [attr.data-drop-type]=\"'onto-node'\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDropOntoNode($event, node)\"\n (click)=\"\n (selectMode() === 'single' || (selectMode() === 'multiple' && checkOnClick())) && onNodeClick(node, $event)\n \"\n (focus)=\"onNodeFocus(node.id)\"\n [tabindex]=\"isNodeFocused(node.id) ? 0 : -1\"\n >\n @if (dragMode() === 'handler') {\n <span class=\"ax-tree-view-drag-handle\" axDragHandle title=\"Drag to reorder\"> \u22EE\u22EE </span>\n }\n <ax-button\n class=\"ax-tree-view-expand-toggle ax-sm\"\n (onClick)=\"toggleNode(node, $any($event))\"\n [class.ax-tree-view-has-children]=\"shouldShowExpandToggle(node)\"\n [class.ax-tree-view-expanded]=\"node.expanded\"\n [disabled]=\"node.disabled || node.loading\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (node.loading) {\n <ax-icon>\n <i class=\"fa-solid fa-spinner fa-spin ax-tree-view-loading-spinner\"></i>\n </ax-icon>\n } @else {\n <ax-icon>\n <i\n [class]=\"node.expanded ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n @if (itemTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"itemTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, 0)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckbox()) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"node.indeterminate ? null : node.selected || false\"\n [indeterminate]=\"node.indeterminate || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && node.icon) {\n <i [class]=\"node.icon\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span class=\"ax-tree-view-node-label\">{{ node.label }}</span>\n @if (showChildrenBadge() && (node.childrenCount || (node.children && node.children.length > 0))) {\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(node.childrenCount ?? node.children?.length ?? 0).toString()\"\n ></ax-badge>\n }\n }\n </div>\n </div>\n @if (node.expanded && node.children && node.children.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: node.children, parent: node, level: 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n</div>\n\n<!-- Recursive children template -->\n<ng-template #childrenList let-children=\"children\" let-parent=\"parent\" let-level=\"level\">\n <div\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"getListId(parent)\"\n [attr.data-node-id]=\"parent.id\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDrop($event, parent)\"\n class=\"ax-tree-view-drop-list\"\n role=\"group\"\n >\n @for (node of children; track node.id) {\n @if (node.visible !== false) {\n <div\n [axDrag]=\"dragMode() !== 'none'\"\n [dragDisabled]=\"node.disabled\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"node.selected\"\n [class.ax-tree-view-node-disabled]=\"node.disabled\"\n [class.ax-tree-view-node-loading]=\"node.loading\"\n [class.ax-tree-view-node-focused]=\"isNodeFocused(node.id)\"\n role=\"treeitem\"\n [attr.aria-level]=\"getNodeAriaLevel(level)\"\n [attr.aria-expanded]=\"getNodeAriaExpanded(node)\"\n [attr.aria-selected]=\"getNodeAriaSelected(node)\"\n [attr.aria-disabled]=\"node.disabled ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [style.padding-inline-start.px]=\"getNodePaddingInline(level)\"\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + node.id\"\n [attr.data-node-id]=\"node.id\"\n [attr.data-tree-node-id]=\"node.id\"\n [attr.data-drop-type]=\"'onto-node'\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDropOntoNode($event, node)\"\n (click)=\"\n (selectMode() === 'single' || (selectMode() === 'multiple' && checkOnClick())) &&\n onNodeClick(node, $event)\n \"\n (focus)=\"onNodeFocus(node.id)\"\n (blur)=\"focusedNodeId.set(null)\"\n [tabindex]=\"isNodeFocused(node.id) ? 0 : -1\"\n >\n @if (dragMode() === 'handler') {\n <span class=\"ax-tree-view-drag-handle\" axDragHandle title=\"Drag to reorder\"> \u22EE\u22EE </span>\n }\n <ax-button\n class=\"ax-tree-view-expand-toggle ax-sm\"\n (onClick)=\"toggleNode(node, $any($event))\"\n [class.ax-tree-view-has-children]=\"shouldShowExpandToggle(node)\"\n [class.ax-tree-view-expanded]=\"node.expanded\"\n [disabled]=\"node.disabled || node.loading\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (node.loading) {\n <ax-icon>\n <i class=\"fa-solid fa-spinner fa-spin ax-tree-view-loading-spinner\"></i>\n </ax-icon>\n } @else {\n <ax-icon>\n <i\n [class]=\"node.expanded ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n\n @if (itemTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"itemTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, level)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckbox()) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"node.indeterminate ? null : node.selected || false\"\n [indeterminate]=\"node.indeterminate || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && node.icon) {\n <i [class]=\"node.icon\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span class=\"ax-tree-view-node-label\">{{ node.label }}</span>\n @if (showChildrenBadge() && (node.childrenCount || (node.children && node.children.length > 0))) {\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(node.childrenCount ?? node.children?.length ?? 0).toString()\"\n ></ax-badge>\n }\n }\n </div>\n </div>\n @if (node.expanded && node.children && node.children.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: node.children, parent: node, level: level + 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n </div>\n</ng-template>\n", styles: [".ax-tree-view{display:block;width:100%;--ax-comp-tree-view-indent-size: 12px;--ax-comp-tree-view-node-hover-bg: rgba(var(--ax-sys-color-on-lightest-surface), .04);--ax-comp-tree-view-node-selected-bg: rgba(var(--ax-sys-color-primary-500), .12);--ax-comp-tree-view-node-border-radius: 6px;--ax-comp-tree-view-node-margin: .25rem;--ax-comp-tree-view-line-color: rgba(var(--ax-sys-color-on-lightest-surface), .15);--ax-comp-tree-view-drag-preview-opacity: .9;--ax-comp-tree-view-drag-placeholder-bg: rgba(var(--ax-sys-color-on-lightest-surface), .02);--ax-comp-tree-view-drop-active-bg: rgba(var(--ax-sys-color-primary-500), .08);--ax-comp-tree-view-drop-active-outline: rgba(var(--ax-sys-color-primary-500), .3);--ax-comp-tree-view-content-padding: 0;--ax-comp-tree-view-content-gap: .5rem;--ax-comp-tree-view-drop-list-min-height: 2rem;--ax-comp-tree-view-drag-handle-padding: .25rem;--ax-comp-tree-view-expand-toggle-padding: .25rem;--ax-comp-tree-view-card-node-margin: .5rem;--ax-comp-tree-view-card-content-padding: 1rem;--ax-comp-tree-view-outline-offset: 2px;--ax-comp-tree-view-outline-offset-negative: -2px}.ax-tree-view-drop-list{min-height:var(--ax-comp-tree-view-drop-list-min-height)}.ax-tree-view-compact .ax-tree-view-node-content{padding:var(--ax-comp-tree-view-content-padding, .25rem .5rem);gap:var(--ax-comp-tree-view-content-gap, .375rem);font-size:.8125rem}.ax-tree-view-comfortable .ax-tree-view-node-content{padding:var(--ax-comp-tree-view-content-padding, .75rem .625rem);gap:var(--ax-comp-tree-view-content-gap, .625rem);font-size:.9375rem}.ax-tree-view-node{position:relative;margin:var(--ax-comp-tree-view-node-margin) 0;border-radius:var(--ax-comp-tree-view-node-border-radius);border:1px solid transparent;cursor:move}.ax-tree-view-node:hover:not(.ax-dragging){background:var(--ax-comp-tree-view-node-hover-bg)}.ax-tree-view-node.ax-tree-view-node-selected{background:var(--ax-comp-tree-view-node-selected-bg);border-color:currentColor}.ax-tree-view-node.ax-dragging{opacity:var(--ax-comp-tree-view-drag-placeholder-opacity);cursor:grabbing!important}.ax-tree-view-node.ax-drag-placeholder{background:var(--ax-comp-tree-view-drag-placeholder-bg)}.ax-drag-preview{opacity:var(--ax-comp-tree-view-drag-preview-opacity)!important;box-shadow:0 4px 12px rgba(var(--ax-sys-color-on-lightest-surface),.2)!important;cursor:grabbing!important;border:2px dashed currentColor!important}.ax-tree-view-node-content.ax-drop-list-sorting-active{background:var(--ax-comp-tree-view-drop-active-bg);border-radius:var(--ax-comp-tree-view-node-border-radius);outline:2px dashed var(--ax-comp-tree-view-drop-active-outline);outline-offset:var(--ax-comp-tree-view-outline-offset-negative)}.ax-tree-view-node-content{display:flex;align-items:center;gap:var(--ax-comp-tree-view-content-gap);padding:var(--ax-comp-tree-view-content-padding);cursor:pointer;-webkit-user-select:none;user-select:none;outline:none;border:1px solid transparent;border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-node-content:focus{outline:none}.ax-tree-view-node-content:focus-visible{outline:2px solid rgba(var(--ax-sys-color-primary-500),.8);outline-offset:var(--ax-comp-tree-view-outline-offset);border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-drag-handle{cursor:grab;opacity:.6;padding:var(--ax-comp-tree-view-drag-handle-padding)}.ax-tree-view-drag-handle:hover{opacity:1}.ax-tree-view-drag-handle:active{cursor:grabbing}.ax-tree-view-expand-toggle{background:none;border:none;cursor:pointer;padding:var(--ax-comp-tree-view-expand-toggle-padding);min-width:1.5rem;height:1.5rem}.ax-tree-view-expand-toggle:not(.ax-tree-view-has-children){opacity:0;pointer-events:none}.ax-tree-view-toggle-icon{font-size:.75rem}.ax-tree-view-node-icon{font-size:1.125rem;flex-shrink:0}.ax-tree-view-node-label{flex:1;font-size:.875rem;line-height:1rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ax-tree-view-children{padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-node-disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ax-tree-view-node-loading{opacity:.7}.ax-tree-view-card .ax-tree-view-node{border:1px solid rgba(var(--ax-sys-color-border-lightest-surface),1);margin:var(--ax-comp-tree-view-card-node-margin) 0}.ax-tree-view-card .ax-tree-view-node-content{padding:var(--ax-comp-tree-view-card-content-padding)}.ax-tree-view-with-lines .ax-tree-view-children{position:relative;padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-with-lines .ax-tree-view-children:before{content:\"\";position:absolute;inset-inline-start:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));top:0;height:calc(100% - .875rem);width:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines .ax-tree-view-node{position:relative}.ax-tree-view-with-lines .ax-tree-view-node:before{content:\"\";position:absolute;inset-inline-start:calc(-1 * var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2)));top:60%;width:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));height:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines>.ax-tree-view-drop-list>.ax-tree-view-node:before,.ax-tree-view-with-lines>.ax-tree-view-node:before{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: AXDragDirective, selector: "[axDrag]", inputs: ["axDrag", "dragData", "dragDisabled", "dragTransition", "dragElementClone", "dropZoneGroup", "dragStartDelay", "dragResetOnDblClick", "dragLockAxis", "dragClonedTemplate", "dragCursor", "dragBoundary", "dragTransitionDuration"], outputs: ["dragPositionChanged"] }, { kind: "directive", type: AXDragHandleDirective, selector: "[axDragHandle]" }, { kind: "directive", type: AXDropListDirective, selector: "[axDropList]", inputs: ["axDropList", "sortingDisabled", "dropListGroup", "dropListOrientation"], outputs: ["dropListDropped"], exportAs: ["axDropList"] }, { kind: "directive", type: AXFocusTrapDirective, selector: "[axFocusTrap]" }, { kind: "component", type: AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "isLoading", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "component", type: AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "component", type: AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
2140
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2141
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: AXTreeViewComponent, isStandalone: true, selector: "ax-tree-view", inputs: { datasource: { classPropertyName: "datasource", publicName: "datasource", isSignal: true, isRequired: true, transformFunction: null }, selectMode: { classPropertyName: "selectMode", publicName: "selectMode", isSignal: true, isRequired: false, transformFunction: null }, showCheckbox: { classPropertyName: "showCheckbox", publicName: "showCheckbox", isSignal: true, isRequired: false, transformFunction: null }, selectionBehavior: { classPropertyName: "selectionBehavior", publicName: "selectionBehavior", isSignal: true, isRequired: false, transformFunction: null }, dragArea: { classPropertyName: "dragArea", publicName: "dragArea", isSignal: true, isRequired: false, transformFunction: null }, dragBehavior: { classPropertyName: "dragBehavior", publicName: "dragBehavior", isSignal: true, isRequired: false, transformFunction: null }, showIcons: { classPropertyName: "showIcons", publicName: "showIcons", isSignal: true, isRequired: false, transformFunction: null }, showChildrenBadge: { classPropertyName: "showChildrenBadge", publicName: "showChildrenBadge", isSignal: true, isRequired: false, transformFunction: null }, expandedIcon: { classPropertyName: "expandedIcon", publicName: "expandedIcon", isSignal: true, isRequired: false, transformFunction: null }, collapsedIcon: { classPropertyName: "collapsedIcon", publicName: "collapsedIcon", isSignal: true, isRequired: false, transformFunction: null }, indentSize: { classPropertyName: "indentSize", publicName: "indentSize", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, nodeTemplate: { classPropertyName: "nodeTemplate", publicName: "nodeTemplate", isSignal: true, isRequired: false, transformFunction: null }, idField: { classPropertyName: "idField", publicName: "idField", isSignal: true, isRequired: false, transformFunction: null }, titleField: { classPropertyName: "titleField", publicName: "titleField", isSignal: true, isRequired: false, transformFunction: null }, tooltipField: { classPropertyName: "tooltipField", publicName: "tooltipField", isSignal: true, isRequired: false, transformFunction: null }, iconField: { classPropertyName: "iconField", publicName: "iconField", isSignal: true, isRequired: false, transformFunction: null }, expandedField: { classPropertyName: "expandedField", publicName: "expandedField", isSignal: true, isRequired: false, transformFunction: null }, selectedField: { classPropertyName: "selectedField", publicName: "selectedField", isSignal: true, isRequired: false, transformFunction: null }, indeterminateField: { classPropertyName: "indeterminateField", publicName: "indeterminateField", isSignal: true, isRequired: false, transformFunction: null }, disabledField: { classPropertyName: "disabledField", publicName: "disabledField", isSignal: true, isRequired: false, transformFunction: null }, hiddenField: { classPropertyName: "hiddenField", publicName: "hiddenField", isSignal: true, isRequired: false, transformFunction: null }, childrenField: { classPropertyName: "childrenField", publicName: "childrenField", isSignal: true, isRequired: false, transformFunction: null }, childrenCountField: { classPropertyName: "childrenCountField", publicName: "childrenCountField", isSignal: true, isRequired: false, transformFunction: null }, dataField: { classPropertyName: "dataField", publicName: "dataField", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { datasource: "datasourceChange", onBeforeDrop: "onBeforeDrop", onNodeToggle: "onNodeToggle", onNodeSelect: "onNodeSelect", onSelectionChange: "onSelectionChange", onOrderChange: "onOrderChange", onMoveChange: "onMoveChange", onItemsChange: "onItemsChange" }, host: { attributes: { "role": "tree", "tabindex": "0" }, listeners: { "keydown": "handleKeyDown($event)", "focus": "onTreeFocus($event)", "blur": "onTreeBlur($event)" }, properties: { "class.ax-tree-view-default": "look() === 'default'", "class.ax-tree-view-card": "look() === 'card'", "class.ax-tree-view-with-line": "look() === 'with-line'", "class.ax-tree-view-rtl": "isRtl", "style.--ax-tree-view-indent-size": "indentSize() + 'px'", "style.--ax-tree-view-line-offset": "(indentSize() / 2) + 'px'", "attr.aria-label": "\"Tree navigation\"" }, classAttribute: "ax-tree-view" }, providers: [AXTreeViewService], ngImport: i0, template: "<!-- Root drop list -->\n<div\n axFocusTrap\n [axDropList]=\"dragBehavior() !== 'none'\"\n [sortingDisabled]=\"false\"\n [id]=\"getListId()\"\n [attr.data-node-id]=\"null\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDrop($event)\"\n class=\"ax-tree-view-drop-list\"\n [class.ax-tree-view-card]=\"look() === 'card'\"\n [class.ax-tree-view-with-lines]=\"look() === 'with-line'\"\n role=\"group\"\n>\n @for (node of nodes(); track getNodeId(node)) {\n @if (getNodeHidden(node) !== true) {\n <div\n [axDrag]=\"dragBehavior() !== 'none'\"\n [dragDisabled]=\"getNodeDisabled(node)\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"getNodeSelected(node)\"\n [class.ax-tree-view-node-disabled]=\"getNodeDisabled(node)\"\n [class.ax-tree-view-node-loading]=\"getNodeLoading(node)\"\n role=\"treeitem\"\n [attr.aria-level]=\"getNodeAriaLevel(0)\"\n [attr.aria-expanded]=\"getNodeAriaExpanded(node)\"\n [attr.aria-selected]=\"getNodeAriaSelected(node)\"\n [attr.aria-disabled]=\"getNodeDisabled(node) || (isLeafOnlyMode() && !isLeafNode(node)) ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [axDropList]=\"dragBehavior() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + getNodeId(node)\"\n [attr.data-node-id]=\"getNodeId(node)\"\n [attr.data-tree-node-id]=\"getNodeId(node)\"\n [attr.data-drop-type]=\"'onto-node'\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDropOntoNode($event, node)\"\n (click)=\"\n (selectMode() === 'single' || (selectMode() === 'multiple' && !showCheckbox())) && onNodeClick(node, $event)\n \"\n (focus)=\"onNodeFocus(getNodeId(node))\"\n [tabindex]=\"isNodeFocused(getNodeId(node)) ? 0 : -1\"\n >\n @if (dragArea() === 'handler' && dragBehavior() !== 'none') {\n <span class=\"ax-tree-view-drag-handle\" axDragHandle title=\"Drag to reorder\"> \u22EE\u22EE </span>\n }\n <ax-button\n class=\"ax-tree-view-expand-toggle ax-sm\"\n (onClick)=\"toggleNode(node, $any($event))\"\n [class.ax-tree-view-has-children]=\"shouldShowExpandToggle(node)\"\n [class.ax-tree-view-expanded]=\"getNodeExpanded(node)\"\n [disabled]=\"getNodeDisabled(node) || getNodeLoading(node)\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (getNodeLoading(node)) {\n <ax-icon>\n <i class=\"fa-solid fa-spinner fa-spin ax-tree-view-loading-spinner\"></i>\n </ax-icon>\n } @else {\n <ax-icon>\n <i\n [class]=\"getNodeExpanded(node) ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n @if (nodeTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, 0)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckboxForNode(node)) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"getNodeIndeterminate(node) ? null : getNodeSelected(node) || false\"\n [indeterminate]=\"getNodeIndeterminate(node) || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && getNodeIcon(node)) {\n <i [class]=\"getNodeIcon(node)\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span\n class=\"ax-tree-view-node-label\"\n [axTooltip]=\"getNodeTooltip(node) || ''\"\n [axTooltipDisabled]=\"!getNodeTooltip(node)\"\n [axTooltipPlacement]=\"'top-start'\"\n >\n {{ getNodeTitle(node) }}\n </span>\n @if (\n showChildrenBadge() &&\n (getNodeChildrenCount(node) || (getNodeChildren(node) && getNodeChildren(node)!.length > 0))\n ) {\n <span class=\"ax-tree-view-node-badge\">\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(getNodeChildrenCount(node) ?? getNodeChildren(node)?.length ?? 0).toString()\"\n ></ax-badge>\n </span>\n }\n }\n </div>\n </div>\n @if (getNodeExpanded(node) && getNodeChildren(node) && getNodeChildren(node)!.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: getNodeChildren(node), parent: node, level: 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n</div>\n\n<!-- Recursive children template -->\n<ng-template #childrenList let-children=\"children\" let-parent=\"parent\" let-level=\"level\">\n <div\n [axDropList]=\"dragBehavior() !== 'none'\"\n [id]=\"getListId(parent)\"\n [attr.data-node-id]=\"getNodeId(parent)\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDrop($event, parent)\"\n class=\"ax-tree-view-drop-list\"\n role=\"group\"\n >\n @for (node of children; track getNodeId(node)) {\n @if (getNodeHidden(node) !== true) {\n <div\n [axDrag]=\"dragBehavior() !== 'none'\"\n [dragDisabled]=\"getNodeDisabled(node)\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"getNodeSelected(node)\"\n [class.ax-tree-view-node-disabled]=\"getNodeDisabled(node)\"\n [class.ax-tree-view-node-loading]=\"getNodeLoading(node)\"\n [class.ax-tree-view-node-focused]=\"isNodeFocused(getNodeId(node))\"\n role=\"treeitem\"\n [attr.aria-level]=\"getNodeAriaLevel(level)\"\n [attr.aria-expanded]=\"getNodeAriaExpanded(node)\"\n [attr.aria-selected]=\"getNodeAriaSelected(node)\"\n [attr.aria-disabled]=\"getNodeDisabled(node) ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [axDropList]=\"dragBehavior() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + getNodeId(node)\"\n [attr.data-node-id]=\"getNodeId(node)\"\n [attr.data-tree-node-id]=\"getNodeId(node)\"\n [attr.data-drop-type]=\"'onto-node'\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDropOntoNode($event, node)\"\n (click)=\"\n (selectMode() === 'single' || (selectMode() === 'multiple' && !showCheckbox())) &&\n onNodeClick(node, $event)\n \"\n (focus)=\"onNodeFocus(getNodeId(node))\"\n (blur)=\"focusedNodeId.set(null)\"\n [tabindex]=\"isNodeFocused(getNodeId(node)) ? 0 : -1\"\n >\n @if (dragArea() === 'handler') {\n <span class=\"ax-tree-view-drag-handle\" axDragHandle title=\"Drag to reorder\"> \u22EE\u22EE </span>\n }\n <ax-button\n class=\"ax-tree-view-expand-toggle ax-sm\"\n (onClick)=\"toggleNode(node, $any($event))\"\n [class.ax-tree-view-has-children]=\"shouldShowExpandToggle(node)\"\n [class.ax-tree-view-expanded]=\"getNodeExpanded(node)\"\n [disabled]=\"getNodeDisabled(node) || getNodeLoading(node)\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (getNodeLoading(node)) {\n <ax-icon>\n <i class=\"fa-solid fa-spinner fa-spin ax-tree-view-loading-spinner\"></i>\n </ax-icon>\n } @else {\n <ax-icon>\n <i\n [class]=\"getNodeExpanded(node) ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n\n @if (nodeTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, level)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckboxForNode(node)) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"getNodeIndeterminate(node) ? null : getNodeSelected(node) || false\"\n [indeterminate]=\"getNodeIndeterminate(node) || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && getNodeIcon(node)) {\n <i [class]=\"getNodeIcon(node)\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span\n class=\"ax-tree-view-node-label\"\n [axTooltip]=\"getNodeTooltip(node) || ''\"\n [axTooltipDisabled]=\"!getNodeTooltip(node)\"\n [axTooltipPlacement]=\"'top-start'\"\n >\n {{ getNodeTitle(node) }}\n </span>\n @if (\n showChildrenBadge() &&\n (getNodeChildrenCount(node) || (getNodeChildren(node) && getNodeChildren(node)!.length > 0))\n ) {\n <span class=\"ax-tree-view-node-badge\">\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(getNodeChildrenCount(node) ?? getNodeChildren(node)?.length ?? 0).toString()\"\n ></ax-badge>\n </span>\n }\n }\n </div>\n </div>\n @if (getNodeExpanded(node) && getNodeChildren(node) && getNodeChildren(node)!.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: getNodeChildren(node), parent: node, level: level + 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n </div>\n</ng-template>\n", styles: [".ax-tree-view{display:block;width:100%;--ax-comp-tree-view-indent-size: 12px;--ax-comp-tree-view-node-hover-bg: rgba(var(--ax-sys-color-on-lightest-surface), .04);--ax-comp-tree-view-node-selected-bg: rgba(var(--ax-sys-color-primary-500), .12);--ax-comp-tree-view-node-border-radius: 6px;--ax-comp-tree-view-node-margin: .25rem;--ax-comp-tree-view-line-color: rgba(var(--ax-sys-color-on-lightest-surface), .15);--ax-comp-tree-view-drag-preview-opacity: .9;--ax-comp-tree-view-drag-placeholder-bg: rgba(var(--ax-sys-color-on-lightest-surface), .02);--ax-comp-tree-view-drop-active-bg: rgba(var(--ax-sys-color-primary-500), .08);--ax-comp-tree-view-drop-active-outline: rgba(var(--ax-sys-color-primary-500), .3);--ax-comp-tree-view-content-padding: 0;--ax-comp-tree-view-content-gap: .5rem;--ax-comp-tree-view-drop-list-min-height: 2rem;--ax-comp-tree-view-drag-handle-padding: .25rem;--ax-comp-tree-view-badge-padding: .25rem;--ax-comp-tree-view-expand-toggle-padding: .25rem;--ax-comp-tree-view-outline-offset: 2px;--ax-comp-tree-view-outline-offset-negative: -2px}.ax-tree-view-drop-list{min-height:var(--ax-comp-tree-view-drop-list-min-height)}.ax-tree-view-node{position:relative;margin:var(--ax-comp-tree-view-node-margin) 0;border-radius:var(--ax-comp-tree-view-node-border-radius);cursor:move}.ax-tree-view-node:hover:not(.ax-dragging){background:var(--ax-comp-tree-view-node-hover-bg)}.ax-tree-view-node.ax-tree-view-node-selected{background:var(--ax-comp-tree-view-node-selected-bg)}.ax-tree-view-node.ax-dragging{opacity:var(--ax-comp-tree-view-drag-placeholder-opacity);cursor:grabbing!important}.ax-tree-view-node.ax-drag-placeholder{background:var(--ax-comp-tree-view-drag-placeholder-bg)}.ax-drag-preview{opacity:var(--ax-comp-tree-view-drag-preview-opacity)!important;box-shadow:0 4px 12px rgba(var(--ax-sys-color-on-lightest-surface),.2)!important;cursor:grabbing!important;border:2px dashed currentColor!important}.ax-tree-view-node-content.ax-drop-list-sorting-active{background:var(--ax-comp-tree-view-drop-active-bg);border-radius:var(--ax-comp-tree-view-node-border-radius);outline:2px dashed var(--ax-comp-tree-view-drop-active-outline);outline-offset:var(--ax-comp-tree-view-outline-offset-negative)}.ax-tree-view-node-content{display:flex;align-items:center;gap:var(--ax-comp-tree-view-content-gap);padding:var(--ax-comp-tree-view-content-padding);cursor:pointer;-webkit-user-select:none;user-select:none;outline:none;border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-node-content:focus{outline:none}.ax-tree-view-node-content:focus-visible{outline:2px solid rgba(var(--ax-sys-color-primary-500),.8);outline-offset:var(--ax-comp-tree-view-outline-offset);border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-drag-handle{cursor:grab;opacity:.6;padding:var(--ax-comp-tree-view-drag-handle-padding);padding-inline-start:calc(var(--ax-comp-tree-view-drag-handle-padding) * 2)}.ax-tree-view-drag-handle:hover{opacity:1}.ax-tree-view-drag-handle:active{cursor:grabbing}.ax-tree-view-expand-toggle{background:none;border:none;cursor:pointer;padding:var(--ax-comp-tree-view-expand-toggle-padding);min-width:1.5rem;height:1.5rem}.ax-tree-view-expand-toggle:not(.ax-tree-view-has-children){opacity:0;pointer-events:none}.ax-tree-view-toggle-icon{font-size:.75rem}.ax-tree-view-node-icon{font-size:1.125rem;flex-shrink:0}.ax-tree-view-node-label{flex:1;font-size:.875rem;line-height:1rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ax-tree-view-node-badge{padding:var(--ax-comp-tree-view-badge-padding);padding-inline-end:calc(var(--ax-comp-tree-view-badge-padding) * 1.5)}.ax-tree-view-children{padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-node-disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ax-tree-view-node-loading{opacity:.7}.ax-tree-view-card .ax-tree-view-node{border:1px solid rgba(var(--ax-sys-color-border-lightest-surface),1)}.ax-tree-view-card .ax-tree-view-node.ax-tree-view-node-selected{border:1px solid rgba(var(--ax-sys-color-border-surface),1)}.ax-tree-view-with-lines .ax-tree-view-children{position:relative;padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-with-lines .ax-tree-view-children:before{content:\"\";position:absolute;inset-inline-start:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));top:0;height:calc(100% - .875rem);width:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines .ax-tree-view-node{position:relative}.ax-tree-view-with-lines .ax-tree-view-node:before{content:\"\";position:absolute;inset-inline-start:calc(-1 * var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2)));top:60%;width:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));height:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines>.ax-tree-view-drop-list>.ax-tree-view-node:before,.ax-tree-view-with-lines>.ax-tree-view-node:before{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: AXDragDirective, selector: "[axDrag]", inputs: ["axDrag", "dragData", "dragDisabled", "dragTransition", "dragElementClone", "dropZoneGroup", "dragStartDelay", "dragResetOnDblClick", "dragLockAxis", "dragClonedTemplate", "dragCursor", "dragBoundary", "dragTransitionDuration"], outputs: ["dragPositionChanged"] }, { kind: "directive", type: AXDragHandleDirective, selector: "[axDragHandle]" }, { kind: "directive", type: AXDropListDirective, selector: "[axDropList]", inputs: ["axDropList", "sortingDisabled", "dropListGroup", "dropListOrientation"], outputs: ["dropListDropped"], exportAs: ["axDropList"] }, { kind: "directive", type: AXFocusTrapDirective, selector: "[axFocusTrap]" }, { kind: "component", type: AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "isLoading", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "component", type: AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "component", type: AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "directive", type: AXTooltipDirective, selector: "[axTooltip]", inputs: ["axTooltipDisabled", "axTooltip", "axTooltipContext", "axTooltipPlacement", "axTooltipOffsetX", "axTooltipOffsetY", "axTooltipOpenAfter", "axTooltipCloseAfter"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1735
2142
|
}
|
|
1736
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
2143
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewComponent, decorators: [{
|
|
1737
2144
|
type: Component,
|
|
1738
2145
|
args: [{ selector: 'ax-tree-view', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [AXTreeViewService], imports: [
|
|
1739
2146
|
CommonModule,
|
|
@@ -1747,29 +2154,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
|
|
|
1747
2154
|
AXCheckBoxComponent,
|
|
1748
2155
|
AXBadgeComponent,
|
|
1749
2156
|
AXDecoratorIconComponent,
|
|
2157
|
+
AXTooltipDirective,
|
|
1750
2158
|
], host: {
|
|
1751
2159
|
class: 'ax-tree-view',
|
|
2160
|
+
role: 'tree',
|
|
2161
|
+
tabindex: '0',
|
|
1752
2162
|
'[class.ax-tree-view-default]': "look() === 'default'",
|
|
1753
2163
|
'[class.ax-tree-view-card]': "look() === 'card'",
|
|
1754
2164
|
'[class.ax-tree-view-with-line]': "look() === 'with-line'",
|
|
1755
2165
|
'[class.ax-tree-view-rtl]': 'isRtl',
|
|
1756
2166
|
'[style.--ax-tree-view-indent-size]': "indentSize() + 'px'",
|
|
1757
2167
|
'[style.--ax-tree-view-line-offset]': "(indentSize() / 2) + 'px'",
|
|
1758
|
-
role: 'tree',
|
|
1759
2168
|
'[attr.aria-label]': '"Tree navigation"',
|
|
1760
2169
|
'(keydown)': 'handleKeyDown($event)',
|
|
1761
2170
|
'(focus)': 'onTreeFocus($event)',
|
|
1762
2171
|
'(blur)': 'onTreeBlur($event)',
|
|
1763
|
-
tabindex: '0',
|
|
1764
|
-
}, template: "<!-- Root drop list -->\n<div\n axFocusTrap\n [axDropList]=\"dragMode() !== 'none'\"\n [sortingDisabled]=\"false\"\n [id]=\"getListId()\"\n [attr.data-node-id]=\"null\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDrop($event)\"\n class=\"ax-tree-view-drop-list\"\n [class.ax-tree-view-card]=\"look() === 'card'\"\n [class.ax-tree-view-with-lines]=\"look() === 'with-line'\"\n [class.ax-tree-view-compact]=\"nodeHeight() === 'compact'\"\n [class.ax-tree-view-comfortable]=\"nodeHeight() === 'comfortable'\"\n role=\"group\"\n>\n @for (node of nodes(); track node.id) {\n @if (node.visible !== false) {\n <div\n [axDrag]=\"dragMode() !== 'none'\"\n [dragDisabled]=\"node.disabled\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"node.selected\"\n [class.ax-tree-view-node-disabled]=\"node.disabled\"\n [class.ax-tree-view-node-loading]=\"node.loading\"\n role=\"treeitem\"\n [attr.aria-level]=\"getNodeAriaLevel(0)\"\n [attr.aria-expanded]=\"getNodeAriaExpanded(node)\"\n [attr.aria-selected]=\"getNodeAriaSelected(node)\"\n [attr.aria-disabled]=\"node.disabled ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + node.id\"\n [attr.data-node-id]=\"node.id\"\n [attr.data-tree-node-id]=\"node.id\"\n [attr.data-drop-type]=\"'onto-node'\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDropOntoNode($event, node)\"\n (click)=\"\n (selectMode() === 'single' || (selectMode() === 'multiple' && checkOnClick())) && onNodeClick(node, $event)\n \"\n (focus)=\"onNodeFocus(node.id)\"\n [tabindex]=\"isNodeFocused(node.id) ? 0 : -1\"\n >\n @if (dragMode() === 'handler') {\n <span class=\"ax-tree-view-drag-handle\" axDragHandle title=\"Drag to reorder\"> \u22EE\u22EE </span>\n }\n <ax-button\n class=\"ax-tree-view-expand-toggle ax-sm\"\n (onClick)=\"toggleNode(node, $any($event))\"\n [class.ax-tree-view-has-children]=\"shouldShowExpandToggle(node)\"\n [class.ax-tree-view-expanded]=\"node.expanded\"\n [disabled]=\"node.disabled || node.loading\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (node.loading) {\n <ax-icon>\n <i class=\"fa-solid fa-spinner fa-spin ax-tree-view-loading-spinner\"></i>\n </ax-icon>\n } @else {\n <ax-icon>\n <i\n [class]=\"node.expanded ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n @if (itemTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"itemTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, 0)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckbox()) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"node.indeterminate ? null : node.selected || false\"\n [indeterminate]=\"node.indeterminate || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && node.icon) {\n <i [class]=\"node.icon\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span class=\"ax-tree-view-node-label\">{{ node.label }}</span>\n @if (showChildrenBadge() && (node.childrenCount || (node.children && node.children.length > 0))) {\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(node.childrenCount ?? node.children?.length ?? 0).toString()\"\n ></ax-badge>\n }\n }\n </div>\n </div>\n @if (node.expanded && node.children && node.children.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: node.children, parent: node, level: 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n</div>\n\n<!-- Recursive children template -->\n<ng-template #childrenList let-children=\"children\" let-parent=\"parent\" let-level=\"level\">\n <div\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"getListId(parent)\"\n [attr.data-node-id]=\"parent.id\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDrop($event, parent)\"\n class=\"ax-tree-view-drop-list\"\n role=\"group\"\n >\n @for (node of children; track node.id) {\n @if (node.visible !== false) {\n <div\n [axDrag]=\"dragMode() !== 'none'\"\n [dragDisabled]=\"node.disabled\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"node.selected\"\n [class.ax-tree-view-node-disabled]=\"node.disabled\"\n [class.ax-tree-view-node-loading]=\"node.loading\"\n [class.ax-tree-view-node-focused]=\"isNodeFocused(node.id)\"\n role=\"treeitem\"\n [attr.aria-level]=\"getNodeAriaLevel(level)\"\n [attr.aria-expanded]=\"getNodeAriaExpanded(node)\"\n [attr.aria-selected]=\"getNodeAriaSelected(node)\"\n [attr.aria-disabled]=\"node.disabled ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [style.padding-inline-start.px]=\"getNodePaddingInline(level)\"\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + node.id\"\n [attr.data-node-id]=\"node.id\"\n [attr.data-tree-node-id]=\"node.id\"\n [attr.data-drop-type]=\"'onto-node'\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDropOntoNode($event, node)\"\n (click)=\"\n (selectMode() === 'single' || (selectMode() === 'multiple' && checkOnClick())) &&\n onNodeClick(node, $event)\n \"\n (focus)=\"onNodeFocus(node.id)\"\n (blur)=\"focusedNodeId.set(null)\"\n [tabindex]=\"isNodeFocused(node.id) ? 0 : -1\"\n >\n @if (dragMode() === 'handler') {\n <span class=\"ax-tree-view-drag-handle\" axDragHandle title=\"Drag to reorder\"> \u22EE\u22EE </span>\n }\n <ax-button\n class=\"ax-tree-view-expand-toggle ax-sm\"\n (onClick)=\"toggleNode(node, $any($event))\"\n [class.ax-tree-view-has-children]=\"shouldShowExpandToggle(node)\"\n [class.ax-tree-view-expanded]=\"node.expanded\"\n [disabled]=\"node.disabled || node.loading\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (node.loading) {\n <ax-icon>\n <i class=\"fa-solid fa-spinner fa-spin ax-tree-view-loading-spinner\"></i>\n </ax-icon>\n } @else {\n <ax-icon>\n <i\n [class]=\"node.expanded ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n\n @if (itemTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"itemTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, level)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckbox()) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"node.indeterminate ? null : node.selected || false\"\n [indeterminate]=\"node.indeterminate || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && node.icon) {\n <i [class]=\"node.icon\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span class=\"ax-tree-view-node-label\">{{ node.label }}</span>\n @if (showChildrenBadge() && (node.childrenCount || (node.children && node.children.length > 0))) {\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(node.childrenCount ?? node.children?.length ?? 0).toString()\"\n ></ax-badge>\n }\n }\n </div>\n </div>\n @if (node.expanded && node.children && node.children.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: node.children, parent: node, level: level + 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n </div>\n</ng-template>\n", styles: [".ax-tree-view{display:block;width:100%;--ax-comp-tree-view-indent-size: 12px;--ax-comp-tree-view-node-hover-bg: rgba(var(--ax-sys-color-on-lightest-surface), .04);--ax-comp-tree-view-node-selected-bg: rgba(var(--ax-sys-color-primary-500), .12);--ax-comp-tree-view-node-border-radius: 6px;--ax-comp-tree-view-node-margin: .25rem;--ax-comp-tree-view-line-color: rgba(var(--ax-sys-color-on-lightest-surface), .15);--ax-comp-tree-view-drag-preview-opacity: .9;--ax-comp-tree-view-drag-placeholder-bg: rgba(var(--ax-sys-color-on-lightest-surface), .02);--ax-comp-tree-view-drop-active-bg: rgba(var(--ax-sys-color-primary-500), .08);--ax-comp-tree-view-drop-active-outline: rgba(var(--ax-sys-color-primary-500), .3);--ax-comp-tree-view-content-padding: 0;--ax-comp-tree-view-content-gap: .5rem;--ax-comp-tree-view-drop-list-min-height: 2rem;--ax-comp-tree-view-drag-handle-padding: .25rem;--ax-comp-tree-view-expand-toggle-padding: .25rem;--ax-comp-tree-view-card-node-margin: .5rem;--ax-comp-tree-view-card-content-padding: 1rem;--ax-comp-tree-view-outline-offset: 2px;--ax-comp-tree-view-outline-offset-negative: -2px}.ax-tree-view-drop-list{min-height:var(--ax-comp-tree-view-drop-list-min-height)}.ax-tree-view-compact .ax-tree-view-node-content{padding:var(--ax-comp-tree-view-content-padding, .25rem .5rem);gap:var(--ax-comp-tree-view-content-gap, .375rem);font-size:.8125rem}.ax-tree-view-comfortable .ax-tree-view-node-content{padding:var(--ax-comp-tree-view-content-padding, .75rem .625rem);gap:var(--ax-comp-tree-view-content-gap, .625rem);font-size:.9375rem}.ax-tree-view-node{position:relative;margin:var(--ax-comp-tree-view-node-margin) 0;border-radius:var(--ax-comp-tree-view-node-border-radius);border:1px solid transparent;cursor:move}.ax-tree-view-node:hover:not(.ax-dragging){background:var(--ax-comp-tree-view-node-hover-bg)}.ax-tree-view-node.ax-tree-view-node-selected{background:var(--ax-comp-tree-view-node-selected-bg);border-color:currentColor}.ax-tree-view-node.ax-dragging{opacity:var(--ax-comp-tree-view-drag-placeholder-opacity);cursor:grabbing!important}.ax-tree-view-node.ax-drag-placeholder{background:var(--ax-comp-tree-view-drag-placeholder-bg)}.ax-drag-preview{opacity:var(--ax-comp-tree-view-drag-preview-opacity)!important;box-shadow:0 4px 12px rgba(var(--ax-sys-color-on-lightest-surface),.2)!important;cursor:grabbing!important;border:2px dashed currentColor!important}.ax-tree-view-node-content.ax-drop-list-sorting-active{background:var(--ax-comp-tree-view-drop-active-bg);border-radius:var(--ax-comp-tree-view-node-border-radius);outline:2px dashed var(--ax-comp-tree-view-drop-active-outline);outline-offset:var(--ax-comp-tree-view-outline-offset-negative)}.ax-tree-view-node-content{display:flex;align-items:center;gap:var(--ax-comp-tree-view-content-gap);padding:var(--ax-comp-tree-view-content-padding);cursor:pointer;-webkit-user-select:none;user-select:none;outline:none;border:1px solid transparent;border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-node-content:focus{outline:none}.ax-tree-view-node-content:focus-visible{outline:2px solid rgba(var(--ax-sys-color-primary-500),.8);outline-offset:var(--ax-comp-tree-view-outline-offset);border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-drag-handle{cursor:grab;opacity:.6;padding:var(--ax-comp-tree-view-drag-handle-padding)}.ax-tree-view-drag-handle:hover{opacity:1}.ax-tree-view-drag-handle:active{cursor:grabbing}.ax-tree-view-expand-toggle{background:none;border:none;cursor:pointer;padding:var(--ax-comp-tree-view-expand-toggle-padding);min-width:1.5rem;height:1.5rem}.ax-tree-view-expand-toggle:not(.ax-tree-view-has-children){opacity:0;pointer-events:none}.ax-tree-view-toggle-icon{font-size:.75rem}.ax-tree-view-node-icon{font-size:1.125rem;flex-shrink:0}.ax-tree-view-node-label{flex:1;font-size:.875rem;line-height:1rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ax-tree-view-children{padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-node-disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ax-tree-view-node-loading{opacity:.7}.ax-tree-view-card .ax-tree-view-node{border:1px solid rgba(var(--ax-sys-color-border-lightest-surface),1);margin:var(--ax-comp-tree-view-card-node-margin) 0}.ax-tree-view-card .ax-tree-view-node-content{padding:var(--ax-comp-tree-view-card-content-padding)}.ax-tree-view-with-lines .ax-tree-view-children{position:relative;padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-with-lines .ax-tree-view-children:before{content:\"\";position:absolute;inset-inline-start:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));top:0;height:calc(100% - .875rem);width:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines .ax-tree-view-node{position:relative}.ax-tree-view-with-lines .ax-tree-view-node:before{content:\"\";position:absolute;inset-inline-start:calc(-1 * var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2)));top:60%;width:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));height:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines>.ax-tree-view-drop-list>.ax-tree-view-node:before,.ax-tree-view-with-lines>.ax-tree-view-node:before{display:none}\n"] }]
|
|
1765
|
-
}], propDecorators: { datasource: [{ type: i0.Input, args: [{ isSignal: true, alias: "datasource", required: true }] }, { type: i0.Output, args: ["datasourceChange"] }], selectMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectMode", required: false }] }], showCheckbox: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCheckbox", required: false }] }], checkChildrenOnSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkChildrenOnSelect", required: false }] }], intermediateState: [{ type: i0.Input, args: [{ isSignal: true, alias: "intermediateState", required: false }] }], checkOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkOnClick", required: false }] }], dragMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragMode", required: false }] }], dragOperationType: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragOperationType", required: false }] }], showIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcons", required: false }] }], showChildrenBadge: [{ type: i0.Input, args: [{ isSignal: true, alias: "showChildrenBadge", required: false }] }], expandedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedIcon", required: false }] }], collapsedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedIcon", required: false }] }], indentSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentSize", required: false }] }], nodeHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeHeight", required: false }] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }], itemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemTemplate", required: false }] }], onBeforeDrop: [{ type: i0.Output, args: ["onBeforeDrop"] }], onNodeToggle: [{ type: i0.Output, args: ["onNodeToggle"] }], onNodeSelect: [{ type: i0.Output, args: ["onNodeSelect"] }], onOrderChange: [{ type: i0.Output, args: ["onOrderChange"] }], onMoveChange: [{ type: i0.Output, args: ["onMoveChange"] }], onItemsChange: [{ type: i0.Output, args: ["onItemsChange"] }] } });
|
|
2172
|
+
}, template: "<!-- Root drop list -->\n<div\n axFocusTrap\n [axDropList]=\"dragBehavior() !== 'none'\"\n [sortingDisabled]=\"false\"\n [id]=\"getListId()\"\n [attr.data-node-id]=\"null\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDrop($event)\"\n class=\"ax-tree-view-drop-list\"\n [class.ax-tree-view-card]=\"look() === 'card'\"\n [class.ax-tree-view-with-lines]=\"look() === 'with-line'\"\n role=\"group\"\n>\n @for (node of nodes(); track getNodeId(node)) {\n @if (getNodeHidden(node) !== true) {\n <div\n [axDrag]=\"dragBehavior() !== 'none'\"\n [dragDisabled]=\"getNodeDisabled(node)\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"getNodeSelected(node)\"\n [class.ax-tree-view-node-disabled]=\"getNodeDisabled(node)\"\n [class.ax-tree-view-node-loading]=\"getNodeLoading(node)\"\n role=\"treeitem\"\n [attr.aria-level]=\"getNodeAriaLevel(0)\"\n [attr.aria-expanded]=\"getNodeAriaExpanded(node)\"\n [attr.aria-selected]=\"getNodeAriaSelected(node)\"\n [attr.aria-disabled]=\"getNodeDisabled(node) || (isLeafOnlyMode() && !isLeafNode(node)) ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [axDropList]=\"dragBehavior() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + getNodeId(node)\"\n [attr.data-node-id]=\"getNodeId(node)\"\n [attr.data-tree-node-id]=\"getNodeId(node)\"\n [attr.data-drop-type]=\"'onto-node'\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDropOntoNode($event, node)\"\n (click)=\"\n (selectMode() === 'single' || (selectMode() === 'multiple' && !showCheckbox())) && onNodeClick(node, $event)\n \"\n (focus)=\"onNodeFocus(getNodeId(node))\"\n [tabindex]=\"isNodeFocused(getNodeId(node)) ? 0 : -1\"\n >\n @if (dragArea() === 'handler' && dragBehavior() !== 'none') {\n <span class=\"ax-tree-view-drag-handle\" axDragHandle title=\"Drag to reorder\"> \u22EE\u22EE </span>\n }\n <ax-button\n class=\"ax-tree-view-expand-toggle ax-sm\"\n (onClick)=\"toggleNode(node, $any($event))\"\n [class.ax-tree-view-has-children]=\"shouldShowExpandToggle(node)\"\n [class.ax-tree-view-expanded]=\"getNodeExpanded(node)\"\n [disabled]=\"getNodeDisabled(node) || getNodeLoading(node)\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (getNodeLoading(node)) {\n <ax-icon>\n <i class=\"fa-solid fa-spinner fa-spin ax-tree-view-loading-spinner\"></i>\n </ax-icon>\n } @else {\n <ax-icon>\n <i\n [class]=\"getNodeExpanded(node) ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n @if (nodeTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, 0)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckboxForNode(node)) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"getNodeIndeterminate(node) ? null : getNodeSelected(node) || false\"\n [indeterminate]=\"getNodeIndeterminate(node) || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && getNodeIcon(node)) {\n <i [class]=\"getNodeIcon(node)\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span\n class=\"ax-tree-view-node-label\"\n [axTooltip]=\"getNodeTooltip(node) || ''\"\n [axTooltipDisabled]=\"!getNodeTooltip(node)\"\n [axTooltipPlacement]=\"'top-start'\"\n >\n {{ getNodeTitle(node) }}\n </span>\n @if (\n showChildrenBadge() &&\n (getNodeChildrenCount(node) || (getNodeChildren(node) && getNodeChildren(node)!.length > 0))\n ) {\n <span class=\"ax-tree-view-node-badge\">\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(getNodeChildrenCount(node) ?? getNodeChildren(node)?.length ?? 0).toString()\"\n ></ax-badge>\n </span>\n }\n }\n </div>\n </div>\n @if (getNodeExpanded(node) && getNodeChildren(node) && getNodeChildren(node)!.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: getNodeChildren(node), parent: node, level: 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n</div>\n\n<!-- Recursive children template -->\n<ng-template #childrenList let-children=\"children\" let-parent=\"parent\" let-level=\"level\">\n <div\n [axDropList]=\"dragBehavior() !== 'none'\"\n [id]=\"getListId(parent)\"\n [attr.data-node-id]=\"getNodeId(parent)\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDrop($event, parent)\"\n class=\"ax-tree-view-drop-list\"\n role=\"group\"\n >\n @for (node of children; track getNodeId(node)) {\n @if (getNodeHidden(node) !== true) {\n <div\n [axDrag]=\"dragBehavior() !== 'none'\"\n [dragDisabled]=\"getNodeDisabled(node)\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"getNodeSelected(node)\"\n [class.ax-tree-view-node-disabled]=\"getNodeDisabled(node)\"\n [class.ax-tree-view-node-loading]=\"getNodeLoading(node)\"\n [class.ax-tree-view-node-focused]=\"isNodeFocused(getNodeId(node))\"\n role=\"treeitem\"\n [attr.aria-level]=\"getNodeAriaLevel(level)\"\n [attr.aria-expanded]=\"getNodeAriaExpanded(node)\"\n [attr.aria-selected]=\"getNodeAriaSelected(node)\"\n [attr.aria-disabled]=\"getNodeDisabled(node) ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [axDropList]=\"dragBehavior() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + getNodeId(node)\"\n [attr.data-node-id]=\"getNodeId(node)\"\n [attr.data-tree-node-id]=\"getNodeId(node)\"\n [attr.data-drop-type]=\"'onto-node'\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDropOntoNode($event, node)\"\n (click)=\"\n (selectMode() === 'single' || (selectMode() === 'multiple' && !showCheckbox())) &&\n onNodeClick(node, $event)\n \"\n (focus)=\"onNodeFocus(getNodeId(node))\"\n (blur)=\"focusedNodeId.set(null)\"\n [tabindex]=\"isNodeFocused(getNodeId(node)) ? 0 : -1\"\n >\n @if (dragArea() === 'handler') {\n <span class=\"ax-tree-view-drag-handle\" axDragHandle title=\"Drag to reorder\"> \u22EE\u22EE </span>\n }\n <ax-button\n class=\"ax-tree-view-expand-toggle ax-sm\"\n (onClick)=\"toggleNode(node, $any($event))\"\n [class.ax-tree-view-has-children]=\"shouldShowExpandToggle(node)\"\n [class.ax-tree-view-expanded]=\"getNodeExpanded(node)\"\n [disabled]=\"getNodeDisabled(node) || getNodeLoading(node)\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (getNodeLoading(node)) {\n <ax-icon>\n <i class=\"fa-solid fa-spinner fa-spin ax-tree-view-loading-spinner\"></i>\n </ax-icon>\n } @else {\n <ax-icon>\n <i\n [class]=\"getNodeExpanded(node) ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n\n @if (nodeTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, level)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckboxForNode(node)) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"getNodeIndeterminate(node) ? null : getNodeSelected(node) || false\"\n [indeterminate]=\"getNodeIndeterminate(node) || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && getNodeIcon(node)) {\n <i [class]=\"getNodeIcon(node)\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span\n class=\"ax-tree-view-node-label\"\n [axTooltip]=\"getNodeTooltip(node) || ''\"\n [axTooltipDisabled]=\"!getNodeTooltip(node)\"\n [axTooltipPlacement]=\"'top-start'\"\n >\n {{ getNodeTitle(node) }}\n </span>\n @if (\n showChildrenBadge() &&\n (getNodeChildrenCount(node) || (getNodeChildren(node) && getNodeChildren(node)!.length > 0))\n ) {\n <span class=\"ax-tree-view-node-badge\">\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(getNodeChildrenCount(node) ?? getNodeChildren(node)?.length ?? 0).toString()\"\n ></ax-badge>\n </span>\n }\n }\n </div>\n </div>\n @if (getNodeExpanded(node) && getNodeChildren(node) && getNodeChildren(node)!.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: getNodeChildren(node), parent: node, level: level + 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n </div>\n</ng-template>\n", styles: [".ax-tree-view{display:block;width:100%;--ax-comp-tree-view-indent-size: 12px;--ax-comp-tree-view-node-hover-bg: rgba(var(--ax-sys-color-on-lightest-surface), .04);--ax-comp-tree-view-node-selected-bg: rgba(var(--ax-sys-color-primary-500), .12);--ax-comp-tree-view-node-border-radius: 6px;--ax-comp-tree-view-node-margin: .25rem;--ax-comp-tree-view-line-color: rgba(var(--ax-sys-color-on-lightest-surface), .15);--ax-comp-tree-view-drag-preview-opacity: .9;--ax-comp-tree-view-drag-placeholder-bg: rgba(var(--ax-sys-color-on-lightest-surface), .02);--ax-comp-tree-view-drop-active-bg: rgba(var(--ax-sys-color-primary-500), .08);--ax-comp-tree-view-drop-active-outline: rgba(var(--ax-sys-color-primary-500), .3);--ax-comp-tree-view-content-padding: 0;--ax-comp-tree-view-content-gap: .5rem;--ax-comp-tree-view-drop-list-min-height: 2rem;--ax-comp-tree-view-drag-handle-padding: .25rem;--ax-comp-tree-view-badge-padding: .25rem;--ax-comp-tree-view-expand-toggle-padding: .25rem;--ax-comp-tree-view-outline-offset: 2px;--ax-comp-tree-view-outline-offset-negative: -2px}.ax-tree-view-drop-list{min-height:var(--ax-comp-tree-view-drop-list-min-height)}.ax-tree-view-node{position:relative;margin:var(--ax-comp-tree-view-node-margin) 0;border-radius:var(--ax-comp-tree-view-node-border-radius);cursor:move}.ax-tree-view-node:hover:not(.ax-dragging){background:var(--ax-comp-tree-view-node-hover-bg)}.ax-tree-view-node.ax-tree-view-node-selected{background:var(--ax-comp-tree-view-node-selected-bg)}.ax-tree-view-node.ax-dragging{opacity:var(--ax-comp-tree-view-drag-placeholder-opacity);cursor:grabbing!important}.ax-tree-view-node.ax-drag-placeholder{background:var(--ax-comp-tree-view-drag-placeholder-bg)}.ax-drag-preview{opacity:var(--ax-comp-tree-view-drag-preview-opacity)!important;box-shadow:0 4px 12px rgba(var(--ax-sys-color-on-lightest-surface),.2)!important;cursor:grabbing!important;border:2px dashed currentColor!important}.ax-tree-view-node-content.ax-drop-list-sorting-active{background:var(--ax-comp-tree-view-drop-active-bg);border-radius:var(--ax-comp-tree-view-node-border-radius);outline:2px dashed var(--ax-comp-tree-view-drop-active-outline);outline-offset:var(--ax-comp-tree-view-outline-offset-negative)}.ax-tree-view-node-content{display:flex;align-items:center;gap:var(--ax-comp-tree-view-content-gap);padding:var(--ax-comp-tree-view-content-padding);cursor:pointer;-webkit-user-select:none;user-select:none;outline:none;border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-node-content:focus{outline:none}.ax-tree-view-node-content:focus-visible{outline:2px solid rgba(var(--ax-sys-color-primary-500),.8);outline-offset:var(--ax-comp-tree-view-outline-offset);border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-drag-handle{cursor:grab;opacity:.6;padding:var(--ax-comp-tree-view-drag-handle-padding);padding-inline-start:calc(var(--ax-comp-tree-view-drag-handle-padding) * 2)}.ax-tree-view-drag-handle:hover{opacity:1}.ax-tree-view-drag-handle:active{cursor:grabbing}.ax-tree-view-expand-toggle{background:none;border:none;cursor:pointer;padding:var(--ax-comp-tree-view-expand-toggle-padding);min-width:1.5rem;height:1.5rem}.ax-tree-view-expand-toggle:not(.ax-tree-view-has-children){opacity:0;pointer-events:none}.ax-tree-view-toggle-icon{font-size:.75rem}.ax-tree-view-node-icon{font-size:1.125rem;flex-shrink:0}.ax-tree-view-node-label{flex:1;font-size:.875rem;line-height:1rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ax-tree-view-node-badge{padding:var(--ax-comp-tree-view-badge-padding);padding-inline-end:calc(var(--ax-comp-tree-view-badge-padding) * 1.5)}.ax-tree-view-children{padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-node-disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ax-tree-view-node-loading{opacity:.7}.ax-tree-view-card .ax-tree-view-node{border:1px solid rgba(var(--ax-sys-color-border-lightest-surface),1)}.ax-tree-view-card .ax-tree-view-node.ax-tree-view-node-selected{border:1px solid rgba(var(--ax-sys-color-border-surface),1)}.ax-tree-view-with-lines .ax-tree-view-children{position:relative;padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-with-lines .ax-tree-view-children:before{content:\"\";position:absolute;inset-inline-start:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));top:0;height:calc(100% - .875rem);width:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines .ax-tree-view-node{position:relative}.ax-tree-view-with-lines .ax-tree-view-node:before{content:\"\";position:absolute;inset-inline-start:calc(-1 * var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2)));top:60%;width:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));height:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines>.ax-tree-view-drop-list>.ax-tree-view-node:before,.ax-tree-view-with-lines>.ax-tree-view-node:before{display:none}\n"] }]
|
|
2173
|
+
}], propDecorators: { datasource: [{ type: i0.Input, args: [{ isSignal: true, alias: "datasource", required: true }] }, { type: i0.Output, args: ["datasourceChange"] }], selectMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectMode", required: false }] }], showCheckbox: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCheckbox", required: false }] }], selectionBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionBehavior", required: false }] }], dragArea: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragArea", required: false }] }], dragBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragBehavior", required: false }] }], showIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcons", required: false }] }], showChildrenBadge: [{ type: i0.Input, args: [{ isSignal: true, alias: "showChildrenBadge", required: false }] }], expandedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedIcon", required: false }] }], collapsedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedIcon", required: false }] }], indentSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentSize", required: false }] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }], nodeTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeTemplate", required: false }] }], idField: [{ type: i0.Input, args: [{ isSignal: true, alias: "idField", required: false }] }], titleField: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleField", required: false }] }], tooltipField: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipField", required: false }] }], iconField: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconField", required: false }] }], expandedField: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedField", required: false }] }], selectedField: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedField", required: false }] }], indeterminateField: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminateField", required: false }] }], disabledField: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledField", required: false }] }], hiddenField: [{ type: i0.Input, args: [{ isSignal: true, alias: "hiddenField", required: false }] }], childrenField: [{ type: i0.Input, args: [{ isSignal: true, alias: "childrenField", required: false }] }], childrenCountField: [{ type: i0.Input, args: [{ isSignal: true, alias: "childrenCountField", required: false }] }], dataField: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataField", required: false }] }], onBeforeDrop: [{ type: i0.Output, args: ["onBeforeDrop"] }], onNodeToggle: [{ type: i0.Output, args: ["onNodeToggle"] }], onNodeSelect: [{ type: i0.Output, args: ["onNodeSelect"] }], onSelectionChange: [{ type: i0.Output, args: ["onSelectionChange"] }], onOrderChange: [{ type: i0.Output, args: ["onOrderChange"] }], onMoveChange: [{ type: i0.Output, args: ["onMoveChange"] }], onItemsChange: [{ type: i0.Output, args: ["onItemsChange"] }] } });
|
|
1766
2174
|
|
|
1767
2175
|
class AXTreeViewModule {
|
|
1768
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
1769
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.
|
|
1770
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.
|
|
2176
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
2177
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, imports: [AXTreeViewComponent] }); }
|
|
2178
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, imports: [AXTreeViewComponent] }); }
|
|
1771
2179
|
}
|
|
1772
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
2180
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, decorators: [{
|
|
1773
2181
|
type: NgModule,
|
|
1774
2182
|
args: [{
|
|
1775
2183
|
imports: [AXTreeViewComponent],
|