@nemigo/svelte 2.10.1 → 2.10.3
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/dist/tree.d.ts +6 -0
- package/dist/tree.js +76 -42
- package/package.json +1 -1
package/dist/tree.d.ts
CHANGED
|
@@ -34,8 +34,14 @@ export declare abstract class SvelteTree<R extends TreeRecord, Item extends Tree
|
|
|
34
34
|
items: ISvelteState<Item[]>;
|
|
35
35
|
map: Map<string, Item>;
|
|
36
36
|
size: ISvelteState<number>;
|
|
37
|
+
root_parent_id: string | null;
|
|
38
|
+
constructor(root_parent_id?: string | null);
|
|
37
39
|
abstract toTreeItem(record: R): Item;
|
|
38
40
|
abstract sort(a: Item, b: Item): number;
|
|
41
|
+
/** true, если запись относится к нашему поддереву (корень или потомок) */
|
|
42
|
+
__inScope(record: R): boolean;
|
|
43
|
+
/** является ли этот parent_id "корнем" нашего поддерева */
|
|
44
|
+
__isRootParent(parent_id: string | null): boolean;
|
|
39
45
|
hooks: {
|
|
40
46
|
create: (record: R) => void;
|
|
41
47
|
update: (record: R, mods: any) => void;
|
package/dist/tree.js
CHANGED
|
@@ -5,8 +5,27 @@ export class SvelteTree extends Emitter {
|
|
|
5
5
|
items = createSvelteRawState([]);
|
|
6
6
|
map = new Map();
|
|
7
7
|
size = createSvelteRawState(0);
|
|
8
|
+
root_parent_id;
|
|
9
|
+
constructor(root_parent_id = null) {
|
|
10
|
+
super();
|
|
11
|
+
this.root_parent_id = root_parent_id;
|
|
12
|
+
}
|
|
13
|
+
/** true, если запись относится к нашему поддереву (корень или потомок) */
|
|
14
|
+
__inScope(record) {
|
|
15
|
+
// корневой уровень нашего поддерева
|
|
16
|
+
if (record.parent_id === this.root_parent_id)
|
|
17
|
+
return true;
|
|
18
|
+
// потомок — значит его родитель уже в map
|
|
19
|
+
return record.parent_id !== null && this.map.has(record.parent_id);
|
|
20
|
+
}
|
|
21
|
+
/** является ли этот parent_id "корнем" нашего поддерева */
|
|
22
|
+
__isRootParent(parent_id) {
|
|
23
|
+
return parent_id === this.root_parent_id;
|
|
24
|
+
}
|
|
8
25
|
hooks = {
|
|
9
26
|
create: (record) => {
|
|
27
|
+
if (!this.__inScope(record))
|
|
28
|
+
return;
|
|
10
29
|
const item = this.toTreeItem(record);
|
|
11
30
|
this.dispatch("before-create", item);
|
|
12
31
|
this.map.set(record.id, item);
|
|
@@ -18,40 +37,33 @@ export class SvelteTree extends Emitter {
|
|
|
18
37
|
},
|
|
19
38
|
update: (record, mods) => {
|
|
20
39
|
const item = this.map.get(record.id);
|
|
21
|
-
|
|
40
|
+
const current = item?.record.signal;
|
|
41
|
+
const preview = { ...(current ?? record), ...mods };
|
|
42
|
+
if (!item) {
|
|
43
|
+
if (this.__inScope(preview))
|
|
44
|
+
this.hooks.create(preview);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const prev_parent_id = current.parent_id;
|
|
48
|
+
const next_parent_id = preview.parent_id;
|
|
49
|
+
const isParentChange = prev_parent_id !== next_parent_id;
|
|
50
|
+
if (isParentChange && !this.__inScope(preview)) {
|
|
51
|
+
this.hooks.delete(record.id);
|
|
22
52
|
return;
|
|
23
|
-
|
|
24
|
-
if (isDataEqual(
|
|
53
|
+
}
|
|
54
|
+
if (!isParentChange && isDataEqual(current, preview))
|
|
25
55
|
return;
|
|
26
|
-
const prev_parent_id = record.parent_id;
|
|
27
|
-
const mod_parent_id = mods.parent_id;
|
|
28
|
-
const isParentChange = mod_parent_id !== undefined && mod_parent_id !== prev_parent_id;
|
|
29
56
|
if (isParentChange) {
|
|
30
|
-
this.dispatch("before-parent-update", {
|
|
31
|
-
|
|
32
|
-
item,
|
|
33
|
-
preview,
|
|
34
|
-
mods,
|
|
35
|
-
});
|
|
36
|
-
this.__parent(item, (items) => {
|
|
37
|
-
this.__delete(items, item);
|
|
38
|
-
});
|
|
57
|
+
this.dispatch("before-parent-update", { prev: prev_parent_id, item, preview, mods });
|
|
58
|
+
this.__parent(item, (items) => this.__delete(items, item));
|
|
39
59
|
item.record.signal = preview;
|
|
40
|
-
this.__parent(item, (items) =>
|
|
41
|
-
|
|
42
|
-
});
|
|
43
|
-
this.dispatch("after-parent-update", {
|
|
44
|
-
prev: prev_parent_id,
|
|
45
|
-
item,
|
|
46
|
-
mods,
|
|
47
|
-
});
|
|
60
|
+
this.__parent(item, (items) => this.__push(items, item));
|
|
61
|
+
this.dispatch("after-parent-update", { prev: prev_parent_id, item, mods });
|
|
48
62
|
}
|
|
49
63
|
else {
|
|
50
64
|
this.dispatch("before-update", item);
|
|
51
65
|
item.record.signal = preview;
|
|
52
|
-
this.__parent(item, (items) =>
|
|
53
|
-
this.__sort(items);
|
|
54
|
-
});
|
|
66
|
+
this.__parent(item, (items) => this.__sort(items));
|
|
55
67
|
this.dispatch("after-update", item);
|
|
56
68
|
}
|
|
57
69
|
this.size.signal = this.map.size;
|
|
@@ -77,15 +89,15 @@ export class SvelteTree extends Emitter {
|
|
|
77
89
|
},
|
|
78
90
|
};
|
|
79
91
|
__sort(items) {
|
|
80
|
-
items.signal = items.signal.toSorted((a, b) => this.sort(a, b));
|
|
92
|
+
items.signal = items.signal.toSorted((a, b) => this.sort(a, b));
|
|
81
93
|
}
|
|
82
94
|
__push(items, item) {
|
|
83
95
|
items.signal.push(item);
|
|
84
|
-
this.__sort(items);
|
|
96
|
+
this.__sort(items);
|
|
85
97
|
}
|
|
86
98
|
__splice(items, idx) {
|
|
87
99
|
items.signal.splice(idx, 1);
|
|
88
|
-
items.signal = items.signal.slice();
|
|
100
|
+
items.signal = items.signal.slice();
|
|
89
101
|
}
|
|
90
102
|
__delete(items, item) {
|
|
91
103
|
const idx = items.signal.indexOf(item);
|
|
@@ -94,14 +106,14 @@ export class SvelteTree extends Emitter {
|
|
|
94
106
|
}
|
|
95
107
|
__parent(item, call) {
|
|
96
108
|
const parent_id = item.record.signal.parent_id;
|
|
97
|
-
if (parent_id) {
|
|
109
|
+
if (this.__isRootParent(parent_id)) {
|
|
110
|
+
call(this.items);
|
|
111
|
+
}
|
|
112
|
+
else if (parent_id) {
|
|
98
113
|
const parent = this.map.get(parent_id);
|
|
99
114
|
if (parent)
|
|
100
115
|
call(parent.child);
|
|
101
116
|
}
|
|
102
|
-
else {
|
|
103
|
-
call(this.items);
|
|
104
|
-
}
|
|
105
117
|
}
|
|
106
118
|
clear() {
|
|
107
119
|
this.items.signal = [];
|
|
@@ -109,20 +121,42 @@ export class SvelteTree extends Emitter {
|
|
|
109
121
|
this.size.signal = 0;
|
|
110
122
|
}
|
|
111
123
|
__build(records) {
|
|
112
|
-
//
|
|
124
|
+
// 1. индексируем все записи, чтобы корректно определять принадлежность к поддереву
|
|
125
|
+
const byId = new Map();
|
|
113
126
|
for (const r of records)
|
|
127
|
+
byId.set(r.id, r);
|
|
128
|
+
// определяем, входит ли запись в наше поддерево (поднимаемся до корня)
|
|
129
|
+
const inScope = (r) => {
|
|
130
|
+
let cur = r;
|
|
131
|
+
const seen = new Set();
|
|
132
|
+
while (cur) {
|
|
133
|
+
if (cur.parent_id === this.root_parent_id)
|
|
134
|
+
return true;
|
|
135
|
+
if (cur.parent_id === null)
|
|
136
|
+
return false;
|
|
137
|
+
if (seen.has(cur.id))
|
|
138
|
+
return false; // защита от циклов
|
|
139
|
+
seen.add(cur.id);
|
|
140
|
+
cur = byId.get(cur.parent_id);
|
|
141
|
+
}
|
|
142
|
+
return false;
|
|
143
|
+
};
|
|
144
|
+
const scoped = records.filter(inScope);
|
|
145
|
+
// 2. создаём элементы
|
|
146
|
+
for (const r of scoped)
|
|
114
147
|
this.map.set(r.id, this.toTreeItem(r));
|
|
115
|
-
//
|
|
116
|
-
for (const r of
|
|
148
|
+
// 3. строим дерево
|
|
149
|
+
for (const r of scoped) {
|
|
117
150
|
const item = this.map.get(r.id);
|
|
118
|
-
|
|
119
|
-
if (parent_id)
|
|
120
|
-
this.map.get(parent_id)?.child.signal.push(item);
|
|
121
|
-
else
|
|
151
|
+
if (this.__isRootParent(r.parent_id)) {
|
|
122
152
|
this.items.signal.push(item);
|
|
153
|
+
}
|
|
154
|
+
else if (r.parent_id) {
|
|
155
|
+
this.map.get(r.parent_id)?.child.signal.push(item);
|
|
156
|
+
}
|
|
123
157
|
}
|
|
124
|
-
//
|
|
125
|
-
for (const r of
|
|
158
|
+
// 4. сортируем
|
|
159
|
+
for (const r of scoped) {
|
|
126
160
|
const item = this.map.get(r.id);
|
|
127
161
|
this.__sort(item.child);
|
|
128
162
|
}
|