@oscarpalmer/tabela 0.14.0 → 0.15.0
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/components/body.component.d.mts +11 -0
- package/dist/components/body.component.mjs +28 -0
- package/dist/components/column.component.d.mts +16 -0
- package/dist/components/column.component.mjs +46 -0
- package/dist/components/footer.component.d.mts +13 -0
- package/dist/components/{footer.component.js → footer.component.mjs} +9 -6
- package/dist/components/group.component.d.mts +20 -0
- package/dist/components/group.component.mjs +57 -0
- package/dist/components/header.component.d.mts +13 -0
- package/dist/components/header.component.mjs +25 -0
- package/dist/components/row.component.d.mts +15 -0
- package/dist/components/row.component.mjs +56 -0
- package/dist/helpers/dom.helpers.d.mts +12 -0
- package/dist/helpers/dom.helpers.mjs +43 -0
- package/dist/helpers/misc.helpers.d.mts +12 -0
- package/dist/helpers/misc.helpers.mjs +20 -0
- package/dist/helpers/style.helper.d.mts +6 -0
- package/dist/helpers/style.helper.mjs +8 -0
- package/dist/index.d.mts +7 -0
- package/dist/{index.js → index.mjs} +3 -1
- package/dist/managers/column.manager.d.mts +17 -0
- package/dist/managers/{column.manager.js → column.manager.mjs} +11 -6
- package/dist/managers/data.manager.d.mts +27 -0
- package/dist/managers/data.manager.mjs +256 -0
- package/dist/managers/event.manager.d.mts +18 -0
- package/dist/managers/event.manager.mjs +79 -0
- package/dist/managers/filter.manager.d.mts +18 -0
- package/dist/managers/filter.manager.mjs +115 -0
- package/dist/managers/group.manager.d.mts +27 -0
- package/dist/managers/group.manager.mjs +93 -0
- package/dist/managers/navigation.manager.d.mts +15 -0
- package/dist/managers/navigation.manager.mjs +80 -0
- package/dist/managers/render.manager.d.mts +19 -0
- package/dist/managers/render.manager.mjs +157 -0
- package/dist/managers/row.manager.d.mts +19 -0
- package/dist/managers/row.manager.mjs +45 -0
- package/dist/managers/selection.manager.d.mts +23 -0
- package/dist/managers/{selection.manager.js → selection.manager.mjs} +38 -31
- package/dist/managers/sort.manager.d.mts +23 -0
- package/dist/managers/sort.manager.mjs +147 -0
- package/dist/managers/style.manager.d.mts +9 -0
- package/dist/managers/style.manager.mjs +181 -0
- package/dist/models/body.model.d.mts +7 -0
- package/dist/models/body.model.mjs +1 -0
- package/dist/models/column.model.d.mts +13 -0
- package/dist/models/column.model.mjs +1 -0
- package/dist/models/data.model.d.mts +28 -0
- package/dist/models/data.model.mjs +1 -0
- package/dist/models/dom.model.d.mts +19 -0
- package/dist/models/dom.model.mjs +19 -0
- package/dist/models/event.model.d.mts +99 -0
- package/dist/models/event.model.mjs +53 -0
- package/dist/models/filter.model.d.mts +26 -0
- package/dist/models/filter.model.mjs +13 -0
- package/dist/models/footer.model.d.mts +8 -0
- package/dist/models/footer.model.mjs +1 -0
- package/dist/models/group.model.d.mts +19 -0
- package/dist/models/group.model.mjs +5 -0
- package/dist/models/header.model.d.mts +7 -0
- package/dist/models/header.model.mjs +1 -0
- package/dist/models/render.model.d.mts +22 -0
- package/dist/models/render.model.mjs +1 -0
- package/dist/models/selection.model.d.mts +12 -0
- package/dist/models/selection.model.mjs +1 -0
- package/dist/models/sort.model.d.mts +19 -0
- package/dist/models/sort.model.mjs +5 -0
- package/dist/models/style.model.d.mts +29 -0
- package/dist/models/style.model.mjs +29 -0
- package/dist/models/tabela.model.d.mts +46 -0
- package/dist/models/tabela.model.mjs +1 -0
- package/dist/models/tabela.options.d.mts +14 -0
- package/dist/models/tabela.options.mjs +1 -0
- package/dist/tabela.d.mts +22 -0
- package/dist/{tabela.full.js → tabela.full.mjs} +1501 -803
- package/dist/tabela.mjs +126 -0
- package/package.json +2 -4
- package/src/components/column.component.ts +4 -4
- package/src/components/group.component.ts +6 -2
- package/src/components/row.component.ts +5 -5
- package/src/helpers/misc.helpers.ts +13 -1
- package/src/managers/column.manager.ts +9 -9
- package/src/managers/data.manager.ts +139 -53
- package/src/managers/event.manager.ts +52 -6
- package/src/managers/filter.manager.ts +36 -20
- package/src/managers/group.manager.ts +43 -10
- package/src/managers/render.manager.ts +30 -17
- package/src/managers/sort.manager.ts +81 -52
- package/src/managers/style.manager.ts +33 -0
- package/src/models/column.model.ts +2 -2
- package/src/models/data.model.ts +6 -6
- package/src/models/dom.model.ts +0 -2
- package/src/models/event.model.ts +168 -0
- package/src/models/filter.model.ts +2 -2
- package/src/models/group.model.ts +9 -0
- package/src/models/render.model.ts +6 -0
- package/src/models/sort.model.ts +7 -5
- package/src/tabela.ts +6 -2
- package/dist/components/body.component.js +0 -23
- package/dist/components/column.component.js +0 -41
- package/dist/components/group.component.js +0 -28
- package/dist/components/header.component.js +0 -22
- package/dist/components/row.component.js +0 -48
- package/dist/helpers/dom.helpers.js +0 -38
- package/dist/helpers/misc.helpers.js +0 -7
- package/dist/helpers/style.helper.js +0 -6
- package/dist/managers/data.manager.js +0 -181
- package/dist/managers/event.manager.js +0 -53
- package/dist/managers/filter.manager.js +0 -98
- package/dist/managers/group.manager.js +0 -46
- package/dist/managers/navigation.manager.js +0 -73
- package/dist/managers/render.manager.js +0 -135
- package/dist/managers/row.manager.js +0 -38
- package/dist/managers/sort.manager.js +0 -122
- package/dist/models/body.model.js +0 -0
- package/dist/models/column.model.js +0 -0
- package/dist/models/data.model.js +0 -0
- package/dist/models/filter.model.js +0 -0
- package/dist/models/footer.model.js +0 -0
- package/dist/models/group.model.js +0 -0
- package/dist/models/header.model.js +0 -0
- package/dist/models/render.model.js +0 -0
- package/dist/models/selection.model.js +0 -0
- package/dist/models/sort.model.js +0 -0
- package/dist/models/tabela.model.js +0 -0
- package/dist/models/tabela.options.js +0 -0
- package/dist/tabela.js +0 -105
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { EVENT_DATA_ADD, EVENT_DATA_CLEAR, EVENT_DATA_REMOVE, EVENT_DATA_SYNCHRONIZE, EVENT_DATA_UPDATE, EVENT_GROUP_ADD, EVENT_GROUP_REMOVE, EVENT_GROUP_UPDATE } from "../models/event.model.mjs";
|
|
2
|
+
import { GroupComponent, updateGroup } from "../components/group.component.mjs";
|
|
3
|
+
import { getGroup, isGroupKey } from "../helpers/misc.helpers.mjs";
|
|
4
|
+
import { SORT_ASCENDING } from "../models/sort.model.mjs";
|
|
5
|
+
import { sortWithGroups } from "./sort.manager.mjs";
|
|
6
|
+
import { chunk, select, sort } from "@oscarpalmer/atoms/array";
|
|
7
|
+
import { toMap } from "@oscarpalmer/atoms/array/to-map";
|
|
8
|
+
import { toRecord } from "@oscarpalmer/atoms/array/to-record";
|
|
9
|
+
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
10
|
+
import { delay } from "@oscarpalmer/atoms/promise/delay";
|
|
11
|
+
import { getValue } from "@oscarpalmer/atoms/value/handle";
|
|
12
|
+
//#region src/managers/data.manager.ts
|
|
13
|
+
var DataManager = class {
|
|
14
|
+
handlers = {
|
|
15
|
+
add: (data) => this.add(data, true),
|
|
16
|
+
clear: () => this.clear(),
|
|
17
|
+
get: (active) => this.get(active),
|
|
18
|
+
remove: (items) => this.remove(items, true),
|
|
19
|
+
synchronize: (data, remove) => this.synchronize(data, remove === true),
|
|
20
|
+
update: (data) => this.update(data, true)
|
|
21
|
+
};
|
|
22
|
+
state;
|
|
23
|
+
get keys() {
|
|
24
|
+
return this.state.keys.active ?? this.state.keys.original;
|
|
25
|
+
}
|
|
26
|
+
get size() {
|
|
27
|
+
return this.keys.length;
|
|
28
|
+
}
|
|
29
|
+
constructor(state) {
|
|
30
|
+
this.state = {
|
|
31
|
+
...state,
|
|
32
|
+
keys: { original: [] },
|
|
33
|
+
values: {
|
|
34
|
+
array: [],
|
|
35
|
+
mapped: /* @__PURE__ */ new Map()
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async add(data, render) {
|
|
40
|
+
const { state } = this;
|
|
41
|
+
const addedData = [];
|
|
42
|
+
const updatedData = [];
|
|
43
|
+
const addedGroups = [];
|
|
44
|
+
const updatedGroups = [];
|
|
45
|
+
let groupColumn;
|
|
46
|
+
let { length } = data;
|
|
47
|
+
for (let index = 0; index < length; index += 1) {
|
|
48
|
+
const item = data[index];
|
|
49
|
+
const key = getValue(item, state.key);
|
|
50
|
+
if (state.values.mapped.has(key)) {
|
|
51
|
+
updatedData.push(item);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
addedData.push(item);
|
|
55
|
+
state.values.array.push(item);
|
|
56
|
+
state.values.mapped.set(key, item);
|
|
57
|
+
if (!state.managers.group.enabled) continue;
|
|
58
|
+
const groupValue = getValue(item, state.managers.group.key);
|
|
59
|
+
let group = state.managers.group.getForValue(groupValue);
|
|
60
|
+
if (group == null) {
|
|
61
|
+
groupColumn ??= state.managers.column.get(state.managers.group.key);
|
|
62
|
+
group = new GroupComponent(`${groupColumn?.options.label ?? state.managers.group.key}: ${groupValue}`, groupValue);
|
|
63
|
+
state.values.array.push(group.key);
|
|
64
|
+
state.managers.group.add(group, false);
|
|
65
|
+
addedGroups.push(group);
|
|
66
|
+
} else if (!addedGroups.includes(group) && !updatedGroups.includes(group)) updatedGroups.push(group);
|
|
67
|
+
if (!group.expanded) state.managers.group.collapsed.add(key);
|
|
68
|
+
group.total += 1;
|
|
69
|
+
}
|
|
70
|
+
length = addedGroups.length;
|
|
71
|
+
if (length > 0) {
|
|
72
|
+
state.managers.event.emit(EVENT_GROUP_ADD, addedGroups.map(getGroup));
|
|
73
|
+
for (let index = 0; index < length; index += 1) updateGroup(state, addedGroups[index], false);
|
|
74
|
+
}
|
|
75
|
+
length = updatedGroups.length;
|
|
76
|
+
if (length > 0) {
|
|
77
|
+
for (let index = 0; index < length; index += 1) updateGroup(state, updatedGroups[index], false);
|
|
78
|
+
state.managers.event.emit(EVENT_GROUP_UPDATE, updatedGroups.map(getGroup));
|
|
79
|
+
}
|
|
80
|
+
await this.update(updatedData, addedData.length === 0);
|
|
81
|
+
if (addedData.length === 0) return;
|
|
82
|
+
state.managers.event.emit(EVENT_DATA_ADD, addedData);
|
|
83
|
+
if (render) this.render();
|
|
84
|
+
}
|
|
85
|
+
async clear() {
|
|
86
|
+
if (this.state.values.array.length > 0) return this.removeItems([], true, true).then(() => void 0);
|
|
87
|
+
}
|
|
88
|
+
destroy() {
|
|
89
|
+
const { state } = this;
|
|
90
|
+
state.values.mapped.clear();
|
|
91
|
+
state.keys.active = void 0;
|
|
92
|
+
state.keys.original.length = 0;
|
|
93
|
+
state.values.array.length = 0;
|
|
94
|
+
this.handlers = void 0;
|
|
95
|
+
this.state = void 0;
|
|
96
|
+
}
|
|
97
|
+
get(active) {
|
|
98
|
+
const { state } = this;
|
|
99
|
+
return (active ?? false) && state.keys.active != null ? select(state.keys.active, (key) => !isGroupKey(key), (key) => state.values.mapped.get(key)) : state.values.array.filter((item) => !isGroupKey(item));
|
|
100
|
+
}
|
|
101
|
+
getIndex(item) {
|
|
102
|
+
return this.keys.indexOf(item);
|
|
103
|
+
}
|
|
104
|
+
async remove(items, render) {
|
|
105
|
+
const { state } = this;
|
|
106
|
+
const keys = items.map((value) => isPlainObject(value) ? getValue(value, state.key) : value).filter((key) => !isGroupKey(key));
|
|
107
|
+
const { length } = keys;
|
|
108
|
+
return length === 0 ? render ? void 0 : [] : this.removeItems(keys, false, render);
|
|
109
|
+
}
|
|
110
|
+
async removeItems(keys, clear, render) {
|
|
111
|
+
const { state } = this;
|
|
112
|
+
if (clear) {
|
|
113
|
+
state.keys.active = void 0;
|
|
114
|
+
state.keys.original = [];
|
|
115
|
+
state.values.array = [];
|
|
116
|
+
state.values.mapped.clear();
|
|
117
|
+
state.managers.row.clear();
|
|
118
|
+
if (state.managers.group.enabled) state.managers.group.clear();
|
|
119
|
+
state.managers.event.emit(EVENT_DATA_CLEAR);
|
|
120
|
+
this.render();
|
|
121
|
+
return render ? void 0 : [];
|
|
122
|
+
}
|
|
123
|
+
const removedGroups = [];
|
|
124
|
+
const updatedGroups = [];
|
|
125
|
+
const removedData = [];
|
|
126
|
+
const chunked = chunk(keys);
|
|
127
|
+
const chunkedLength = chunked.length;
|
|
128
|
+
for (let chunkedIndex = 0; chunkedIndex < chunkedLength; chunkedIndex += 1) {
|
|
129
|
+
const chunk = chunked[chunkedIndex];
|
|
130
|
+
const chunkLength = chunk.length;
|
|
131
|
+
for (let keyIndex = 0; keyIndex < chunkLength; keyIndex += 1) {
|
|
132
|
+
const key = chunk[keyIndex];
|
|
133
|
+
const dataIndex = state.keys.original.indexOf(key);
|
|
134
|
+
let dataValue;
|
|
135
|
+
[dataValue] = state.values.array.splice(dataIndex, 1);
|
|
136
|
+
removedData.push(dataValue);
|
|
137
|
+
state.keys.original.splice(dataIndex, 1);
|
|
138
|
+
state.managers.row.remove(key);
|
|
139
|
+
state.values.mapped.delete(key);
|
|
140
|
+
if (!state.managers.group.enabled || isGroupKey(key)) continue;
|
|
141
|
+
state.managers.group.collapsed.delete(key);
|
|
142
|
+
const groupValue = getValue(dataValue, state.managers.group.key);
|
|
143
|
+
const group = state.managers.group.getForValue(groupValue);
|
|
144
|
+
if (group == null) continue;
|
|
145
|
+
group.total -= 1;
|
|
146
|
+
if (group.total > 0) {
|
|
147
|
+
updatedGroups.push(group);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
let groupIndex = updatedGroups.indexOf(group);
|
|
151
|
+
if (groupIndex > -1) updatedGroups.splice(groupIndex, 1);
|
|
152
|
+
groupIndex = state.values.array.indexOf(group.key);
|
|
153
|
+
if (groupIndex > -1) {
|
|
154
|
+
state.keys.original.splice(groupIndex, 1);
|
|
155
|
+
state.values.array.splice(groupIndex, 1);
|
|
156
|
+
}
|
|
157
|
+
removedGroups.push(group);
|
|
158
|
+
state.managers.group.remove(group, false);
|
|
159
|
+
if (keys.length >= 1e4) await delay(25);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
let { length } = updatedGroups;
|
|
163
|
+
if (length > 0) {
|
|
164
|
+
for (let index = 0; index < length; index += 1) updateGroup(state, updatedGroups[index], false);
|
|
165
|
+
state.managers.event.emit(EVENT_GROUP_UPDATE, updatedGroups.map(getGroup));
|
|
166
|
+
}
|
|
167
|
+
length = removedGroups.length;
|
|
168
|
+
if (length > 0) state.managers.event.emit(EVENT_GROUP_REMOVE, removedGroups.map(getGroup));
|
|
169
|
+
state.managers.event.emit(EVENT_DATA_REMOVE, removedData);
|
|
170
|
+
if (render) this.render();
|
|
171
|
+
return render ? void 0 : removedData;
|
|
172
|
+
}
|
|
173
|
+
render() {
|
|
174
|
+
const { state } = this;
|
|
175
|
+
if (state.managers.group.enabled) sortWithGroups(state, state.values.array, [{
|
|
176
|
+
direction: SORT_ASCENDING,
|
|
177
|
+
key: state.key
|
|
178
|
+
}]);
|
|
179
|
+
else sort(state.values.array, [{
|
|
180
|
+
direction: SORT_ASCENDING,
|
|
181
|
+
key: state.key
|
|
182
|
+
}]);
|
|
183
|
+
state.keys.active = void 0;
|
|
184
|
+
state.keys.original = state.values.array.map((item) => typeof item === "string" ? item : getValue(item, state.key));
|
|
185
|
+
state.values.mapped = toMap(state.values.array.filter((item) => !isGroupKey(item)), (item) => getValue(item, state.key));
|
|
186
|
+
if (Object.keys(state.managers.filter.items).length > 0) state.managers.filter.filter();
|
|
187
|
+
else if (state.managers.sort.items.length > 0) state.managers.sort.sort();
|
|
188
|
+
else state.managers.render.update(true, true);
|
|
189
|
+
}
|
|
190
|
+
set(data) {
|
|
191
|
+
const { state } = this;
|
|
192
|
+
const array = data.slice();
|
|
193
|
+
if (state.managers.group.enabled) {
|
|
194
|
+
const column = state.managers.column.get(state.managers.group.key);
|
|
195
|
+
const grouped = toRecord.arrays(data, state.managers.group.key);
|
|
196
|
+
const entries = Object.entries(grouped);
|
|
197
|
+
const { length } = entries;
|
|
198
|
+
const groups = [];
|
|
199
|
+
for (let index = 0; index < length; index += 1) {
|
|
200
|
+
const [value, items] = entries[index];
|
|
201
|
+
const group = new GroupComponent(`${column?.options.label ?? state.managers.group.key}: ${value}`, value);
|
|
202
|
+
group.total = items.length;
|
|
203
|
+
groups.push(group);
|
|
204
|
+
array.push(group.key);
|
|
205
|
+
}
|
|
206
|
+
state.managers.group.set(groups);
|
|
207
|
+
}
|
|
208
|
+
state.values.array = array;
|
|
209
|
+
this.render();
|
|
210
|
+
}
|
|
211
|
+
async synchronize(data, remove) {
|
|
212
|
+
const { state } = this;
|
|
213
|
+
const added = [];
|
|
214
|
+
const updated = [];
|
|
215
|
+
const keys = /* @__PURE__ */ new Set([]);
|
|
216
|
+
const { length } = data;
|
|
217
|
+
for (let index = 0; index < length; index += 1) {
|
|
218
|
+
const object = data[index];
|
|
219
|
+
const key = getValue(object, state.key);
|
|
220
|
+
if (state.values.mapped.has(key)) updated.push(object);
|
|
221
|
+
else added.push(object);
|
|
222
|
+
keys.add(key);
|
|
223
|
+
}
|
|
224
|
+
if (keys.size === 0) return;
|
|
225
|
+
let removed = [];
|
|
226
|
+
if (remove) {
|
|
227
|
+
const toRemove = state.keys.original.filter((key) => !isGroupKey(key) && !keys.has(key));
|
|
228
|
+
if (toRemove.length > 0) removed = await this.remove(toRemove, false);
|
|
229
|
+
}
|
|
230
|
+
await this.update(updated, added.length === 0);
|
|
231
|
+
await this.add(added, false);
|
|
232
|
+
state.managers.event.emit(EVENT_DATA_SYNCHRONIZE, {
|
|
233
|
+
added,
|
|
234
|
+
removed,
|
|
235
|
+
updated
|
|
236
|
+
});
|
|
237
|
+
if (added.length > 0 || remove) this.render();
|
|
238
|
+
}
|
|
239
|
+
async update(data, render) {
|
|
240
|
+
const { state } = this;
|
|
241
|
+
const { length } = data;
|
|
242
|
+
const updated = [];
|
|
243
|
+
for (let index = 0; index < length; index += 1) {
|
|
244
|
+
const item = data[index];
|
|
245
|
+
const key = getValue(item, state.key);
|
|
246
|
+
const existing = state.keys.original.indexOf(key);
|
|
247
|
+
if (existing === -1) continue;
|
|
248
|
+
Object.assign(state.values.array[existing], item);
|
|
249
|
+
updated.push(state.values.array[existing]);
|
|
250
|
+
if (render && state.managers.render.visible.keys.has(key)) state.managers.row.update(key);
|
|
251
|
+
}
|
|
252
|
+
if (updated.length > 0) state.managers.event.emit(EVENT_DATA_UPDATE, updated);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
//#endregion
|
|
256
|
+
export { DataManager };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { EventMap, EventName, Events, TabelaEvents } from "../models/event.model.mjs";
|
|
2
|
+
import { State } from "../models/tabela.model.mjs";
|
|
3
|
+
import { GenericCallback } from "@oscarpalmer/atoms/models";
|
|
4
|
+
|
|
5
|
+
//#region src/managers/event.manager.d.ts
|
|
6
|
+
declare class EventManager {
|
|
7
|
+
state: State;
|
|
8
|
+
events: Events;
|
|
9
|
+
handlers: TabelaEvents;
|
|
10
|
+
constructor(state: State);
|
|
11
|
+
emit<Name extends EventName>(name: Name, ...parameters: Parameters<EventMap[Name]>): void;
|
|
12
|
+
destroy(): void;
|
|
13
|
+
onSort(event: MouseEvent, target: HTMLElement): void;
|
|
14
|
+
subscribe(name: string, callback: GenericCallback): void;
|
|
15
|
+
unsubscribe(name: string, callback: GenericCallback): void;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { EventManager };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ATTRIBUTE_DATA_EVENT, ATTRIBUTE_DATA_KEY, ATTRIBUTE_DATA_SORT_DIRECTION } from "../models/dom.model.mjs";
|
|
2
|
+
import { CSS_TABLE } from "../models/style.model.mjs";
|
|
3
|
+
import { EVENT_GROUP, EVENT_HEADING } from "../models/event.model.mjs";
|
|
4
|
+
import { isEvent } from "../helpers/misc.helpers.mjs";
|
|
5
|
+
import { on } from "@oscarpalmer/toretto/event";
|
|
6
|
+
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
7
|
+
//#region src/managers/event.manager.ts
|
|
8
|
+
var EventManager = class {
|
|
9
|
+
events = {};
|
|
10
|
+
handlers = {
|
|
11
|
+
subscribe: (name, callback) => this.subscribe(name, callback),
|
|
12
|
+
unsubscribe: (name, callback) => this.unsubscribe(name, callback)
|
|
13
|
+
};
|
|
14
|
+
constructor(state) {
|
|
15
|
+
this.state = state;
|
|
16
|
+
mapped.set(state.element, this);
|
|
17
|
+
}
|
|
18
|
+
emit(name, ...parameters) {
|
|
19
|
+
if (this.events[name] == null) return;
|
|
20
|
+
const handlers = [...this.events[name]];
|
|
21
|
+
const { length } = handlers;
|
|
22
|
+
for (let index = 0; index < length; index += 1) handlers[index](...parameters);
|
|
23
|
+
}
|
|
24
|
+
destroy() {
|
|
25
|
+
mapped.delete(this.state.element);
|
|
26
|
+
this.state = void 0;
|
|
27
|
+
}
|
|
28
|
+
onSort(event, target) {
|
|
29
|
+
const direction = target.getAttribute(ATTRIBUTE_DATA_SORT_DIRECTION);
|
|
30
|
+
const key = target.getAttribute(ATTRIBUTE_DATA_KEY);
|
|
31
|
+
if (key != null) this.state.managers.sort.toggle(event, key, direction);
|
|
32
|
+
}
|
|
33
|
+
subscribe(name, callback) {
|
|
34
|
+
if (!isEvent(name) || typeof callback !== "function") return;
|
|
35
|
+
this.events[name] ??= /* @__PURE__ */ new Set();
|
|
36
|
+
this.events[name].add(callback);
|
|
37
|
+
}
|
|
38
|
+
unsubscribe(name, callback) {
|
|
39
|
+
if (isEvent(name) && typeof callback === "function") this.events[name]?.delete(callback);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
function onClick(event) {
|
|
43
|
+
const target = findAncestor(event, eventAttribute);
|
|
44
|
+
const table = findAncestor(event, tableClassName);
|
|
45
|
+
if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
|
|
46
|
+
const manager = mapped.get(table);
|
|
47
|
+
if (manager == null) return;
|
|
48
|
+
switch (target?.getAttribute(ATTRIBUTE_DATA_EVENT)) {
|
|
49
|
+
case EVENT_GROUP:
|
|
50
|
+
manager.state.managers.group.handle(target);
|
|
51
|
+
break;
|
|
52
|
+
case EVENT_HEADING:
|
|
53
|
+
manager.onSort(event, target);
|
|
54
|
+
break;
|
|
55
|
+
case "row":
|
|
56
|
+
manager.state.managers.selection.handle(event, target);
|
|
57
|
+
break;
|
|
58
|
+
default: break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function onKeydown(event) {
|
|
62
|
+
const target = findAncestor(event, eventAttribute);
|
|
63
|
+
const table = findAncestor(event, tableClassName);
|
|
64
|
+
if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
|
|
65
|
+
const manager = mapped.get(table);
|
|
66
|
+
if (manager == null) return;
|
|
67
|
+
if (event.key === " ") {
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
manager.state.managers.navigation.handle(event);
|
|
72
|
+
}
|
|
73
|
+
const eventAttribute = `[${ATTRIBUTE_DATA_EVENT}]`;
|
|
74
|
+
const mapped = /* @__PURE__ */ new WeakMap();
|
|
75
|
+
const tableClassName = `.${CSS_TABLE}`;
|
|
76
|
+
on(document, "click", onClick);
|
|
77
|
+
on(document, "keydown", onKeydown, { passive: false });
|
|
78
|
+
//#endregion
|
|
79
|
+
export { EventManager };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { TabelaFilter, TabelaFilterItem } from "../models/filter.model.mjs";
|
|
2
|
+
import { State } from "../models/tabela.model.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/managers/filter.manager.d.ts
|
|
5
|
+
declare class FilterManager {
|
|
6
|
+
state: State;
|
|
7
|
+
handlers: TabelaFilter;
|
|
8
|
+
items: Record<string, TabelaFilterItem[]>;
|
|
9
|
+
constructor(state: State);
|
|
10
|
+
add(item: TabelaFilterItem): void;
|
|
11
|
+
clear(): void;
|
|
12
|
+
destroy(): void;
|
|
13
|
+
filter(): void;
|
|
14
|
+
remove(value: string | TabelaFilterItem): void;
|
|
15
|
+
set(items: TabelaFilterItem[]): void;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { FilterManager };
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { isGroupKey } from "../helpers/misc.helpers.mjs";
|
|
2
|
+
import { FILTER_CONTAINS, FILTER_ENDS_WITH, FILTER_EQUALS, FILTER_GREATER_THAN, FILTER_GREATER_THAN_OR_EQUAL, FILTER_LESS_THAN, FILTER_LESS_THAN_OR_EQUAL, FILTER_NOT_CONTAINS, FILTER_NOT_EQUALS, FILTER_STARTS_WITH } from "../models/filter.model.mjs";
|
|
3
|
+
import { getString } from "@oscarpalmer/atoms/string";
|
|
4
|
+
import { getNumber } from "@oscarpalmer/atoms/number";
|
|
5
|
+
import { endsWith, includes, startsWith } from "@oscarpalmer/atoms/string/match";
|
|
6
|
+
import { equal } from "@oscarpalmer/atoms/value/equal";
|
|
7
|
+
//#region src/managers/filter.manager.ts
|
|
8
|
+
var FilterManager = class {
|
|
9
|
+
handlers = {
|
|
10
|
+
add: (item) => this.add(item),
|
|
11
|
+
clear: () => this.clear(),
|
|
12
|
+
remove: (value) => this.remove(value),
|
|
13
|
+
set: (items) => this.set(items)
|
|
14
|
+
};
|
|
15
|
+
items = {};
|
|
16
|
+
constructor(state) {
|
|
17
|
+
this.state = state;
|
|
18
|
+
}
|
|
19
|
+
add(item) {
|
|
20
|
+
const { items, state } = this;
|
|
21
|
+
if (items[item.key] == null) items[item.key] = [];
|
|
22
|
+
else if (items[item.key].findIndex((existing) => equal(existing, item)) > -1) return;
|
|
23
|
+
items[item.key].push(item);
|
|
24
|
+
state.managers.event.emit("filter:add", [item]);
|
|
25
|
+
this.filter();
|
|
26
|
+
}
|
|
27
|
+
clear() {
|
|
28
|
+
if (Object.keys(this.items).length === 0) return;
|
|
29
|
+
this.items = {};
|
|
30
|
+
this.state.managers.event.emit("filter:clear");
|
|
31
|
+
this.filter();
|
|
32
|
+
}
|
|
33
|
+
destroy() {
|
|
34
|
+
this.handlers = void 0;
|
|
35
|
+
this.items = void 0;
|
|
36
|
+
this.state = void 0;
|
|
37
|
+
}
|
|
38
|
+
filter() {
|
|
39
|
+
const { state } = this;
|
|
40
|
+
const filtered = [];
|
|
41
|
+
const filters = Object.entries(this.items);
|
|
42
|
+
const itemsLength = state.managers.data.state.keys.original.length;
|
|
43
|
+
rowLoop: for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
|
|
44
|
+
const item = state.managers.data.state.keys.original[itemIndex];
|
|
45
|
+
if (isGroupKey(item)) {
|
|
46
|
+
filtered.push(item);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const row = state.managers.data.state.values.mapped.get(item);
|
|
50
|
+
if (row == null) continue;
|
|
51
|
+
filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
|
|
52
|
+
const [key, items] = filters[filterIndex];
|
|
53
|
+
const value = row[key];
|
|
54
|
+
for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
|
|
55
|
+
const filter = items[itemIndex];
|
|
56
|
+
if (comparators[filter.comparison](value, filter.value)) continue filterLoop;
|
|
57
|
+
}
|
|
58
|
+
continue rowLoop;
|
|
59
|
+
}
|
|
60
|
+
filtered.push(item);
|
|
61
|
+
}
|
|
62
|
+
state.managers.data.state.keys.active = filtered;
|
|
63
|
+
if (state.managers.sort.items.length > 0) state.managers.sort.sort();
|
|
64
|
+
else state.managers.render.update(true, true);
|
|
65
|
+
}
|
|
66
|
+
remove(value) {
|
|
67
|
+
const removed = [];
|
|
68
|
+
if (typeof value === "string") {
|
|
69
|
+
if (this.items[value] == null) return;
|
|
70
|
+
const keyed = {};
|
|
71
|
+
const keys = Object.keys(this.items);
|
|
72
|
+
const { length } = keys;
|
|
73
|
+
for (let index = 0; index < length; index += 1) {
|
|
74
|
+
const key = keys[index];
|
|
75
|
+
if (key === value) removed.push(...this.items[key]);
|
|
76
|
+
else keyed[key] = this.items[key];
|
|
77
|
+
}
|
|
78
|
+
this.items = keyed;
|
|
79
|
+
} else {
|
|
80
|
+
const { key } = value;
|
|
81
|
+
if (this.items[key] == null) return;
|
|
82
|
+
const index = this.items[key].findIndex((item) => equal(item, value));
|
|
83
|
+
if (index === -1) return;
|
|
84
|
+
removed.push(this.items[key][index]);
|
|
85
|
+
}
|
|
86
|
+
this.state.managers.event.emit("filter:remove", removed);
|
|
87
|
+
this.filter();
|
|
88
|
+
}
|
|
89
|
+
set(items) {
|
|
90
|
+
const keyed = {};
|
|
91
|
+
const { length } = items;
|
|
92
|
+
for (let index = 0; index < length; index += 1) {
|
|
93
|
+
const item = items[index];
|
|
94
|
+
keyed[item.key] ??= [];
|
|
95
|
+
keyed[item.key].push(item);
|
|
96
|
+
}
|
|
97
|
+
this.items = keyed;
|
|
98
|
+
this.filter();
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const comparators = {
|
|
102
|
+
[FILTER_CONTAINS]: (row, filter) => includes(getString(row), getString(filter), true),
|
|
103
|
+
[FILTER_ENDS_WITH]: (row, filter) => endsWith(getString(row), getString(filter), true),
|
|
104
|
+
[FILTER_EQUALS]: (row, filter) => equalizer(row, filter),
|
|
105
|
+
[FILTER_GREATER_THAN]: (row, filter) => getNumber(row) > getNumber(filter),
|
|
106
|
+
[FILTER_GREATER_THAN_OR_EQUAL]: (row, filter) => getNumber(row) >= getNumber(filter),
|
|
107
|
+
[FILTER_LESS_THAN]: (row, filter) => getNumber(row) < getNumber(filter),
|
|
108
|
+
[FILTER_LESS_THAN_OR_EQUAL]: (row, filter) => getNumber(row) <= getNumber(filter),
|
|
109
|
+
[FILTER_NOT_CONTAINS]: (row, filter) => !includes(getString(row), getString(filter), true),
|
|
110
|
+
[FILTER_NOT_EQUALS]: (row, filter) => !equalizer(row, filter),
|
|
111
|
+
[FILTER_STARTS_WITH]: (row, filter) => startsWith(getString(row), getString(filter), true)
|
|
112
|
+
};
|
|
113
|
+
const equalizer = equal.initialize({ ignoreCase: true });
|
|
114
|
+
//#endregion
|
|
115
|
+
export { FilterManager };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TabelaGroupHandlers } from "../models/group.model.mjs";
|
|
2
|
+
import { GroupComponent } from "../components/group.component.mjs";
|
|
3
|
+
import { State } from "../models/tabela.model.mjs";
|
|
4
|
+
import { Key } from "@oscarpalmer/atoms/models";
|
|
5
|
+
|
|
6
|
+
//#region src/managers/group.manager.d.ts
|
|
7
|
+
declare class GroupManager {
|
|
8
|
+
state: State;
|
|
9
|
+
collapsed: Set<Key>;
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
key: string;
|
|
12
|
+
handlers: TabelaGroupHandlers;
|
|
13
|
+
items: GroupComponent[];
|
|
14
|
+
mapped: Map<string, GroupComponent>;
|
|
15
|
+
order: Record<never, number>;
|
|
16
|
+
constructor(state: State);
|
|
17
|
+
add(group: GroupComponent, emit: boolean): void;
|
|
18
|
+
clear(): void;
|
|
19
|
+
destroy(): void;
|
|
20
|
+
getForKey(key: string): GroupComponent | undefined;
|
|
21
|
+
getForValue(value: unknown): GroupComponent | undefined;
|
|
22
|
+
handle(button: HTMLElement): void;
|
|
23
|
+
remove(group: GroupComponent, update: boolean): void;
|
|
24
|
+
set(items: GroupComponent[]): void;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { GroupManager };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { EVENT_GROUP_ADD, EVENT_GROUP_CLEAR, EVENT_GROUP_REMOVE, EVENT_GROUP_TOGGLE } from "../models/event.model.mjs";
|
|
2
|
+
import { removeGroup } from "../components/group.component.mjs";
|
|
3
|
+
import { getGroup } from "../helpers/misc.helpers.mjs";
|
|
4
|
+
import { sort } from "@oscarpalmer/atoms/array";
|
|
5
|
+
import { toMap } from "@oscarpalmer/atoms/array/to-map";
|
|
6
|
+
import { toRecord } from "@oscarpalmer/atoms/array/to-record";
|
|
7
|
+
import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
|
|
8
|
+
import { getString } from "@oscarpalmer/atoms/string";
|
|
9
|
+
import { compare } from "@oscarpalmer/atoms/value/compare";
|
|
10
|
+
//#region src/managers/group.manager.ts
|
|
11
|
+
var GroupManager = class {
|
|
12
|
+
collapsed = /* @__PURE__ */ new Set();
|
|
13
|
+
enabled = false;
|
|
14
|
+
key;
|
|
15
|
+
handlers = { set: (group) => {
|
|
16
|
+
if (group === this.key) return;
|
|
17
|
+
this.enabled = !isNullableOrWhitespace(group);
|
|
18
|
+
this.key = group ?? "";
|
|
19
|
+
this.state.managers.data.set(this.state.managers.data.get());
|
|
20
|
+
} };
|
|
21
|
+
items = [];
|
|
22
|
+
mapped = /* @__PURE__ */ new Map();
|
|
23
|
+
order = {};
|
|
24
|
+
constructor(state) {
|
|
25
|
+
this.state = state;
|
|
26
|
+
if (isNullableOrWhitespace(state.options.grouping)) return;
|
|
27
|
+
this.enabled = true;
|
|
28
|
+
this.key = state.options.grouping;
|
|
29
|
+
}
|
|
30
|
+
add(group, emit) {
|
|
31
|
+
this.set([...this.items, group]);
|
|
32
|
+
if (emit) this.state.managers.event.emit(EVENT_GROUP_ADD, [getGroup(group)]);
|
|
33
|
+
}
|
|
34
|
+
clear() {
|
|
35
|
+
if (this.items.length === 0) return;
|
|
36
|
+
const groups = this.items.splice(0);
|
|
37
|
+
const { length } = groups;
|
|
38
|
+
for (let index = 0; index < length; index += 1) this.remove(groups[index], false);
|
|
39
|
+
this.collapsed.clear();
|
|
40
|
+
this.set([]);
|
|
41
|
+
this.state.managers.event.emit(EVENT_GROUP_CLEAR);
|
|
42
|
+
}
|
|
43
|
+
destroy() {
|
|
44
|
+
const groups = this.items.splice(0);
|
|
45
|
+
const { length } = groups;
|
|
46
|
+
for (let index = 0; index < length; index += 1) removeGroup(groups[index]);
|
|
47
|
+
this.collapsed.clear();
|
|
48
|
+
this.handlers = void 0;
|
|
49
|
+
this.state = void 0;
|
|
50
|
+
}
|
|
51
|
+
getForKey(key) {
|
|
52
|
+
return this.mapped.get(key);
|
|
53
|
+
}
|
|
54
|
+
getForValue(value) {
|
|
55
|
+
const asString = getString(value);
|
|
56
|
+
return this.items.find((item) => item.value.stringified === asString);
|
|
57
|
+
}
|
|
58
|
+
handle(button) {
|
|
59
|
+
const key = button.dataset.key?.replace(`${this.state.prefix}_`, "");
|
|
60
|
+
const group = this.getForKey(key ?? "");
|
|
61
|
+
if (group == null) return;
|
|
62
|
+
const { collapsed, items, state } = this;
|
|
63
|
+
group.expanded = !group.expanded;
|
|
64
|
+
const index = items.indexOf(group);
|
|
65
|
+
let first = state.managers.data.state.keys.original.indexOf(group.key) + 1;
|
|
66
|
+
const last = items[index + 1] == null ? state.managers.data.state.keys.original.length - 1 : state.managers.data.state.keys.original.indexOf(items[index + 1].key) - 1;
|
|
67
|
+
for (; first <= last; first += 1) {
|
|
68
|
+
const key = state.managers.data.state.keys.original[first];
|
|
69
|
+
if (group.expanded) collapsed.delete(key);
|
|
70
|
+
else collapsed.add(key);
|
|
71
|
+
}
|
|
72
|
+
state.managers.event.emit(EVENT_GROUP_TOGGLE, {
|
|
73
|
+
collapsed: group.expanded ? [] : [getGroup(group)],
|
|
74
|
+
expanded: group.expanded ? [getGroup(group)] : []
|
|
75
|
+
});
|
|
76
|
+
if (Object.keys(state.managers.filter.items).length > 0) state.managers.filter.filter();
|
|
77
|
+
else if (state.managers.sort.items.length > 0) state.managers.sort.sort();
|
|
78
|
+
else state.managers.render.update(true, true);
|
|
79
|
+
}
|
|
80
|
+
remove(group, update) {
|
|
81
|
+
removeGroup(group);
|
|
82
|
+
if (!update) return;
|
|
83
|
+
this.set(this.items.filter((item) => item !== group));
|
|
84
|
+
this.state.managers.event.emit(EVENT_GROUP_REMOVE, [getGroup(group)]);
|
|
85
|
+
}
|
|
86
|
+
set(items) {
|
|
87
|
+
this.items = sort(items, (first, second) => compare(first.label, second.label));
|
|
88
|
+
this.mapped = toMap(items, (group) => group.key);
|
|
89
|
+
this.order = toRecord(items, (group) => group.value.stringified, (_, index) => index);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
//#endregion
|
|
93
|
+
export { GroupManager };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { State } from "../models/tabela.model.mjs";
|
|
2
|
+
import { Key } from "@oscarpalmer/atoms/models";
|
|
3
|
+
|
|
4
|
+
//#region src/managers/navigation.manager.d.ts
|
|
5
|
+
declare class NavigationManager {
|
|
6
|
+
state: State;
|
|
7
|
+
active: Key | undefined;
|
|
8
|
+
constructor(state: State);
|
|
9
|
+
destroy(): void;
|
|
10
|
+
handle(event: KeyboardEvent): void;
|
|
11
|
+
setActive(item: Key | undefined, scroll?: boolean): void;
|
|
12
|
+
}
|
|
13
|
+
declare const attributeDataActiveTrue = "[data-active=\"true\"]";
|
|
14
|
+
//#endregion
|
|
15
|
+
export { NavigationManager, attributeDataActiveTrue };
|