@oscarpalmer/tabela 0.7.0 → 0.9.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 -1
- package/dist/components/column.component.js +29 -9
- package/dist/components/header.component.js +1 -1
- package/dist/helpers/dom.helpers.js +6 -4
- package/dist/managers/column.manager.js +6 -1
- package/dist/managers/data.manager.js +15 -10
- package/dist/managers/event.manager.js +30 -0
- package/dist/managers/filter.manager.js +92 -0
- package/dist/managers/row.manager.js +9 -2
- package/dist/managers/sort.manager.js +94 -0
- package/dist/managers/virtualization.manager.js +4 -2
- package/dist/models/filter.model.js +0 -0
- package/dist/models/sort.model.js +0 -0
- package/dist/tabela.full.js +1441 -108
- package/dist/tabela.js +16 -0
- package/package.json +1 -1
- package/src/components/body.component.ts +1 -0
- package/src/components/column.component.ts +58 -19
- package/src/components/header.component.ts +1 -1
- package/src/helpers/dom.helpers.ts +6 -0
- package/src/managers/column.manager.ts +8 -0
- package/src/managers/data.manager.ts +25 -15
- package/src/managers/event.manager.ts +55 -0
- package/src/managers/filter.manager.ts +154 -0
- package/src/managers/row.manager.ts +16 -2
- package/src/managers/sort.manager.ts +149 -0
- package/src/managers/virtualization.manager.ts +6 -3
- package/src/models/filter.model.ts +17 -0
- package/src/models/sort.model.ts +6 -0
- package/src/models/tabela.model.ts +24 -0
- package/src/tabela.ts +25 -1
- package/types/components/column.component.d.ts +9 -2
- package/types/helpers/dom.helpers.d.ts +1 -1
- package/types/managers/data.manager.d.ts +10 -2
- package/types/managers/event.manager.d.ts +10 -0
- package/types/managers/filter.manager.d.ts +19 -0
- package/types/managers/sort.manager.d.ts +26 -0
- package/types/managers/virtualization.manager.d.ts +2 -2
- package/types/models/filter.model.d.ts +6 -0
- package/types/models/sort.model.d.ts +5 -0
- package/types/models/tabela.model.d.ts +22 -0
- package/types/tabela.d.ts +3 -1
package/dist/tabela.full.js
CHANGED
|
@@ -3,14 +3,25 @@
|
|
|
3
3
|
* @param value Original value
|
|
4
4
|
* @returns String representation of the value
|
|
5
5
|
*/
|
|
6
|
-
function getString(value) {
|
|
6
|
+
function getString$1(value) {
|
|
7
7
|
if (typeof value === "string") return value;
|
|
8
8
|
if (value == null) return "";
|
|
9
|
-
if (typeof value === "function") return getString(value());
|
|
9
|
+
if (typeof value === "function") return getString$1(value());
|
|
10
10
|
if (typeof value !== "object") return String(value);
|
|
11
11
|
const asString = String(value.valueOf?.() ?? value);
|
|
12
12
|
return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Is the value a plain object?
|
|
16
|
+
* @param value Value to check
|
|
17
|
+
* @returns `true` if the value is a plain object, otherwise `false`
|
|
18
|
+
*/
|
|
19
|
+
function isPlainObject$1(value) {
|
|
20
|
+
if (value === null || typeof value !== "object") return false;
|
|
21
|
+
if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
|
|
22
|
+
const prototype = Object.getPrototypeOf(value);
|
|
23
|
+
return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
|
|
24
|
+
}
|
|
14
25
|
function getBoolean(value, defaultValue) {
|
|
15
26
|
return typeof value === "boolean" ? value : defaultValue ?? false;
|
|
16
27
|
}
|
|
@@ -43,10 +54,80 @@ new Set([
|
|
|
43
54
|
* @returns `true` if the value is nullable or a whitespace-only string, otherwise `false`
|
|
44
55
|
*/
|
|
45
56
|
function isNullableOrWhitespace(value) {
|
|
46
|
-
return value == null || EXPRESSION_WHITESPACE.test(getString(value));
|
|
57
|
+
return value == null || EXPRESSION_WHITESPACE$1.test(getString$1(value));
|
|
58
|
+
}
|
|
59
|
+
var EXPRESSION_WHITESPACE$1 = /^\s*$/;
|
|
60
|
+
function badAttributeHandler(name, value) {
|
|
61
|
+
if (typeof name !== "string" || name.trim().length === 0 || typeof value !== "string") return true;
|
|
62
|
+
if (EXPRESSION_CLOBBERED_NAME.test(name) && (value in document || value in formElement) || EXPRESSION_EVENT_NAME.test(name)) return true;
|
|
63
|
+
if (EXPRESSION_SKIP_NAME.test(name) || EXPRESSION_URI_VALUE.test(value) || isValidSourceAttribute(name, value)) return false;
|
|
64
|
+
return EXPRESSION_DATA_OR_SCRIPT.test(value);
|
|
65
|
+
}
|
|
66
|
+
function booleanAttributeHandler(name, value) {
|
|
67
|
+
if (typeof name !== "string" || name.trim().length === 0 || typeof value !== "string") return true;
|
|
68
|
+
const normalizedName = name.toLowerCase();
|
|
69
|
+
if (!booleanAttributesSet.has(normalizedName)) return false;
|
|
70
|
+
const normalized = value.toLowerCase();
|
|
71
|
+
return !(normalized.length === 0 || normalized === normalizedName);
|
|
72
|
+
}
|
|
73
|
+
function decodeAttribute(value) {
|
|
74
|
+
textArea ??= document.createElement("textarea");
|
|
75
|
+
textArea.innerHTML = value;
|
|
76
|
+
return decodeURIComponent(textArea.value);
|
|
77
|
+
}
|
|
78
|
+
function handleAttribute(callback, decode, first, second) {
|
|
79
|
+
let name;
|
|
80
|
+
let value;
|
|
81
|
+
if (isAttribute(first)) {
|
|
82
|
+
name = first.name;
|
|
83
|
+
value = String(first.value);
|
|
84
|
+
} else if (typeof first === "string" && typeof second === "string") {
|
|
85
|
+
name = first;
|
|
86
|
+
value = second;
|
|
87
|
+
}
|
|
88
|
+
if (decode && value != null) value = decodeAttribute(value);
|
|
89
|
+
return callback(name, value?.replace(EXPRESSION_WHITESPACE, ""));
|
|
90
|
+
}
|
|
91
|
+
function isAttribute(value) {
|
|
92
|
+
return value instanceof Attr || isPlainObject$1(value) && typeof value.name === "string" && "value" in value;
|
|
93
|
+
}
|
|
94
|
+
function _isBadAttribute(first, second, decode) {
|
|
95
|
+
return handleAttribute(badAttributeHandler, decode, first, second);
|
|
96
|
+
}
|
|
97
|
+
function _isEmptyNonBooleanAttribute(first, second, decode) {
|
|
98
|
+
return handleAttribute((name, value) => name != null && value != null && !booleanAttributesSet.has(name) && value.trim().length === 0, decode, first, second);
|
|
99
|
+
}
|
|
100
|
+
function _isInvalidBooleanAttribute(first, second, decode) {
|
|
101
|
+
return handleAttribute(booleanAttributeHandler, decode, first, second);
|
|
102
|
+
}
|
|
103
|
+
function isValidSourceAttribute(name, value) {
|
|
104
|
+
return EXPRESSION_SOURCE_NAME.test(name) && EXPRESSION_SOURCE_VALUE.test(value);
|
|
105
|
+
}
|
|
106
|
+
function updateAttribute(element, name, value, dispatch) {
|
|
107
|
+
const normalizedName = name.toLowerCase();
|
|
108
|
+
const isBoolean = booleanAttributesSet.has(normalizedName);
|
|
109
|
+
const next = isBoolean ? value === true || typeof value === "string" && (value === "" || value.toLowerCase() === normalizedName) : value == null ? "" : value;
|
|
110
|
+
if (name in element) updateProperty(element, normalizedName, next, dispatch);
|
|
111
|
+
updateElementValue(element, name, isBoolean ? next ? "" : null : value, element.setAttribute, element.removeAttribute, isBoolean, false);
|
|
112
|
+
}
|
|
113
|
+
function updateProperty(element, name, value, dispatch) {
|
|
114
|
+
if (Object.is(element[name], value)) return;
|
|
115
|
+
element[name] = value;
|
|
116
|
+
const event = dispatch !== false && elementEvents[element.tagName]?.[name];
|
|
117
|
+
if (typeof event === "string") element.dispatchEvent(new Event(event, { bubbles: true }));
|
|
47
118
|
}
|
|
48
|
-
var
|
|
49
|
-
|
|
119
|
+
var EXPRESSION_CLOBBERED_NAME = /^(id|name)$/i;
|
|
120
|
+
var EXPRESSION_DATA_OR_SCRIPT = /^(?:data|\w+script):/i;
|
|
121
|
+
var EXPRESSION_EVENT_NAME = /^on/i;
|
|
122
|
+
var EXPRESSION_SKIP_NAME = /^(aria-[-\w]+|data-[-\w.\u00B7-\uFFFF]+)$/i;
|
|
123
|
+
var EXPRESSION_SOURCE_NAME = /^src$/i;
|
|
124
|
+
var EXPRESSION_SOURCE_VALUE = /^data:/i;
|
|
125
|
+
var EXPRESSION_URI_VALUE = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
|
|
126
|
+
var EXPRESSION_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
|
|
127
|
+
/**
|
|
128
|
+
* List of boolean attributes
|
|
129
|
+
*/
|
|
130
|
+
const booleanAttributes = Object.freeze([
|
|
50
131
|
"async",
|
|
51
132
|
"autofocus",
|
|
52
133
|
"autoplay",
|
|
@@ -72,7 +153,23 @@ Object.freeze([
|
|
|
72
153
|
"reversed",
|
|
73
154
|
"selected"
|
|
74
155
|
]);
|
|
75
|
-
|
|
156
|
+
var booleanAttributesSet = new Set(booleanAttributes);
|
|
157
|
+
var elementEvents = {
|
|
158
|
+
DETAILS: { open: "toggle" },
|
|
159
|
+
INPUT: {
|
|
160
|
+
checked: "change",
|
|
161
|
+
value: "input"
|
|
162
|
+
},
|
|
163
|
+
SELECT: { value: "change" },
|
|
164
|
+
TEXTAREA: { value: "input" }
|
|
165
|
+
};
|
|
166
|
+
var formElement = document.createElement("form");
|
|
167
|
+
var textArea;
|
|
168
|
+
function setElementValue(element, first, second, third, callback) {
|
|
169
|
+
if (!isHTMLOrSVGElement(element)) return;
|
|
170
|
+
if (typeof first === "string") setElementValues(element, first, second, third, callback);
|
|
171
|
+
else if (isAttribute(first)) setElementValues(element, first.name, first.value, third, callback);
|
|
172
|
+
}
|
|
76
173
|
function setElementValues(element, first, second, third, callback) {
|
|
77
174
|
if (!isHTMLOrSVGElement(element)) return;
|
|
78
175
|
if (typeof first === "string") {
|
|
@@ -110,18 +207,25 @@ function updateStyleProperty(element, key, value) {
|
|
|
110
207
|
this.style[property] = "";
|
|
111
208
|
}, false, false);
|
|
112
209
|
}
|
|
210
|
+
function setAttribute(element, first, second, third) {
|
|
211
|
+
setElementValue(element, first, second, third, updateAttribute);
|
|
212
|
+
}
|
|
213
|
+
function setAttributes(element, attributes, dispatch) {
|
|
214
|
+
setElementValues(element, attributes, null, dispatch, updateAttribute);
|
|
215
|
+
}
|
|
113
216
|
function createCell(width, body) {
|
|
114
217
|
const cell = createElement("div", {
|
|
115
218
|
className: "tabela__cell",
|
|
116
219
|
role: "cell"
|
|
117
|
-
}, { width: `${width}px` });
|
|
220
|
+
}, {}, { width: `${width}px` });
|
|
118
221
|
if (body ?? true) cell.classList.add("tabela__cell-body");
|
|
119
222
|
return cell;
|
|
120
223
|
}
|
|
121
|
-
function createElement(tagName, properties, style) {
|
|
224
|
+
function createElement(tagName, properties, attributes, style) {
|
|
122
225
|
const element = document.createElement(tagName);
|
|
123
226
|
const keys = Object.keys(properties);
|
|
124
227
|
for (const key of keys) element[key] = properties[key];
|
|
228
|
+
setAttributes(element, attributes);
|
|
125
229
|
setStyles(element, style);
|
|
126
230
|
return element;
|
|
127
231
|
}
|
|
@@ -129,7 +233,7 @@ function createRowGroup(withRow) {
|
|
|
129
233
|
const group = createElement("div", {
|
|
130
234
|
className: "tabela__rowgroup",
|
|
131
235
|
role: "rowgroup"
|
|
132
|
-
}, {});
|
|
236
|
+
}, {}, {});
|
|
133
237
|
if (!(withRow ?? true)) return group;
|
|
134
238
|
const row = createRow(false);
|
|
135
239
|
group.append(row);
|
|
@@ -142,7 +246,7 @@ function createRow(withStyle) {
|
|
|
142
246
|
const row = createElement("div", {
|
|
143
247
|
className: "tabela__row",
|
|
144
248
|
role: "row"
|
|
145
|
-
}, {});
|
|
249
|
+
}, {}, {});
|
|
146
250
|
if (withStyle ?? true) setStyles(row, {
|
|
147
251
|
inset: "0 auto auto 0",
|
|
148
252
|
position: "absolute"
|
|
@@ -150,7 +254,7 @@ function createRow(withStyle) {
|
|
|
150
254
|
return row;
|
|
151
255
|
}
|
|
152
256
|
function createFaker() {
|
|
153
|
-
return createElement("div", {}, {
|
|
257
|
+
return createElement("div", {}, {}, {
|
|
154
258
|
height: "0",
|
|
155
259
|
inset: "0 auto auto 0",
|
|
156
260
|
opacity: "0",
|
|
@@ -229,18 +333,11 @@ var HeaderComponent = class {
|
|
|
229
333
|
}
|
|
230
334
|
update(columns) {
|
|
231
335
|
this.elements.row.innerHTML = "";
|
|
232
|
-
this.elements.row.append(...columns.map((column) => column.
|
|
336
|
+
this.elements.row.append(...columns.map((column) => column.elements.wrapper));
|
|
233
337
|
}
|
|
234
338
|
};
|
|
235
|
-
function createHeading(title, width) {
|
|
236
|
-
return createElement("div", {
|
|
237
|
-
className: "tabela__heading",
|
|
238
|
-
role: "columnheader",
|
|
239
|
-
textContent: title
|
|
240
|
-
}, { width: `${width}px` });
|
|
241
|
-
}
|
|
242
339
|
var ColumnComponent = class {
|
|
243
|
-
|
|
340
|
+
elements;
|
|
244
341
|
options;
|
|
245
342
|
constructor(options) {
|
|
246
343
|
const width = Number.parseInt(getComputedStyle(document.body).fontSize, 10) * (options.width ?? options.title.length * 1.5);
|
|
@@ -248,9 +345,36 @@ var ColumnComponent = class {
|
|
|
248
345
|
...options,
|
|
249
346
|
width
|
|
250
347
|
};
|
|
251
|
-
this.
|
|
348
|
+
this.elements = createHeading(options.field, options.title, width);
|
|
349
|
+
}
|
|
350
|
+
destroy() {
|
|
351
|
+
this.elements.content.remove();
|
|
352
|
+
this.elements.wrapper.remove();
|
|
353
|
+
this.elements.sorter.remove();
|
|
354
|
+
this.elements = void 0;
|
|
355
|
+
this.options = void 0;
|
|
252
356
|
}
|
|
253
357
|
};
|
|
358
|
+
function createHeading(field, title, width) {
|
|
359
|
+
const wrapper = createElement("div", {
|
|
360
|
+
className: "tabela__heading",
|
|
361
|
+
role: "columnheader"
|
|
362
|
+
}, {
|
|
363
|
+
"data-event": "heading",
|
|
364
|
+
"data-field": field
|
|
365
|
+
}, { width: `${width}px` });
|
|
366
|
+
const content = createElement("div", {
|
|
367
|
+
className: "tabela__heading__content",
|
|
368
|
+
textContent: title
|
|
369
|
+
}, {}, {});
|
|
370
|
+
const sorter = createElement("div", { className: "tabela__heading__sorter" }, {}, {});
|
|
371
|
+
wrapper.append(content, sorter);
|
|
372
|
+
return {
|
|
373
|
+
content,
|
|
374
|
+
sorter,
|
|
375
|
+
wrapper
|
|
376
|
+
};
|
|
377
|
+
}
|
|
254
378
|
var ColumnManager = class {
|
|
255
379
|
items = [];
|
|
256
380
|
constructor(managers, components, columns) {
|
|
@@ -259,6 +383,8 @@ var ColumnManager = class {
|
|
|
259
383
|
this.set(columns);
|
|
260
384
|
}
|
|
261
385
|
destroy() {
|
|
386
|
+
const { length } = this.items;
|
|
387
|
+
for (let index = 0; index < length; index += 1) this.items[index].destroy();
|
|
262
388
|
this.items.length = 0;
|
|
263
389
|
}
|
|
264
390
|
remove(value) {
|
|
@@ -268,7 +394,10 @@ var ColumnManager = class {
|
|
|
268
394
|
if (length === 0) return;
|
|
269
395
|
for (let fieldIndex = 0; fieldIndex < length; fieldIndex += 1) {
|
|
270
396
|
const itemIndex = items.findIndex((component) => component.options.field === fields[fieldIndex]);
|
|
271
|
-
if (itemIndex > -1)
|
|
397
|
+
if (itemIndex > -1) {
|
|
398
|
+
items[itemIndex].destroy();
|
|
399
|
+
items.splice(itemIndex, 1);
|
|
400
|
+
}
|
|
272
401
|
}
|
|
273
402
|
components.header.update(items);
|
|
274
403
|
components.footer.update(items);
|
|
@@ -297,6 +426,408 @@ function getArrayCallbacks(bool, key, value) {
|
|
|
297
426
|
value: getArrayCallback(value)
|
|
298
427
|
};
|
|
299
428
|
}
|
|
429
|
+
function findValues(type, array, parameters, mapper) {
|
|
430
|
+
const result = {
|
|
431
|
+
matched: [],
|
|
432
|
+
notMatched: []
|
|
433
|
+
};
|
|
434
|
+
if (!Array.isArray(array) || array.length === 0) return result;
|
|
435
|
+
const { length } = array;
|
|
436
|
+
const { bool, key, value } = getParameters(parameters);
|
|
437
|
+
const callbacks = getArrayCallbacks(bool, key);
|
|
438
|
+
if (type === "unique" && callbacks?.keyed == null && length >= UNIQUE_THRESHOLD) {
|
|
439
|
+
result.matched = [...new Set(array)];
|
|
440
|
+
return result;
|
|
441
|
+
}
|
|
442
|
+
const mapCallback = typeof mapper === "function" ? mapper : void 0;
|
|
443
|
+
if (callbacks?.bool != null || type === "all" && key == null) {
|
|
444
|
+
const callback = callbacks?.bool ?? ((item) => Object.is(item, value));
|
|
445
|
+
for (let index = 0; index < length; index += 1) {
|
|
446
|
+
const item = array[index];
|
|
447
|
+
if (callback(item, index, array)) result.matched.push(mapCallback?.(item, index, array) ?? item);
|
|
448
|
+
else result.notMatched.push(item);
|
|
449
|
+
}
|
|
450
|
+
return result;
|
|
451
|
+
}
|
|
452
|
+
const keys = /* @__PURE__ */ new Set();
|
|
453
|
+
for (let index = 0; index < length; index += 1) {
|
|
454
|
+
const item = array[index];
|
|
455
|
+
const keyed = callbacks?.keyed?.(item, index, array) ?? item;
|
|
456
|
+
if (type === "all" && Object.is(keyed, value) || type === "unique" && !keys.has(keyed)) {
|
|
457
|
+
keys.add(keyed);
|
|
458
|
+
result.matched.push(mapCallback?.(item, index, array) ?? item);
|
|
459
|
+
} else result.notMatched.push(item);
|
|
460
|
+
}
|
|
461
|
+
return result;
|
|
462
|
+
}
|
|
463
|
+
function getParameters(original) {
|
|
464
|
+
const { length } = original;
|
|
465
|
+
return {
|
|
466
|
+
bool: length === 1 && typeof original[0] === "function" ? original[0] : void 0,
|
|
467
|
+
key: length === 2 ? original[0] : void 0,
|
|
468
|
+
value: length === 1 && typeof original[0] !== "function" ? original[0] : original[1]
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
var UNIQUE_THRESHOLD = 100;
|
|
472
|
+
function filter(array, ...parameters) {
|
|
473
|
+
return findValues("all", array, parameters).matched;
|
|
474
|
+
}
|
|
475
|
+
filter.remove = removeFiltered;
|
|
476
|
+
function removeFiltered(array, ...parameters) {
|
|
477
|
+
return findValues("all", array, parameters).notMatched;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Is the value a constructor function?
|
|
481
|
+
* @param value Value to check
|
|
482
|
+
* @returns `true` if the value is a constructor function, otherwise `false`
|
|
483
|
+
*/
|
|
484
|
+
function isConstructor(value) {
|
|
485
|
+
return typeof value === "function" && value.prototype?.constructor === value;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Is the value a number?
|
|
489
|
+
* @param value Value to check
|
|
490
|
+
* @returns `true` if the value is a `number`, otherwise `false`
|
|
491
|
+
*/
|
|
492
|
+
function isNumber(value) {
|
|
493
|
+
return typeof value === "number" && !Number.isNaN(value);
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Is the value a plain object?
|
|
497
|
+
* @param value Value to check
|
|
498
|
+
* @returns `true` if the value is a plain object, otherwise `false`
|
|
499
|
+
*/
|
|
500
|
+
function isPlainObject(value) {
|
|
501
|
+
if (value === null || typeof value !== "object") return false;
|
|
502
|
+
if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
|
|
503
|
+
const prototype = Object.getPrototypeOf(value);
|
|
504
|
+
return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Is the value a typed array?
|
|
508
|
+
* @param value Value to check
|
|
509
|
+
* @returns `true` if the value is a typed array, otherwise `false`
|
|
510
|
+
*/
|
|
511
|
+
function isTypedArray(value) {
|
|
512
|
+
TYPED_ARRAYS ??= new Set([
|
|
513
|
+
Int8Array,
|
|
514
|
+
Uint8Array,
|
|
515
|
+
Uint8ClampedArray,
|
|
516
|
+
Int16Array,
|
|
517
|
+
Uint16Array,
|
|
518
|
+
Int32Array,
|
|
519
|
+
Uint32Array,
|
|
520
|
+
Float32Array,
|
|
521
|
+
Float64Array,
|
|
522
|
+
BigInt64Array,
|
|
523
|
+
BigUint64Array
|
|
524
|
+
]);
|
|
525
|
+
return TYPED_ARRAYS.has(value?.constructor);
|
|
526
|
+
}
|
|
527
|
+
var TYPED_ARRAYS;
|
|
528
|
+
/**
|
|
529
|
+
* Chunk an array into smaller arrays
|
|
530
|
+
* @param array Array to chunk
|
|
531
|
+
* @param size Size of each chunk _(minimum is `1`, maximum is `5000`; defaults to `5000`)_
|
|
532
|
+
* @returns Array of arrays
|
|
533
|
+
*/
|
|
534
|
+
function chunk(array, size) {
|
|
535
|
+
if (!Array.isArray(array)) return [];
|
|
536
|
+
if (array.length === 0) return [];
|
|
537
|
+
const { length } = array;
|
|
538
|
+
const actualSize = typeof size === "number" && size > 0 && size <= MAX_SIZE ? size : MAX_SIZE;
|
|
539
|
+
if (length <= actualSize) return [array];
|
|
540
|
+
const chunks = [];
|
|
541
|
+
let index = 0;
|
|
542
|
+
while (index < length) {
|
|
543
|
+
chunks.push(array.slice(index, index + actualSize));
|
|
544
|
+
index += actualSize;
|
|
545
|
+
}
|
|
546
|
+
return chunks;
|
|
547
|
+
}
|
|
548
|
+
var MAX_SIZE = 5e3;
|
|
549
|
+
function compact(array, strict) {
|
|
550
|
+
if (!Array.isArray(array)) return [];
|
|
551
|
+
if (strict === true) return array.filter(Boolean);
|
|
552
|
+
const { length } = array;
|
|
553
|
+
const compacted = [];
|
|
554
|
+
for (let index = 0; index < length; index += 1) {
|
|
555
|
+
const item = array[index];
|
|
556
|
+
if (item != null) compacted.push(item);
|
|
557
|
+
}
|
|
558
|
+
return compacted;
|
|
559
|
+
}
|
|
560
|
+
function insertChunkedValues(type, array, items, start, deleteCount) {
|
|
561
|
+
const actualDeleteCount = deleteCount < 0 ? 0 : deleteCount;
|
|
562
|
+
const actualStart = Math.min(Math.max(0, start), array.length);
|
|
563
|
+
const chunked = chunk(items);
|
|
564
|
+
const lastIndex = chunked.length - 1;
|
|
565
|
+
let index = Number(chunked.length);
|
|
566
|
+
let returned;
|
|
567
|
+
while (index > 0) {
|
|
568
|
+
index -= 1;
|
|
569
|
+
const spliced = array.splice(actualStart, index === lastIndex ? actualDeleteCount : 0, ...chunked[index]);
|
|
570
|
+
if (returned == null) returned = spliced;
|
|
571
|
+
else returned.push(...spliced);
|
|
572
|
+
}
|
|
573
|
+
if (type === "insert") return array;
|
|
574
|
+
return type === "splice" ? returned : array.length;
|
|
575
|
+
}
|
|
576
|
+
function insertValues(type, array, items, start, deleteCount) {
|
|
577
|
+
const spliceArray = type === "insert" || type === "splice";
|
|
578
|
+
if (!Array.isArray(array) || typeof start !== "number" || !Array.isArray(items) || items.length === 0) return spliceArray ? [] : 0;
|
|
579
|
+
return insertChunkedValues(type, array, items, start, spliceArray ? deleteCount : 0);
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Push items into an array _(at the end)_
|
|
583
|
+
* @param array Original array
|
|
584
|
+
* @param pushed Pushed items
|
|
585
|
+
* @returns New length of the array
|
|
586
|
+
*/
|
|
587
|
+
function push(array, pushed) {
|
|
588
|
+
return insertValues("push", array, pushed, array.length, 0);
|
|
589
|
+
}
|
|
590
|
+
function aggregate(type, array, key) {
|
|
591
|
+
const length = Array.isArray(array) ? array.length : 0;
|
|
592
|
+
if (length === 0) return {
|
|
593
|
+
count: 0,
|
|
594
|
+
value: NaN
|
|
595
|
+
};
|
|
596
|
+
const aggregator = aggregators[type];
|
|
597
|
+
const callback = getAggregateCallback(key);
|
|
598
|
+
let counted = 0;
|
|
599
|
+
let aggregated = NaN;
|
|
600
|
+
let notNumber = true;
|
|
601
|
+
for (let index = 0; index < length; index += 1) {
|
|
602
|
+
const item = array[index];
|
|
603
|
+
const value = callback == null ? item : callback(item, index, array);
|
|
604
|
+
if (!isNumber(value)) continue;
|
|
605
|
+
aggregated = aggregator(aggregated, value, notNumber);
|
|
606
|
+
counted += 1;
|
|
607
|
+
notNumber = false;
|
|
608
|
+
}
|
|
609
|
+
return {
|
|
610
|
+
count: counted,
|
|
611
|
+
value: aggregated
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
function getAggregateCallback(key) {
|
|
615
|
+
if (key == null) return;
|
|
616
|
+
return typeof key === "function" ? key : (item) => item[key];
|
|
617
|
+
}
|
|
618
|
+
function max(array, key) {
|
|
619
|
+
return getAggregated("max", array, key);
|
|
620
|
+
}
|
|
621
|
+
function calculateSum(current, value, notNumber) {
|
|
622
|
+
return notNumber ? value : current + value;
|
|
623
|
+
}
|
|
624
|
+
function getAggregated(type, array, key) {
|
|
625
|
+
const aggregated = aggregate(type, array, key);
|
|
626
|
+
return aggregated.count > 0 ? aggregated.value : NaN;
|
|
627
|
+
}
|
|
628
|
+
var aggregators = {
|
|
629
|
+
average: calculateSum,
|
|
630
|
+
max: (current, value, notNumber) => notNumber || value > current ? value : current,
|
|
631
|
+
min: (current, value, notNumber) => notNumber || value < current ? value : current,
|
|
632
|
+
sum: calculateSum
|
|
633
|
+
};
|
|
634
|
+
/**
|
|
635
|
+
* Get the string value from any value
|
|
636
|
+
* @param value Original value
|
|
637
|
+
* @returns String representation of the value
|
|
638
|
+
*/
|
|
639
|
+
function getString(value) {
|
|
640
|
+
if (typeof value === "string") return value;
|
|
641
|
+
if (value == null) return "";
|
|
642
|
+
if (typeof value === "function") return getString(value());
|
|
643
|
+
if (typeof value !== "object") return String(value);
|
|
644
|
+
const asString = String(value.valueOf?.() ?? value);
|
|
645
|
+
return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Join an array of values into a string
|
|
649
|
+
* @param value Array of values
|
|
650
|
+
* @param delimiter Delimiter to use between values
|
|
651
|
+
* @returns Joined string
|
|
652
|
+
*/
|
|
653
|
+
function join(value, delimiter) {
|
|
654
|
+
return compact(value).map(getString).join(typeof delimiter === "string" ? delimiter : "");
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Split a string into words _(and other readable parts)_
|
|
658
|
+
* @param value Original string
|
|
659
|
+
* @returns Array of words found in the string
|
|
660
|
+
*/
|
|
661
|
+
function words(value) {
|
|
662
|
+
return typeof value === "string" ? value.match(EXPRESSION_WORDS) ?? [] : [];
|
|
663
|
+
}
|
|
664
|
+
var EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
|
|
665
|
+
function getCompareHandlers(owner, options) {
|
|
666
|
+
const { get, register, unregister } = getHandlers(owner, options);
|
|
667
|
+
return {
|
|
668
|
+
register,
|
|
669
|
+
unregister,
|
|
670
|
+
handle(first, second, ...parameters) {
|
|
671
|
+
const handler = get(first, second);
|
|
672
|
+
if (handler == null) return options.callback(first, second, ...parameters);
|
|
673
|
+
return typeof handler === "function" ? handler(first, second) : first[handler](second);
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
function getHandlers(owner, options) {
|
|
678
|
+
const handlers = /* @__PURE__ */ new WeakMap();
|
|
679
|
+
return {
|
|
680
|
+
get(first, second) {
|
|
681
|
+
if (isConstructable(first) && isConstructable(second) && first.constructor === second.constructor) return handlers.get(first.constructor);
|
|
682
|
+
},
|
|
683
|
+
register(constructor, handler) {
|
|
684
|
+
if (!isConstructor(constructor) || handler === owner) return;
|
|
685
|
+
let actual = handler ?? options.method;
|
|
686
|
+
if (typeof actual !== "function" && typeof actual !== "string") return;
|
|
687
|
+
if (typeof actual === "string") actual = typeof constructor.prototype[actual] === "function" ? actual : void 0;
|
|
688
|
+
if (actual != null) handlers.set(constructor, actual);
|
|
689
|
+
},
|
|
690
|
+
unregister(constructor) {
|
|
691
|
+
handlers.delete(constructor);
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
function isConstructable(value) {
|
|
696
|
+
return typeof value === "object" && value !== null;
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Compare two values _(for sorting purposes)_
|
|
700
|
+
* @param first First value
|
|
701
|
+
* @param second Second value
|
|
702
|
+
* @returns `0` if equal; `-1` first comes before second; `1` first comes after second
|
|
703
|
+
*/
|
|
704
|
+
function compare(first, second) {
|
|
705
|
+
if (Object.is(first, second)) return 0;
|
|
706
|
+
if (first == null) return -1;
|
|
707
|
+
if (second == null) return 1;
|
|
708
|
+
let comparison = compareValue(first, second, false);
|
|
709
|
+
if (comparison != null) return comparison;
|
|
710
|
+
const firstParts = getComparisonParts(first);
|
|
711
|
+
const secondParts = getComparisonParts(second);
|
|
712
|
+
const length = max([firstParts.length, secondParts.length]);
|
|
713
|
+
const lastIndex = length - 1;
|
|
714
|
+
for (let index = 0; index < length; index += 1) {
|
|
715
|
+
const firstPart = firstParts[index];
|
|
716
|
+
const secondPart = secondParts[index];
|
|
717
|
+
comparison = compareValue(firstPart, secondPart, true);
|
|
718
|
+
if (comparison === 0) {
|
|
719
|
+
if (index === lastIndex) break;
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
return comparison;
|
|
723
|
+
}
|
|
724
|
+
return 0;
|
|
725
|
+
}
|
|
726
|
+
compare.handlers = getCompareHandlers(compare, {
|
|
727
|
+
callback: (first, second, compareStrings) => {
|
|
728
|
+
if (compareStrings) return getString(first).localeCompare(getString(second));
|
|
729
|
+
},
|
|
730
|
+
method: "compare"
|
|
731
|
+
});
|
|
732
|
+
compare.register = registerComparator;
|
|
733
|
+
compare.unregister = unregisterComparator;
|
|
734
|
+
/**
|
|
735
|
+
* Register a custom comparison handler for a class
|
|
736
|
+
* @param constructor Class constructor
|
|
737
|
+
* @param handler Method name or comparison function _(defaults to `compare`)_
|
|
738
|
+
*/
|
|
739
|
+
function registerComparator(constructor, handler) {
|
|
740
|
+
compare.handlers.register(constructor, handler);
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Unregister a custom comparison handler for a class
|
|
744
|
+
* @param constructor Class constructor
|
|
745
|
+
*/
|
|
746
|
+
function unregisterComparator(constructor) {
|
|
747
|
+
compare.handlers.unregister(constructor);
|
|
748
|
+
}
|
|
749
|
+
function compareNumbers(first, second) {
|
|
750
|
+
const firstNumber = Number(first);
|
|
751
|
+
const secondNumber = Number(second);
|
|
752
|
+
if (firstNumber === secondNumber) return 0;
|
|
753
|
+
return firstNumber > secondNumber ? 1 : -1;
|
|
754
|
+
}
|
|
755
|
+
function compareSymbols(first, second) {
|
|
756
|
+
return getString(first.description ?? first).localeCompare(getString(second.description ?? second));
|
|
757
|
+
}
|
|
758
|
+
function compareValue(first, second, compareStrings) {
|
|
759
|
+
const firstType = typeof first;
|
|
760
|
+
if (firstType === typeof second && firstType in comparators$1) return comparators$1[firstType](first, second);
|
|
761
|
+
if (first instanceof Date && second instanceof Date) return compareNumbers(first.getTime(), second.getTime());
|
|
762
|
+
return compare.handlers.handle(first, second, compareStrings);
|
|
763
|
+
}
|
|
764
|
+
function getComparisonParts(value) {
|
|
765
|
+
if (Array.isArray(value)) return value;
|
|
766
|
+
return typeof value === "object" ? [value] : words(getString(value));
|
|
767
|
+
}
|
|
768
|
+
var comparators$1 = {
|
|
769
|
+
bigint: compareNumbers,
|
|
770
|
+
boolean: compareNumbers,
|
|
771
|
+
number: compareNumbers,
|
|
772
|
+
symbol: compareSymbols
|
|
773
|
+
};
|
|
774
|
+
function getCallback(value, key, forObject) {
|
|
775
|
+
if (key != null) return;
|
|
776
|
+
if (forObject && typeof value.value === "function") return value.value;
|
|
777
|
+
return typeof value === "function" ? value : void 0;
|
|
778
|
+
}
|
|
779
|
+
function getKey(value, forObject) {
|
|
780
|
+
if (forObject && typeof value.key === "string") return value.key;
|
|
781
|
+
return typeof value === "string" ? value : void 0;
|
|
782
|
+
}
|
|
783
|
+
function getModifier(value, modifier, forObject) {
|
|
784
|
+
if (!forObject || typeof value.direction !== "string") return modifier;
|
|
785
|
+
if (value.direction === "ascending") return 1;
|
|
786
|
+
return value.direction === "descending" ? -1 : modifier;
|
|
787
|
+
}
|
|
788
|
+
function getSorter(value, modifier) {
|
|
789
|
+
const forObject = isPlainObject(value);
|
|
790
|
+
const sorter = {
|
|
791
|
+
identifier: "",
|
|
792
|
+
modifier
|
|
793
|
+
};
|
|
794
|
+
sorter.compare = forObject && typeof value.compare === "function" ? value.compare : void 0;
|
|
795
|
+
sorter.key = getKey(value, forObject);
|
|
796
|
+
sorter.modifier = getModifier(value, modifier, forObject);
|
|
797
|
+
sorter.callback = getCallback(value, sorter.key, forObject);
|
|
798
|
+
if (sorter.key != null || sorter.callback != null) {
|
|
799
|
+
sorter.identifier = `${sorter.key ?? sorter.callback}`;
|
|
800
|
+
return sorter;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
function sort(array, first, second) {
|
|
804
|
+
if (!Array.isArray(array)) return [];
|
|
805
|
+
if (array.length < 2) return array;
|
|
806
|
+
const modifier = (first === true || second === true ? "desc" : "asc") === "asc" ? 1 : -1;
|
|
807
|
+
const sorters = (Array.isArray(first) ? first : [first]).map((item) => getSorter(item, modifier)).filter((sorter) => sorter != null).filter((current, index, filtered) => filtered.findIndex((next) => next.identifier === current.identifier) === index);
|
|
808
|
+
const { length } = sorters;
|
|
809
|
+
if (length === 0) return array.sort((firstItem, secondItem) => compare(firstItem, secondItem) * modifier);
|
|
810
|
+
if (length === 1) {
|
|
811
|
+
const sorter = sorters[0];
|
|
812
|
+
const { callback, key } = sorter;
|
|
813
|
+
return array.sort((firstItem, secondItem) => {
|
|
814
|
+
const firstValue = key == null ? callback?.(firstItem) : firstItem[key];
|
|
815
|
+
const secondValue = key == null ? callback?.(secondItem) : secondItem[key];
|
|
816
|
+
return (sorter.compare?.(firstItem, firstValue, secondItem, secondValue) ?? compare(firstValue, secondValue)) * sorter.modifier;
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
return array.sort((firstItem, secondItem) => {
|
|
820
|
+
for (let index = 0; index < length; index += 1) {
|
|
821
|
+
const sorter = sorters[index];
|
|
822
|
+
const { callback, key } = sorter;
|
|
823
|
+
const firstValue = key == null ? callback?.(firstItem) : firstItem[key];
|
|
824
|
+
const secondValue = key == null ? callback?.(secondItem) : secondItem[key];
|
|
825
|
+
const compared = (sorter.compare?.(firstItem, firstValue, secondItem, secondValue) ?? compare(firstValue, secondValue)) * sorter.modifier;
|
|
826
|
+
if (compared !== 0) return compared;
|
|
827
|
+
}
|
|
828
|
+
return 0;
|
|
829
|
+
});
|
|
830
|
+
}
|
|
300
831
|
function getMapValues(array, first, second, arrays) {
|
|
301
832
|
if (!Array.isArray(array)) return /* @__PURE__ */ new Map();
|
|
302
833
|
const { length } = array;
|
|
@@ -321,17 +852,6 @@ toMap.arrays = toMapArrays;
|
|
|
321
852
|
function toMapArrays(array, first, second) {
|
|
322
853
|
return getMapValues(array, first, second, true);
|
|
323
854
|
}
|
|
324
|
-
/**
|
|
325
|
-
* Is the value a plain object?
|
|
326
|
-
* @param value Value to check
|
|
327
|
-
* @returns `true` if the value is a plain object, otherwise `false`
|
|
328
|
-
*/
|
|
329
|
-
function isPlainObject(value) {
|
|
330
|
-
if (value === null || typeof value !== "object") return false;
|
|
331
|
-
if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
|
|
332
|
-
const prototype = Object.getPrototypeOf(value);
|
|
333
|
-
return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
|
|
334
|
-
}
|
|
335
855
|
var DataManager = class {
|
|
336
856
|
handlers = Object.freeze({
|
|
337
857
|
add: (data) => void this.add(data, true),
|
|
@@ -358,10 +878,9 @@ var DataManager = class {
|
|
|
358
878
|
}
|
|
359
879
|
async add(data, render) {
|
|
360
880
|
const { field, values } = this;
|
|
361
|
-
values.objects.array
|
|
881
|
+
push(values.objects.array, data);
|
|
362
882
|
values.objects.mapped = toMap(values.objects.array, field);
|
|
363
|
-
|
|
364
|
-
if (render) this.managers.virtualization.update(true);
|
|
883
|
+
if (render) this.render();
|
|
365
884
|
}
|
|
366
885
|
clear() {
|
|
367
886
|
if (this.values.objects.array.length > 0) this.set([]);
|
|
@@ -372,6 +891,7 @@ var DataManager = class {
|
|
|
372
891
|
values.keys.active = void 0;
|
|
373
892
|
values.keys.original.length = 0;
|
|
374
893
|
values.objects.array.length = 0;
|
|
894
|
+
this.handlers = void 0;
|
|
375
895
|
}
|
|
376
896
|
get(active) {
|
|
377
897
|
const { values } = this;
|
|
@@ -390,16 +910,20 @@ var DataManager = class {
|
|
|
390
910
|
values.keys.original.splice(values.keys.original.indexOf(key), 1);
|
|
391
911
|
managers.row.remove(key);
|
|
392
912
|
}
|
|
393
|
-
if (render) this.
|
|
913
|
+
if (render) this.render();
|
|
914
|
+
}
|
|
915
|
+
render() {
|
|
916
|
+
const { field, managers, values } = this;
|
|
917
|
+
values.keys.original = sort(values.objects.array.map((item) => item[field]));
|
|
918
|
+
if (Object.keys(managers.filter.items).length > 0) managers.filter.filter();
|
|
919
|
+
else if (managers.sort.items.length > 0) managers.sort.sort();
|
|
920
|
+
else managers.virtualization.update(true);
|
|
394
921
|
}
|
|
395
922
|
set(data) {
|
|
396
923
|
const { field, values } = this;
|
|
397
|
-
|
|
398
|
-
values.keys.active = void 0;
|
|
399
|
-
values.keys.original = [...mapped.keys()];
|
|
400
|
-
values.objects.mapped = mapped;
|
|
924
|
+
values.objects.mapped = toMap(data, field);
|
|
401
925
|
values.objects.array = data;
|
|
402
|
-
this.
|
|
926
|
+
this.render();
|
|
403
927
|
}
|
|
404
928
|
async synchronize(data, remove) {
|
|
405
929
|
const { field, values } = this;
|
|
@@ -421,7 +945,7 @@ var DataManager = class {
|
|
|
421
945
|
}
|
|
422
946
|
await this.update(updated);
|
|
423
947
|
if (add.length > 0) await this.add(add, false);
|
|
424
|
-
if (add.length > 0 || (remove ?? false)) this.
|
|
948
|
+
if (add.length > 0 || (remove ?? false)) this.render();
|
|
425
949
|
}
|
|
426
950
|
async update(data) {
|
|
427
951
|
const { field, managers, values } = this;
|
|
@@ -440,69 +964,6 @@ var DataManager = class {
|
|
|
440
964
|
}
|
|
441
965
|
}
|
|
442
966
|
};
|
|
443
|
-
function removeRow(pool, row) {
|
|
444
|
-
if (row.element != null) {
|
|
445
|
-
row.element.innerHTML = "";
|
|
446
|
-
pool.rows.push(row.element);
|
|
447
|
-
row.element.remove();
|
|
448
|
-
row.element = void 0;
|
|
449
|
-
}
|
|
450
|
-
row.cells = {};
|
|
451
|
-
}
|
|
452
|
-
function renderRow(managers, row) {
|
|
453
|
-
const element = row.element ?? managers.virtualization.pool.rows.shift() ?? createRow();
|
|
454
|
-
row.element = element;
|
|
455
|
-
element.dataset.key = String(row.key);
|
|
456
|
-
element.innerHTML = "";
|
|
457
|
-
const columns = managers.column.items;
|
|
458
|
-
const { length } = columns;
|
|
459
|
-
const data = managers.data.values.objects.mapped.get(row.key);
|
|
460
|
-
if (data == null) return;
|
|
461
|
-
for (let index = 0; index < length; index += 1) {
|
|
462
|
-
const { options } = columns[index];
|
|
463
|
-
managers.virtualization.pool.cells[options.field] ??= [];
|
|
464
|
-
const cell = managers.virtualization.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
|
|
465
|
-
cell.textContent = String(data[options.field]);
|
|
466
|
-
row.cells[options.field] = cell;
|
|
467
|
-
element.append(cell);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
var RowComponent = class {
|
|
471
|
-
cells = {};
|
|
472
|
-
element;
|
|
473
|
-
constructor(key) {
|
|
474
|
-
this.key = key;
|
|
475
|
-
}
|
|
476
|
-
};
|
|
477
|
-
var RowManager = class {
|
|
478
|
-
components = /* @__PURE__ */ new Map();
|
|
479
|
-
height;
|
|
480
|
-
constructor(managers, rowHeight) {
|
|
481
|
-
this.managers = managers;
|
|
482
|
-
this.height = rowHeight;
|
|
483
|
-
}
|
|
484
|
-
destroy() {
|
|
485
|
-
this.components.clear();
|
|
486
|
-
}
|
|
487
|
-
get(key) {
|
|
488
|
-
let row = this.components.get(key);
|
|
489
|
-
if (row == null) {
|
|
490
|
-
row = new RowComponent(key);
|
|
491
|
-
this.components.set(key, row);
|
|
492
|
-
}
|
|
493
|
-
return row;
|
|
494
|
-
}
|
|
495
|
-
has(key) {
|
|
496
|
-
return this.components.has(key);
|
|
497
|
-
}
|
|
498
|
-
remove(key) {
|
|
499
|
-
this.components.delete(key);
|
|
500
|
-
}
|
|
501
|
-
update(key) {
|
|
502
|
-
const row = this.components.get(key);
|
|
503
|
-
if (row != null) renderRow(this.managers, row);
|
|
504
|
-
}
|
|
505
|
-
};
|
|
506
967
|
function addDelegatedHandler(doc, type, name, passive) {
|
|
507
968
|
if (DELEGATED.has(name)) return;
|
|
508
969
|
DELEGATED.add(name);
|
|
@@ -607,6 +1068,863 @@ function on(target, type, listener, options) {
|
|
|
607
1068
|
target.removeEventListener(type, listener, extended);
|
|
608
1069
|
};
|
|
609
1070
|
}
|
|
1071
|
+
function findAncestor(origin, selector) {
|
|
1072
|
+
const element = getElement(origin);
|
|
1073
|
+
if (element == null || selector == null) return null;
|
|
1074
|
+
if (typeof selector === "string") {
|
|
1075
|
+
if (Element.prototype.matches.call(element, selector)) return element;
|
|
1076
|
+
return Element.prototype.closest.call(element, selector);
|
|
1077
|
+
}
|
|
1078
|
+
if (typeof selector !== "function") return null;
|
|
1079
|
+
if (selector(element)) return element;
|
|
1080
|
+
let parent = element.parentElement;
|
|
1081
|
+
while (parent != null && !selector(parent)) {
|
|
1082
|
+
if (parent === document.body) return null;
|
|
1083
|
+
parent = parent.parentElement;
|
|
1084
|
+
}
|
|
1085
|
+
return parent;
|
|
1086
|
+
}
|
|
1087
|
+
function getElement(origin) {
|
|
1088
|
+
if (origin instanceof Element) return origin;
|
|
1089
|
+
return origin instanceof Event && origin.target instanceof Element ? origin.target : void 0;
|
|
1090
|
+
}
|
|
1091
|
+
function isInert(item) {
|
|
1092
|
+
return (item.element.inert ?? false) || EXPRESSION_TRUEISH.test(item.element.getAttribute(ATTRIBUTE_INERT)) || item.element.parentElement != null && isInert({
|
|
1093
|
+
element: item.element.parentElement,
|
|
1094
|
+
tabIndex: TABINDEX_DEFAULT
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
var ATTRIBUTE_INERT = "inert";
|
|
1098
|
+
var EXPRESSION_TRUEISH = /^(|true)$/i;
|
|
1099
|
+
[
|
|
1100
|
+
"[contenteditable]:not([contenteditable=\"false\"])",
|
|
1101
|
+
"[tabindex]:not(slot)",
|
|
1102
|
+
"a[href]",
|
|
1103
|
+
"audio[controls]",
|
|
1104
|
+
"button",
|
|
1105
|
+
"details",
|
|
1106
|
+
"details > summary:first-of-type",
|
|
1107
|
+
"input",
|
|
1108
|
+
"select",
|
|
1109
|
+
"textarea",
|
|
1110
|
+
"video[controls]"
|
|
1111
|
+
].map((selector) => `${selector}:not([inert])`).join(",");
|
|
1112
|
+
var TABINDEX_DEFAULT = -1;
|
|
1113
|
+
function handleElement(element, depth) {
|
|
1114
|
+
if (depth === 0) {
|
|
1115
|
+
const removable = element.querySelectorAll(REMOVE_SELECTOR);
|
|
1116
|
+
for (const item of removable) item.remove();
|
|
1117
|
+
}
|
|
1118
|
+
sanitizeAttributes(element, [...element.attributes]);
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Is the element clobbered?
|
|
1122
|
+
*
|
|
1123
|
+
* Thanks, DOMPurify _(https://github.com/cure53/DOMPurify)_
|
|
1124
|
+
*/
|
|
1125
|
+
function isClobbered(value) {
|
|
1126
|
+
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");
|
|
1127
|
+
}
|
|
1128
|
+
function removeNode(node) {
|
|
1129
|
+
if (typeof node.remove === "function") node.remove();
|
|
1130
|
+
}
|
|
1131
|
+
function sanitizeAttributes(element, attributes) {
|
|
1132
|
+
const { length } = attributes;
|
|
1133
|
+
for (let index = 0; index < length; index += 1) {
|
|
1134
|
+
const { name, value } = attributes[index];
|
|
1135
|
+
if (_isBadAttribute(name, value, false) || _isEmptyNonBooleanAttribute(name, value, false)) element.removeAttribute(name);
|
|
1136
|
+
else if (_isInvalidBooleanAttribute(name, value, false)) setAttribute(element, name, true);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
function sanitizeNodes(nodes, depth) {
|
|
1140
|
+
const actual = nodes.filter((node) => node instanceof Node);
|
|
1141
|
+
let { length } = nodes;
|
|
1142
|
+
for (let index = 0; index < length; index += 1) {
|
|
1143
|
+
const node = actual[index];
|
|
1144
|
+
let remove = isClobbered(node);
|
|
1145
|
+
if (!remove) switch (node.nodeType) {
|
|
1146
|
+
case Node.ELEMENT_NODE:
|
|
1147
|
+
handleElement(node, depth);
|
|
1148
|
+
break;
|
|
1149
|
+
case Node.COMMENT_NODE:
|
|
1150
|
+
remove = COMMENT_HARMFUL.test(node.data);
|
|
1151
|
+
break;
|
|
1152
|
+
case Node.DOCUMENT_TYPE_NODE:
|
|
1153
|
+
case Node.PROCESSING_INSTRUCTION_NODE:
|
|
1154
|
+
remove = true;
|
|
1155
|
+
break;
|
|
1156
|
+
}
|
|
1157
|
+
if (remove) {
|
|
1158
|
+
removeNode(node);
|
|
1159
|
+
actual.splice(index, 1);
|
|
1160
|
+
index -= 1;
|
|
1161
|
+
length -= 1;
|
|
1162
|
+
continue;
|
|
1163
|
+
}
|
|
1164
|
+
if (node.hasChildNodes()) sanitizeNodes([...node.childNodes], depth + 1);
|
|
1165
|
+
}
|
|
1166
|
+
return nodes;
|
|
1167
|
+
}
|
|
1168
|
+
var COMMENT_HARMFUL = /<[/\w]/g;
|
|
1169
|
+
var REMOVE_SELECTOR = "script, toretto-temporary";
|
|
1170
|
+
function createHtml(value) {
|
|
1171
|
+
const parsed = getParser().parseFromString(getHtml(value), PARSE_TYPE_HTML);
|
|
1172
|
+
parsed.body.normalize();
|
|
1173
|
+
sanitizeNodes([parsed.body], 0);
|
|
1174
|
+
return parsed.body.innerHTML;
|
|
1175
|
+
}
|
|
1176
|
+
function createTemplate(value, options) {
|
|
1177
|
+
const template = document.createElement(TEMPLATE_TAG);
|
|
1178
|
+
template.innerHTML = createHtml(value);
|
|
1179
|
+
if (typeof value === "string" && options.cache) templates[value] = template;
|
|
1180
|
+
return template;
|
|
1181
|
+
}
|
|
1182
|
+
function getHtml(value) {
|
|
1183
|
+
return `${TEMPORARY_ELEMENT}${typeof value === "string" ? value : value.innerHTML}${TEMPORARY_ELEMENT}`;
|
|
1184
|
+
}
|
|
1185
|
+
function getNodes(value, options) {
|
|
1186
|
+
if (typeof value !== "string" && !(value instanceof HTMLTemplateElement)) return [];
|
|
1187
|
+
const template = getTemplate(value, options);
|
|
1188
|
+
return template == null ? [] : [...template.content.cloneNode(true).childNodes];
|
|
1189
|
+
}
|
|
1190
|
+
function getOptions(input) {
|
|
1191
|
+
const options = isPlainObject$1(input) ? input : {};
|
|
1192
|
+
options.cache = typeof options.cache === "boolean" ? options.cache : true;
|
|
1193
|
+
return options;
|
|
1194
|
+
}
|
|
1195
|
+
function getParser() {
|
|
1196
|
+
parser ??= new DOMParser();
|
|
1197
|
+
return parser;
|
|
1198
|
+
}
|
|
1199
|
+
function getTemplate(value, options) {
|
|
1200
|
+
if (value instanceof HTMLTemplateElement) return createTemplate(value, options);
|
|
1201
|
+
if (value.trim().length === 0) return;
|
|
1202
|
+
let template = templates[value];
|
|
1203
|
+
if (template != null) return template;
|
|
1204
|
+
const element = EXPRESSION_ID.test(value) ? document.querySelector(`#${value}`) : null;
|
|
1205
|
+
return createTemplate(element instanceof HTMLTemplateElement ? element : value, options);
|
|
1206
|
+
}
|
|
1207
|
+
var html = ((value, options) => {
|
|
1208
|
+
return getNodes(value, getOptions(options));
|
|
1209
|
+
});
|
|
1210
|
+
html.clear = () => {
|
|
1211
|
+
templates = {};
|
|
1212
|
+
};
|
|
1213
|
+
html.remove = (template) => {
|
|
1214
|
+
if (typeof template !== "string" || templates[template] == null) return;
|
|
1215
|
+
const keys = Object.keys(templates);
|
|
1216
|
+
const { length } = keys;
|
|
1217
|
+
const updated = {};
|
|
1218
|
+
for (let index = 0; index < length; index += 1) {
|
|
1219
|
+
const key = keys[index];
|
|
1220
|
+
if (key !== template) updated[key] = templates[key];
|
|
1221
|
+
}
|
|
1222
|
+
templates = updated;
|
|
1223
|
+
};
|
|
1224
|
+
var EXPRESSION_ID = /^[a-z][\w-]*$/i;
|
|
1225
|
+
var PARSE_TYPE_HTML = "text/html";
|
|
1226
|
+
var TEMPLATE_TAG = "template";
|
|
1227
|
+
var TEMPORARY_ELEMENT = "<toretto-temporary></toretto-temporary>";
|
|
1228
|
+
var parser;
|
|
1229
|
+
var templates = {};
|
|
1230
|
+
function getSupport() {
|
|
1231
|
+
if (window == null || navigator == null) return false;
|
|
1232
|
+
if ("matchMedia" in window) {
|
|
1233
|
+
const media = matchMedia?.("(pointer: coarse)");
|
|
1234
|
+
if (typeof media?.matches === "boolean" && media.matches) return true;
|
|
1235
|
+
}
|
|
1236
|
+
if ("ontouchstart" in window) return true;
|
|
1237
|
+
if (typeof navigator.maxTouchPoints === "number" && navigator.maxTouchPoints > 0) return true;
|
|
1238
|
+
if (typeof navigator.msMaxTouchPoints === "number" && navigator.msMaxTouchPoints > 0) return true;
|
|
1239
|
+
return false;
|
|
1240
|
+
}
|
|
1241
|
+
(() => {
|
|
1242
|
+
let support = getSupport();
|
|
1243
|
+
const instance = Object.create({
|
|
1244
|
+
get() {
|
|
1245
|
+
return support;
|
|
1246
|
+
},
|
|
1247
|
+
update() {
|
|
1248
|
+
support = getSupport();
|
|
1249
|
+
return support;
|
|
1250
|
+
}
|
|
1251
|
+
});
|
|
1252
|
+
Object.defineProperty(instance, "value", { get() {
|
|
1253
|
+
return support;
|
|
1254
|
+
} });
|
|
1255
|
+
return instance;
|
|
1256
|
+
})();
|
|
1257
|
+
var EventManager = class {
|
|
1258
|
+
listener;
|
|
1259
|
+
constructor(managers, element) {
|
|
1260
|
+
this.managers = managers;
|
|
1261
|
+
this.listener = on(element, "click", (event) => {
|
|
1262
|
+
this.onClick(event);
|
|
1263
|
+
}, { passive: false });
|
|
1264
|
+
}
|
|
1265
|
+
destroy() {
|
|
1266
|
+
this.listener();
|
|
1267
|
+
}
|
|
1268
|
+
onClick(event) {
|
|
1269
|
+
const target = findAncestor(event, "[data-event]");
|
|
1270
|
+
if (!(target instanceof HTMLElement)) return;
|
|
1271
|
+
switch (target?.getAttribute("data-event")) {
|
|
1272
|
+
case "heading":
|
|
1273
|
+
this.onSort(event, target);
|
|
1274
|
+
break;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
onSort(event, target) {
|
|
1278
|
+
const { managers } = this;
|
|
1279
|
+
const direction = target.getAttribute("data-sort-direction");
|
|
1280
|
+
const field = target.getAttribute("data-field");
|
|
1281
|
+
if (field != null) managers.sort.toggle(event, field, direction);
|
|
1282
|
+
}
|
|
1283
|
+
};
|
|
1284
|
+
/**
|
|
1285
|
+
* Clamp a number between a minimum and maximum value
|
|
1286
|
+
* @param value Value to clamp
|
|
1287
|
+
* @param minimum Minimum value
|
|
1288
|
+
* @param maximum Maximum value
|
|
1289
|
+
* @param loop If `true`, the value will loop around when smaller than the minimum or larger than the maximum _(defaults to `false`)_
|
|
1290
|
+
* @returns Clamped value
|
|
1291
|
+
*/
|
|
1292
|
+
function clamp(value, minimum, maximum, loop) {
|
|
1293
|
+
if (![
|
|
1294
|
+
value,
|
|
1295
|
+
minimum,
|
|
1296
|
+
maximum
|
|
1297
|
+
].every(isNumber)) return NaN;
|
|
1298
|
+
if (value < minimum) return loop === true ? maximum : minimum;
|
|
1299
|
+
return value > maximum ? loop === true ? minimum : maximum : value;
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Get the number value from an unknown value _(based on Lodash)_
|
|
1303
|
+
* @param value Original value
|
|
1304
|
+
* @returns Original value as a number, or `NaN` if the value is unable to be parsed
|
|
1305
|
+
*/
|
|
1306
|
+
function getNumber(value) {
|
|
1307
|
+
if (typeof value === "number") return value;
|
|
1308
|
+
if (typeof value === "bigint" || typeof value === "boolean") return Number(value);
|
|
1309
|
+
if (value == null || typeof value === "symbol") return NaN;
|
|
1310
|
+
if (typeof value === "function") return getNumber(value());
|
|
1311
|
+
let parsed = value.valueOf();
|
|
1312
|
+
if (typeof parsed === "object") parsed = parsed.toString();
|
|
1313
|
+
if (typeof parsed !== "string") return getNumber(parsed);
|
|
1314
|
+
const trimmed = parsed.trim();
|
|
1315
|
+
if (trimmed.length === 0) return NaN;
|
|
1316
|
+
if (EXPRESSION_ZEROISH.test(parsed)) return 0;
|
|
1317
|
+
const isBinary = EXPRESSION_BINARY.test(trimmed);
|
|
1318
|
+
if (isBinary || EXPRESSION_OCTAL.test(trimmed)) return Number.parseInt(trimmed.slice(2), isBinary ? 2 : OCTAL_VALUE);
|
|
1319
|
+
return Number(EXPRESSION_HEX.test(trimmed) ? trimmed : trimmed.replace(EXPRESSION_UNDERSCORE, ""));
|
|
1320
|
+
}
|
|
1321
|
+
var EXPRESSION_BINARY = /^0b[01]+$/i;
|
|
1322
|
+
var EXPRESSION_HEX = /^0x[0-9a-f]+$/i;
|
|
1323
|
+
var EXPRESSION_OCTAL = /^0o[0-7]+$/i;
|
|
1324
|
+
var EXPRESSION_UNDERSCORE = /_/g;
|
|
1325
|
+
var EXPRESSION_ZEROISH = /^\s*0+\s*$/;
|
|
1326
|
+
var OCTAL_VALUE = 8;
|
|
1327
|
+
function getSizedMaximum(first, second) {
|
|
1328
|
+
let actual;
|
|
1329
|
+
if (typeof first === "number") actual = first;
|
|
1330
|
+
else actual = typeof second === "number" ? second : MAXIMUM_DEFAULT;
|
|
1331
|
+
return clamp(actual, 1, MAXIMUM_ABSOLUTE);
|
|
1332
|
+
}
|
|
1333
|
+
var MAXIMUM_ABSOLUTE = 16777216;
|
|
1334
|
+
var MAXIMUM_DEFAULT = 1048576;
|
|
1335
|
+
/**
|
|
1336
|
+
* A Map with a maximum size
|
|
1337
|
+
*
|
|
1338
|
+
* Behavior is similar to a _LRU_-cache, where the least recently used entries are removed
|
|
1339
|
+
*/
|
|
1340
|
+
var SizedMap = class extends Map {
|
|
1341
|
+
/**
|
|
1342
|
+
* The maximum size of the Map
|
|
1343
|
+
*/
|
|
1344
|
+
#maximumSize;
|
|
1345
|
+
/**
|
|
1346
|
+
* Is the Map full?
|
|
1347
|
+
*/
|
|
1348
|
+
get full() {
|
|
1349
|
+
return this.size >= this.#maximumSize;
|
|
1350
|
+
}
|
|
1351
|
+
get maximum() {
|
|
1352
|
+
return this.#maximumSize;
|
|
1353
|
+
}
|
|
1354
|
+
constructor(first, second) {
|
|
1355
|
+
const maximum = getSizedMaximum(first, second);
|
|
1356
|
+
super();
|
|
1357
|
+
this.#maximumSize = maximum;
|
|
1358
|
+
if (Array.isArray(first)) {
|
|
1359
|
+
const { length } = first;
|
|
1360
|
+
if (length <= maximum) for (let index = 0; index < length; index += 1) this.set(...first[index]);
|
|
1361
|
+
else for (let index = 0; index < maximum; index += 1) this.set(...first[length - maximum + index]);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
/**
|
|
1365
|
+
* @inheritdoc
|
|
1366
|
+
*/
|
|
1367
|
+
get(key) {
|
|
1368
|
+
const value = super.get(key);
|
|
1369
|
+
if (value !== void 0 || this.has(key)) this.set(key, value);
|
|
1370
|
+
return value;
|
|
1371
|
+
}
|
|
1372
|
+
/**
|
|
1373
|
+
* @inheritdoc
|
|
1374
|
+
*/
|
|
1375
|
+
set(key, value) {
|
|
1376
|
+
if (this.has(key)) this.delete(key);
|
|
1377
|
+
else if (this.size >= this.#maximumSize) this.delete(this.keys().next().value);
|
|
1378
|
+
return super.set(key, value);
|
|
1379
|
+
}
|
|
1380
|
+
};
|
|
1381
|
+
var Memoized = class {
|
|
1382
|
+
#state;
|
|
1383
|
+
/**
|
|
1384
|
+
* Maximum cache size
|
|
1385
|
+
*/
|
|
1386
|
+
get maximum() {
|
|
1387
|
+
return this.#state.cache?.maximum ?? NaN;
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* Current cache size
|
|
1391
|
+
*/
|
|
1392
|
+
get size() {
|
|
1393
|
+
return this.#state.cache?.size ?? NaN;
|
|
1394
|
+
}
|
|
1395
|
+
constructor(callback, options) {
|
|
1396
|
+
const cache = new SizedMap(options.cacheSize);
|
|
1397
|
+
const getter = (...parameters) => {
|
|
1398
|
+
const key = options.cacheKey?.(...parameters) ?? (parameters.length === 1 ? parameters[0] : join(parameters.map(getString), "_"));
|
|
1399
|
+
if (cache.has(key)) return cache.get(key);
|
|
1400
|
+
const value = callback(...parameters);
|
|
1401
|
+
cache.set(key, value);
|
|
1402
|
+
return value;
|
|
1403
|
+
};
|
|
1404
|
+
this.#state = {
|
|
1405
|
+
cache,
|
|
1406
|
+
getter
|
|
1407
|
+
};
|
|
1408
|
+
}
|
|
1409
|
+
/**
|
|
1410
|
+
* Clear the cache
|
|
1411
|
+
*/
|
|
1412
|
+
clear() {
|
|
1413
|
+
this.#state.cache?.clear();
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* Delete a result from the cache
|
|
1417
|
+
* @param key Key to delete
|
|
1418
|
+
* @returns `true` if the key existed and was removed, otherwise `false`
|
|
1419
|
+
*/
|
|
1420
|
+
delete(key) {
|
|
1421
|
+
return this.#state.cache?.delete(key) ?? false;
|
|
1422
|
+
}
|
|
1423
|
+
/**
|
|
1424
|
+
* Destroy the instance _(clearing its cache and removing its callback)_
|
|
1425
|
+
*/
|
|
1426
|
+
destroy() {
|
|
1427
|
+
this.#state.cache?.clear();
|
|
1428
|
+
this.#state.cache = void 0;
|
|
1429
|
+
this.#state.getter = void 0;
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Get a result from the cache
|
|
1433
|
+
* @param key Key to get
|
|
1434
|
+
* @returns Cached result or `undefined` if it does not exist
|
|
1435
|
+
*/
|
|
1436
|
+
get(key) {
|
|
1437
|
+
return this.#state.cache?.get(key);
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Does the result exist?
|
|
1441
|
+
* @param key Key to check
|
|
1442
|
+
* @returns `true` if the result exists, otherwise `false`
|
|
1443
|
+
*/
|
|
1444
|
+
has(key) {
|
|
1445
|
+
return this.#state.cache?.has(key) ?? false;
|
|
1446
|
+
}
|
|
1447
|
+
/**
|
|
1448
|
+
* Run the callback with the provided parameters
|
|
1449
|
+
* @param parameters Parameters to pass to the callback
|
|
1450
|
+
* @returns Cached or computed _(then cached)_ result
|
|
1451
|
+
*/
|
|
1452
|
+
run(...parameters) {
|
|
1453
|
+
if (this.#state.cache == null || this.#state.getter == null) throw new Error("The Memoized instance has been destroyed");
|
|
1454
|
+
return this.#state.getter(...parameters);
|
|
1455
|
+
}
|
|
1456
|
+
};
|
|
1457
|
+
function getMemoizationOptions(input) {
|
|
1458
|
+
const { cacheKey, cacheSize } = isPlainObject(input) ? input : {};
|
|
1459
|
+
return {
|
|
1460
|
+
cacheKey: typeof cacheKey === "function" ? cacheKey : void 0,
|
|
1461
|
+
cacheSize: typeof cacheSize === "number" && cacheSize > 0 ? cacheSize : DEFAULT_CACHE_SIZE
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* Memoize a function, caching and retrieving results based on the first parameter
|
|
1466
|
+
* @param callback Callback to memoize
|
|
1467
|
+
* @param options Memoization options
|
|
1468
|
+
* @returns Memoized instance
|
|
1469
|
+
*/
|
|
1470
|
+
function memoize(callback, options) {
|
|
1471
|
+
return new Memoized(callback, getMemoizationOptions(options));
|
|
1472
|
+
}
|
|
1473
|
+
var DEFAULT_CACHE_SIZE = 1024;
|
|
1474
|
+
/**
|
|
1475
|
+
* Check if a string ends with a specified substring
|
|
1476
|
+
* @param haystack String to look in
|
|
1477
|
+
* @param needle String to look for
|
|
1478
|
+
* @param ignoreCase Ignore case when matching? _(defaults to `false`)_
|
|
1479
|
+
* @returns `true` if the string ends with the given substring, otherwise `false`
|
|
1480
|
+
*/
|
|
1481
|
+
function endsWith(haystack, needle, ignoreCase) {
|
|
1482
|
+
return match("endsWith", haystack, needle, ignoreCase === true);
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Check if a string includes a specified substring
|
|
1486
|
+
* @param haystack String to look in
|
|
1487
|
+
* @param needle String to look for
|
|
1488
|
+
* @param ignoreCase Ignore case when matching? _(defaults to `false`)_
|
|
1489
|
+
* @returns `true` if the string includes the given substring, otherwise `false`
|
|
1490
|
+
*/
|
|
1491
|
+
function includes(haystack, needle, ignoreCase) {
|
|
1492
|
+
return match("includes", haystack, needle, ignoreCase === true);
|
|
1493
|
+
}
|
|
1494
|
+
function match(type, haystack, needle, ignoreCase) {
|
|
1495
|
+
if (typeof haystack !== "string" || typeof needle !== "string") return false;
|
|
1496
|
+
matchMemoizers[type] ??= memoize(matchCallback.bind(type));
|
|
1497
|
+
return matchMemoizers[type].run(haystack, needle, ignoreCase);
|
|
1498
|
+
}
|
|
1499
|
+
function matchCallback(haystack, needle, ignoreCase) {
|
|
1500
|
+
return (ignoreCase ? haystack.toLocaleLowerCase() : haystack)[this](ignoreCase ? needle.toLocaleLowerCase() : needle);
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Check if a string starts with a specified substring
|
|
1504
|
+
* @param haystack String to look in
|
|
1505
|
+
* @param needle String to look for
|
|
1506
|
+
* @param ignoreCase Ignore case when matching? _(defaults to `false`)_
|
|
1507
|
+
* @returns `true` if the string starts with the given substring, otherwise `false`
|
|
1508
|
+
*/
|
|
1509
|
+
function startsWith(haystack, needle, ignoreCase) {
|
|
1510
|
+
return match("startsWith", haystack, needle, ignoreCase === true);
|
|
1511
|
+
}
|
|
1512
|
+
var matchMemoizers = {};
|
|
1513
|
+
function equal(first, second, options) {
|
|
1514
|
+
return equalValue(first, second, getEqualOptions(options));
|
|
1515
|
+
}
|
|
1516
|
+
equal.handlers = getCompareHandlers(equal, { callback: Object.is });
|
|
1517
|
+
equal.initialize = initializeEqualizer;
|
|
1518
|
+
equal.register = registerEqualizer;
|
|
1519
|
+
equal.unregister = unregisterEqualizer;
|
|
1520
|
+
function equalArray(first, second, options) {
|
|
1521
|
+
const { length } = first;
|
|
1522
|
+
if (length !== second.length) return false;
|
|
1523
|
+
let offset = 0;
|
|
1524
|
+
if (length >= ARRAY_THRESHOLD) {
|
|
1525
|
+
offset = Math.round(length / ARRAY_PEEK_PERCENTAGE);
|
|
1526
|
+
offset = offset > ARRAY_THRESHOLD ? ARRAY_THRESHOLD : offset;
|
|
1527
|
+
for (let index = 0; index < offset; index += 1) if (!(equalValue(first[index], second[index], options) && equalValue(first[length - index - 1], second[length - index - 1], options))) return false;
|
|
1528
|
+
}
|
|
1529
|
+
const firstChunks = chunk(first.slice(offset, length - offset), ARRAY_THRESHOLD);
|
|
1530
|
+
const secondChunks = chunk(second.slice(offset, length - offset), ARRAY_THRESHOLD);
|
|
1531
|
+
const chunksLength = firstChunks.length;
|
|
1532
|
+
for (let chunkIndex = 0; chunkIndex < chunksLength; chunkIndex += 1) {
|
|
1533
|
+
const firstChunk = firstChunks[chunkIndex];
|
|
1534
|
+
const secondChunk = secondChunks[chunkIndex];
|
|
1535
|
+
const chunkLength = firstChunk.length;
|
|
1536
|
+
for (let index = 0; index < chunkLength; index += 1) if (!equalValue(firstChunk[index], secondChunk[index], options)) return false;
|
|
1537
|
+
}
|
|
1538
|
+
return true;
|
|
1539
|
+
}
|
|
1540
|
+
function equalArrayBuffer(first, second, options) {
|
|
1541
|
+
return first.byteLength === second.byteLength ? equalArray(new Uint8Array(first), new Uint8Array(second), options) : false;
|
|
1542
|
+
}
|
|
1543
|
+
function equalDataView(first, second, options) {
|
|
1544
|
+
return first.byteOffset === second.byteOffset ? equalArrayBuffer(first.buffer, second.buffer, options) : false;
|
|
1545
|
+
}
|
|
1546
|
+
function equalMap(first, second, options) {
|
|
1547
|
+
const { size } = first;
|
|
1548
|
+
if (size !== second.size) return false;
|
|
1549
|
+
const firstKeys = [...first.keys()];
|
|
1550
|
+
const secondKeys = [...second.keys()];
|
|
1551
|
+
if (firstKeys.some((key) => !secondKeys.includes(key))) return false;
|
|
1552
|
+
for (let index = 0; index < size; index += 1) {
|
|
1553
|
+
const key = firstKeys[index];
|
|
1554
|
+
if (!equalValue(first.get(key), second.get(key), options)) return false;
|
|
1555
|
+
}
|
|
1556
|
+
return true;
|
|
1557
|
+
}
|
|
1558
|
+
function equalPlainObject(first, second, options) {
|
|
1559
|
+
let firstKeys = [...Object.keys(first), ...Object.getOwnPropertySymbols(first)];
|
|
1560
|
+
let secondKeys = [...Object.keys(second), ...Object.getOwnPropertySymbols(second)];
|
|
1561
|
+
if (options.ignoreKeys.enabled || options.ignoreExpressions.enabled) {
|
|
1562
|
+
firstKeys = firstKeys.filter((key) => filterKey(key, options));
|
|
1563
|
+
secondKeys = secondKeys.filter((key) => filterKey(key, options));
|
|
1564
|
+
}
|
|
1565
|
+
const { length } = firstKeys;
|
|
1566
|
+
if (length !== secondKeys.length || firstKeys.some((key) => !secondKeys.includes(key))) return false;
|
|
1567
|
+
for (let index = 0; index < length; index += 1) {
|
|
1568
|
+
const key = firstKeys[index];
|
|
1569
|
+
if (!equalValue(first[key], second[key], options)) return false;
|
|
1570
|
+
}
|
|
1571
|
+
return true;
|
|
1572
|
+
}
|
|
1573
|
+
function equalProperties(first, second, properties, options) {
|
|
1574
|
+
const { length } = properties;
|
|
1575
|
+
for (let index = 0; index < length; index += 1) {
|
|
1576
|
+
const property = properties[index];
|
|
1577
|
+
if (!equalValue(first[property], second[property], options)) return false;
|
|
1578
|
+
}
|
|
1579
|
+
return true;
|
|
1580
|
+
}
|
|
1581
|
+
function equalSet(first, second, options) {
|
|
1582
|
+
const { size } = first;
|
|
1583
|
+
if (size !== second.size) return false;
|
|
1584
|
+
const firstValues = [...first];
|
|
1585
|
+
const secondValues = [...second];
|
|
1586
|
+
for (let index = 0; index < size; index += 1) {
|
|
1587
|
+
const firstValue = firstValues[index];
|
|
1588
|
+
if (!secondValues.some((secondValue) => equalValue(firstValue, secondValue, options))) return false;
|
|
1589
|
+
}
|
|
1590
|
+
return true;
|
|
1591
|
+
}
|
|
1592
|
+
function equalTypedArray(first, second) {
|
|
1593
|
+
if (first.constructor !== second.constructor) return false;
|
|
1594
|
+
if (first.byteLength !== second.byteLength) return false;
|
|
1595
|
+
const { length } = first;
|
|
1596
|
+
for (let index = 0; index < length; index += 1) if (first[index] !== second[index]) return false;
|
|
1597
|
+
return true;
|
|
1598
|
+
}
|
|
1599
|
+
function equalValue(first, second, options) {
|
|
1600
|
+
if (options.relaxedNullish && first == null && second == null) return true;
|
|
1601
|
+
switch (true) {
|
|
1602
|
+
case Object.is(first, second): return true;
|
|
1603
|
+
case first == null || second == null: return first === second;
|
|
1604
|
+
case typeof first !== typeof second: return false;
|
|
1605
|
+
case typeof first === "string" && options.ignoreCase === true: return Object.is(first.toLocaleLowerCase(), second.toLocaleLowerCase());
|
|
1606
|
+
case first instanceof ArrayBuffer && second instanceof ArrayBuffer: return equalArrayBuffer(first, second, options);
|
|
1607
|
+
case first instanceof Date && second instanceof Date: return Object.is(Number(first), Number(second));
|
|
1608
|
+
case first instanceof DataView && second instanceof DataView: return equalDataView(first, second, options);
|
|
1609
|
+
case first instanceof Error && second instanceof Error: return equalProperties(first, second, ["name", "message"], options);
|
|
1610
|
+
case first instanceof Map && second instanceof Map: return equalMap(first, second, options);
|
|
1611
|
+
case first instanceof RegExp && second instanceof RegExp: return equalProperties(first, second, ["source", "flags"], options);
|
|
1612
|
+
case first instanceof Set && second instanceof Set: return equalSet(first, second, options);
|
|
1613
|
+
case Array.isArray(first) && Array.isArray(second): return equalArray(first, second, options);
|
|
1614
|
+
case isPlainObject(first) && isPlainObject(second): return equalPlainObject(first, second, options);
|
|
1615
|
+
case isTypedArray(first) && isTypedArray(second): return equalTypedArray(first, second);
|
|
1616
|
+
default: return equal.handlers.handle(first, second, options);
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
/**
|
|
1620
|
+
* Create an equalizer with predefined options
|
|
1621
|
+
* @param options Comparison options
|
|
1622
|
+
* @returns Equalizer function
|
|
1623
|
+
*/
|
|
1624
|
+
function initializeEqualizer(options) {
|
|
1625
|
+
const actual = getEqualOptions(options);
|
|
1626
|
+
const equalizer = (first, second) => equalValue(first, second, actual);
|
|
1627
|
+
equalizer.register = registerEqualizer;
|
|
1628
|
+
equalizer.unregister = unregisterEqualizer;
|
|
1629
|
+
return equalizer;
|
|
1630
|
+
}
|
|
1631
|
+
/**
|
|
1632
|
+
* Register a equality comparison function for a specific class
|
|
1633
|
+
* @param constructor Class constructor
|
|
1634
|
+
* @param fn Comparison function
|
|
1635
|
+
*/
|
|
1636
|
+
function registerEqualizer(constructor, handler) {
|
|
1637
|
+
equal.handlers.register(constructor, handler);
|
|
1638
|
+
}
|
|
1639
|
+
/**
|
|
1640
|
+
* Unregister a equality comparison handler for a specific class
|
|
1641
|
+
* @param constructor Class constructor
|
|
1642
|
+
*/
|
|
1643
|
+
function unregisterEqualizer(constructor) {
|
|
1644
|
+
equal.handlers.unregister(constructor);
|
|
1645
|
+
}
|
|
1646
|
+
function filterKey(key, options) {
|
|
1647
|
+
if (typeof key !== "string") return true;
|
|
1648
|
+
if (options.ignoreExpressions.enabled && options.ignoreExpressions.values.some((expression) => expression.test(key))) return false;
|
|
1649
|
+
if (options.ignoreKeys.enabled && options.ignoreKeys.values.has(key)) return false;
|
|
1650
|
+
return true;
|
|
1651
|
+
}
|
|
1652
|
+
function getEqualOptions(input) {
|
|
1653
|
+
const options = {
|
|
1654
|
+
ignoreCase: false,
|
|
1655
|
+
ignoreExpressions: {
|
|
1656
|
+
enabled: false,
|
|
1657
|
+
values: []
|
|
1658
|
+
},
|
|
1659
|
+
ignoreKeys: {
|
|
1660
|
+
enabled: false,
|
|
1661
|
+
values: /* @__PURE__ */ new Set()
|
|
1662
|
+
},
|
|
1663
|
+
relaxedNullish: false
|
|
1664
|
+
};
|
|
1665
|
+
if (typeof input === "boolean") {
|
|
1666
|
+
options.ignoreCase = input;
|
|
1667
|
+
return options;
|
|
1668
|
+
}
|
|
1669
|
+
if (!isPlainObject(input)) return options;
|
|
1670
|
+
options.ignoreCase = typeof input.ignoreCase === "boolean" ? input.ignoreCase : false;
|
|
1671
|
+
options.ignoreExpressions.values = (Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => key instanceof RegExp);
|
|
1672
|
+
options.ignoreKeys.values = new Set((Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => typeof key === "string"));
|
|
1673
|
+
options.ignoreExpressions.enabled = options.ignoreExpressions.values.length > 0;
|
|
1674
|
+
options.ignoreKeys.enabled = options.ignoreKeys.values.size > 0;
|
|
1675
|
+
options.relaxedNullish = input.relaxedNullish === true;
|
|
1676
|
+
return options;
|
|
1677
|
+
}
|
|
1678
|
+
var ARRAY_PEEK_PERCENTAGE = 10;
|
|
1679
|
+
var ARRAY_THRESHOLD = 100;
|
|
1680
|
+
var FilterManager = class {
|
|
1681
|
+
handlers = Object.freeze({
|
|
1682
|
+
add: (item) => this.add(item),
|
|
1683
|
+
clear: () => this.clear(),
|
|
1684
|
+
remove: (value) => this.remove(value),
|
|
1685
|
+
set: (items) => this.set(items)
|
|
1686
|
+
});
|
|
1687
|
+
items = {};
|
|
1688
|
+
constructor(managers) {
|
|
1689
|
+
this.managers = managers;
|
|
1690
|
+
}
|
|
1691
|
+
add(item) {
|
|
1692
|
+
if (this.items[item.field] == null) this.items[item.field] = [];
|
|
1693
|
+
else if (this.items[item.field].findIndex((existing) => equal(existing, item)) !== -1) return;
|
|
1694
|
+
this.items[item.field].push(item);
|
|
1695
|
+
this.filter();
|
|
1696
|
+
}
|
|
1697
|
+
clear() {
|
|
1698
|
+
if (Object.keys(this.items).length > 0) {
|
|
1699
|
+
this.items = {};
|
|
1700
|
+
this.filter();
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
destroy() {
|
|
1704
|
+
this.handlers = void 0;
|
|
1705
|
+
this.items = {};
|
|
1706
|
+
}
|
|
1707
|
+
filter() {
|
|
1708
|
+
const { managers } = this;
|
|
1709
|
+
const filtered = [];
|
|
1710
|
+
const filters = Object.entries(this.items);
|
|
1711
|
+
const keysLength = managers.data.values.keys.original.length;
|
|
1712
|
+
rowLoop: for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
1713
|
+
const key = managers.data.values.keys.original[keyIndex];
|
|
1714
|
+
const row = managers.data.values.objects.mapped.get(key);
|
|
1715
|
+
if (row == null) continue;
|
|
1716
|
+
filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
|
|
1717
|
+
const [field, items] = filters[filterIndex];
|
|
1718
|
+
const value = row[field];
|
|
1719
|
+
for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
|
|
1720
|
+
const filter = items[itemIndex];
|
|
1721
|
+
if (comparators[filter.comparison](value, filter.value)) continue filterLoop;
|
|
1722
|
+
}
|
|
1723
|
+
continue rowLoop;
|
|
1724
|
+
}
|
|
1725
|
+
filtered.push(key);
|
|
1726
|
+
}
|
|
1727
|
+
managers.data.values.keys.active = filtered;
|
|
1728
|
+
if (managers.sort.items.length > 0) managers.sort.sort();
|
|
1729
|
+
else managers.virtualization.update(true, true);
|
|
1730
|
+
}
|
|
1731
|
+
remove(value) {
|
|
1732
|
+
if (typeof value === "string") {
|
|
1733
|
+
if (this.items[value] == null) return;
|
|
1734
|
+
this.items = {};
|
|
1735
|
+
} else {
|
|
1736
|
+
const { field } = value;
|
|
1737
|
+
if (this.items[field] == null) return;
|
|
1738
|
+
if (this.items[field].findIndex((item) => equal(item, value)) === -1) return;
|
|
1739
|
+
}
|
|
1740
|
+
this.filter();
|
|
1741
|
+
}
|
|
1742
|
+
set(items) {
|
|
1743
|
+
const keyed = {};
|
|
1744
|
+
const { length } = items;
|
|
1745
|
+
for (let index = 0; index < length; index += 1) {
|
|
1746
|
+
const item = items[index];
|
|
1747
|
+
keyed[item.field] ??= [];
|
|
1748
|
+
keyed[item.field].push(item);
|
|
1749
|
+
}
|
|
1750
|
+
this.items = keyed;
|
|
1751
|
+
this.filter();
|
|
1752
|
+
}
|
|
1753
|
+
};
|
|
1754
|
+
const comparators = {
|
|
1755
|
+
contains: (row, filter) => includes(getString(row), getString(filter), true),
|
|
1756
|
+
"ends-with": (row, filter) => endsWith(getString(row), getString(filter), true),
|
|
1757
|
+
equals: (row, filter) => equalizer(row, filter),
|
|
1758
|
+
"greater-than": (row, filter) => getNumber(row) > getNumber(filter),
|
|
1759
|
+
"greater-than-or-equal": (row, filter) => getNumber(row) >= getNumber(filter),
|
|
1760
|
+
"less-than": (row, filter) => getNumber(row) < getNumber(filter),
|
|
1761
|
+
"less-than-or-equal": (row, filter) => getNumber(row) <= getNumber(filter),
|
|
1762
|
+
"not-contains": (row, filter) => !includes(getString(row), getString(filter), true),
|
|
1763
|
+
"not-equals": (row, filter) => !equalizer(row, filter),
|
|
1764
|
+
"starts-with": (row, filter) => startsWith(getString(row), getString(filter), true)
|
|
1765
|
+
};
|
|
1766
|
+
const equalizer = equal.initialize({ ignoreCase: true });
|
|
1767
|
+
function removeRow(pool, row) {
|
|
1768
|
+
if (row.element != null) {
|
|
1769
|
+
row.element.innerHTML = "";
|
|
1770
|
+
pool.rows.push(row.element);
|
|
1771
|
+
row.element.remove();
|
|
1772
|
+
row.element = void 0;
|
|
1773
|
+
}
|
|
1774
|
+
row.cells = {};
|
|
1775
|
+
}
|
|
1776
|
+
function renderRow(managers, row) {
|
|
1777
|
+
const element = row.element ?? managers.virtualization.pool.rows.shift() ?? createRow();
|
|
1778
|
+
row.element = element;
|
|
1779
|
+
element.dataset.key = String(row.key);
|
|
1780
|
+
element.innerHTML = "";
|
|
1781
|
+
const columns = managers.column.items;
|
|
1782
|
+
const { length } = columns;
|
|
1783
|
+
const data = managers.data.values.objects.mapped.get(row.key);
|
|
1784
|
+
if (data == null) return;
|
|
1785
|
+
for (let index = 0; index < length; index += 1) {
|
|
1786
|
+
const { options } = columns[index];
|
|
1787
|
+
managers.virtualization.pool.cells[options.field] ??= [];
|
|
1788
|
+
const cell = managers.virtualization.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
|
|
1789
|
+
cell.textContent = String(data[options.field]);
|
|
1790
|
+
row.cells[options.field] = cell;
|
|
1791
|
+
element.append(cell);
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
var RowComponent = class {
|
|
1795
|
+
cells = {};
|
|
1796
|
+
element;
|
|
1797
|
+
constructor(key) {
|
|
1798
|
+
this.key = key;
|
|
1799
|
+
}
|
|
1800
|
+
};
|
|
1801
|
+
var RowManager = class {
|
|
1802
|
+
components = /* @__PURE__ */ new Map();
|
|
1803
|
+
height;
|
|
1804
|
+
constructor(managers, rowHeight) {
|
|
1805
|
+
this.managers = managers;
|
|
1806
|
+
this.height = rowHeight;
|
|
1807
|
+
}
|
|
1808
|
+
destroy() {
|
|
1809
|
+
const components = [...this.components.values()];
|
|
1810
|
+
const { length } = components;
|
|
1811
|
+
for (let index = 0; index < length; index += 1) removeRow(this.managers.virtualization.pool, components[index]);
|
|
1812
|
+
this.components.clear();
|
|
1813
|
+
}
|
|
1814
|
+
get(key) {
|
|
1815
|
+
let row = this.components.get(key);
|
|
1816
|
+
if (row == null) {
|
|
1817
|
+
row = new RowComponent(key);
|
|
1818
|
+
this.components.set(key, row);
|
|
1819
|
+
}
|
|
1820
|
+
return row;
|
|
1821
|
+
}
|
|
1822
|
+
has(key) {
|
|
1823
|
+
return this.components.has(key);
|
|
1824
|
+
}
|
|
1825
|
+
remove(key) {
|
|
1826
|
+
const row = this.components.get(key);
|
|
1827
|
+
if (row != null) {
|
|
1828
|
+
removeRow(this.managers.virtualization.pool, row);
|
|
1829
|
+
this.components.delete(key);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
update(key) {
|
|
1833
|
+
const row = this.components.get(key);
|
|
1834
|
+
if (row != null) renderRow(this.managers, row);
|
|
1835
|
+
}
|
|
1836
|
+
};
|
|
1837
|
+
var SortManager = class {
|
|
1838
|
+
handlers = Object.freeze({
|
|
1839
|
+
add: (field, direction) => this.add(field, direction),
|
|
1840
|
+
flip: (field) => this.flip(field),
|
|
1841
|
+
clear: () => this.clear(),
|
|
1842
|
+
remove: (field) => this.remove(field),
|
|
1843
|
+
set: (items) => this.set(items)
|
|
1844
|
+
});
|
|
1845
|
+
items = [];
|
|
1846
|
+
constructor(managers) {
|
|
1847
|
+
this.managers = managers;
|
|
1848
|
+
}
|
|
1849
|
+
add(field, direction) {
|
|
1850
|
+
if (this.items.findIndex((item) => item.key === field) > -1) return;
|
|
1851
|
+
this.items.push({
|
|
1852
|
+
key: field,
|
|
1853
|
+
direction: direction ?? "ascending"
|
|
1854
|
+
});
|
|
1855
|
+
this.sort();
|
|
1856
|
+
}
|
|
1857
|
+
addOrSet(event, field) {
|
|
1858
|
+
if (event.ctrlKey || event.metaKey) this.add(field);
|
|
1859
|
+
else this.set([{
|
|
1860
|
+
field,
|
|
1861
|
+
direction: "ascending"
|
|
1862
|
+
}]);
|
|
1863
|
+
}
|
|
1864
|
+
clear() {
|
|
1865
|
+
if (this.items.length > 0) {
|
|
1866
|
+
this.items.length = 0;
|
|
1867
|
+
this.sort();
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
destroy() {
|
|
1871
|
+
this.handlers = void 0;
|
|
1872
|
+
this.items.length = 0;
|
|
1873
|
+
}
|
|
1874
|
+
flip(field) {
|
|
1875
|
+
const item = this.items.find((item) => item.key === field);
|
|
1876
|
+
if (item == null) return;
|
|
1877
|
+
item.direction = item.direction === "ascending" ? "descending" : "ascending";
|
|
1878
|
+
this.sort();
|
|
1879
|
+
}
|
|
1880
|
+
remove(field) {
|
|
1881
|
+
const index = this.items.findIndex((item) => item.key === field);
|
|
1882
|
+
if (index > -1) {
|
|
1883
|
+
this.items.splice(index, 1);
|
|
1884
|
+
this.sort();
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
removeOrClear(event, field) {
|
|
1888
|
+
if (event.ctrlKey || event.metaKey) this.remove(field);
|
|
1889
|
+
else this.clear();
|
|
1890
|
+
}
|
|
1891
|
+
set(items) {
|
|
1892
|
+
this.items.splice(0, this.items.length, ...items.map((item) => ({
|
|
1893
|
+
key: item.field,
|
|
1894
|
+
direction: item.direction
|
|
1895
|
+
})));
|
|
1896
|
+
this.sort();
|
|
1897
|
+
}
|
|
1898
|
+
sort() {
|
|
1899
|
+
const { items, managers } = this;
|
|
1900
|
+
const { length } = managers.column.items;
|
|
1901
|
+
for (let index = 0; index < length; index += 1) {
|
|
1902
|
+
const column = managers.column.items[index];
|
|
1903
|
+
const sorterIndex = items.findIndex((item) => item.key === column.options.field);
|
|
1904
|
+
const sorterItem = items[sorterIndex];
|
|
1905
|
+
setAttributes(column.elements.wrapper, {
|
|
1906
|
+
"aria-sort": sorterItem == null ? "none" : items.length > 1 ? "other" : sorterItem.direction,
|
|
1907
|
+
"data-sort-direction": sorterItem == null ? void 0 : sorterItem.direction
|
|
1908
|
+
});
|
|
1909
|
+
setAttribute(column.elements.sorter, "data-sort-position", sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
|
|
1910
|
+
}
|
|
1911
|
+
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]);
|
|
1912
|
+
managers.virtualization.update(true, true);
|
|
1913
|
+
}
|
|
1914
|
+
toggle(event, field, direction) {
|
|
1915
|
+
switch (direction) {
|
|
1916
|
+
case "ascending":
|
|
1917
|
+
this.flip(field);
|
|
1918
|
+
return;
|
|
1919
|
+
case "descending":
|
|
1920
|
+
this.removeOrClear(event, field);
|
|
1921
|
+
return;
|
|
1922
|
+
default:
|
|
1923
|
+
this.addOrSet(event, field);
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
};
|
|
610
1928
|
function getRange(down) {
|
|
611
1929
|
const { components, managers } = this;
|
|
612
1930
|
const { clientHeight, scrollTop } = components.body.elements.group;
|
|
@@ -656,6 +1974,8 @@ var VirtualizationManager = class {
|
|
|
656
1974
|
}
|
|
657
1975
|
this.pool.cells = {};
|
|
658
1976
|
this.pool.rows = [];
|
|
1977
|
+
this.listener = void 0;
|
|
1978
|
+
this.visible = void 0;
|
|
659
1979
|
}
|
|
660
1980
|
removeCells(fields) {
|
|
661
1981
|
const { length } = fields;
|
|
@@ -671,13 +1991,13 @@ var VirtualizationManager = class {
|
|
|
671
1991
|
this.fragment.replaceChildren();
|
|
672
1992
|
return this.fragment;
|
|
673
1993
|
}
|
|
674
|
-
update(down) {
|
|
1994
|
+
update(down, rerender) {
|
|
675
1995
|
const { components, managers, pool, visible } = this;
|
|
676
1996
|
components.body.elements.faker.style.height = `${managers.data.size * managers.row.height}px`;
|
|
677
1997
|
const indices = /* @__PURE__ */ new Set();
|
|
678
1998
|
const range = getRange.call(this, down);
|
|
679
1999
|
for (let index = range.start; index <= range.end; index += 1) indices.add(index);
|
|
680
|
-
let remove = false;
|
|
2000
|
+
let remove = rerender ?? false;
|
|
681
2001
|
for (const [index, row] of visible) {
|
|
682
2002
|
if (!managers.row.has(row.key) || !indices.has(index)) remove = true;
|
|
683
2003
|
if (remove) {
|
|
@@ -714,10 +2034,15 @@ var Tabela = class {
|
|
|
714
2034
|
#managers = {
|
|
715
2035
|
column: void 0,
|
|
716
2036
|
data: void 0,
|
|
2037
|
+
event: void 0,
|
|
2038
|
+
filter: void 0,
|
|
717
2039
|
row: void 0,
|
|
2040
|
+
sort: void 0,
|
|
718
2041
|
virtualization: void 0
|
|
719
2042
|
};
|
|
720
2043
|
data;
|
|
2044
|
+
filter;
|
|
2045
|
+
sort;
|
|
721
2046
|
get key() {
|
|
722
2047
|
return this.#key;
|
|
723
2048
|
}
|
|
@@ -733,11 +2058,16 @@ var Tabela = class {
|
|
|
733
2058
|
this.#components.footer = new FooterComponent();
|
|
734
2059
|
this.#managers.column = new ColumnManager(this.#managers, this.#components, options.columns);
|
|
735
2060
|
this.#managers.data = new DataManager(this.#managers, this.#components, options.key);
|
|
2061
|
+
this.#managers.event = new EventManager(this.#managers, this.#element);
|
|
2062
|
+
this.#managers.filter = new FilterManager(this.#managers);
|
|
736
2063
|
this.#managers.row = new RowManager(this.#managers, options.rowHeight);
|
|
2064
|
+
this.#managers.sort = new SortManager(this.#managers);
|
|
737
2065
|
this.#managers.virtualization = new VirtualizationManager(this.#managers, this.#components);
|
|
738
2066
|
element.append(this.#components.header.elements.group, this.#components.body.elements.group, this.#components.footer.elements.group);
|
|
739
2067
|
this.#managers.data.set(options.data);
|
|
740
2068
|
this.data = this.#managers.data.handlers;
|
|
2069
|
+
this.filter = this.#managers.filter.handlers;
|
|
2070
|
+
this.sort = this.#managers.sort.handlers;
|
|
741
2071
|
}
|
|
742
2072
|
destroy() {
|
|
743
2073
|
const components = this.#components;
|
|
@@ -748,7 +2078,10 @@ var Tabela = class {
|
|
|
748
2078
|
components.header.destroy();
|
|
749
2079
|
managers.column.destroy();
|
|
750
2080
|
managers.data.destroy();
|
|
2081
|
+
managers.event.destroy();
|
|
2082
|
+
managers.filter.destroy();
|
|
751
2083
|
managers.row.destroy();
|
|
2084
|
+
managers.sort.destroy();
|
|
752
2085
|
managers.virtualization.destroy();
|
|
753
2086
|
element.innerHTML = "";
|
|
754
2087
|
element.role = "";
|