@oscarpalmer/tabela 0.10.0 → 0.12.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.js +1 -0
- package/dist/components/column.component.js +4 -4
- package/dist/components/group.component.js +28 -0
- package/dist/components/row.component.js +11 -8
- package/dist/helpers/dom.helpers.js +1 -1
- package/dist/managers/column.manager.js +9 -8
- package/dist/managers/data.manager.js +95 -30
- package/dist/managers/event.manager.js +42 -23
- package/dist/managers/filter.manager.js +16 -10
- package/dist/managers/group.manager.js +46 -0
- package/dist/managers/navigation.manager.js +73 -0
- package/dist/managers/render.manager.js +61 -31
- package/dist/managers/row.manager.js +7 -7
- package/dist/managers/selection.manager.js +49 -46
- package/dist/managers/sort.manager.js +37 -9
- package/dist/models/group.model.js +0 -0
- package/dist/models/selection.model.js +0 -0
- package/dist/tabela.full.js +682 -591
- package/dist/tabela.js +31 -10
- package/package.json +1 -1
- package/src/components/body.component.ts +2 -0
- package/src/components/column.component.ts +6 -6
- package/src/components/group.component.ts +43 -0
- package/src/components/row.component.ts +14 -9
- package/src/helpers/dom.helpers.ts +3 -1
- package/src/managers/column.manager.ts +13 -15
- package/src/managers/data.manager.ts +176 -38
- package/src/managers/event.manager.ts +68 -41
- package/src/managers/filter.manager.ts +29 -20
- package/src/managers/group.manager.ts +79 -0
- package/src/managers/navigation.manager.ts +146 -0
- package/src/managers/render.manager.ts +84 -40
- package/src/managers/row.manager.ts +9 -14
- package/src/managers/selection.manager.ts +68 -67
- package/src/managers/sort.manager.ts +85 -22
- package/src/models/column.model.ts +2 -2
- package/src/models/data.model.ts +14 -3
- package/src/models/filter.model.ts +11 -3
- package/src/models/group.model.ts +4 -0
- package/src/models/render.model.ts +3 -1
- package/src/models/selection.model.ts +9 -0
- package/src/models/sort.model.ts +11 -3
- package/src/models/tabela.model.ts +14 -36
- package/src/models/tabela.options.ts +3 -2
- package/src/tabela.ts +43 -19
- package/types/components/column.component.d.ts +3 -3
- package/types/components/group.component.d.ts +14 -0
- package/types/components/row.component.d.ts +2 -2
- package/types/helpers/style.helper.d.ts +1 -1
- package/types/managers/column.manager.d.ts +6 -7
- package/types/managers/data.manager.d.ts +7 -6
- package/types/managers/event.manager.d.ts +3 -6
- package/types/managers/filter.manager.d.ts +11 -11
- package/types/managers/group.manager.d.ts +17 -0
- package/types/managers/navigation.manager.d.ts +10 -0
- package/types/managers/render.manager.d.ts +6 -7
- package/types/managers/row.manager.d.ts +4 -5
- package/types/managers/selection.manager.d.ts +12 -7
- package/types/managers/sort.manager.d.ts +11 -9
- package/types/models/column.model.d.ts +2 -2
- package/types/models/data.model.d.ts +13 -3
- package/types/models/filter.model.d.ts +10 -3
- package/types/models/group.model.d.ts +4 -0
- package/types/models/render.model.d.ts +2 -1
- package/types/models/selection.model.d.ts +8 -0
- package/types/models/sort.model.d.ts +10 -3
- package/types/models/tabela.model.d.ts +14 -33
- package/types/models/tabela.options.d.ts +3 -2
- package/types/tabela.d.ts +4 -1
package/dist/tabela.full.js
CHANGED
|
@@ -318,7 +318,7 @@ new Set([
|
|
|
318
318
|
* @param value Value to check
|
|
319
319
|
* @returns `true` if the value is nullable or a whitespace-only string, otherwise `false`
|
|
320
320
|
*/
|
|
321
|
-
function isNullableOrWhitespace(value) {
|
|
321
|
+
function isNullableOrWhitespace$1(value) {
|
|
322
322
|
return value == null || EXPRESSION_WHITESPACE$1.test(getString$1(value));
|
|
323
323
|
}
|
|
324
324
|
var EXPRESSION_WHITESPACE$1 = /^\s*$/;
|
|
@@ -346,55 +346,12 @@ function setElementValues(element, first, second, third, callback) {
|
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
function updateElementValue(element, key, value, set, remove, isBoolean, json) {
|
|
349
|
-
if (isBoolean ? value == null : isNullableOrWhitespace(value)) remove.call(element, key);
|
|
349
|
+
if (isBoolean ? value == null : isNullableOrWhitespace$1(value)) remove.call(element, key);
|
|
350
350
|
else set.call(element, key, json ? JSON.stringify(value) : String(value));
|
|
351
351
|
}
|
|
352
|
-
function badAttributeHandler(name, value) {
|
|
353
|
-
if (typeof name !== "string" || name.trim().length === 0 || typeof value !== "string") return true;
|
|
354
|
-
if (EXPRESSION_CLOBBERED_NAME.test(name) && (value in document || value in formElement) || EXPRESSION_EVENT_NAME.test(name)) return true;
|
|
355
|
-
if (EXPRESSION_SKIP_NAME.test(name) || EXPRESSION_URI_VALUE.test(value) || isValidSourceAttribute(name, value)) return false;
|
|
356
|
-
return EXPRESSION_DATA_OR_SCRIPT.test(value);
|
|
357
|
-
}
|
|
358
|
-
function booleanAttributeHandler(name, value) {
|
|
359
|
-
if (typeof name !== "string" || name.trim().length === 0 || typeof value !== "string") return true;
|
|
360
|
-
const normalizedName = name.toLowerCase();
|
|
361
|
-
if (!booleanAttributesSet.has(normalizedName)) return false;
|
|
362
|
-
const normalized = value.toLowerCase();
|
|
363
|
-
return !(normalized.length === 0 || normalized === normalizedName);
|
|
364
|
-
}
|
|
365
|
-
function decodeAttribute(value) {
|
|
366
|
-
textArea ??= document.createElement("textarea");
|
|
367
|
-
textArea.innerHTML = value;
|
|
368
|
-
return decodeURIComponent(textArea.value);
|
|
369
|
-
}
|
|
370
|
-
function handleAttribute(callback, decode, first, second) {
|
|
371
|
-
let name;
|
|
372
|
-
let value;
|
|
373
|
-
if (isAttribute(first)) {
|
|
374
|
-
name = first.name;
|
|
375
|
-
value = String(first.value);
|
|
376
|
-
} else if (typeof first === "string" && typeof second === "string") {
|
|
377
|
-
name = first;
|
|
378
|
-
value = second;
|
|
379
|
-
}
|
|
380
|
-
if (decode && value != null) value = decodeAttribute(value);
|
|
381
|
-
return callback(name, value?.replace(EXPRESSION_WHITESPACE, ""));
|
|
382
|
-
}
|
|
383
352
|
function isAttribute(value) {
|
|
384
353
|
return value instanceof Attr || isPlainObject$1(value) && typeof value.name === "string" && "value" in value;
|
|
385
354
|
}
|
|
386
|
-
function _isBadAttribute(first, second, decode) {
|
|
387
|
-
return handleAttribute(badAttributeHandler, decode, first, second);
|
|
388
|
-
}
|
|
389
|
-
function _isEmptyNonBooleanAttribute(first, second, decode) {
|
|
390
|
-
return handleAttribute((name, value) => name != null && value != null && !booleanAttributesSet.has(name) && value.trim().length === 0, decode, first, second);
|
|
391
|
-
}
|
|
392
|
-
function _isInvalidBooleanAttribute(first, second, decode) {
|
|
393
|
-
return handleAttribute(booleanAttributeHandler, decode, first, second);
|
|
394
|
-
}
|
|
395
|
-
function isValidSourceAttribute(name, value) {
|
|
396
|
-
return EXPRESSION_SOURCE_NAME.test(name) && EXPRESSION_SOURCE_VALUE.test(value);
|
|
397
|
-
}
|
|
398
355
|
function updateAttribute(element, name, value, dispatch) {
|
|
399
356
|
const normalizedName = name.toLowerCase();
|
|
400
357
|
const isBoolean = booleanAttributesSet.has(normalizedName);
|
|
@@ -408,14 +365,6 @@ function updateProperty(element, name, value, dispatch) {
|
|
|
408
365
|
const event = dispatch !== false && elementEvents[element.tagName]?.[name];
|
|
409
366
|
if (typeof event === "string") element.dispatchEvent(new Event(event, { bubbles: true }));
|
|
410
367
|
}
|
|
411
|
-
var EXPRESSION_CLOBBERED_NAME = /^(id|name)$/i;
|
|
412
|
-
var EXPRESSION_DATA_OR_SCRIPT = /^(?:data|\w+script):/i;
|
|
413
|
-
var EXPRESSION_EVENT_NAME = /^on/i;
|
|
414
|
-
var EXPRESSION_SKIP_NAME = /^(aria-[-\w]+|data-[-\w.\u00B7-\uFFFF]+)$/i;
|
|
415
|
-
var EXPRESSION_SOURCE_NAME = /^src$/i;
|
|
416
|
-
var EXPRESSION_SOURCE_VALUE = /^data:/i;
|
|
417
|
-
var EXPRESSION_URI_VALUE = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
|
|
418
|
-
var EXPRESSION_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
|
|
419
368
|
/**
|
|
420
369
|
* List of boolean attributes
|
|
421
370
|
*/
|
|
@@ -455,8 +404,7 @@ var elementEvents = {
|
|
|
455
404
|
SELECT: { value: "change" },
|
|
456
405
|
TEXTAREA: { value: "input" }
|
|
457
406
|
};
|
|
458
|
-
|
|
459
|
-
var textArea;
|
|
407
|
+
document.createElement("form");
|
|
460
408
|
function setAttribute(element, first, second, third) {
|
|
461
409
|
setElementValue(element, first, second, third, updateAttribute);
|
|
462
410
|
}
|
|
@@ -560,7 +508,7 @@ function createRow() {
|
|
|
560
508
|
return createElement("div", {
|
|
561
509
|
className: "tabela__row",
|
|
562
510
|
role: "row"
|
|
563
|
-
}, {}, {});
|
|
511
|
+
}, {}, { height: "32px" });
|
|
564
512
|
}
|
|
565
513
|
function createFaker() {
|
|
566
514
|
return createElement("div", { className: "tabela__faker" }, {}, {});
|
|
@@ -575,6 +523,7 @@ var BodyComponent = class {
|
|
|
575
523
|
this.elements.group = group;
|
|
576
524
|
group.className += " tabela__rowgroup--body";
|
|
577
525
|
group.tabIndex = 0;
|
|
526
|
+
group.setAttribute("data-event", "body");
|
|
578
527
|
group.append(this.elements.faker);
|
|
579
528
|
}
|
|
580
529
|
destroy() {
|
|
@@ -636,13 +585,13 @@ var HeaderComponent = class {
|
|
|
636
585
|
var ColumnComponent = class {
|
|
637
586
|
elements;
|
|
638
587
|
options;
|
|
639
|
-
constructor(
|
|
640
|
-
const width = Number.parseInt(getComputedStyle(document.body).fontSize, 10) * (
|
|
588
|
+
constructor(column) {
|
|
589
|
+
const width = Number.parseInt(getComputedStyle(document.body).fontSize, 10) * (column.width ?? column.title.length * 1.5);
|
|
641
590
|
this.options = {
|
|
642
|
-
...
|
|
591
|
+
...column,
|
|
643
592
|
width
|
|
644
593
|
};
|
|
645
|
-
this.elements = createHeading(options.field, options.title, width);
|
|
594
|
+
this.elements = createHeading(this.options.field, this.options.title, width);
|
|
646
595
|
}
|
|
647
596
|
destroy() {
|
|
648
597
|
this.elements.content.remove();
|
|
@@ -674,18 +623,19 @@ function createHeading(field, title, width) {
|
|
|
674
623
|
}
|
|
675
624
|
var ColumnManager = class {
|
|
676
625
|
items = [];
|
|
677
|
-
constructor(
|
|
678
|
-
this.
|
|
679
|
-
this.
|
|
680
|
-
this.set(columns);
|
|
626
|
+
constructor(state) {
|
|
627
|
+
this.state = state;
|
|
628
|
+
this.set(state.options.columns);
|
|
681
629
|
}
|
|
682
630
|
destroy() {
|
|
683
631
|
const { length } = this.items;
|
|
684
632
|
for (let index = 0; index < length; index += 1) this.items[index].destroy();
|
|
685
|
-
this.items
|
|
633
|
+
this.items = void 0;
|
|
634
|
+
this.state = void 0;
|
|
686
635
|
}
|
|
687
636
|
remove(value) {
|
|
688
|
-
const {
|
|
637
|
+
const { items, state } = this;
|
|
638
|
+
const { components, managers } = state;
|
|
689
639
|
const fields = (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string");
|
|
690
640
|
const { length } = fields;
|
|
691
641
|
if (length === 0) return;
|
|
@@ -701,8 +651,8 @@ var ColumnManager = class {
|
|
|
701
651
|
managers.render.removeCells(fields);
|
|
702
652
|
}
|
|
703
653
|
set(columns) {
|
|
704
|
-
const {
|
|
705
|
-
const { footer, header } = components;
|
|
654
|
+
const { items, state } = this;
|
|
655
|
+
const { footer, header } = state.components;
|
|
706
656
|
items.splice(0, items.length, ...columns.map((column) => new ColumnComponent(column)));
|
|
707
657
|
header.update(items);
|
|
708
658
|
footer.update(items);
|
|
@@ -862,35 +812,8 @@ function compact(array, strict) {
|
|
|
862
812
|
}
|
|
863
813
|
return compacted;
|
|
864
814
|
}
|
|
865
|
-
function
|
|
866
|
-
|
|
867
|
-
const actualStart = Math.min(Math.max(0, start), array.length);
|
|
868
|
-
const chunked = chunk(items);
|
|
869
|
-
const lastIndex = chunked.length - 1;
|
|
870
|
-
let index = Number(chunked.length);
|
|
871
|
-
let returned;
|
|
872
|
-
while (index > 0) {
|
|
873
|
-
index -= 1;
|
|
874
|
-
const spliced = array.splice(actualStart, index === lastIndex ? actualDeleteCount : 0, ...chunked[index]);
|
|
875
|
-
if (returned == null) returned = spliced;
|
|
876
|
-
else returned.push(...spliced);
|
|
877
|
-
}
|
|
878
|
-
if (type === "insert") return array;
|
|
879
|
-
return type === "splice" ? returned : array.length;
|
|
880
|
-
}
|
|
881
|
-
function insertValues(type, array, items, start, deleteCount) {
|
|
882
|
-
const spliceArray = type === "insert" || type === "splice";
|
|
883
|
-
if (!Array.isArray(array) || typeof start !== "number" || !Array.isArray(items) || items.length === 0) return spliceArray ? [] : 0;
|
|
884
|
-
return insertChunkedValues(type, array, items, start, spliceArray ? deleteCount : 0);
|
|
885
|
-
}
|
|
886
|
-
/**
|
|
887
|
-
* Push items into an array _(at the end)_
|
|
888
|
-
* @param array Original array
|
|
889
|
-
* @param pushed Pushed items
|
|
890
|
-
* @returns New length of the array
|
|
891
|
-
*/
|
|
892
|
-
function push(array, pushed) {
|
|
893
|
-
return insertValues("push", array, pushed, array.length, 0);
|
|
815
|
+
function select(array, ...parameters) {
|
|
816
|
+
return findValues("all", array, parameters, parameters.pop()).matched;
|
|
894
817
|
}
|
|
895
818
|
function aggregate(type, array, key) {
|
|
896
819
|
const length = Array.isArray(array) ? array.length : 0;
|
|
@@ -1157,6 +1080,181 @@ toMap.arrays = toMapArrays;
|
|
|
1157
1080
|
function toMapArrays(array, first, second) {
|
|
1158
1081
|
return getMapValues(array, first, second, true);
|
|
1159
1082
|
}
|
|
1083
|
+
function groupValues(array, key, value, arrays) {
|
|
1084
|
+
if (!Array.isArray(array) || array.length === 0) return {};
|
|
1085
|
+
const { length } = array;
|
|
1086
|
+
const callbacks = getArrayCallbacks(void 0, key, value);
|
|
1087
|
+
const record = {};
|
|
1088
|
+
for (let index = 0; index < length; index += 1) {
|
|
1089
|
+
const item = array[index];
|
|
1090
|
+
const keyed = callbacks?.keyed?.(item, index, array) ?? index;
|
|
1091
|
+
const valued = callbacks?.value?.(item, index, array) ?? item;
|
|
1092
|
+
if (arrays) {
|
|
1093
|
+
const existing = record[keyed];
|
|
1094
|
+
if (existing == null) record[keyed] = [valued];
|
|
1095
|
+
else existing.push(valued);
|
|
1096
|
+
} else record[keyed] = valued;
|
|
1097
|
+
}
|
|
1098
|
+
return record;
|
|
1099
|
+
}
|
|
1100
|
+
function toRecord(array, first, second) {
|
|
1101
|
+
return groupValues(array, first, second, false);
|
|
1102
|
+
}
|
|
1103
|
+
toRecord.arrays = toRecordArrays;
|
|
1104
|
+
function toRecordArrays(array, first, second) {
|
|
1105
|
+
return groupValues(array, first, second, true);
|
|
1106
|
+
}
|
|
1107
|
+
var GroupComponent = class {
|
|
1108
|
+
element;
|
|
1109
|
+
expanded = true;
|
|
1110
|
+
filtered = 0;
|
|
1111
|
+
selected = 0;
|
|
1112
|
+
total = 0;
|
|
1113
|
+
constructor(key, label, value) {
|
|
1114
|
+
this.key = key;
|
|
1115
|
+
this.label = label;
|
|
1116
|
+
this.value = value;
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
1119
|
+
function renderGroup(state, component) {
|
|
1120
|
+
component.element ??= createElement("div", {
|
|
1121
|
+
className: "tabela__row tabela__row--group",
|
|
1122
|
+
innerHTML: `<div class="tabela__cell tabela__cell--group" role="cell">
|
|
1123
|
+
<button class="tabela__button tabela__button--group" data-event="group" data-key="${component.key}" type="button">
|
|
1124
|
+
<span aria-hidden="true"></span>
|
|
1125
|
+
<span>Open/close</span>
|
|
1126
|
+
</button>
|
|
1127
|
+
<p>${component.label}</p>
|
|
1128
|
+
</div>`,
|
|
1129
|
+
role: "row"
|
|
1130
|
+
}, {}, { height: `${state.options.rowHeight}px` });
|
|
1131
|
+
}
|
|
1132
|
+
var SortManager = class {
|
|
1133
|
+
handlers = Object.freeze({
|
|
1134
|
+
add: (field, direction) => this.add(field, direction),
|
|
1135
|
+
flip: (field) => this.flip(field),
|
|
1136
|
+
clear: () => this.clear(),
|
|
1137
|
+
remove: (field) => this.remove(field),
|
|
1138
|
+
set: (items) => this.set(items)
|
|
1139
|
+
});
|
|
1140
|
+
items = [];
|
|
1141
|
+
constructor(state) {
|
|
1142
|
+
this.state = state;
|
|
1143
|
+
}
|
|
1144
|
+
add(field, direction) {
|
|
1145
|
+
if (this.items.findIndex((item) => item.key === field) > -1) return;
|
|
1146
|
+
this.items.push({
|
|
1147
|
+
key: field,
|
|
1148
|
+
direction: direction ?? "ascending"
|
|
1149
|
+
});
|
|
1150
|
+
this.sort();
|
|
1151
|
+
}
|
|
1152
|
+
addOrSet(event, field) {
|
|
1153
|
+
if (event.ctrlKey || event.metaKey) this.add(field);
|
|
1154
|
+
else this.set([{
|
|
1155
|
+
field,
|
|
1156
|
+
direction: "ascending"
|
|
1157
|
+
}]);
|
|
1158
|
+
}
|
|
1159
|
+
clear() {
|
|
1160
|
+
if (this.items.length > 0) {
|
|
1161
|
+
this.items.length = 0;
|
|
1162
|
+
this.sort();
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
destroy() {
|
|
1166
|
+
this.handlers = void 0;
|
|
1167
|
+
this.items = void 0;
|
|
1168
|
+
this.state = void 0;
|
|
1169
|
+
}
|
|
1170
|
+
flip(field) {
|
|
1171
|
+
const item = this.items.find((item) => item.key === field);
|
|
1172
|
+
if (item == null) return;
|
|
1173
|
+
item.direction = item.direction === "ascending" ? "descending" : "ascending";
|
|
1174
|
+
this.sort();
|
|
1175
|
+
}
|
|
1176
|
+
remove(field) {
|
|
1177
|
+
const index = this.items.findIndex((item) => item.key === field);
|
|
1178
|
+
if (index > -1) {
|
|
1179
|
+
this.items.splice(index, 1);
|
|
1180
|
+
this.sort();
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
removeOrClear(event, field) {
|
|
1184
|
+
if (event.ctrlKey || event.metaKey) this.remove(field);
|
|
1185
|
+
else this.clear();
|
|
1186
|
+
}
|
|
1187
|
+
set(items) {
|
|
1188
|
+
this.items.splice(0, this.items.length, ...items.map((item) => ({
|
|
1189
|
+
key: item.field,
|
|
1190
|
+
direction: item.direction
|
|
1191
|
+
})));
|
|
1192
|
+
this.sort();
|
|
1193
|
+
}
|
|
1194
|
+
sort() {
|
|
1195
|
+
const { items, state } = this;
|
|
1196
|
+
const { length } = state.managers.column.items;
|
|
1197
|
+
for (let index = 0; index < length; index += 1) {
|
|
1198
|
+
const column = state.managers.column.items[index];
|
|
1199
|
+
const sorterIndex = items.findIndex((item) => item.key === column.options.field);
|
|
1200
|
+
const sorterItem = items[sorterIndex];
|
|
1201
|
+
setAttributes(column.elements.wrapper, {
|
|
1202
|
+
"aria-sort": sorterItem == null ? "none" : items.length > 1 ? "other" : sorterItem.direction,
|
|
1203
|
+
"data-sort-direction": sorterItem == null ? void 0 : sorterItem.direction
|
|
1204
|
+
});
|
|
1205
|
+
setAttribute(column.elements.sorter, "data-sort-position", sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
|
|
1206
|
+
}
|
|
1207
|
+
state.managers.data.values.keys.active = items.length === 0 ? void 0 : getSortedKeys(state, items);
|
|
1208
|
+
state.managers.render.update(true, true);
|
|
1209
|
+
}
|
|
1210
|
+
toggle(event, field, direction) {
|
|
1211
|
+
switch (direction) {
|
|
1212
|
+
case "ascending":
|
|
1213
|
+
this.flip(field);
|
|
1214
|
+
return;
|
|
1215
|
+
case "descending":
|
|
1216
|
+
this.removeOrClear(event, field);
|
|
1217
|
+
return;
|
|
1218
|
+
default:
|
|
1219
|
+
this.addOrSet(event, field);
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
1224
|
+
function getSortedKeys(state, sorters) {
|
|
1225
|
+
const data = state.managers.data.values.keys.active?.map((key) => key instanceof GroupComponent ? key : state.managers.data.values.objects.mapped.get(key)) ?? state.managers.data.values.objects.array.slice();
|
|
1226
|
+
if (!state.managers.group.enabled) return sort(data, sorters).map((item) => item[state.key]);
|
|
1227
|
+
return sortWithGroups(state, data, sorters).map((item) => item instanceof GroupComponent ? item : item[state.key]);
|
|
1228
|
+
}
|
|
1229
|
+
function sortWithGroups(state, data, sorters) {
|
|
1230
|
+
const { length } = sorters;
|
|
1231
|
+
return data.sort((first, second) => {
|
|
1232
|
+
const firstValue = first instanceof GroupComponent ? first.value : first[state.managers.group.field];
|
|
1233
|
+
const secondValue = second instanceof GroupComponent ? second.value : second[state.managers.group.field];
|
|
1234
|
+
const firstOrder = state.managers.group.order[firstValue];
|
|
1235
|
+
const secondOrder = state.managers.group.order[secondValue];
|
|
1236
|
+
const groupComparison = compare(firstOrder, secondOrder);
|
|
1237
|
+
if (groupComparison !== 0) return groupComparison;
|
|
1238
|
+
const firstIsGroup = first instanceof GroupComponent;
|
|
1239
|
+
const secondIsGroup = second instanceof GroupComponent;
|
|
1240
|
+
if (firstIsGroup || secondIsGroup) return firstIsGroup && secondIsGroup ? 0 : firstIsGroup ? -1 : 1;
|
|
1241
|
+
for (let index = 0; index < length; index += 1) {
|
|
1242
|
+
const sorter = sorters[index];
|
|
1243
|
+
const comparison = compare(first[sorter.key], second[sorter.key]);
|
|
1244
|
+
if (comparison !== 0) return comparison * (sorter.direction === "ascending" ? 1 : -1);
|
|
1245
|
+
}
|
|
1246
|
+
return 0;
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Is the value `undefined`, `null`, or a whitespace-only string?
|
|
1251
|
+
* @param value Value to check
|
|
1252
|
+
* @returns `true` if the value is nullable or a whitespace-only string, otherwise `false`
|
|
1253
|
+
*/
|
|
1254
|
+
function isNullableOrWhitespace(value) {
|
|
1255
|
+
return value == null || EXPRESSION_WHITESPACE.test(getString(value));
|
|
1256
|
+
}
|
|
1257
|
+
var EXPRESSION_WHITESPACE = /^\s*$/;
|
|
1160
1258
|
var DataManager = class {
|
|
1161
1259
|
handlers = Object.freeze({
|
|
1162
1260
|
add: (data) => void this.add(data, true),
|
|
@@ -1173,19 +1271,41 @@ var DataManager = class {
|
|
|
1173
1271
|
array: []
|
|
1174
1272
|
}
|
|
1175
1273
|
};
|
|
1274
|
+
get keys() {
|
|
1275
|
+
return this.values.keys.active ?? this.values.keys.original;
|
|
1276
|
+
}
|
|
1176
1277
|
get size() {
|
|
1177
|
-
return this.
|
|
1278
|
+
return this.keys.length;
|
|
1178
1279
|
}
|
|
1179
|
-
constructor(
|
|
1180
|
-
this.
|
|
1181
|
-
this.components = components;
|
|
1182
|
-
this.field = field;
|
|
1280
|
+
constructor(state) {
|
|
1281
|
+
this.state = state;
|
|
1183
1282
|
}
|
|
1184
1283
|
async add(data, render) {
|
|
1185
|
-
const {
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1284
|
+
const { state, values } = this;
|
|
1285
|
+
const { length } = data;
|
|
1286
|
+
const updates = [];
|
|
1287
|
+
for (let index = 0; index < length; index += 1) {
|
|
1288
|
+
const item = data[index];
|
|
1289
|
+
const key = item[state.key];
|
|
1290
|
+
if (values.objects.mapped.has(key)) {
|
|
1291
|
+
updates.push(item);
|
|
1292
|
+
continue;
|
|
1293
|
+
}
|
|
1294
|
+
values.objects.array.push(item);
|
|
1295
|
+
values.objects.mapped.set(key, item);
|
|
1296
|
+
if (!state.managers.group.enabled) continue;
|
|
1297
|
+
const groupKey = item[state.managers.group.field];
|
|
1298
|
+
let group = state.managers.group.get(groupKey);
|
|
1299
|
+
if (group == null) {
|
|
1300
|
+
group = new GroupComponent(String(groupKey), String(groupKey), groupKey);
|
|
1301
|
+
values.objects.array.push(group);
|
|
1302
|
+
state.managers.group.add(group);
|
|
1303
|
+
}
|
|
1304
|
+
if (!group.expanded) state.managers.group.collapsed.add(key);
|
|
1305
|
+
group.total += 1;
|
|
1306
|
+
}
|
|
1307
|
+
if (updates.length > 0) this.update(updates);
|
|
1308
|
+
else if (render) this.render();
|
|
1189
1309
|
}
|
|
1190
1310
|
clear() {
|
|
1191
1311
|
if (this.values.objects.array.length > 0) this.set([]);
|
|
@@ -1197,55 +1317,95 @@ var DataManager = class {
|
|
|
1197
1317
|
values.keys.original.length = 0;
|
|
1198
1318
|
values.objects.array.length = 0;
|
|
1199
1319
|
this.handlers = void 0;
|
|
1320
|
+
this.state = void 0;
|
|
1321
|
+
this.values = void 0;
|
|
1200
1322
|
}
|
|
1201
1323
|
get(active) {
|
|
1202
1324
|
const { values } = this;
|
|
1203
|
-
return active ?? false ? values.keys.active
|
|
1325
|
+
return active ?? false ? select(values.keys.active ?? [], (key) => !(key instanceof GroupComponent), (key) => values.objects.mapped.get(key)) : values.objects.array.filter((item) => !(item instanceof GroupComponent));
|
|
1326
|
+
}
|
|
1327
|
+
getIndex(key) {
|
|
1328
|
+
return this.keys.indexOf(key);
|
|
1204
1329
|
}
|
|
1205
1330
|
async remove(items, render) {
|
|
1206
|
-
const {
|
|
1207
|
-
const keys = items.map((value) => isPlainObject(value) ? value[
|
|
1331
|
+
const { state, values } = this;
|
|
1332
|
+
const keys = items.map((value) => isPlainObject(value) ? value[state.key] : value).filter((key) => values.objects.mapped.has(key));
|
|
1208
1333
|
const { length } = keys;
|
|
1209
1334
|
if (length === 0) return;
|
|
1210
1335
|
for (let keyIndex = 0; keyIndex < length; keyIndex += 1) {
|
|
1211
1336
|
const key = keys[keyIndex];
|
|
1212
1337
|
values.objects.mapped.delete(key);
|
|
1213
|
-
const arrayIndex = values.objects.array.findIndex((
|
|
1214
|
-
|
|
1338
|
+
const arrayIndex = values.objects.array.findIndex((item) => !(item instanceof GroupComponent) && item[state.key] === key);
|
|
1339
|
+
let item;
|
|
1340
|
+
if (arrayIndex > -1) [item] = values.objects.array.splice(arrayIndex, 1);
|
|
1215
1341
|
values.keys.original.splice(values.keys.original.indexOf(key), 1);
|
|
1216
|
-
managers.row.remove(key);
|
|
1342
|
+
state.managers.row.remove(key);
|
|
1343
|
+
if (!state.managers.group.enabled || item == null) continue;
|
|
1344
|
+
state.managers.group.collapsed.delete(key);
|
|
1345
|
+
const groupKey = item[state.managers.group.field];
|
|
1346
|
+
const group = state.managers.group.get(groupKey);
|
|
1347
|
+
if (group == null) continue;
|
|
1348
|
+
group.total -= 1;
|
|
1349
|
+
if (group.total > 0) continue;
|
|
1350
|
+
const groupIndex = values.objects.array.findIndex((item) => item instanceof GroupComponent && item.value === groupKey);
|
|
1351
|
+
if (groupIndex > -1) values.objects.array.splice(groupIndex, 1);
|
|
1352
|
+
state.managers.group.remove(group);
|
|
1217
1353
|
}
|
|
1218
1354
|
if (render) this.render();
|
|
1219
1355
|
}
|
|
1220
1356
|
render() {
|
|
1221
|
-
const {
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1357
|
+
const { state, values } = this;
|
|
1358
|
+
if (state.managers.group.enabled) sortWithGroups(state, values.objects.array, [{
|
|
1359
|
+
direction: "ascending",
|
|
1360
|
+
key: state.key
|
|
1361
|
+
}]);
|
|
1362
|
+
else sort(values.objects.array, [{
|
|
1363
|
+
direction: "ascending",
|
|
1364
|
+
key: state.key
|
|
1365
|
+
}]);
|
|
1366
|
+
values.keys.original = values.objects.array.map((item) => item instanceof GroupComponent ? item : item[state.key]);
|
|
1367
|
+
values.objects.mapped = toMap(values.objects.array.filter((item) => !(item instanceof GroupComponent)), (item) => item[state.key]);
|
|
1368
|
+
if (Object.keys(state.managers.filter.items).length > 0) state.managers.filter.filter();
|
|
1369
|
+
else if (state.managers.sort.items.length > 0) state.managers.sort.sort();
|
|
1370
|
+
else state.managers.render.update(true, true);
|
|
1226
1371
|
}
|
|
1227
1372
|
set(data) {
|
|
1228
|
-
const {
|
|
1229
|
-
|
|
1230
|
-
|
|
1373
|
+
const { state, values } = this;
|
|
1374
|
+
const array = data.slice();
|
|
1375
|
+
if (state.managers.group.enabled) {
|
|
1376
|
+
const grouped = toRecord.arrays(data, state.managers.group.field);
|
|
1377
|
+
const entries = Object.entries(grouped);
|
|
1378
|
+
const { length } = entries;
|
|
1379
|
+
const groups = [];
|
|
1380
|
+
for (let index = 0; index < length; index += 1) {
|
|
1381
|
+
const [value, items] = entries[index];
|
|
1382
|
+
const key = String(value);
|
|
1383
|
+
const group = new GroupComponent(key, key, value);
|
|
1384
|
+
group.total = items.length;
|
|
1385
|
+
groups.push(group);
|
|
1386
|
+
array.push(group);
|
|
1387
|
+
}
|
|
1388
|
+
state.managers.group.set(groups);
|
|
1389
|
+
}
|
|
1390
|
+
values.objects.array = array;
|
|
1231
1391
|
this.render();
|
|
1232
1392
|
}
|
|
1233
1393
|
async synchronize(data, remove) {
|
|
1234
|
-
const {
|
|
1394
|
+
const { state, values } = this;
|
|
1235
1395
|
const add = [];
|
|
1236
1396
|
const updated = [];
|
|
1237
1397
|
const keys = /* @__PURE__ */ new Set([]);
|
|
1238
1398
|
const { length } = data;
|
|
1239
1399
|
for (let index = 0; index < length; index += 1) {
|
|
1240
1400
|
const object = data[index];
|
|
1241
|
-
const key = object[
|
|
1401
|
+
const key = object[state.key];
|
|
1242
1402
|
if (values.objects.mapped.has(key)) updated.push(object);
|
|
1243
1403
|
else add.push(object);
|
|
1244
1404
|
keys.add(key);
|
|
1245
1405
|
}
|
|
1246
1406
|
if (keys.size === 0) return;
|
|
1247
1407
|
if (remove ?? false) {
|
|
1248
|
-
const toRemove = values.keys.original.filter((key) => !keys.has(key));
|
|
1408
|
+
const toRemove = values.keys.original.filter((key) => !(key instanceof GroupComponent) && !keys.has(key));
|
|
1249
1409
|
if (toRemove.length > 0) await this.remove(toRemove, false);
|
|
1250
1410
|
}
|
|
1251
1411
|
await this.update(updated);
|
|
@@ -1253,18 +1413,18 @@ var DataManager = class {
|
|
|
1253
1413
|
if (add.length > 0 || (remove ?? false)) this.render();
|
|
1254
1414
|
}
|
|
1255
1415
|
async update(data) {
|
|
1256
|
-
const {
|
|
1416
|
+
const { state, values } = this;
|
|
1257
1417
|
const { length } = data;
|
|
1258
1418
|
for (let index = 0; index < length; index += 1) {
|
|
1259
1419
|
const object = data[index];
|
|
1260
|
-
const key = object[
|
|
1420
|
+
const key = object[state.key];
|
|
1261
1421
|
const value = values.objects.mapped.get(key);
|
|
1262
1422
|
if (value != null) {
|
|
1263
1423
|
values.objects.mapped.set(key, {
|
|
1264
1424
|
...value,
|
|
1265
1425
|
...object
|
|
1266
1426
|
});
|
|
1267
|
-
managers.row.update(key);
|
|
1427
|
+
state.managers.row.update(key);
|
|
1268
1428
|
}
|
|
1269
1429
|
}
|
|
1270
1430
|
}
|
|
@@ -1413,203 +1573,56 @@ function getElement(origin) {
|
|
|
1413
1573
|
if (origin instanceof Element) return origin;
|
|
1414
1574
|
return origin instanceof Event && origin.target instanceof Element ? origin.target : void 0;
|
|
1415
1575
|
}
|
|
1416
|
-
function isInert(item) {
|
|
1417
|
-
return (item.element.inert ?? false) || EXPRESSION_TRUEISH.test(item.element.getAttribute(ATTRIBUTE_INERT)) || item.element.parentElement != null && isInert({
|
|
1418
|
-
element: item.element.parentElement,
|
|
1419
|
-
tabIndex: TABINDEX_DEFAULT
|
|
1420
|
-
});
|
|
1421
|
-
}
|
|
1422
|
-
var ATTRIBUTE_INERT = "inert";
|
|
1423
|
-
var EXPRESSION_TRUEISH = /^(|true)$/i;
|
|
1424
|
-
[
|
|
1425
|
-
"[contenteditable]:not([contenteditable=\"false\"])",
|
|
1426
|
-
"[tabindex]:not(slot)",
|
|
1427
|
-
"a[href]",
|
|
1428
|
-
"audio[controls]",
|
|
1429
|
-
"button",
|
|
1430
|
-
"details",
|
|
1431
|
-
"details > summary:first-of-type",
|
|
1432
|
-
"input",
|
|
1433
|
-
"select",
|
|
1434
|
-
"textarea",
|
|
1435
|
-
"video[controls]"
|
|
1436
|
-
].map((selector) => `${selector}:not([inert])`).join(",");
|
|
1437
|
-
var TABINDEX_DEFAULT = -1;
|
|
1438
|
-
function handleElement(element, depth) {
|
|
1439
|
-
if (depth === 0) {
|
|
1440
|
-
const removable = element.querySelectorAll(REMOVE_SELECTOR);
|
|
1441
|
-
for (const item of removable) item.remove();
|
|
1442
|
-
}
|
|
1443
|
-
sanitizeAttributes(element, [...element.attributes]);
|
|
1444
|
-
}
|
|
1445
|
-
/**
|
|
1446
|
-
* Is the element clobbered?
|
|
1447
|
-
*
|
|
1448
|
-
* Thanks, DOMPurify _(https://github.com/cure53/DOMPurify)_
|
|
1449
|
-
*/
|
|
1450
|
-
function isClobbered(value) {
|
|
1451
|
-
return value instanceof HTMLFormElement && (typeof value.nodeName !== "string" || typeof value.textContent !== "string" || typeof value.removeChild !== "function" || !(value.attributes instanceof NamedNodeMap) || typeof value.removeAttribute !== "function" || typeof value.setAttribute !== "function" || typeof value.namespaceURI !== "string" || typeof value.insertBefore !== "function" || typeof value.hasChildNodes !== "function");
|
|
1452
|
-
}
|
|
1453
|
-
function removeNode(node) {
|
|
1454
|
-
if (typeof node.remove === "function") node.remove();
|
|
1455
|
-
}
|
|
1456
|
-
function sanitizeAttributes(element, attributes) {
|
|
1457
|
-
const { length } = attributes;
|
|
1458
|
-
for (let index = 0; index < length; index += 1) {
|
|
1459
|
-
const { name, value } = attributes[index];
|
|
1460
|
-
if (_isBadAttribute(name, value, false) || _isEmptyNonBooleanAttribute(name, value, false)) element.removeAttribute(name);
|
|
1461
|
-
else if (_isInvalidBooleanAttribute(name, value, false)) setAttribute(element, name, true);
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
function sanitizeNodes(nodes, depth) {
|
|
1465
|
-
const actual = nodes.filter((node) => node instanceof Node);
|
|
1466
|
-
let { length } = nodes;
|
|
1467
|
-
for (let index = 0; index < length; index += 1) {
|
|
1468
|
-
const node = actual[index];
|
|
1469
|
-
let remove = isClobbered(node);
|
|
1470
|
-
if (!remove) switch (node.nodeType) {
|
|
1471
|
-
case Node.ELEMENT_NODE:
|
|
1472
|
-
handleElement(node, depth);
|
|
1473
|
-
break;
|
|
1474
|
-
case Node.COMMENT_NODE:
|
|
1475
|
-
remove = COMMENT_HARMFUL.test(node.data);
|
|
1476
|
-
break;
|
|
1477
|
-
case Node.DOCUMENT_TYPE_NODE:
|
|
1478
|
-
case Node.PROCESSING_INSTRUCTION_NODE:
|
|
1479
|
-
remove = true;
|
|
1480
|
-
break;
|
|
1481
|
-
}
|
|
1482
|
-
if (remove) {
|
|
1483
|
-
removeNode(node);
|
|
1484
|
-
actual.splice(index, 1);
|
|
1485
|
-
index -= 1;
|
|
1486
|
-
length -= 1;
|
|
1487
|
-
continue;
|
|
1488
|
-
}
|
|
1489
|
-
if (node.hasChildNodes()) sanitizeNodes([...node.childNodes], depth + 1);
|
|
1490
|
-
}
|
|
1491
|
-
return nodes;
|
|
1492
|
-
}
|
|
1493
|
-
var COMMENT_HARMFUL = /<[/\w]/g;
|
|
1494
|
-
var REMOVE_SELECTOR = "script, toretto-temporary";
|
|
1495
|
-
function createHtml(value) {
|
|
1496
|
-
const parsed = getParser().parseFromString(getHtml(value), PARSE_TYPE_HTML);
|
|
1497
|
-
parsed.body.normalize();
|
|
1498
|
-
sanitizeNodes([parsed.body], 0);
|
|
1499
|
-
return parsed.body.innerHTML;
|
|
1500
|
-
}
|
|
1501
|
-
function createTemplate(value, options) {
|
|
1502
|
-
const template = document.createElement(TEMPLATE_TAG);
|
|
1503
|
-
template.innerHTML = createHtml(value);
|
|
1504
|
-
if (typeof value === "string" && options.cache) templates[value] = template;
|
|
1505
|
-
return template;
|
|
1506
|
-
}
|
|
1507
|
-
function getHtml(value) {
|
|
1508
|
-
return `${TEMPORARY_ELEMENT}${typeof value === "string" ? value : value.innerHTML}${TEMPORARY_ELEMENT}`;
|
|
1509
|
-
}
|
|
1510
|
-
function getNodes(value, options) {
|
|
1511
|
-
if (typeof value !== "string" && !(value instanceof HTMLTemplateElement)) return [];
|
|
1512
|
-
const template = getTemplate(value, options);
|
|
1513
|
-
return template == null ? [] : [...template.content.cloneNode(true).childNodes];
|
|
1514
|
-
}
|
|
1515
|
-
function getOptions(input) {
|
|
1516
|
-
const options = isPlainObject$1(input) ? input : {};
|
|
1517
|
-
options.cache = typeof options.cache === "boolean" ? options.cache : true;
|
|
1518
|
-
return options;
|
|
1519
|
-
}
|
|
1520
|
-
function getParser() {
|
|
1521
|
-
parser ??= new DOMParser();
|
|
1522
|
-
return parser;
|
|
1523
|
-
}
|
|
1524
|
-
function getTemplate(value, options) {
|
|
1525
|
-
if (value instanceof HTMLTemplateElement) return createTemplate(value, options);
|
|
1526
|
-
if (value.trim().length === 0) return;
|
|
1527
|
-
let template = templates[value];
|
|
1528
|
-
if (template != null) return template;
|
|
1529
|
-
const element = EXPRESSION_ID.test(value) ? document.querySelector(`#${value}`) : null;
|
|
1530
|
-
return createTemplate(element instanceof HTMLTemplateElement ? element : value, options);
|
|
1531
|
-
}
|
|
1532
|
-
var html = ((value, options) => {
|
|
1533
|
-
return getNodes(value, getOptions(options));
|
|
1534
|
-
});
|
|
1535
|
-
html.clear = () => {
|
|
1536
|
-
templates = {};
|
|
1537
|
-
};
|
|
1538
|
-
html.remove = (template) => {
|
|
1539
|
-
if (typeof template !== "string" || templates[template] == null) return;
|
|
1540
|
-
const keys = Object.keys(templates);
|
|
1541
|
-
const { length } = keys;
|
|
1542
|
-
const updated = {};
|
|
1543
|
-
for (let index = 0; index < length; index += 1) {
|
|
1544
|
-
const key = keys[index];
|
|
1545
|
-
if (key !== template) updated[key] = templates[key];
|
|
1546
|
-
}
|
|
1547
|
-
templates = updated;
|
|
1548
|
-
};
|
|
1549
|
-
var EXPRESSION_ID = /^[a-z][\w-]*$/i;
|
|
1550
|
-
var PARSE_TYPE_HTML = "text/html";
|
|
1551
|
-
var TEMPLATE_TAG = "template";
|
|
1552
|
-
var TEMPORARY_ELEMENT = "<toretto-temporary></toretto-temporary>";
|
|
1553
|
-
var parser;
|
|
1554
|
-
var templates = {};
|
|
1555
|
-
function getSupport() {
|
|
1556
|
-
if (window == null || navigator == null) return false;
|
|
1557
|
-
if ("matchMedia" in window) {
|
|
1558
|
-
const media = matchMedia?.("(pointer: coarse)");
|
|
1559
|
-
if (typeof media?.matches === "boolean" && media.matches) return true;
|
|
1560
|
-
}
|
|
1561
|
-
if ("ontouchstart" in window) return true;
|
|
1562
|
-
if (typeof navigator.maxTouchPoints === "number" && navigator.maxTouchPoints > 0) return true;
|
|
1563
|
-
if (typeof navigator.msMaxTouchPoints === "number" && navigator.msMaxTouchPoints > 0) return true;
|
|
1564
|
-
return false;
|
|
1565
|
-
}
|
|
1566
|
-
(() => {
|
|
1567
|
-
let support = getSupport();
|
|
1568
|
-
const instance = Object.create({
|
|
1569
|
-
get() {
|
|
1570
|
-
return support;
|
|
1571
|
-
},
|
|
1572
|
-
update() {
|
|
1573
|
-
support = getSupport();
|
|
1574
|
-
return support;
|
|
1575
|
-
}
|
|
1576
|
-
});
|
|
1577
|
-
Object.defineProperty(instance, "value", { get() {
|
|
1578
|
-
return support;
|
|
1579
|
-
} });
|
|
1580
|
-
return instance;
|
|
1581
|
-
})();
|
|
1582
1576
|
var EventManager = class {
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
this.listener = on(element, "click", (event) => {
|
|
1587
|
-
this.onClick(event);
|
|
1588
|
-
}, { passive: false });
|
|
1577
|
+
constructor(state) {
|
|
1578
|
+
this.state = state;
|
|
1579
|
+
mapped$1.set(state.element, this);
|
|
1589
1580
|
}
|
|
1590
1581
|
destroy() {
|
|
1591
|
-
this.
|
|
1592
|
-
|
|
1593
|
-
onClick(event) {
|
|
1594
|
-
const target = findAncestor(event, "[data-event]");
|
|
1595
|
-
if (!(target instanceof HTMLElement)) return;
|
|
1596
|
-
switch (target?.getAttribute("data-event")) {
|
|
1597
|
-
case "heading":
|
|
1598
|
-
this.onSort(event, target);
|
|
1599
|
-
break;
|
|
1600
|
-
case "row":
|
|
1601
|
-
this.managers.selection.handle(event, target);
|
|
1602
|
-
break;
|
|
1603
|
-
default: break;
|
|
1604
|
-
}
|
|
1582
|
+
mapped$1.delete(this.state.element);
|
|
1583
|
+
this.state = void 0;
|
|
1605
1584
|
}
|
|
1606
1585
|
onSort(event, target) {
|
|
1607
|
-
const { managers } = this;
|
|
1608
1586
|
const direction = target.getAttribute("data-sort-direction");
|
|
1609
1587
|
const field = target.getAttribute("data-field");
|
|
1610
|
-
if (field != null) managers.sort.toggle(event, field, direction);
|
|
1588
|
+
if (field != null) this.state.managers.sort.toggle(event, field, direction);
|
|
1611
1589
|
}
|
|
1612
1590
|
};
|
|
1591
|
+
function onClick(event) {
|
|
1592
|
+
const target = findAncestor(event, "[data-event]");
|
|
1593
|
+
const table = findAncestor(event, ".tabela");
|
|
1594
|
+
if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
|
|
1595
|
+
const manager = mapped$1.get(table);
|
|
1596
|
+
if (manager == null) return;
|
|
1597
|
+
switch (target?.getAttribute("data-event")) {
|
|
1598
|
+
case "group":
|
|
1599
|
+
manager.state.managers.group.handle(target);
|
|
1600
|
+
break;
|
|
1601
|
+
case "heading":
|
|
1602
|
+
manager.onSort(event, target);
|
|
1603
|
+
break;
|
|
1604
|
+
case "row":
|
|
1605
|
+
manager.state.managers.selection.handle(event, target);
|
|
1606
|
+
break;
|
|
1607
|
+
default: break;
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
function onKeydown(event) {
|
|
1611
|
+
const target = findAncestor(event, "[data-event]");
|
|
1612
|
+
const table = findAncestor(event, ".tabela");
|
|
1613
|
+
if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
|
|
1614
|
+
const manager = mapped$1.get(table);
|
|
1615
|
+
if (manager == null) return;
|
|
1616
|
+
switch (target?.getAttribute("data-event")) {
|
|
1617
|
+
case "body":
|
|
1618
|
+
manager.state.managers.navigation.handle(event);
|
|
1619
|
+
break;
|
|
1620
|
+
default: break;
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
const mapped$1 = /* @__PURE__ */ new WeakMap();
|
|
1624
|
+
on(document, "click", onClick);
|
|
1625
|
+
on(document, "keydown", onKeydown, { passive: false });
|
|
1613
1626
|
/**
|
|
1614
1627
|
* Clamp a number between a minimum and maximum value
|
|
1615
1628
|
* @param value Value to clamp
|
|
@@ -2014,8 +2027,8 @@ var FilterManager = class {
|
|
|
2014
2027
|
set: (items) => this.set(items)
|
|
2015
2028
|
});
|
|
2016
2029
|
items = {};
|
|
2017
|
-
constructor(
|
|
2018
|
-
this.
|
|
2030
|
+
constructor(state) {
|
|
2031
|
+
this.state = state;
|
|
2019
2032
|
}
|
|
2020
2033
|
add(item) {
|
|
2021
2034
|
if (this.items[item.field] == null) this.items[item.field] = [];
|
|
@@ -2031,16 +2044,21 @@ var FilterManager = class {
|
|
|
2031
2044
|
}
|
|
2032
2045
|
destroy() {
|
|
2033
2046
|
this.handlers = void 0;
|
|
2034
|
-
this.items =
|
|
2047
|
+
this.items = void 0;
|
|
2048
|
+
this.state = void 0;
|
|
2035
2049
|
}
|
|
2036
2050
|
filter() {
|
|
2037
|
-
const {
|
|
2051
|
+
const { state } = this;
|
|
2038
2052
|
const filtered = [];
|
|
2039
2053
|
const filters = Object.entries(this.items);
|
|
2040
|
-
const keysLength = managers.data.values.keys.original.length;
|
|
2054
|
+
const keysLength = state.managers.data.values.keys.original.length;
|
|
2041
2055
|
rowLoop: for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
2042
|
-
const key = managers.data.values.keys.original[keyIndex];
|
|
2043
|
-
|
|
2056
|
+
const key = state.managers.data.values.keys.original[keyIndex];
|
|
2057
|
+
if (key instanceof GroupComponent) {
|
|
2058
|
+
filtered.push(key);
|
|
2059
|
+
continue;
|
|
2060
|
+
}
|
|
2061
|
+
const row = state.managers.data.values.objects.mapped.get(key);
|
|
2044
2062
|
if (row == null) continue;
|
|
2045
2063
|
filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
|
|
2046
2064
|
const [field, items] = filters[filterIndex];
|
|
@@ -2053,9 +2071,9 @@ var FilterManager = class {
|
|
|
2053
2071
|
}
|
|
2054
2072
|
filtered.push(key);
|
|
2055
2073
|
}
|
|
2056
|
-
managers.data.values.keys.active = filtered;
|
|
2057
|
-
if (managers.sort.items.length > 0) managers.sort.sort();
|
|
2058
|
-
else managers.render.update(true, true);
|
|
2074
|
+
state.managers.data.values.keys.active = filtered;
|
|
2075
|
+
if (state.managers.sort.items.length > 0) state.managers.sort.sort();
|
|
2076
|
+
else state.managers.render.update(true, true);
|
|
2059
2077
|
}
|
|
2060
2078
|
remove(value) {
|
|
2061
2079
|
if (typeof value === "string") {
|
|
@@ -2093,6 +2111,123 @@ const comparators = {
|
|
|
2093
2111
|
"starts-with": (row, filter) => startsWith(getString(row), getString(filter), true)
|
|
2094
2112
|
};
|
|
2095
2113
|
const equalizer = equal.initialize({ ignoreCase: true });
|
|
2114
|
+
var GroupManager = class {
|
|
2115
|
+
collapsed = /* @__PURE__ */ new Set();
|
|
2116
|
+
enabled = false;
|
|
2117
|
+
field;
|
|
2118
|
+
items = [];
|
|
2119
|
+
order = {};
|
|
2120
|
+
constructor(state) {
|
|
2121
|
+
this.state = state;
|
|
2122
|
+
if (isNullableOrWhitespace(state.options.grouping)) return;
|
|
2123
|
+
this.enabled = true;
|
|
2124
|
+
this.field = state.options.grouping;
|
|
2125
|
+
}
|
|
2126
|
+
add(group) {
|
|
2127
|
+
this.set([...this.items, group]);
|
|
2128
|
+
}
|
|
2129
|
+
get(value) {
|
|
2130
|
+
return this.items.find((item) => item.value === value);
|
|
2131
|
+
}
|
|
2132
|
+
handle(button) {
|
|
2133
|
+
const key = button.dataset.key;
|
|
2134
|
+
const group = this.get(key);
|
|
2135
|
+
if (group == null) return;
|
|
2136
|
+
const { collapsed, items, state } = this;
|
|
2137
|
+
group.expanded = !group.expanded;
|
|
2138
|
+
const index = items.indexOf(group);
|
|
2139
|
+
let first = state.managers.data.values.keys.original.indexOf(items[index]) + 1;
|
|
2140
|
+
const last = items[index + 1] == null ? state.managers.data.keys.length - 1 : state.managers.data.values.keys.original.indexOf(items[index + 1]) - 1;
|
|
2141
|
+
for (; first <= last; first += 1) {
|
|
2142
|
+
const key = state.managers.data.values.keys.original[first];
|
|
2143
|
+
if (group.expanded) collapsed.delete(key);
|
|
2144
|
+
else collapsed.add(key);
|
|
2145
|
+
}
|
|
2146
|
+
state.managers.render.update(true, true);
|
|
2147
|
+
}
|
|
2148
|
+
remove(group) {
|
|
2149
|
+
this.set(this.items.filter((item) => item !== group));
|
|
2150
|
+
}
|
|
2151
|
+
set(items) {
|
|
2152
|
+
this.items = sort(items, (item) => item.label);
|
|
2153
|
+
this.order = toRecord(items, "value", (_, index) => index);
|
|
2154
|
+
}
|
|
2155
|
+
};
|
|
2156
|
+
function getKey(value) {
|
|
2157
|
+
if (typeof value === "number") return value;
|
|
2158
|
+
if (typeof value !== "string") return;
|
|
2159
|
+
return integerExpression.test(value) ? Number.parseInt(value, 10) : value;
|
|
2160
|
+
}
|
|
2161
|
+
const integerExpression = /^\d+$/;
|
|
2162
|
+
var NavigationManager = class {
|
|
2163
|
+
active;
|
|
2164
|
+
constructor(state) {
|
|
2165
|
+
this.state = state;
|
|
2166
|
+
}
|
|
2167
|
+
destroy() {
|
|
2168
|
+
this.state = void 0;
|
|
2169
|
+
}
|
|
2170
|
+
handle(event) {
|
|
2171
|
+
if (!allKeys.has(event.key)) return;
|
|
2172
|
+
event.preventDefault();
|
|
2173
|
+
const { components, id, managers } = this.state;
|
|
2174
|
+
const activeDescendant = components.body.elements.group.getAttribute("aria-activedescendant");
|
|
2175
|
+
const { keys } = managers.data;
|
|
2176
|
+
const { length } = keys;
|
|
2177
|
+
let next;
|
|
2178
|
+
if (isNullableOrWhitespace(activeDescendant)) next = getDefaultIndex(event.key, length);
|
|
2179
|
+
else next = getIndex(event, activeDescendant, id, keys);
|
|
2180
|
+
if (next != null) this.setActive(keys.at(next));
|
|
2181
|
+
}
|
|
2182
|
+
setActive(key, scroll) {
|
|
2183
|
+
const { components, managers, options } = this.state;
|
|
2184
|
+
this.active = key;
|
|
2185
|
+
const active = components.body.elements.group.querySelectorAll("[data-active=\"true\"]");
|
|
2186
|
+
for (const item of active) item.setAttribute("data-active", "false");
|
|
2187
|
+
const row = managers.row.get(key);
|
|
2188
|
+
if (row != null) {
|
|
2189
|
+
row.element?.setAttribute("data-active", "true");
|
|
2190
|
+
if (scroll ?? true) if (row.element == null) components.body.elements.group.scrollTo({
|
|
2191
|
+
top: managers.data.getIndex(key) * options.rowHeight,
|
|
2192
|
+
behavior: "smooth"
|
|
2193
|
+
});
|
|
2194
|
+
else row.element.scrollIntoView({ block: "nearest" });
|
|
2195
|
+
}
|
|
2196
|
+
components.body.elements.group.setAttribute("aria-activedescendant", row == null ? "" : `tabela_${this.state.id}_row_${key}`);
|
|
2197
|
+
}
|
|
2198
|
+
};
|
|
2199
|
+
function getDefaultIndex(key, max) {
|
|
2200
|
+
switch (true) {
|
|
2201
|
+
case negativeDefaultKeys.has(key): return -1;
|
|
2202
|
+
case key === "PageDown": return Math.min(9, max - 1);
|
|
2203
|
+
case key === "PageUp": return max < 10 ? 0 : max - 10;
|
|
2204
|
+
default: return 0;
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
function getIndex(event, active, id, keys) {
|
|
2208
|
+
const key = getKey(active.replace(`tabela_${id}_row_`, ""));
|
|
2209
|
+
if (key == null) return;
|
|
2210
|
+
if (absoluteKeys.has(event.key)) return event.key === "Home" ? 0 : keys.length - 1;
|
|
2211
|
+
return clamp(keys.indexOf(key) + getOffset(event.key), 0, keys.length - 1, true);
|
|
2212
|
+
}
|
|
2213
|
+
function getOffset(key) {
|
|
2214
|
+
switch (key) {
|
|
2215
|
+
case "ArrowDown": return 1;
|
|
2216
|
+
case "ArrowUp": return -1;
|
|
2217
|
+
case "PageDown": return 10;
|
|
2218
|
+
case "PageUp": return -10;
|
|
2219
|
+
default: return 0;
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
const absoluteKeys = new Set(["End", "Home"]);
|
|
2223
|
+
const arrowKeys = new Set(["ArrowDown", "ArrowUp"]);
|
|
2224
|
+
const negativeDefaultKeys = new Set(["ArrowUp", "End"]);
|
|
2225
|
+
const pageKeys = new Set(["PageDown", "PageUp"]);
|
|
2226
|
+
const allKeys = new Set([
|
|
2227
|
+
...absoluteKeys,
|
|
2228
|
+
...arrowKeys,
|
|
2229
|
+
...pageKeys
|
|
2230
|
+
]);
|
|
2096
2231
|
function removeRow(pool, row) {
|
|
2097
2232
|
if (row.element != null) {
|
|
2098
2233
|
row.element.innerHTML = "";
|
|
@@ -2102,27 +2237,30 @@ function removeRow(pool, row) {
|
|
|
2102
2237
|
}
|
|
2103
2238
|
row.cells = {};
|
|
2104
2239
|
}
|
|
2105
|
-
function renderRow(
|
|
2106
|
-
const element = row.element ?? managers.render.pool.rows.shift() ?? createRow();
|
|
2240
|
+
function renderRow(state, row) {
|
|
2241
|
+
const element = row.element ?? state.managers.render.pool.rows.shift() ?? createRow();
|
|
2107
2242
|
row.element = element;
|
|
2108
2243
|
element.innerHTML = "";
|
|
2109
|
-
const selected = managers.selection.items.has(row.key);
|
|
2244
|
+
const selected = state.managers.selection.items.has(row.key);
|
|
2245
|
+
const key = String(row.key);
|
|
2110
2246
|
setAttributes(element, {
|
|
2111
2247
|
"aria-selected": String(selected),
|
|
2248
|
+
"data-active": String(state.managers.navigation.active === row.key),
|
|
2112
2249
|
"data-event": "row",
|
|
2113
|
-
"data-key":
|
|
2250
|
+
"data-key": key,
|
|
2251
|
+
id: `tabela_${state.id}_row_${key}`
|
|
2114
2252
|
});
|
|
2115
2253
|
element.classList.add("tabela__row--body");
|
|
2116
2254
|
if (selected) element.classList.add("tabela__row--selected");
|
|
2117
2255
|
else element.classList.remove("tabela__row--selected");
|
|
2118
|
-
const columns = managers.column.items;
|
|
2256
|
+
const columns = state.managers.column.items;
|
|
2119
2257
|
const { length } = columns;
|
|
2120
|
-
const data = managers.data.values.objects.mapped.get(row.key);
|
|
2258
|
+
const data = state.managers.data.values.objects.mapped.get(row.key);
|
|
2121
2259
|
if (data == null) return;
|
|
2122
2260
|
for (let index = 0; index < length; index += 1) {
|
|
2123
2261
|
const { options } = columns[index];
|
|
2124
|
-
managers.render.pool.cells[options.field] ??= [];
|
|
2125
|
-
const cell = managers.render.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
|
|
2262
|
+
state.managers.render.pool.cells[options.field] ??= [];
|
|
2263
|
+
const cell = state.managers.render.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
|
|
2126
2264
|
cell.textContent = String(data[options.field]);
|
|
2127
2265
|
row.cells[options.field] = cell;
|
|
2128
2266
|
element.append(cell);
|
|
@@ -2135,18 +2273,149 @@ var RowComponent = class {
|
|
|
2135
2273
|
this.key = key;
|
|
2136
2274
|
}
|
|
2137
2275
|
};
|
|
2276
|
+
function getRange(state, down) {
|
|
2277
|
+
const { components, managers, options } = state;
|
|
2278
|
+
const { clientHeight, scrollTop } = components.body.elements.group;
|
|
2279
|
+
const { keys } = managers.data;
|
|
2280
|
+
const first = Math.floor(scrollTop / options.rowHeight);
|
|
2281
|
+
const last = Math.min(keys.length - managers.group.collapsed.size - 1, Math.ceil((scrollTop + clientHeight) / options.rowHeight) - 1);
|
|
2282
|
+
const before = Math.ceil(clientHeight / options.rowHeight) * (down ? 1 : 2);
|
|
2283
|
+
const after = Math.ceil(clientHeight / options.rowHeight) * (down ? 2 : 1);
|
|
2284
|
+
const start = Math.max(0, first - before);
|
|
2285
|
+
return {
|
|
2286
|
+
end: Math.min(keys.length - managers.group.collapsed.size - 1, last + after),
|
|
2287
|
+
start
|
|
2288
|
+
};
|
|
2289
|
+
}
|
|
2290
|
+
function onScroll() {
|
|
2291
|
+
const { state } = this;
|
|
2292
|
+
if (!state.active) {
|
|
2293
|
+
requestAnimationFrame(() => {
|
|
2294
|
+
const top = state.components.body.elements.group.scrollTop;
|
|
2295
|
+
this.update(top > state.top);
|
|
2296
|
+
state.active = false;
|
|
2297
|
+
state.top = top;
|
|
2298
|
+
});
|
|
2299
|
+
state.active = true;
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
var RenderManager = class {
|
|
2303
|
+
fragment;
|
|
2304
|
+
listener;
|
|
2305
|
+
pool = {
|
|
2306
|
+
cells: {},
|
|
2307
|
+
rows: []
|
|
2308
|
+
};
|
|
2309
|
+
state;
|
|
2310
|
+
visible = /* @__PURE__ */ new Map();
|
|
2311
|
+
constructor(state) {
|
|
2312
|
+
this.listener = on(state.components.body.elements.group, "scroll", onScroll.bind(this));
|
|
2313
|
+
this.state = {
|
|
2314
|
+
...state,
|
|
2315
|
+
active: false,
|
|
2316
|
+
top: 0
|
|
2317
|
+
};
|
|
2318
|
+
}
|
|
2319
|
+
destroy() {
|
|
2320
|
+
const { listener, pool, visible } = this;
|
|
2321
|
+
listener();
|
|
2322
|
+
visible.clear();
|
|
2323
|
+
pool.cells = {};
|
|
2324
|
+
pool.rows = [];
|
|
2325
|
+
this.fragment = void 0;
|
|
2326
|
+
this.listener = void 0;
|
|
2327
|
+
this.pool = void 0;
|
|
2328
|
+
this.state = void 0;
|
|
2329
|
+
this.visible = void 0;
|
|
2330
|
+
}
|
|
2331
|
+
removeCells(fields) {
|
|
2332
|
+
const { pool, state, visible } = this;
|
|
2333
|
+
const { length } = fields;
|
|
2334
|
+
for (let index = 0; index < length; index += 1) delete pool.cells[fields[index]];
|
|
2335
|
+
for (const [, key] of visible) {
|
|
2336
|
+
if (key instanceof GroupComponent) continue;
|
|
2337
|
+
const row = state.managers.row.get(key);
|
|
2338
|
+
if (row == null || row.element == null) continue;
|
|
2339
|
+
for (let index = 0; index < length; index += 1) {
|
|
2340
|
+
row.cells[fields[index]].innerHTML = "";
|
|
2341
|
+
row.cells[fields[index]].remove();
|
|
2342
|
+
delete row.cells[fields[index]];
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
getFragment() {
|
|
2347
|
+
this.fragment ??= document.createDocumentFragment();
|
|
2348
|
+
this.fragment.replaceChildren();
|
|
2349
|
+
return this.fragment;
|
|
2350
|
+
}
|
|
2351
|
+
update(down, rerender) {
|
|
2352
|
+
const { state, pool, visible } = this;
|
|
2353
|
+
const { components, managers, options } = state;
|
|
2354
|
+
components.body.elements.faker.style.height = `${(managers.data.size - managers.group.collapsed.size) * options.rowHeight}px`;
|
|
2355
|
+
const indices = /* @__PURE__ */ new Set();
|
|
2356
|
+
const range = getRange(state, down);
|
|
2357
|
+
for (let index = range.start; index <= range.end; index += 1) indices.add(index);
|
|
2358
|
+
let remove = rerender ?? false;
|
|
2359
|
+
for (const [index, key] of visible) {
|
|
2360
|
+
if (key instanceof GroupComponent) {
|
|
2361
|
+
if (remove || !indices.has(index)) {
|
|
2362
|
+
visible.delete(index);
|
|
2363
|
+
key.element?.remove();
|
|
2364
|
+
}
|
|
2365
|
+
continue;
|
|
2366
|
+
}
|
|
2367
|
+
const row = managers.row.get(key);
|
|
2368
|
+
if (remove || row == null || !indices.has(index) || managers.group.collapsed.has(key)) {
|
|
2369
|
+
visible.delete(index);
|
|
2370
|
+
if (row != null) removeRow(pool, row);
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
const fragment = this.getFragment();
|
|
2374
|
+
const { keys } = managers.data;
|
|
2375
|
+
let count = 0;
|
|
2376
|
+
let offset = 0;
|
|
2377
|
+
for (let index = range.start; index <= range.end + offset; index += 1) {
|
|
2378
|
+
if (visible.has(index)) continue;
|
|
2379
|
+
const key = keys[index];
|
|
2380
|
+
if (key instanceof GroupComponent) {
|
|
2381
|
+
count += 1;
|
|
2382
|
+
renderGroup(state, key);
|
|
2383
|
+
visible.set(index, key);
|
|
2384
|
+
if (key.element != null) {
|
|
2385
|
+
key.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
|
|
2386
|
+
fragment.append(key.element);
|
|
2387
|
+
}
|
|
2388
|
+
continue;
|
|
2389
|
+
}
|
|
2390
|
+
const row = managers.row.get(key);
|
|
2391
|
+
if (row == null) continue;
|
|
2392
|
+
if (managers.group.collapsed.has(key)) {
|
|
2393
|
+
offset += 1;
|
|
2394
|
+
continue;
|
|
2395
|
+
}
|
|
2396
|
+
count += 1;
|
|
2397
|
+
renderRow(state, row);
|
|
2398
|
+
visible.set(index, key);
|
|
2399
|
+
if (row.element != null) {
|
|
2400
|
+
row.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
|
|
2401
|
+
fragment.append(row.element);
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
if (count > 0) components.body.elements.group[down ? "append" : "prepend"](fragment);
|
|
2405
|
+
}
|
|
2406
|
+
};
|
|
2138
2407
|
var RowManager = class {
|
|
2139
2408
|
components = /* @__PURE__ */ new Map();
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
this.managers = managers;
|
|
2143
|
-
this.height = rowHeight;
|
|
2409
|
+
constructor(state) {
|
|
2410
|
+
this.state = state;
|
|
2144
2411
|
}
|
|
2145
2412
|
destroy() {
|
|
2146
2413
|
const components = [...this.components.values()];
|
|
2147
2414
|
const { length } = components;
|
|
2148
|
-
for (let index = 0; index < length; index += 1) removeRow(this.managers.render.pool, components[index]);
|
|
2415
|
+
for (let index = 0; index < length; index += 1) removeRow(this.state.managers.render.pool, components[index]);
|
|
2149
2416
|
this.components.clear();
|
|
2417
|
+
this.components = void 0;
|
|
2418
|
+
this.state = void 0;
|
|
2150
2419
|
}
|
|
2151
2420
|
get(key) {
|
|
2152
2421
|
let row = this.components.get(key);
|
|
@@ -2162,38 +2431,44 @@ var RowManager = class {
|
|
|
2162
2431
|
remove(key) {
|
|
2163
2432
|
const row = this.components.get(key);
|
|
2164
2433
|
if (row != null) {
|
|
2165
|
-
removeRow(this.managers.render.pool, row);
|
|
2434
|
+
removeRow(this.state.managers.render.pool, row);
|
|
2166
2435
|
this.components.delete(key);
|
|
2167
2436
|
}
|
|
2168
2437
|
}
|
|
2169
2438
|
update(key) {
|
|
2170
2439
|
const row = this.components.get(key);
|
|
2171
|
-
if (row != null) renderRow(this.
|
|
2440
|
+
if (row != null) renderRow(this.state, row);
|
|
2172
2441
|
}
|
|
2173
2442
|
};
|
|
2174
|
-
function getKey(value) {
|
|
2175
|
-
if (typeof value === "number") return value;
|
|
2176
|
-
if (typeof value !== "string") return;
|
|
2177
|
-
return integerExpression.test(value) ? Number.parseInt(value, 10) : value;
|
|
2178
|
-
}
|
|
2179
|
-
const integerExpression = /^\d+$/;
|
|
2180
2443
|
const dragStyling = toggleStyles(document.body, {
|
|
2181
2444
|
userSelect: "none",
|
|
2182
2445
|
webkitUserSelect: "none"
|
|
2183
2446
|
});
|
|
2184
2447
|
var SelectionManager = class {
|
|
2185
2448
|
handlers = Object.freeze({
|
|
2449
|
+
add: (keys) => this.add(keys),
|
|
2186
2450
|
clear: () => this.clear(),
|
|
2187
|
-
|
|
2188
|
-
|
|
2451
|
+
remove: (keys) => this.remove(keys),
|
|
2452
|
+
set: (keys) => this.set(keys),
|
|
2189
2453
|
toggle: () => this.toggle()
|
|
2190
2454
|
});
|
|
2191
2455
|
items = /* @__PURE__ */ new Set();
|
|
2192
2456
|
last;
|
|
2193
|
-
constructor(
|
|
2194
|
-
this.
|
|
2195
|
-
|
|
2196
|
-
|
|
2457
|
+
constructor(state) {
|
|
2458
|
+
this.state = state;
|
|
2459
|
+
mapped.set(state.element, this);
|
|
2460
|
+
}
|
|
2461
|
+
add(keys) {
|
|
2462
|
+
const { length } = keys;
|
|
2463
|
+
let update = false;
|
|
2464
|
+
for (let index = 0; index < length; index += 1) {
|
|
2465
|
+
const key = keys[index];
|
|
2466
|
+
if (!this.items.has(key)) {
|
|
2467
|
+
this.items.add(key);
|
|
2468
|
+
update = true;
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
if (update) this.update([]);
|
|
2197
2472
|
}
|
|
2198
2473
|
clear() {
|
|
2199
2474
|
if (this.items.size === 0) return;
|
|
@@ -2201,70 +2476,60 @@ var SelectionManager = class {
|
|
|
2201
2476
|
this.items.clear();
|
|
2202
2477
|
this.update(removed);
|
|
2203
2478
|
}
|
|
2204
|
-
deselect(keys) {
|
|
2205
|
-
const { length } = keys;
|
|
2206
|
-
const removed = [];
|
|
2207
|
-
for (let index = 0; index < length; index += 1) {
|
|
2208
|
-
const key = keys[index];
|
|
2209
|
-
if (this.items.delete(key)) removed.push(key);
|
|
2210
|
-
}
|
|
2211
|
-
if (removed.length > 0) this.update(removed);
|
|
2212
|
-
}
|
|
2213
2479
|
destroy() {
|
|
2214
|
-
mapped.delete(this.element);
|
|
2480
|
+
mapped.delete(this.state.element);
|
|
2215
2481
|
this.handlers = void 0;
|
|
2216
|
-
this.element = void 0;
|
|
2217
2482
|
this.items = void 0;
|
|
2483
|
+
this.last = void 0;
|
|
2484
|
+
this.state = void 0;
|
|
2218
2485
|
}
|
|
2219
2486
|
handle(event, target) {
|
|
2220
2487
|
const key = getKey(target.getAttribute("data-key"));
|
|
2221
2488
|
if (key == null) return;
|
|
2222
2489
|
const { items } = this;
|
|
2223
2490
|
if (event.shiftKey) {
|
|
2224
|
-
if (this.last == null)
|
|
2225
|
-
|
|
2226
|
-
return;
|
|
2227
|
-
}
|
|
2228
|
-
this.range(this.last, key);
|
|
2229
|
-
this.last = key;
|
|
2491
|
+
if (this.last == null) this.state.managers.navigation.setActive(key, false);
|
|
2492
|
+
else this.range(this.last, key);
|
|
2230
2493
|
return;
|
|
2231
2494
|
}
|
|
2232
2495
|
this.last = key;
|
|
2496
|
+
this.state.managers.navigation.setActive(key, false);
|
|
2233
2497
|
if (event.ctrlKey || event.metaKey) {
|
|
2234
|
-
if (items.has(key)) this.
|
|
2235
|
-
else this.
|
|
2498
|
+
if (items.has(key)) this.remove([key]);
|
|
2499
|
+
else this.add([key]);
|
|
2236
2500
|
return;
|
|
2237
2501
|
}
|
|
2238
|
-
|
|
2239
|
-
else this.set([key]);
|
|
2240
|
-
else this.set([key]);
|
|
2502
|
+
this.set([key]);
|
|
2241
2503
|
}
|
|
2242
2504
|
range(from, to) {
|
|
2505
|
+
const { state } = this;
|
|
2243
2506
|
const keyed = isKey(from) && isKey(to);
|
|
2244
2507
|
const fromKey = keyed ? from : getKey(from.getAttribute("data-key"));
|
|
2245
2508
|
const toKey = keyed ? to : getKey(to.getAttribute("data-key"));
|
|
2246
2509
|
if (fromKey === toKey) return;
|
|
2247
|
-
const keys =
|
|
2248
|
-
const fromIndex =
|
|
2249
|
-
const toIndex =
|
|
2510
|
+
const { keys } = state.managers.data;
|
|
2511
|
+
const fromIndex = state.managers.data.getIndex(fromKey);
|
|
2512
|
+
const toIndex = state.managers.data.getIndex(toKey);
|
|
2250
2513
|
if (fromIndex === -1 || toIndex === -1) return;
|
|
2251
2514
|
const [start, end] = fromIndex < toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
|
|
2252
2515
|
const selected = [];
|
|
2253
|
-
for (let index = start; index <= end; index += 1)
|
|
2254
|
-
|
|
2516
|
+
for (let index = start; index <= end; index += 1) {
|
|
2517
|
+
const key = keys[index];
|
|
2518
|
+
if (!(key instanceof GroupComponent)) selected.push(key);
|
|
2519
|
+
}
|
|
2520
|
+
if (keyed) this.add(selected);
|
|
2255
2521
|
else this.set(selected);
|
|
2522
|
+
this.last = toKey;
|
|
2523
|
+
this.state.managers.navigation.setActive(toKey, false);
|
|
2256
2524
|
}
|
|
2257
|
-
|
|
2525
|
+
remove(keys) {
|
|
2258
2526
|
const { length } = keys;
|
|
2259
|
-
|
|
2527
|
+
const removed = [];
|
|
2260
2528
|
for (let index = 0; index < length; index += 1) {
|
|
2261
2529
|
const key = keys[index];
|
|
2262
|
-
if (
|
|
2263
|
-
this.items.add(key);
|
|
2264
|
-
update = true;
|
|
2265
|
-
}
|
|
2530
|
+
if (this.items.delete(key)) removed.push(key);
|
|
2266
2531
|
}
|
|
2267
|
-
if (
|
|
2532
|
+
if (removed.length > 0) this.update(removed);
|
|
2268
2533
|
}
|
|
2269
2534
|
set(keys) {
|
|
2270
2535
|
const { items } = this;
|
|
@@ -2275,10 +2540,10 @@ var SelectionManager = class {
|
|
|
2275
2540
|
this.update(removed);
|
|
2276
2541
|
}
|
|
2277
2542
|
toggle() {
|
|
2278
|
-
const { items,
|
|
2279
|
-
const
|
|
2280
|
-
if (items.size ===
|
|
2281
|
-
else this.
|
|
2543
|
+
const { items, state } = this;
|
|
2544
|
+
const { keys } = state.managers.data;
|
|
2545
|
+
if (items.size === keys.length - state.managers.group.items.length) this.clear();
|
|
2546
|
+
else this.set(keys.filter((key) => !(key instanceof GroupComponent)));
|
|
2282
2547
|
}
|
|
2283
2548
|
update(removed) {
|
|
2284
2549
|
const items = [...removed.map((key) => ({
|
|
@@ -2291,7 +2556,7 @@ var SelectionManager = class {
|
|
|
2291
2556
|
const { length } = items;
|
|
2292
2557
|
for (let index = 0; index < length; index += 1) {
|
|
2293
2558
|
const { key, removed } = items[index];
|
|
2294
|
-
const row = this.managers.row.get(key);
|
|
2559
|
+
const row = this.state.managers.row.get(key);
|
|
2295
2560
|
if (row == null || row.element == null) continue;
|
|
2296
2561
|
setAttribute(row.element, "aria-selected", String(!removed));
|
|
2297
2562
|
if (removed) row.element.classList.remove("tabela__row--selected");
|
|
@@ -2364,199 +2629,6 @@ on(document, "keyup", onShiftUp);
|
|
|
2364
2629
|
on(document, "mousedown", onMouseDown);
|
|
2365
2630
|
on(document, "mousemove", onMouseMove);
|
|
2366
2631
|
on(document, "mouseup", onMouseUp);
|
|
2367
|
-
var SortManager = class {
|
|
2368
|
-
handlers = Object.freeze({
|
|
2369
|
-
add: (field, direction) => this.add(field, direction),
|
|
2370
|
-
flip: (field) => this.flip(field),
|
|
2371
|
-
clear: () => this.clear(),
|
|
2372
|
-
remove: (field) => this.remove(field),
|
|
2373
|
-
set: (items) => this.set(items)
|
|
2374
|
-
});
|
|
2375
|
-
items = [];
|
|
2376
|
-
constructor(managers) {
|
|
2377
|
-
this.managers = managers;
|
|
2378
|
-
}
|
|
2379
|
-
add(field, direction) {
|
|
2380
|
-
if (this.items.findIndex((item) => item.key === field) > -1) return;
|
|
2381
|
-
this.items.push({
|
|
2382
|
-
key: field,
|
|
2383
|
-
direction: direction ?? "ascending"
|
|
2384
|
-
});
|
|
2385
|
-
this.sort();
|
|
2386
|
-
}
|
|
2387
|
-
addOrSet(event, field) {
|
|
2388
|
-
if (event.ctrlKey || event.metaKey) this.add(field);
|
|
2389
|
-
else this.set([{
|
|
2390
|
-
field,
|
|
2391
|
-
direction: "ascending"
|
|
2392
|
-
}]);
|
|
2393
|
-
}
|
|
2394
|
-
clear() {
|
|
2395
|
-
if (this.items.length > 0) {
|
|
2396
|
-
this.items.length = 0;
|
|
2397
|
-
this.sort();
|
|
2398
|
-
}
|
|
2399
|
-
}
|
|
2400
|
-
destroy() {
|
|
2401
|
-
this.handlers = void 0;
|
|
2402
|
-
this.items.length = 0;
|
|
2403
|
-
}
|
|
2404
|
-
flip(field) {
|
|
2405
|
-
const item = this.items.find((item) => item.key === field);
|
|
2406
|
-
if (item == null) return;
|
|
2407
|
-
item.direction = item.direction === "ascending" ? "descending" : "ascending";
|
|
2408
|
-
this.sort();
|
|
2409
|
-
}
|
|
2410
|
-
remove(field) {
|
|
2411
|
-
const index = this.items.findIndex((item) => item.key === field);
|
|
2412
|
-
if (index > -1) {
|
|
2413
|
-
this.items.splice(index, 1);
|
|
2414
|
-
this.sort();
|
|
2415
|
-
}
|
|
2416
|
-
}
|
|
2417
|
-
removeOrClear(event, field) {
|
|
2418
|
-
if (event.ctrlKey || event.metaKey) this.remove(field);
|
|
2419
|
-
else this.clear();
|
|
2420
|
-
}
|
|
2421
|
-
set(items) {
|
|
2422
|
-
this.items.splice(0, this.items.length, ...items.map((item) => ({
|
|
2423
|
-
key: item.field,
|
|
2424
|
-
direction: item.direction
|
|
2425
|
-
})));
|
|
2426
|
-
this.sort();
|
|
2427
|
-
}
|
|
2428
|
-
sort() {
|
|
2429
|
-
const { items, managers } = this;
|
|
2430
|
-
const { length } = managers.column.items;
|
|
2431
|
-
for (let index = 0; index < length; index += 1) {
|
|
2432
|
-
const column = managers.column.items[index];
|
|
2433
|
-
const sorterIndex = items.findIndex((item) => item.key === column.options.field);
|
|
2434
|
-
const sorterItem = items[sorterIndex];
|
|
2435
|
-
setAttributes(column.elements.wrapper, {
|
|
2436
|
-
"aria-sort": sorterItem == null ? "none" : items.length > 1 ? "other" : sorterItem.direction,
|
|
2437
|
-
"data-sort-direction": sorterItem == null ? void 0 : sorterItem.direction
|
|
2438
|
-
});
|
|
2439
|
-
setAttribute(column.elements.sorter, "data-sort-position", sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
|
|
2440
|
-
}
|
|
2441
|
-
managers.data.values.keys.active = items.length === 0 ? void 0 : sort(managers.data.values.keys.active?.map((key) => managers.data.values.objects.mapped.get(key)) ?? managers.data.values.objects.array, items).map((row) => row[managers.data.field]);
|
|
2442
|
-
managers.render.update(true, true);
|
|
2443
|
-
}
|
|
2444
|
-
toggle(event, field, direction) {
|
|
2445
|
-
switch (direction) {
|
|
2446
|
-
case "ascending":
|
|
2447
|
-
this.flip(field);
|
|
2448
|
-
return;
|
|
2449
|
-
case "descending":
|
|
2450
|
-
this.removeOrClear(event, field);
|
|
2451
|
-
return;
|
|
2452
|
-
default:
|
|
2453
|
-
this.addOrSet(event, field);
|
|
2454
|
-
return;
|
|
2455
|
-
}
|
|
2456
|
-
}
|
|
2457
|
-
};
|
|
2458
|
-
function getRange(down) {
|
|
2459
|
-
const { components, managers } = this;
|
|
2460
|
-
const { clientHeight, scrollTop } = components.body.elements.group;
|
|
2461
|
-
const first = Math.floor(scrollTop / managers.row.height);
|
|
2462
|
-
const last = Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, Math.ceil((scrollTop + clientHeight) / managers.row.height) - 1);
|
|
2463
|
-
const before = Math.ceil(clientHeight / managers.row.height) * (down ? 1 : 2);
|
|
2464
|
-
const after = Math.ceil(clientHeight / managers.row.height) * (down ? 2 : 1);
|
|
2465
|
-
const start = Math.max(0, first - before);
|
|
2466
|
-
return {
|
|
2467
|
-
end: Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, last + after),
|
|
2468
|
-
start
|
|
2469
|
-
};
|
|
2470
|
-
}
|
|
2471
|
-
function onScroll() {
|
|
2472
|
-
if (!this.state.active) {
|
|
2473
|
-
requestAnimationFrame(() => {
|
|
2474
|
-
const top = this.components.body.elements.group.scrollTop;
|
|
2475
|
-
this.update(top > this.state.top);
|
|
2476
|
-
this.state.active = false;
|
|
2477
|
-
this.state.top = top;
|
|
2478
|
-
});
|
|
2479
|
-
this.state.active = true;
|
|
2480
|
-
}
|
|
2481
|
-
}
|
|
2482
|
-
var RenderManager = class {
|
|
2483
|
-
fragment;
|
|
2484
|
-
listener;
|
|
2485
|
-
pool = {
|
|
2486
|
-
cells: {},
|
|
2487
|
-
rows: []
|
|
2488
|
-
};
|
|
2489
|
-
state = {
|
|
2490
|
-
active: false,
|
|
2491
|
-
top: 0
|
|
2492
|
-
};
|
|
2493
|
-
visible = /* @__PURE__ */ new Map();
|
|
2494
|
-
constructor(managers, components) {
|
|
2495
|
-
this.managers = managers;
|
|
2496
|
-
this.components = components;
|
|
2497
|
-
this.listener = on(components.body.elements.group, "scroll", onScroll.bind(this));
|
|
2498
|
-
}
|
|
2499
|
-
destroy() {
|
|
2500
|
-
const { listener, pool, visible } = this;
|
|
2501
|
-
listener();
|
|
2502
|
-
visible.clear();
|
|
2503
|
-
pool.cells = {};
|
|
2504
|
-
pool.rows = [];
|
|
2505
|
-
this.listener = void 0;
|
|
2506
|
-
this.visible = void 0;
|
|
2507
|
-
}
|
|
2508
|
-
removeCells(fields) {
|
|
2509
|
-
const { managers, pool, visible } = this;
|
|
2510
|
-
const { length } = fields;
|
|
2511
|
-
for (let index = 0; index < length; index += 1) delete pool.cells[fields[index]];
|
|
2512
|
-
for (const [, key] of visible) {
|
|
2513
|
-
const row = managers.row.get(key);
|
|
2514
|
-
if (row == null || row.element == null) continue;
|
|
2515
|
-
for (let index = 0; index < length; index += 1) {
|
|
2516
|
-
row.cells[fields[index]].innerHTML = "";
|
|
2517
|
-
row.cells[fields[index]].remove();
|
|
2518
|
-
delete row.cells[fields[index]];
|
|
2519
|
-
}
|
|
2520
|
-
}
|
|
2521
|
-
}
|
|
2522
|
-
getFragment() {
|
|
2523
|
-
this.fragment ??= document.createDocumentFragment();
|
|
2524
|
-
this.fragment.replaceChildren();
|
|
2525
|
-
return this.fragment;
|
|
2526
|
-
}
|
|
2527
|
-
update(down, rerender) {
|
|
2528
|
-
const { components, managers, pool, visible } = this;
|
|
2529
|
-
components.body.elements.faker.style.height = `${managers.data.size * managers.row.height}px`;
|
|
2530
|
-
const indices = /* @__PURE__ */ new Set();
|
|
2531
|
-
const range = getRange.call(this, down);
|
|
2532
|
-
for (let index = range.start; index <= range.end; index += 1) indices.add(index);
|
|
2533
|
-
let remove = rerender ?? false;
|
|
2534
|
-
for (const [index, key] of visible) {
|
|
2535
|
-
const row = managers.row.get(key);
|
|
2536
|
-
if (remove || row == null || !indices.has(index)) {
|
|
2537
|
-
visible.delete(index);
|
|
2538
|
-
if (row != null) removeRow(pool, row);
|
|
2539
|
-
}
|
|
2540
|
-
}
|
|
2541
|
-
const fragment = this.getFragment();
|
|
2542
|
-
const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
|
|
2543
|
-
let count = 0;
|
|
2544
|
-
for (let index = range.start; index <= range.end; index += 1) {
|
|
2545
|
-
if (visible.has(index)) continue;
|
|
2546
|
-
const key = keys[index];
|
|
2547
|
-
const row = managers.row.get(key);
|
|
2548
|
-
if (row == null) continue;
|
|
2549
|
-
count += 1;
|
|
2550
|
-
renderRow(managers, row);
|
|
2551
|
-
visible.set(index, key);
|
|
2552
|
-
if (row.element != null) {
|
|
2553
|
-
row.element.style.transform = `translateY(${index * managers.row.height}px)`;
|
|
2554
|
-
fragment.append(row.element);
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
if (count > 0) components.body.elements.group[down ? "append" : "prepend"](fragment);
|
|
2558
|
-
}
|
|
2559
|
-
};
|
|
2560
2632
|
var Tabela = class {
|
|
2561
2633
|
#components = {
|
|
2562
2634
|
header: void 0,
|
|
@@ -2564,12 +2636,15 @@ var Tabela = class {
|
|
|
2564
2636
|
footer: void 0
|
|
2565
2637
|
};
|
|
2566
2638
|
#element;
|
|
2639
|
+
#id = getId();
|
|
2567
2640
|
#key;
|
|
2568
2641
|
#managers = {
|
|
2569
2642
|
column: void 0,
|
|
2570
2643
|
data: void 0,
|
|
2571
2644
|
event: void 0,
|
|
2572
2645
|
filter: void 0,
|
|
2646
|
+
group: void 0,
|
|
2647
|
+
navigation: void 0,
|
|
2573
2648
|
render: void 0,
|
|
2574
2649
|
row: void 0,
|
|
2575
2650
|
selection: void 0,
|
|
@@ -2592,14 +2667,24 @@ var Tabela = class {
|
|
|
2592
2667
|
this.#components.header = new HeaderComponent();
|
|
2593
2668
|
this.#components.body = new BodyComponent();
|
|
2594
2669
|
this.#components.footer = new FooterComponent();
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2670
|
+
const state = {
|
|
2671
|
+
element,
|
|
2672
|
+
options,
|
|
2673
|
+
components: this.#components,
|
|
2674
|
+
id: this.#id,
|
|
2675
|
+
key: this.#key,
|
|
2676
|
+
managers: this.#managers
|
|
2677
|
+
};
|
|
2678
|
+
this.#managers.column = new ColumnManager(state);
|
|
2679
|
+
this.#managers.data = new DataManager(state);
|
|
2680
|
+
this.#managers.event = new EventManager(state);
|
|
2681
|
+
this.#managers.filter = new FilterManager(state);
|
|
2682
|
+
this.#managers.group = new GroupManager(state);
|
|
2683
|
+
this.#managers.navigation = new NavigationManager(state);
|
|
2684
|
+
this.#managers.render = new RenderManager(state);
|
|
2685
|
+
this.#managers.row = new RowManager(state);
|
|
2686
|
+
this.#managers.selection = new SelectionManager(state);
|
|
2687
|
+
this.#managers.sort = new SortManager(state);
|
|
2603
2688
|
element.append(this.#components.header.elements.group, this.#components.body.elements.group, this.#components.footer.elements.group);
|
|
2604
2689
|
this.#managers.data.set(options.data);
|
|
2605
2690
|
this.data = this.#managers.data.handlers;
|
|
@@ -2620,6 +2705,7 @@ var Tabela = class {
|
|
|
2620
2705
|
managers.filter.destroy();
|
|
2621
2706
|
managers.render.destroy();
|
|
2622
2707
|
managers.row.destroy();
|
|
2708
|
+
managers.selection.destroy();
|
|
2623
2709
|
managers.sort.destroy();
|
|
2624
2710
|
element.innerHTML = "";
|
|
2625
2711
|
element.role = "";
|
|
@@ -2629,6 +2715,11 @@ var Tabela = class {
|
|
|
2629
2715
|
this.#element = void 0;
|
|
2630
2716
|
}
|
|
2631
2717
|
};
|
|
2718
|
+
function getId() {
|
|
2719
|
+
id += 1;
|
|
2720
|
+
return id;
|
|
2721
|
+
}
|
|
2722
|
+
let id = 0;
|
|
2632
2723
|
function tabela(element, options) {
|
|
2633
2724
|
return new Tabela(element, options);
|
|
2634
2725
|
}
|