@pictogrammers/components 0.5.14 → 0.5.17
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/package.json +1 -1
- package/pg/autocompleteItem/__examples__/basic/basic.html +3 -0
- package/pg/autocompleteItem/autocompleteItem.css +55 -0
- package/pg/autocompleteItem/autocompleteItem.html +1 -0
- package/pg/autocompleteItem/autocompleteItem.ts +65 -0
- package/pg/button/button.css +5 -0
- package/pg/buttonMenu/buttonMenu.ts +1 -1
- package/pg/inputCombobox/__examples__/basic/basic.ts +33 -0
- package/pg/inputCombobox/inputCombobox.ts +158 -0
- package/pg/inputCombobox/inputCombobox.ts.tmp.44252.751480cb81cc +158 -0
- package/pg/inputCombobox/inputCombobox.ts.tmp.44252.dcea847c40a8 +156 -0
- package/pg/inputNumber/inputNumber.ts +31 -13
- package/pg/inputPill/inputPill.html +6 -0
- package/pg/inputPill/inputPill.html.tmp.26852.84ac63f4c46f +6 -0
- package/pg/inputPill/inputPill.ts +41 -0
- package/pg/inputPills/__examples__/basic/basic.html +9 -0
- package/pg/inputPills/__examples__/basic/basic.html.tmp.26852.4771e4cad5b7 +9 -0
- package/pg/inputPills/__examples__/basic/basic.ts.tmp.26852.d8fe41df18bd +0 -0
- package/pg/inputPixelEditor/README.md +104 -69
- package/pg/inputPixelEditor/README.md.tmp.42596.658de5f0a6f5 +0 -0
- package/pg/inputPixelEditor/__examples__/basic/basic.ts +6 -5
- package/pg/inputPixelEditor/inputPixelEditor.ts +95 -23
- package/pg/inputPixelEditor/inputPixelEditor.ts.tmp.38516.96529dd82670 +1703 -0
- package/pg/inputPixelEditor/inputPixelEditor.ts.tmp.42596.48ecc3ad9c72 +1724 -0
- package/pg/inputPixelEditor/utils/bitmapToMask.ts +113 -79
- package/pg/inputPixelEditor/utils/getLassoPixels.ts +51 -0
- package/pg/inputRange/inputRange.css +7 -0
- package/pg/inputSelect/__examples__/basic/basic.ts +2 -2
- package/pg/inputSelect/inputSelect.css +1 -1
- package/pg/inputSelect/inputSelect.ts +62 -5
- package/pg/inputText/README.md +6 -6
- package/pg/inputText/__examples__/basic/basic.ts +1 -1
- package/pg/inputText/inputText.css +2 -2
- package/pg/inputText copy/README.md +38 -0
- package/pg/inputText copy/inputText.css +41 -0
- package/pg/inputText copy/inputText.html +1 -0
- package/pg/inputText copy/inputText.spec.ts +59 -0
- package/pg/inputText copy/inputText.ts +67 -0
- package/pg/inputTextarea/README.md +39 -0
- package/pg/inputTextarea/__examples__/basic/basic.html +9 -0
- package/pg/inputTextarea/__examples__/basic/basic.ts +30 -0
- package/pg/inputTextarea/inputTextarea.ts +121 -0
- package/pg/inputTextarea copy/README.md +39 -0
- package/pg/inputTextarea copy/inputTextarea.css +41 -0
- package/pg/inputTextarea copy/inputTextarea.html +1 -0
- package/pg/inputTextarea copy/inputTextarea.spec.ts +59 -0
- package/pg/inputTextarea copy/inputTextarea.ts +79 -0
- package/pg/inputTextareaAutocomplete/README.md +70 -0
- package/pg/inputTextareaAutocomplete/__examples__/basic/basic.ts +67 -0
- package/pg/inputTextareaAutocomplete/inputTextareaAutocomplete.ts +267 -0
- package/pg/node/README.md +35 -0
- package/pg/node/__examples__/basic/basic.ts +34 -0
- package/pg/node/index.ts +3 -0
- package/pg/node/node.css +53 -0
- package/pg/node/node.html +5 -0
- package/pg/node/node.ts +270 -0
- package/pg/nodeEditorLink/nodeEditorLink.css +69 -0
- package/pg/nodeEditorLink/nodeEditorLink.css.tmp.1408.09e961fd0dcc +69 -0
- package/pg/nodeEditorLink/nodeEditorLink.html +9 -0
- package/pg/nodeEditorNumber/nodeEditorNumber.css +59 -0
- package/pg/nodeEditorNumber/nodeEditorNumber.ts +57 -0
- package/pg/nodeEditorRange/nodeEditorRange.css +23 -0
- package/pg/nodeEditorRange/nodeEditorRange.ts +69 -0
- package/pg/nodeEditorText/__examples__/basic/basic.html +9 -0
- package/pg/nodeEditorText/__examples__/basic/basic.ts +30 -0
- package/pg/nodeEditorText/nodeEditorText.css +17 -0
- package/pg/nodeEditorText/nodeEditorText.html +4 -0
- package/pg/nodeEditorText/nodeEditorText.ts +57 -0
- package/pg/nodeEditorText copy/README.md +35 -0
- package/pg/nodeEditorText copy/nodeEditorText.css +49 -0
- package/pg/nodeEditorText copy/nodeEditorText.html +4 -0
- package/pg/nodeEditorText copy/nodeEditorText.ts +50 -0
- package/pg/nodeEditorTextArray/nodeEditorTextArray.css +68 -0
- package/pg/nodeEditorTextArray/nodeEditorTextArray.html +9 -0
- package/pg/nodeEditorTextArray/nodeEditorTextArray.ts +162 -0
- package/pg/nodeEntry/nodeEntry.css +61 -0
- package/pg/nodeEntry/nodeEntry.ts +164 -0
- package/pg/nodeEntry/nodeEntry.ts.tmp.28724.dda67762bca5 +164 -0
- package/pg/nodeInputText/nodeInputText.css +75 -0
- package/pg/nodeInputText/nodeInputText.html +4 -0
- package/pg/nodeInputText/nodeInputText.ts +105 -0
- package/pg/nodeOutput/nodeOutput.css +32 -0
- package/pg/nodeResize/README.md +3 -0
- package/pg/nodeResize/THINKING.md +81 -0
- package/pg/nodeResize/THINKING.md.tmp.24812.99a70ba81062 +81 -0
- package/pg/nodeResize/basic/basic.ts +17 -0
- package/pg/nodeResize/dragUtil.ts +105 -0
- package/pg/nodeResize/dragUtil.ts.tmp.34372.787464c73309 +75 -0
- package/pg/nodeResize/nodeResize.css +187 -0
- package/pg/nodeResize/nodeResize.html +9 -0
- package/pg/nodeResize/nodeResize.ts +156 -0
- package/pg/nodes/README.md +177 -0
- package/pg/nodes/__examples__/basic/basic.html +33 -0
- package/pg/nodes/__examples__/basic/basic.ts +716 -0
- package/pg/nodes/__examples__/basic/exampleNodes.ts +129 -0
- package/pg/nodes/__examples__/basic/exampleScripts.ts +129 -0
- package/pg/nodes/__examples__/basic/keystore.ts +38 -0
- package/pg/nodes/executeInSandbox.ts +32 -0
- package/pg/nodes/index.ts +3 -0
- package/pg/nodes/nodes.css +69 -0
- package/pg/nodes/nodes.html +6 -0
- package/pg/nodes/nodes.ts +1240 -0
- package/pg/nodes copy/nodes.css +41 -0
- package/pg/nodes copy/nodes.html +1 -0
- package/pg/overlayContextMenu/__examples__/filter/filter.ts +87 -0
- package/pg/overlayContextMenu/overlayContextMenu.css +14 -0
- package/pg/overlayContextMenu/overlayContextMenu.html +4 -3
- package/pg/overlayContextMenu/overlayContextMenu.ts +6 -2
- package/pg/overlayContextMenu/overlayContextMenu.ts.tmp.37088.530ff1c0a321 +0 -0
- package/pg/overlayMenu/overlayMenu.css +3 -1
- package/pg/overlayMenu/overlayMenu.ts +11 -2
- package/pg/overlayMenu/overlayMenu.ts.tmp.44252.9bb22fd59ede +80 -0
- package/pg/overlaySelectMenu/overlaySelectMenu.css +2 -0
- package/pg/overlaySubMenu/overlaySubMenu.css +8 -6
- package/pg/poco/README.md +22 -0
- package/pg/poco/__examples__/basic/basic.html +11 -0
- package/pg/poco/__examples__/basic/basic.ts +95 -0
- package/pg/poco/__examples__/basic/examples.ts +258 -0
- package/pg/poco/__examples__/basic/myFont.ts +1300 -0
- package/pg/poco/index.ts +3 -0
- package/pg/poco/mockPoco.ts +640 -0
- package/pg/poco/poco.css +7 -0
- package/pg/poco/poco.html +1 -0
- package/pg/poco/poco.ts +75 -0
- package/pg/popover/README.md +47 -0
- package/pg/popover/__examples__/basic/basic.html +3 -0
- package/pg/popover/popover.html +3 -0
- package/pg/popover/popover.ts +44 -0
- package/pg/popoverAutocomplete/__examples__/basic/basic.html +4 -0
- package/pg/popoverAutocomplete/__examples__/basic/basic.ts +46 -0
- package/pg/popoverAutocomplete/popoverAutocomplete.css +25 -0
- package/pg/popoverAutocomplete/popoverAutocomplete.html +1 -0
- package/pg/popoverAutocomplete/popoverAutocomplete.ts +134 -0
- package/pg/popoverAutocompleteItem/popoverAutocompleteItem.css +69 -0
- package/pg/popoverAutocompleteItem/popoverAutocompleteItem.ts +90 -0
- package/pg/table/__examples__/basic/basic.ts +1 -0
- package/pg/tableCellFileLocal/tableCellFileLocal.html +3 -0
- package/pg/tableCellFileLocal/tableCellFileLocal.html.tmp.20484.68ee2e30710e +3 -0
- package/pg/tableCellFileLocal/tableCellFileLocal.ts +44 -0
- package/pg/tableCellSelect/tableCellSelect.html +3 -0
- package/pg/tableCellSelect/tableCellSelect.html.tmp.41808.99c1a6f14340 +3 -0
- package/pg/tableCellSelect/tableCellSelect.ts +51 -0
- package/pg/tree/__examples__/basic/basic.ts +12 -5
- package/pg/tree/tree.html +1 -1
- package/pg/tree/tree.ts +385 -227
- package/pg/tree/tree.ts.tmp.38376.07d376a04f41 +343 -0
- package/pg/tree/tree.ts.tmp.38376.2a04599ade9f +361 -0
- package/pg/tree/tree.ts.tmp.38376.6cb2c663d476 +0 -0
- package/pg/tree/tree.ts.tmp.38376.ac5af1aff2b0 +393 -0
- package/pg/tree/tree.ts.tmp.38376.ac9acfc4f95f +324 -0
- package/pg/treeItem/treeItem.ts +536 -558
- package/pg/treeItem/treeItem.ts.tmp.38376.145d3121d648 +530 -0
- package/pg/treeItem/treeItem.ts.tmp.38376.b5224d48e5c0 +0 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import { Component, Prop, Part, forEach, getProxyValue } from '@pictogrammers/element';
|
|
2
|
+
|
|
3
|
+
import PgTreeItem from '../treeItem/treeItem';
|
|
4
|
+
|
|
5
|
+
import template from './tree.html';
|
|
6
|
+
import style from './tree.css';
|
|
7
|
+
|
|
8
|
+
export type SelectedTreeItem = {
|
|
9
|
+
indexes: number[];
|
|
10
|
+
remove: () => void;
|
|
11
|
+
getData: () => any;
|
|
12
|
+
getParentData: () => any;
|
|
13
|
+
move: (item: SelectedTreeItem, position: string) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@Component({
|
|
17
|
+
selector: 'pg-tree',
|
|
18
|
+
style,
|
|
19
|
+
template
|
|
20
|
+
})
|
|
21
|
+
export default class PgTree extends HTMLElement {
|
|
22
|
+
@Prop() items: any[] = [];
|
|
23
|
+
|
|
24
|
+
@Part() $items: HTMLDivElement;
|
|
25
|
+
|
|
26
|
+
#selectedIndexes = new Map();
|
|
27
|
+
#lastSelectedIndexes: number[] | null = null;
|
|
28
|
+
|
|
29
|
+
connectedCallback() {
|
|
30
|
+
forEach({
|
|
31
|
+
container: this.$items,
|
|
32
|
+
items: this.items,
|
|
33
|
+
type: () => PgTreeItem
|
|
34
|
+
});
|
|
35
|
+
this.$items.addEventListener('action', (e: any) => {
|
|
36
|
+
e.stopPropagation();
|
|
37
|
+
this.dispatchEvent(new CustomEvent('action', {
|
|
38
|
+
detail: {
|
|
39
|
+
actionIndex: e.detail.actionIndex,
|
|
40
|
+
item: this.#wrap(e.detail.indexes),
|
|
41
|
+
}
|
|
42
|
+
}));
|
|
43
|
+
});
|
|
44
|
+
this.$items.addEventListener('move', (e: any) => {
|
|
45
|
+
e.stopPropagation();
|
|
46
|
+
const selectedIdxsList = [...this.#selectedIndexes.values()] as number[][];
|
|
47
|
+
this.#batchMove(selectedIdxsList, e.detail.indexes, e.detail.position);
|
|
48
|
+
this.dispatchEvent(new CustomEvent('move', {
|
|
49
|
+
detail: { position: e.detail.position }
|
|
50
|
+
}));
|
|
51
|
+
});
|
|
52
|
+
this.$items.addEventListener('rename', (e: any) => {
|
|
53
|
+
e.stopPropagation();
|
|
54
|
+
this.dispatchEvent(new CustomEvent('rename', {
|
|
55
|
+
detail: {
|
|
56
|
+
item: this.#wrap(e.detail.indexes),
|
|
57
|
+
label: e.detail.label,
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
60
|
+
});
|
|
61
|
+
this.$items.addEventListener('toggle', (e: any) => {
|
|
62
|
+
const item = this.#getItem(e.detail.indexes);
|
|
63
|
+
item.expanded = !item.expanded;
|
|
64
|
+
});
|
|
65
|
+
this.$items.addEventListener('expand', (e: any) => {
|
|
66
|
+
this.#getItem(e.detail.indexes).expanded = true;
|
|
67
|
+
});
|
|
68
|
+
this.$items.addEventListener('menu', (e: any) => {
|
|
69
|
+
e.stopPropagation();
|
|
70
|
+
this.dispatchEvent(new CustomEvent('menu', {
|
|
71
|
+
detail: {
|
|
72
|
+
item: this.#wrap(e.detail.indexes),
|
|
73
|
+
x: e.detail.x,
|
|
74
|
+
y: e.detail.y,
|
|
75
|
+
}
|
|
76
|
+
}));
|
|
77
|
+
});
|
|
78
|
+
this.$items.addEventListener('select', (e: any) => {
|
|
79
|
+
e.stopPropagation();
|
|
80
|
+
const { indexes, type, ctrlKey, shiftKey } = e.detail;
|
|
81
|
+
const item = this.#getItem(indexes);
|
|
82
|
+
const unproxyItem = getProxyValue(item);
|
|
83
|
+
|
|
84
|
+
if (shiftKey && this.#lastSelectedIndexes) {
|
|
85
|
+
const visible = this.#getVisibleIndexes();
|
|
86
|
+
const lastPos = visible.findIndex(v => v.join(',') === this.#lastSelectedIndexes!.join(','));
|
|
87
|
+
const currPos = visible.findIndex(v => v.join(',') === indexes.join(','));
|
|
88
|
+
this.#selectedIndexes.forEach((x: any) => this.#getItem(x).selected = false);
|
|
89
|
+
this.#selectedIndexes.clear();
|
|
90
|
+
const start = Math.min(lastPos, currPos);
|
|
91
|
+
const end = Math.max(lastPos, currPos);
|
|
92
|
+
for (let i = start; i <= end; i++) {
|
|
93
|
+
const rangeItem = this.#getItem(visible[i]);
|
|
94
|
+
rangeItem.selected = true;
|
|
95
|
+
this.#selectedIndexes.set(getProxyValue(rangeItem), visible[i]);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
if (!ctrlKey && this.#selectedIndexes.size && !this.#selectedIndexes.has(unproxyItem)) {
|
|
99
|
+
this.#selectedIndexes.forEach((x: any) => this.#getItem(x).selected = false);
|
|
100
|
+
this.#selectedIndexes.clear();
|
|
101
|
+
}
|
|
102
|
+
item.selected = type === 'rename' ? true : !item.selected;
|
|
103
|
+
if (item.selected) {
|
|
104
|
+
this.#selectedIndexes.set(unproxyItem, indexes);
|
|
105
|
+
this.#lastSelectedIndexes = indexes;
|
|
106
|
+
} else {
|
|
107
|
+
this.#selectedIndexes.delete(unproxyItem);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.dispatchEvent(new CustomEvent('select', {
|
|
112
|
+
detail: {
|
|
113
|
+
items: [...this.#selectedIndexes.values()].map((idxs: any) => this.#wrap(idxs)),
|
|
114
|
+
}
|
|
115
|
+
}));
|
|
116
|
+
});
|
|
117
|
+
this.$items.addEventListener('up', (e: any) => {
|
|
118
|
+
e.stopPropagation();
|
|
119
|
+
const visible = this.#getVisibleIndexes();
|
|
120
|
+
const idx = visible.findIndex(v => v.join(',') === e.detail.indexes.join(','));
|
|
121
|
+
if (idx > 0) {
|
|
122
|
+
this.#focusItem(visible[idx - 1]);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
this.$items.addEventListener('down', (e: any) => {
|
|
126
|
+
e.stopPropagation();
|
|
127
|
+
const visible = this.#getVisibleIndexes();
|
|
128
|
+
const idx = visible.findIndex(v => v.join(',') === e.detail.indexes.join(','));
|
|
129
|
+
if (idx < visible.length - 1) {
|
|
130
|
+
this.#focusItem(visible[idx + 1]);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
this.$items.addEventListener('keydown', (e: any) => {
|
|
134
|
+
if (e.key === 'Delete') {
|
|
135
|
+
const toRemove = [...this.#selectedIndexes.values()] as number[][];
|
|
136
|
+
// Remove higher sibling indexes first to avoid index shifts
|
|
137
|
+
toRemove.sort((a, b) => {
|
|
138
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
139
|
+
const ai = i < a.length ? a[i] : -1;
|
|
140
|
+
const bi = i < b.length ? b[i] : -1;
|
|
141
|
+
if (ai !== bi) return bi - ai;
|
|
142
|
+
}
|
|
143
|
+
return 0;
|
|
144
|
+
});
|
|
145
|
+
toRemove.forEach((indexes: number[]) => this.#removeItem(indexes));
|
|
146
|
+
this.#selectedIndexes.clear();
|
|
147
|
+
this.#lastSelectedIndexes = null;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
this.$items.addEventListener('itemdragstart', (e: any) => {
|
|
151
|
+
const { indexes, callback, ctrlKey } = e.detail;
|
|
152
|
+
const item = this.#getItem(indexes);
|
|
153
|
+
const unproxyItem = getProxyValue(item);
|
|
154
|
+
if (!ctrlKey && this.#selectedIndexes.size && !this.#selectedIndexes.has(unproxyItem)) {
|
|
155
|
+
this.#selectedIndexes.forEach((x: any) => this.#getItem(x).selected = false);
|
|
156
|
+
this.#selectedIndexes.clear();
|
|
157
|
+
}
|
|
158
|
+
item.selected = true;
|
|
159
|
+
this.#selectedIndexes.set(unproxyItem, indexes);
|
|
160
|
+
let count = 0;
|
|
161
|
+
this.#selectedIndexes.forEach((idxs: any) => {
|
|
162
|
+
count = this.#getDragCount(this.#getItem(idxs), count);
|
|
163
|
+
});
|
|
164
|
+
callback(count);
|
|
165
|
+
this.$items.classList.toggle('dragging', true);
|
|
166
|
+
// Sync selection to consumers so #selectedItems reflects the dragged item
|
|
167
|
+
this.dispatchEvent(new CustomEvent('select', {
|
|
168
|
+
detail: {
|
|
169
|
+
items: [...this.#selectedIndexes.values()].map((idxs: any) => this.#wrap(idxs)),
|
|
170
|
+
}
|
|
171
|
+
}));
|
|
172
|
+
});
|
|
173
|
+
this.$items.addEventListener('itemdragend', () => {
|
|
174
|
+
this.$items.classList.toggle('dragging', false);
|
|
175
|
+
this.#clearDropHighlights(this.$items);
|
|
176
|
+
});
|
|
177
|
+
this.$items.addEventListener('itemdropenter', this.#handleDropEnter.bind(this));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
#getDragCount(item: any, count: number): number {
|
|
181
|
+
count += 1;
|
|
182
|
+
if (item.items?.length) {
|
|
183
|
+
item.items.forEach((itm: any) => {
|
|
184
|
+
count = this.#getDragCount(itm, count);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return count;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
#handleDropEnter(e: any) {
|
|
191
|
+
const { indexes, callback } = e.detail;
|
|
192
|
+
const excludes = this.#calculateDragExcludes();
|
|
193
|
+
const joined = indexes.join(',') as string;
|
|
194
|
+
// Use comma-terminated prefix to prevent "0,1" from matching "0,10"
|
|
195
|
+
const isInvalid = excludes.some(ex => joined === ex || joined.startsWith(ex + ','));
|
|
196
|
+
callback(!isInvalid);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
#removeItem(indexes: number[]) {
|
|
200
|
+
const deleteIndex = indexes[indexes.length - 1];
|
|
201
|
+
const parentIndexes = indexes.slice(0, indexes.length - 1);
|
|
202
|
+
const parent = parentIndexes.reduce((acc: any, i) => acc.items[i], this);
|
|
203
|
+
parent.items.splice(deleteIndex, 1);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
#getItem(indexes: number[]) {
|
|
207
|
+
return indexes.reduce((acc: any, i) => acc.items[i], this);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
#getItemElement(indexes: number[]): PgTreeItem | null {
|
|
211
|
+
let container: HTMLElement = this.$items;
|
|
212
|
+
let element: PgTreeItem | null = null;
|
|
213
|
+
for (const i of indexes) {
|
|
214
|
+
element = container.children[i] as PgTreeItem;
|
|
215
|
+
if (!element) return null;
|
|
216
|
+
container = (element as any).$items;
|
|
217
|
+
if (!container) return null;
|
|
218
|
+
}
|
|
219
|
+
return element;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
#focusItem(indexes: number[]) {
|
|
223
|
+
const element = this.#getItemElement(indexes);
|
|
224
|
+
if (element) {
|
|
225
|
+
(element as any).$labelButton.focus();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
#getVisibleIndexes(): number[][] {
|
|
230
|
+
const result: number[][] = [];
|
|
231
|
+
const traverse = (items: any[], prefix: number[]) => {
|
|
232
|
+
items.forEach((item: any, i: number) => {
|
|
233
|
+
const indexes = [...prefix, i];
|
|
234
|
+
result.push(indexes);
|
|
235
|
+
if (item.expanded && item.items?.length) {
|
|
236
|
+
traverse(item.items, indexes);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
};
|
|
240
|
+
traverse(this.items, []);
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#clearDropHighlights(container: HTMLElement) {
|
|
245
|
+
Array.from(container.children).forEach((child: any) => {
|
|
246
|
+
if (child.$dropabove) {
|
|
247
|
+
child.$dropabove.classList.remove('drop');
|
|
248
|
+
child.$dropon.classList.remove('drop');
|
|
249
|
+
child.$dropbelow.classList.remove('drop');
|
|
250
|
+
}
|
|
251
|
+
if (child.$items) {
|
|
252
|
+
this.#clearDropHighlights(child.$items);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
#batchMove(selectedIdxsList: number[][], targetIdxs: number[], position: string) {
|
|
258
|
+
if (selectedIdxsList.length === 0) return;
|
|
259
|
+
|
|
260
|
+
// Ascending order preserves the original relative order of dragged items on insertion
|
|
261
|
+
const ascending = [...selectedIdxsList].sort((a, b) => {
|
|
262
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
263
|
+
const av = i < a.length ? a[i] : -1;
|
|
264
|
+
const bv = i < b.length ? b[i] : -1;
|
|
265
|
+
if (av !== bv) return av - bv;
|
|
266
|
+
}
|
|
267
|
+
return 0;
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Capture data references before any structural changes
|
|
271
|
+
const caches = ascending.map(idxs => this.#getItem(idxs));
|
|
272
|
+
|
|
273
|
+
if (position === 'on') {
|
|
274
|
+
// Capture target by reference so it's unaffected by the removals below
|
|
275
|
+
const targetData = this.#getItem(targetIdxs);
|
|
276
|
+
// Remove descending so higher sibling indexes don't shift lower ones mid-loop
|
|
277
|
+
[...ascending].reverse().forEach(idxs => this.#removeItem(idxs));
|
|
278
|
+
if (!Array.isArray(targetData.items)) targetData.items = [];
|
|
279
|
+
caches.forEach(cache => targetData.items.push(cache));
|
|
280
|
+
targetData.expanded = true;
|
|
281
|
+
} else {
|
|
282
|
+
// Count how many selected items are in the same parent as the target and
|
|
283
|
+
// precede it — each one shifts the target index down by one after removal.
|
|
284
|
+
const targetParent = targetIdxs.slice(0, -1).join(',');
|
|
285
|
+
let shift = 0;
|
|
286
|
+
for (const sidxs of ascending) {
|
|
287
|
+
if (sidxs.slice(0, -1).join(',') === targetParent &&
|
|
288
|
+
sidxs[sidxs.length - 1] < targetIdxs[targetIdxs.length - 1]) {
|
|
289
|
+
shift++;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const adjustedIdx = targetIdxs[targetIdxs.length - 1] - shift;
|
|
293
|
+
const adjustedParent = targetIdxs.slice(0, -1);
|
|
294
|
+
// Remove descending to keep earlier indexes stable
|
|
295
|
+
[...ascending].reverse().forEach(idxs => this.#removeItem(idxs));
|
|
296
|
+
const insertAt = position === 'after' ? adjustedIdx + 1 : adjustedIdx;
|
|
297
|
+
if (adjustedParent.length === 0) {
|
|
298
|
+
this.items.splice(insertAt, 0, ...caches);
|
|
299
|
+
} else {
|
|
300
|
+
this.#getItem(adjustedParent).items.splice(insertAt, 0, ...caches);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
caches.forEach(cache => { cache.selected = false; });
|
|
305
|
+
this.#selectedIndexes.clear();
|
|
306
|
+
this.#lastSelectedIndexes = null;
|
|
307
|
+
this.$items.classList.toggle('dragging', false);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
#wrap(indexes: number[]): SelectedTreeItem {
|
|
311
|
+
return {
|
|
312
|
+
indexes,
|
|
313
|
+
remove: () => {
|
|
314
|
+
this.#removeItem(indexes);
|
|
315
|
+
this.#selectedIndexes.clear();
|
|
316
|
+
this.#lastSelectedIndexes = null;
|
|
317
|
+
},
|
|
318
|
+
getData: () => this.#getItem(indexes),
|
|
319
|
+
getParentData: () => {
|
|
320
|
+
const parent = indexes.slice(0, indexes.length - 1);
|
|
321
|
+
return parent.length === 0 ? this : this.#getItem(parent);
|
|
322
|
+
},
|
|
323
|
+
move: (item: SelectedTreeItem, position: string) => {
|
|
324
|
+
this.#batchMove([indexes], item.indexes, position);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
unselect(indexes: number[]) {
|
|
330
|
+
const item = this.#getItem(indexes);
|
|
331
|
+
const unproxyItem = getProxyValue(item);
|
|
332
|
+
item.selected = false;
|
|
333
|
+
this.#selectedIndexes.delete(unproxyItem);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
#calculateDragExcludes(): string[] {
|
|
337
|
+
const exclude: string[] = [];
|
|
338
|
+
this.#selectedIndexes.forEach((indexes: number[]) => {
|
|
339
|
+
exclude.push(indexes.join(','));
|
|
340
|
+
});
|
|
341
|
+
return exclude;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { Component, Prop, Part, forEach, getProxyValue } from '@pictogrammers/element';
|
|
2
|
+
|
|
3
|
+
import PgTreeItem from '../treeItem/treeItem';
|
|
4
|
+
|
|
5
|
+
import template from './tree.html';
|
|
6
|
+
import style from './tree.css';
|
|
7
|
+
|
|
8
|
+
export type SelectedTreeItem = {
|
|
9
|
+
indexes: number[];
|
|
10
|
+
remove: () => void;
|
|
11
|
+
getData: () => any;
|
|
12
|
+
getParentData: () => any;
|
|
13
|
+
move: (item: SelectedTreeItem, position: string) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@Component({
|
|
17
|
+
selector: 'pg-tree',
|
|
18
|
+
style,
|
|
19
|
+
template
|
|
20
|
+
})
|
|
21
|
+
export default class PgTree extends HTMLElement {
|
|
22
|
+
@Prop() items: any[] = [];
|
|
23
|
+
|
|
24
|
+
@Part() $items: HTMLDivElement;
|
|
25
|
+
|
|
26
|
+
#selectedIndexes = new Map();
|
|
27
|
+
#lastSelectedIndexes: number[] | null = null;
|
|
28
|
+
#draggingElements: Set<HTMLElement> = new Set();
|
|
29
|
+
|
|
30
|
+
connectedCallback() {
|
|
31
|
+
forEach({
|
|
32
|
+
container: this.$items,
|
|
33
|
+
items: this.items,
|
|
34
|
+
type: () => PgTreeItem
|
|
35
|
+
});
|
|
36
|
+
this.$items.addEventListener('action', (e: any) => {
|
|
37
|
+
e.stopPropagation();
|
|
38
|
+
this.dispatchEvent(new CustomEvent('action', {
|
|
39
|
+
detail: {
|
|
40
|
+
actionIndex: e.detail.actionIndex,
|
|
41
|
+
item: this.#wrap(e.detail.indexes),
|
|
42
|
+
}
|
|
43
|
+
}));
|
|
44
|
+
});
|
|
45
|
+
this.$items.addEventListener('move', (e: any) => {
|
|
46
|
+
e.stopPropagation();
|
|
47
|
+
const selectedIdxsList = [...this.#selectedIndexes.values()] as number[][];
|
|
48
|
+
this.#batchMove(selectedIdxsList, e.detail.indexes, e.detail.position);
|
|
49
|
+
this.dispatchEvent(new CustomEvent('move', {
|
|
50
|
+
detail: { position: e.detail.position }
|
|
51
|
+
}));
|
|
52
|
+
this.dispatchEvent(new CustomEvent('select', {
|
|
53
|
+
detail: {
|
|
54
|
+
items: [...this.#selectedIndexes.values()].map((idxs: any) => this.#wrap(idxs)),
|
|
55
|
+
}
|
|
56
|
+
}));
|
|
57
|
+
});
|
|
58
|
+
this.$items.addEventListener('rename', (e: any) => {
|
|
59
|
+
e.stopPropagation();
|
|
60
|
+
this.dispatchEvent(new CustomEvent('rename', {
|
|
61
|
+
detail: {
|
|
62
|
+
item: this.#wrap(e.detail.indexes),
|
|
63
|
+
label: e.detail.label,
|
|
64
|
+
}
|
|
65
|
+
}));
|
|
66
|
+
});
|
|
67
|
+
this.$items.addEventListener('toggle', (e: any) => {
|
|
68
|
+
const item = this.#getItem(e.detail.indexes);
|
|
69
|
+
item.expanded = !item.expanded;
|
|
70
|
+
});
|
|
71
|
+
this.$items.addEventListener('expand', (e: any) => {
|
|
72
|
+
this.#getItem(e.detail.indexes).expanded = true;
|
|
73
|
+
});
|
|
74
|
+
this.$items.addEventListener('menu', (e: any) => {
|
|
75
|
+
e.stopPropagation();
|
|
76
|
+
this.dispatchEvent(new CustomEvent('menu', {
|
|
77
|
+
detail: {
|
|
78
|
+
item: this.#wrap(e.detail.indexes),
|
|
79
|
+
x: e.detail.x,
|
|
80
|
+
y: e.detail.y,
|
|
81
|
+
}
|
|
82
|
+
}));
|
|
83
|
+
});
|
|
84
|
+
this.$items.addEventListener('select', (e: any) => {
|
|
85
|
+
e.stopPropagation();
|
|
86
|
+
const { indexes, type, ctrlKey, shiftKey } = e.detail;
|
|
87
|
+
const item = this.#getItem(indexes);
|
|
88
|
+
const unproxyItem = getProxyValue(item);
|
|
89
|
+
|
|
90
|
+
if (shiftKey && this.#lastSelectedIndexes) {
|
|
91
|
+
const visible = this.#getVisibleIndexes();
|
|
92
|
+
const lastPos = visible.findIndex(v => v.join(',') === this.#lastSelectedIndexes!.join(','));
|
|
93
|
+
const currPos = visible.findIndex(v => v.join(',') === indexes.join(','));
|
|
94
|
+
this.#selectedIndexes.forEach((x: any) => this.#getItem(x).selected = false);
|
|
95
|
+
this.#selectedIndexes.clear();
|
|
96
|
+
const start = Math.min(lastPos, currPos);
|
|
97
|
+
const end = Math.max(lastPos, currPos);
|
|
98
|
+
for (let i = start; i <= end; i++) {
|
|
99
|
+
const rangeItem = this.#getItem(visible[i]);
|
|
100
|
+
rangeItem.selected = true;
|
|
101
|
+
this.#selectedIndexes.set(getProxyValue(rangeItem), visible[i]);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
if (!ctrlKey && this.#selectedIndexes.size && !this.#selectedIndexes.has(unproxyItem)) {
|
|
105
|
+
this.#selectedIndexes.forEach((x: any) => this.#getItem(x).selected = false);
|
|
106
|
+
this.#selectedIndexes.clear();
|
|
107
|
+
}
|
|
108
|
+
item.selected = type === 'rename' ? true : !item.selected;
|
|
109
|
+
if (item.selected) {
|
|
110
|
+
this.#selectedIndexes.set(unproxyItem, indexes);
|
|
111
|
+
this.#lastSelectedIndexes = indexes;
|
|
112
|
+
} else {
|
|
113
|
+
this.#selectedIndexes.delete(unproxyItem);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
this.dispatchEvent(new CustomEvent('select', {
|
|
118
|
+
detail: {
|
|
119
|
+
items: [...this.#selectedIndexes.values()].map((idxs: any) => this.#wrap(idxs)),
|
|
120
|
+
}
|
|
121
|
+
}));
|
|
122
|
+
});
|
|
123
|
+
this.$items.addEventListener('up', (e: any) => {
|
|
124
|
+
e.stopPropagation();
|
|
125
|
+
const visible = this.#getVisibleIndexes();
|
|
126
|
+
const idx = visible.findIndex(v => v.join(',') === e.detail.indexes.join(','));
|
|
127
|
+
if (idx > 0) {
|
|
128
|
+
this.#focusItem(visible[idx - 1]);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
this.$items.addEventListener('down', (e: any) => {
|
|
132
|
+
e.stopPropagation();
|
|
133
|
+
const visible = this.#getVisibleIndexes();
|
|
134
|
+
const idx = visible.findIndex(v => v.join(',') === e.detail.indexes.join(','));
|
|
135
|
+
if (idx < visible.length - 1) {
|
|
136
|
+
this.#focusItem(visible[idx + 1]);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
this.$items.addEventListener('keydown', (e: any) => {
|
|
140
|
+
if (e.key === 'Delete') {
|
|
141
|
+
const toRemove = [...this.#selectedIndexes.values()] as number[][];
|
|
142
|
+
// Remove higher sibling indexes first to avoid index shifts
|
|
143
|
+
toRemove.sort((a, b) => {
|
|
144
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
145
|
+
const ai = i < a.length ? a[i] : -1;
|
|
146
|
+
const bi = i < b.length ? b[i] : -1;
|
|
147
|
+
if (ai !== bi) return bi - ai;
|
|
148
|
+
}
|
|
149
|
+
return 0;
|
|
150
|
+
});
|
|
151
|
+
toRemove.forEach((indexes: number[]) => this.#removeItem(indexes));
|
|
152
|
+
this.#selectedIndexes.clear();
|
|
153
|
+
this.#lastSelectedIndexes = null;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
this.$items.addEventListener('itemdragstart', (e: any) => {
|
|
157
|
+
const { indexes, callback, ctrlKey } = e.detail;
|
|
158
|
+
const item = this.#getItem(indexes);
|
|
159
|
+
const unproxyItem = getProxyValue(item);
|
|
160
|
+
if (!ctrlKey && this.#selectedIndexes.size && !this.#selectedIndexes.has(unproxyItem)) {
|
|
161
|
+
this.#selectedIndexes.forEach((x: any) => this.#getItem(x).selected = false);
|
|
162
|
+
this.#selectedIndexes.clear();
|
|
163
|
+
}
|
|
164
|
+
item.selected = true;
|
|
165
|
+
this.#selectedIndexes.set(unproxyItem, indexes);
|
|
166
|
+
let count = 0;
|
|
167
|
+
this.#selectedIndexes.forEach((idxs: any) => {
|
|
168
|
+
count = this.#getDragCount(this.#getItem(idxs), count);
|
|
169
|
+
});
|
|
170
|
+
callback(count);
|
|
171
|
+
this.$items.classList.toggle('dragging', true);
|
|
172
|
+
// Sync selection to consumers so #selectedItems reflects the dragged item
|
|
173
|
+
this.dispatchEvent(new CustomEvent('select', {
|
|
174
|
+
detail: {
|
|
175
|
+
items: [...this.#selectedIndexes.values()].map((idxs: any) => this.#wrap(idxs)),
|
|
176
|
+
}
|
|
177
|
+
}));
|
|
178
|
+
});
|
|
179
|
+
this.$items.addEventListener('itemdragend', () => {
|
|
180
|
+
this.$items.classList.toggle('dragging', false);
|
|
181
|
+
this.#clearDropHighlights(this.$items);
|
|
182
|
+
});
|
|
183
|
+
this.$items.addEventListener('itemdropenter', this.#handleDropEnter.bind(this));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
#getDragCount(item: any, count: number): number {
|
|
187
|
+
count += 1;
|
|
188
|
+
if (item.items?.length) {
|
|
189
|
+
item.items.forEach((itm: any) => {
|
|
190
|
+
count = this.#getDragCount(itm, count);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return count;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
#handleDropEnter(e: any) {
|
|
197
|
+
const { indexes, callback } = e.detail;
|
|
198
|
+
const excludes = this.#calculateDragExcludes();
|
|
199
|
+
const joined = indexes.join(',') as string;
|
|
200
|
+
// Use comma-terminated prefix to prevent "0,1" from matching "0,10"
|
|
201
|
+
const isInvalid = excludes.some(ex => joined === ex || joined.startsWith(ex + ','));
|
|
202
|
+
callback(!isInvalid);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
#removeItem(indexes: number[]) {
|
|
206
|
+
const deleteIndex = indexes[indexes.length - 1];
|
|
207
|
+
const parentIndexes = indexes.slice(0, indexes.length - 1);
|
|
208
|
+
const parent = parentIndexes.reduce((acc: any, i) => acc.items[i], this);
|
|
209
|
+
parent.items.splice(deleteIndex, 1);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
#getItem(indexes: number[]) {
|
|
213
|
+
return indexes.reduce((acc: any, i) => acc.items[i], this);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
#getItemElement(indexes: number[]): PgTreeItem | null {
|
|
217
|
+
let container: HTMLElement = this.$items;
|
|
218
|
+
let element: PgTreeItem | null = null;
|
|
219
|
+
for (const i of indexes) {
|
|
220
|
+
element = container.children[i] as PgTreeItem;
|
|
221
|
+
if (!element) return null;
|
|
222
|
+
container = (element as any).$items;
|
|
223
|
+
if (!container) return null;
|
|
224
|
+
}
|
|
225
|
+
return element;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
#focusItem(indexes: number[]) {
|
|
229
|
+
const element = this.#getItemElement(indexes);
|
|
230
|
+
if (element) {
|
|
231
|
+
(element as any).$labelButton.focus();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
#getVisibleIndexes(): number[][] {
|
|
236
|
+
const result: number[][] = [];
|
|
237
|
+
const traverse = (items: any[], prefix: number[]) => {
|
|
238
|
+
items.forEach((item: any, i: number) => {
|
|
239
|
+
const indexes = [...prefix, i];
|
|
240
|
+
result.push(indexes);
|
|
241
|
+
if (item.expanded && item.items?.length) {
|
|
242
|
+
traverse(item.items, indexes);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
traverse(this.items, []);
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
#clearDropHighlights(container: HTMLElement) {
|
|
251
|
+
Array.from(container.children).forEach((child: any) => {
|
|
252
|
+
if (child.$dropabove) {
|
|
253
|
+
child.$dropabove.classList.remove('drop');
|
|
254
|
+
child.$dropon.classList.remove('drop');
|
|
255
|
+
child.$dropbelow.classList.remove('drop');
|
|
256
|
+
}
|
|
257
|
+
if (child.$items) {
|
|
258
|
+
this.#clearDropHighlights(child.$items);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
#batchMove(selectedIdxsList: number[][], targetIdxs: number[], position: string) {
|
|
264
|
+
if (selectedIdxsList.length === 0) return;
|
|
265
|
+
|
|
266
|
+
// Ascending order preserves the original relative order of dragged items on insertion
|
|
267
|
+
const ascending = [...selectedIdxsList].sort((a, b) => {
|
|
268
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
269
|
+
const av = i < a.length ? a[i] : -1;
|
|
270
|
+
const bv = i < b.length ? b[i] : -1;
|
|
271
|
+
if (av !== bv) return av - bv;
|
|
272
|
+
}
|
|
273
|
+
return 0;
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Capture data references before any structural changes
|
|
277
|
+
const caches = ascending.map(idxs => this.#getItem(idxs));
|
|
278
|
+
|
|
279
|
+
// Count how many selected siblings precede the target — each one shifts its index down after removal
|
|
280
|
+
const targetParentStr = targetIdxs.slice(0, -1).join(',');
|
|
281
|
+
let targetShift = 0;
|
|
282
|
+
for (const sidxs of ascending) {
|
|
283
|
+
if (sidxs.slice(0, -1).join(',') === targetParentStr &&
|
|
284
|
+
sidxs[sidxs.length - 1] < targetIdxs[targetIdxs.length - 1]) {
|
|
285
|
+
targetShift++;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const adjustedTargetIdxs = [
|
|
289
|
+
...targetIdxs.slice(0, -1),
|
|
290
|
+
targetIdxs[targetIdxs.length - 1] - targetShift
|
|
291
|
+
];
|
|
292
|
+
|
|
293
|
+
// Remove descending so higher sibling indexes don't shift lower ones mid-loop
|
|
294
|
+
[...ascending].reverse().forEach(idxs => this.#removeItem(idxs));
|
|
295
|
+
|
|
296
|
+
// Rebuild selection map with post-move positions so items stay selected
|
|
297
|
+
this.#selectedIndexes.clear();
|
|
298
|
+
this.#lastSelectedIndexes = null;
|
|
299
|
+
|
|
300
|
+
if (position === 'on') {
|
|
301
|
+
const targetData = this.#getItem(adjustedTargetIdxs);
|
|
302
|
+
const prevLen = Array.isArray(targetData.items) ? targetData.items.length : 0;
|
|
303
|
+
if (!Array.isArray(targetData.items)) targetData.items = [];
|
|
304
|
+
caches.forEach((cache, i) => {
|
|
305
|
+
targetData.items.push(cache);
|
|
306
|
+
const newIdxs = [...adjustedTargetIdxs, prevLen + i];
|
|
307
|
+
this.#selectedIndexes.set(getProxyValue(this.#getItem(newIdxs)), newIdxs);
|
|
308
|
+
});
|
|
309
|
+
targetData.expanded = true;
|
|
310
|
+
} else {
|
|
311
|
+
const adjustedParent = adjustedTargetIdxs.slice(0, -1);
|
|
312
|
+
const adjustedIdx = adjustedTargetIdxs[adjustedTargetIdxs.length - 1];
|
|
313
|
+
const insertAt = position === 'after' ? adjustedIdx + 1 : adjustedIdx;
|
|
314
|
+
if (adjustedParent.length === 0) {
|
|
315
|
+
this.items.splice(insertAt, 0, ...caches);
|
|
316
|
+
} else {
|
|
317
|
+
this.#getItem(adjustedParent).items.splice(insertAt, 0, ...caches);
|
|
318
|
+
}
|
|
319
|
+
caches.forEach((_, i) => {
|
|
320
|
+
const newIdxs = [...adjustedParent, insertAt + i];
|
|
321
|
+
this.#selectedIndexes.set(getProxyValue(this.#getItem(newIdxs)), newIdxs);
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
this.$items.classList.toggle('dragging', false);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
#wrap(indexes: number[]): SelectedTreeItem {
|
|
329
|
+
return {
|
|
330
|
+
indexes,
|
|
331
|
+
remove: () => {
|
|
332
|
+
this.#removeItem(indexes);
|
|
333
|
+
this.#selectedIndexes.clear();
|
|
334
|
+
this.#lastSelectedIndexes = null;
|
|
335
|
+
},
|
|
336
|
+
getData: () => this.#getItem(indexes),
|
|
337
|
+
getParentData: () => {
|
|
338
|
+
const parent = indexes.slice(0, indexes.length - 1);
|
|
339
|
+
return parent.length === 0 ? this : this.#getItem(parent);
|
|
340
|
+
},
|
|
341
|
+
move: (item: SelectedTreeItem, position: string) => {
|
|
342
|
+
this.#batchMove([indexes], item.indexes, position);
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
unselect(indexes: number[]) {
|
|
348
|
+
const item = this.#getItem(indexes);
|
|
349
|
+
const unproxyItem = getProxyValue(item);
|
|
350
|
+
item.selected = false;
|
|
351
|
+
this.#selectedIndexes.delete(unproxyItem);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
#calculateDragExcludes(): string[] {
|
|
355
|
+
const exclude: string[] = [];
|
|
356
|
+
this.#selectedIndexes.forEach((indexes: number[]) => {
|
|
357
|
+
exclude.push(indexes.join(','));
|
|
358
|
+
});
|
|
359
|
+
return exclude;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
File without changes
|