@keenthemes/ktui 1.2.6 → 1.2.7
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/README.md +14 -5
- package/dist/ktui.js +3775 -2298
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +25 -5
- package/lib/cjs/components/datatable/datatable-checkbox.d.ts +37 -1
- package/lib/cjs/components/datatable/datatable-checkbox.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-checkbox.js +143 -156
- package/lib/cjs/components/datatable/datatable-checkbox.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-column-utils.d.ts +30 -0
- package/lib/cjs/components/datatable/datatable-column-utils.d.ts.map +1 -0
- package/lib/cjs/components/datatable/datatable-column-utils.js +42 -0
- package/lib/cjs/components/datatable/datatable-column-utils.js.map +1 -0
- package/lib/cjs/components/datatable/datatable-contracts.d.ts +2 -4
- package/lib/cjs/components/datatable/datatable-contracts.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-defaults.d.ts +20 -0
- package/lib/cjs/components/datatable/datatable-defaults.d.ts.map +1 -0
- package/lib/cjs/components/datatable/datatable-defaults.js +193 -0
- package/lib/cjs/components/datatable/datatable-defaults.js.map +1 -0
- package/lib/cjs/components/datatable/datatable-layout-plugin.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-layout-plugin.js +11 -1
- package/lib/cjs/components/datatable/datatable-layout-plugin.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-local-provider.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-local-provider.js +80 -24
- package/lib/cjs/components/datatable/datatable-local-provider.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-pagination-renderer.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-pagination-renderer.js +3 -2
- package/lib/cjs/components/datatable/datatable-pagination-renderer.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-registry.d.ts +18 -0
- package/lib/cjs/components/datatable/datatable-registry.d.ts.map +1 -0
- package/lib/cjs/components/datatable/datatable-registry.js +66 -0
- package/lib/cjs/components/datatable/datatable-registry.js.map +1 -0
- package/lib/cjs/components/datatable/datatable-remote-provider.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-remote-provider.js +1 -2
- package/lib/cjs/components/datatable/datatable-remote-provider.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-search-handler.d.ts +10 -0
- package/lib/cjs/components/datatable/datatable-search-handler.d.ts.map +1 -0
- package/lib/cjs/components/datatable/datatable-search-handler.js +65 -0
- package/lib/cjs/components/datatable/datatable-search-handler.js.map +1 -0
- package/lib/cjs/components/datatable/datatable-sort.d.ts +31 -4
- package/lib/cjs/components/datatable/datatable-sort.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-sort.js +86 -58
- package/lib/cjs/components/datatable/datatable-sort.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-spinner.d.ts +30 -0
- package/lib/cjs/components/datatable/datatable-spinner.d.ts.map +1 -0
- package/lib/cjs/components/datatable/datatable-spinner.js +54 -0
- package/lib/cjs/components/datatable/datatable-spinner.js.map +1 -0
- package/lib/cjs/components/datatable/datatable-state-persistence.d.ts +19 -0
- package/lib/cjs/components/datatable/datatable-state-persistence.d.ts.map +1 -0
- package/lib/cjs/components/datatable/datatable-state-persistence.js +59 -0
- package/lib/cjs/components/datatable/datatable-state-persistence.js.map +1 -0
- package/lib/cjs/components/datatable/datatable-table-renderer.d.ts +2 -0
- package/lib/cjs/components/datatable/datatable-table-renderer.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-table-renderer.js +75 -16
- package/lib/cjs/components/datatable/datatable-table-renderer.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-utils.d.ts +10 -0
- package/lib/cjs/components/datatable/datatable-utils.d.ts.map +1 -0
- package/lib/cjs/components/datatable/datatable-utils.js +15 -0
- package/lib/cjs/components/datatable/datatable-utils.js.map +1 -0
- package/lib/cjs/components/datatable/datatable.d.ts +26 -34
- package/lib/cjs/components/datatable/datatable.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable.js +155 -492
- package/lib/cjs/components/datatable/datatable.js.map +1 -1
- package/lib/cjs/components/datatable/index.d.ts +1 -1
- package/lib/cjs/components/datatable/index.d.ts.map +1 -1
- package/lib/cjs/components/datatable/types.d.ts +100 -11
- package/lib/cjs/components/datatable/types.d.ts.map +1 -1
- package/lib/cjs/index.d.ts +1 -1
- package/lib/cjs/index.d.ts.map +1 -1
- package/lib/cjs/index.js +6 -0
- package/lib/cjs/index.js.map +1 -1
- package/lib/esm/components/datatable/datatable-checkbox.d.ts +37 -1
- package/lib/esm/components/datatable/datatable-checkbox.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-checkbox.js +142 -155
- package/lib/esm/components/datatable/datatable-checkbox.js.map +1 -1
- package/lib/esm/components/datatable/datatable-column-utils.d.ts +30 -0
- package/lib/esm/components/datatable/datatable-column-utils.d.ts.map +1 -0
- package/lib/esm/components/datatable/datatable-column-utils.js +38 -0
- package/lib/esm/components/datatable/datatable-column-utils.js.map +1 -0
- package/lib/esm/components/datatable/datatable-contracts.d.ts +2 -4
- package/lib/esm/components/datatable/datatable-contracts.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-defaults.d.ts +20 -0
- package/lib/esm/components/datatable/datatable-defaults.d.ts.map +1 -0
- package/lib/esm/components/datatable/datatable-defaults.js +190 -0
- package/lib/esm/components/datatable/datatable-defaults.js.map +1 -0
- package/lib/esm/components/datatable/datatable-layout-plugin.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-layout-plugin.js +11 -1
- package/lib/esm/components/datatable/datatable-layout-plugin.js.map +1 -1
- package/lib/esm/components/datatable/datatable-local-provider.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-local-provider.js +80 -24
- package/lib/esm/components/datatable/datatable-local-provider.js.map +1 -1
- package/lib/esm/components/datatable/datatable-pagination-renderer.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-pagination-renderer.js +3 -2
- package/lib/esm/components/datatable/datatable-pagination-renderer.js.map +1 -1
- package/lib/esm/components/datatable/datatable-registry.d.ts +18 -0
- package/lib/esm/components/datatable/datatable-registry.d.ts.map +1 -0
- package/lib/esm/components/datatable/datatable-registry.js +63 -0
- package/lib/esm/components/datatable/datatable-registry.js.map +1 -0
- package/lib/esm/components/datatable/datatable-remote-provider.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-remote-provider.js +1 -2
- package/lib/esm/components/datatable/datatable-remote-provider.js.map +1 -1
- package/lib/esm/components/datatable/datatable-search-handler.d.ts +10 -0
- package/lib/esm/components/datatable/datatable-search-handler.d.ts.map +1 -0
- package/lib/esm/components/datatable/datatable-search-handler.js +62 -0
- package/lib/esm/components/datatable/datatable-search-handler.js.map +1 -0
- package/lib/esm/components/datatable/datatable-sort.d.ts +31 -4
- package/lib/esm/components/datatable/datatable-sort.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-sort.js +85 -57
- package/lib/esm/components/datatable/datatable-sort.js.map +1 -1
- package/lib/esm/components/datatable/datatable-spinner.d.ts +30 -0
- package/lib/esm/components/datatable/datatable-spinner.d.ts.map +1 -0
- package/lib/esm/components/datatable/datatable-spinner.js +51 -0
- package/lib/esm/components/datatable/datatable-spinner.js.map +1 -0
- package/lib/esm/components/datatable/datatable-state-persistence.d.ts +19 -0
- package/lib/esm/components/datatable/datatable-state-persistence.d.ts.map +1 -0
- package/lib/esm/components/datatable/datatable-state-persistence.js +55 -0
- package/lib/esm/components/datatable/datatable-state-persistence.js.map +1 -0
- package/lib/esm/components/datatable/datatable-table-renderer.d.ts +2 -0
- package/lib/esm/components/datatable/datatable-table-renderer.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-table-renderer.js +75 -16
- package/lib/esm/components/datatable/datatable-table-renderer.js.map +1 -1
- package/lib/esm/components/datatable/datatable-utils.d.ts +10 -0
- package/lib/esm/components/datatable/datatable-utils.d.ts.map +1 -0
- package/lib/esm/components/datatable/datatable-utils.js +12 -0
- package/lib/esm/components/datatable/datatable-utils.js.map +1 -0
- package/lib/esm/components/datatable/datatable.d.ts +26 -34
- package/lib/esm/components/datatable/datatable.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable.js +157 -494
- package/lib/esm/components/datatable/datatable.js.map +1 -1
- package/lib/esm/components/datatable/index.d.ts +1 -1
- package/lib/esm/components/datatable/index.d.ts.map +1 -1
- package/lib/esm/components/datatable/types.d.ts +100 -11
- package/lib/esm/components/datatable/types.d.ts.map +1 -1
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/index.d.ts.map +1 -1
- package/lib/esm/index.js +6 -0
- package/lib/esm/index.js.map +1 -1
- package/package.json +5 -1
- package/skills/ktui/SKILL.md +711 -0
- package/skills/ktui-datatable/SKILL.md +302 -0
- package/skills/ktui-install/SKILL.md +150 -0
- package/skills/ktui-select/SKILL.md +271 -0
- package/src/components/__tests__/component.test.ts +347 -0
- package/src/components/collapse/collapse.css +2 -2
- package/src/components/datatable/__tests__/architecture-boundaries.test.ts +56 -8
- package/src/components/datatable/__tests__/currency-sort.test.ts +25 -28
- package/src/components/datatable/__tests__/datatable-checkbox.test.ts +527 -0
- package/src/components/datatable/__tests__/datatable-column-utils.test.ts +117 -0
- package/src/components/datatable/__tests__/datatable-defaults.test.ts +57 -0
- package/src/components/datatable/__tests__/datatable-finalize-extended.test.ts +361 -0
- package/src/components/datatable/__tests__/datatable-fixed-layout.test.ts +427 -0
- package/src/components/datatable/__tests__/datatable-improvements.test.ts +484 -0
- package/src/components/datatable/__tests__/datatable-pagination-extended.test.ts +508 -0
- package/src/components/datatable/__tests__/datatable-public-api.test.ts +269 -0
- package/src/components/datatable/__tests__/datatable-registry.test.ts +172 -0
- package/src/components/datatable/__tests__/datatable-remote-provider.test.ts +468 -0
- package/src/components/datatable/__tests__/datatable-search-handler.test.ts +124 -0
- package/src/components/datatable/__tests__/datatable-sort-extended.test.ts +417 -0
- package/src/components/datatable/__tests__/datatable-spinner.test.ts +95 -0
- package/src/components/datatable/__tests__/datatable-table-renderer-extended.test.ts +425 -0
- package/src/components/datatable/__tests__/datatable-types.test.ts +117 -0
- package/src/components/datatable/__tests__/datatable-utils.test.ts +52 -0
- package/src/components/datatable/__tests__/multi-row-headers.test.ts +7 -7
- package/src/components/datatable/__tests__/pagination-reset.test.ts +129 -6
- package/src/components/datatable/__tests__/race-conditions.test.ts +11 -11
- package/src/components/datatable/__tests__/setup.ts +12 -4
- package/src/components/datatable/datatable-checkbox.ts +144 -145
- package/src/components/datatable/datatable-column-utils.ts +63 -0
- package/src/components/datatable/datatable-contracts.ts +2 -3
- package/src/components/datatable/datatable-defaults.ts +204 -0
- package/src/components/datatable/datatable-layout-plugin.ts +11 -1
- package/src/components/datatable/datatable-local-provider.ts +91 -28
- package/src/components/datatable/datatable-pagination-renderer.ts +3 -2
- package/src/components/datatable/datatable-registry.ts +89 -0
- package/src/components/datatable/datatable-remote-provider.ts +1 -3
- package/src/components/datatable/datatable-search-handler.ts +97 -0
- package/src/components/datatable/datatable-sort.ts +111 -66
- package/src/components/datatable/datatable-spinner.ts +103 -0
- package/src/components/datatable/datatable-state-persistence.ts +67 -0
- package/src/components/datatable/datatable-table-renderer.ts +81 -18
- package/src/components/datatable/datatable-utils.ts +12 -0
- package/src/components/datatable/datatable.ts +191 -580
- package/src/components/datatable/index.ts +3 -0
- package/src/components/datatable/types.ts +124 -23
- package/src/helpers/__tests__/dom.test.ts +776 -0
- package/src/helpers/__tests__/utils.test.ts +332 -0
- package/src/index.ts +10 -0
- package/skills/ktui-components/SKILL.md +0 -41
- package/skills/ktui-theming/SKILL.md +0 -50
- package/src/components/datatable/datatable-event-adapter.ts +0 -21
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
vi.mock('../../../index', () => ({
|
|
4
|
+
default: { init: vi.fn() },
|
|
5
|
+
}));
|
|
6
|
+
|
|
7
|
+
vi.mock('../../helpers/data', () => {
|
|
8
|
+
const map = new Map();
|
|
9
|
+
return {
|
|
10
|
+
default: {
|
|
11
|
+
set: vi.fn((el: HTMLElement, key: string, val: unknown) => {
|
|
12
|
+
if (!map.has(el)) map.set(el, new Map());
|
|
13
|
+
map.get(el).set(key, val);
|
|
14
|
+
}),
|
|
15
|
+
get: vi.fn((el: HTMLElement, key: string) => {
|
|
16
|
+
return map.has(el) ? map.get(el).get(key) ?? null : null;
|
|
17
|
+
}),
|
|
18
|
+
has: vi.fn((el: HTMLElement, key: string) => {
|
|
19
|
+
return map.has(el) && map.get(el).has(key);
|
|
20
|
+
}),
|
|
21
|
+
remove: vi.fn((el: HTMLElement, key: string) => {
|
|
22
|
+
if (map.has(el)) map.get(el).delete(key);
|
|
23
|
+
}),
|
|
24
|
+
clear: vi.fn((el: HTMLElement) => {
|
|
25
|
+
map.delete(el);
|
|
26
|
+
}),
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
import { KTDataTable, initAllDataTables } from '../datatable';
|
|
32
|
+
|
|
33
|
+
function createLocalTableHtml(): string {
|
|
34
|
+
return `
|
|
35
|
+
<div data-kt-datatable="true">
|
|
36
|
+
<table data-kt-datatable-table="true">
|
|
37
|
+
<thead>
|
|
38
|
+
<tr>
|
|
39
|
+
<th data-kt-datatable-column="0" data-kt-datatable-column-sort="false">Name</th>
|
|
40
|
+
<th data-kt-datatable-column="1">Age</th>
|
|
41
|
+
</tr>
|
|
42
|
+
</thead>
|
|
43
|
+
<tbody>
|
|
44
|
+
<tr><td>Alice</td><td>30</td></tr>
|
|
45
|
+
<tr><td>Bob</td><td>25</td></tr>
|
|
46
|
+
<tr><td>Charlie</td><td>35</td></tr>
|
|
47
|
+
</tbody>
|
|
48
|
+
</table>
|
|
49
|
+
</div>
|
|
50
|
+
`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function createLocalDatatable() {
|
|
54
|
+
const container = document.createElement('div');
|
|
55
|
+
container.innerHTML = createLocalTableHtml();
|
|
56
|
+
document.body.appendChild(container);
|
|
57
|
+
const table = container.querySelector(
|
|
58
|
+
'[data-kt-datatable]',
|
|
59
|
+
) as HTMLElement;
|
|
60
|
+
return { container, table };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
describe('KTDataTable public API', () => {
|
|
64
|
+
describe('reload and redraw', () => {
|
|
65
|
+
it('reload() calls _updateData (local mode, synchronous)', () => {
|
|
66
|
+
const { table } = createLocalDatatable();
|
|
67
|
+
const dt = new KTDataTable(table);
|
|
68
|
+
const spy = vi.spyOn(dt as any, '_updateData');
|
|
69
|
+
dt.reload();
|
|
70
|
+
expect(spy).toHaveBeenCalled();
|
|
71
|
+
dt.dispose();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('redraw() calls _paginateData with default page 1', () => {
|
|
75
|
+
const { table } = createLocalDatatable();
|
|
76
|
+
const dt = new KTDataTable(table);
|
|
77
|
+
const spy = vi.spyOn(dt as any, '_paginateData');
|
|
78
|
+
dt.redraw();
|
|
79
|
+
expect(spy).toHaveBeenCalledWith(1);
|
|
80
|
+
dt.dispose();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('redraw(3) calls _paginateData with page 3', () => {
|
|
84
|
+
const { table } = createLocalDatatable();
|
|
85
|
+
const dt = new KTDataTable(table);
|
|
86
|
+
const spy = vi.spyOn(dt as any, '_paginateData');
|
|
87
|
+
dt.redraw(3);
|
|
88
|
+
expect(spy).toHaveBeenCalledWith(3);
|
|
89
|
+
dt.dispose();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('Spinner', () => {
|
|
94
|
+
it('showSpinner() shows loading spinner', () => {
|
|
95
|
+
const { table } = createLocalDatatable();
|
|
96
|
+
const dt = new KTDataTable(table);
|
|
97
|
+
const spinner = (dt as any)._spinner;
|
|
98
|
+
const spy = vi.spyOn(spinner, 'show');
|
|
99
|
+
dt.showSpinner();
|
|
100
|
+
expect(spy).toHaveBeenCalled();
|
|
101
|
+
dt.dispose();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('hideSpinner() hides loading spinner', () => {
|
|
105
|
+
const { table } = createLocalDatatable();
|
|
106
|
+
const dt = new KTDataTable(table);
|
|
107
|
+
const spinner = (dt as any)._spinner;
|
|
108
|
+
const spy = vi.spyOn(spinner, 'hide');
|
|
109
|
+
dt.hideSpinner();
|
|
110
|
+
expect(spy).toHaveBeenCalled();
|
|
111
|
+
dt.dispose();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('setFilter', () => {
|
|
116
|
+
it('setFilter() stores filter and returns this (chainable)', () => {
|
|
117
|
+
const { table } = createLocalDatatable();
|
|
118
|
+
const dt = new KTDataTable(table);
|
|
119
|
+
const result = dt.setFilter({
|
|
120
|
+
column: 'name',
|
|
121
|
+
type: 'text',
|
|
122
|
+
value: 'Alice',
|
|
123
|
+
});
|
|
124
|
+
expect(result).toBe(dt);
|
|
125
|
+
const state = dt.getState();
|
|
126
|
+
expect(state.filters).toContainEqual({
|
|
127
|
+
column: 'name',
|
|
128
|
+
type: 'text',
|
|
129
|
+
value: 'Alice',
|
|
130
|
+
});
|
|
131
|
+
dt.dispose();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe('search', () => {
|
|
136
|
+
it('search("query") sets search state and reloads', () => {
|
|
137
|
+
const { table } = createLocalDatatable();
|
|
138
|
+
const dt = new KTDataTable(table);
|
|
139
|
+
const reloadSpy = vi.spyOn(dt, 'reload');
|
|
140
|
+
dt.search('Alice');
|
|
141
|
+
expect(reloadSpy).toHaveBeenCalled();
|
|
142
|
+
const state = dt.getState();
|
|
143
|
+
expect(state.search).toBe('Alice');
|
|
144
|
+
dt.dispose();
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe('Static methods', () => {
|
|
149
|
+
it('KTDataTable.getInstance() returns instance for registered element', () => {
|
|
150
|
+
const { table } = createLocalDatatable();
|
|
151
|
+
const dt = new KTDataTable(table);
|
|
152
|
+
const instance = KTDataTable.getInstance(table);
|
|
153
|
+
expect(instance).toBe(dt);
|
|
154
|
+
dt.dispose();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('KTDataTable.getInstance() returns undefined for unregistered element', () => {
|
|
158
|
+
const el = document.createElement('div');
|
|
159
|
+
expect(KTDataTable.getInstance(el)).toBeUndefined();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('KTDataTable.createInstances() creates instances for [data-kt-datatable] elements', () => {
|
|
163
|
+
const container = document.createElement('div');
|
|
164
|
+
container.innerHTML = `
|
|
165
|
+
<div data-kt-datatable="true">
|
|
166
|
+
<table data-kt-datatable-table="true">
|
|
167
|
+
<thead><tr><th>Name</th></tr></thead>
|
|
168
|
+
<tbody><tr><td>Test</td></tr></tbody>
|
|
169
|
+
</table>
|
|
170
|
+
</div>
|
|
171
|
+
`;
|
|
172
|
+
document.body.appendChild(container);
|
|
173
|
+
|
|
174
|
+
KTDataTable.createInstances();
|
|
175
|
+
const el = container.querySelector('[data-kt-datatable]') as HTMLElement;
|
|
176
|
+
const instance = KTDataTable.getInstance(el);
|
|
177
|
+
expect(instance).toBeDefined();
|
|
178
|
+
instance?.dispose();
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe('dispose', () => {
|
|
183
|
+
it('dispose() calls remoteProvider.dispose() if remote mode', () => {
|
|
184
|
+
const { table } = createLocalDatatable();
|
|
185
|
+
const dt = new KTDataTable(table);
|
|
186
|
+
const remoteProvider = (dt as any)._remoteProvider;
|
|
187
|
+
const spy = vi.spyOn(remoteProvider, 'dispose');
|
|
188
|
+
dt.dispose();
|
|
189
|
+
expect(spy).toHaveBeenCalled();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('dispose() calls _dispose() cleanup', () => {
|
|
193
|
+
const { table } = createLocalDatatable();
|
|
194
|
+
const dt = new KTDataTable(table);
|
|
195
|
+
const spy = vi.spyOn(dt as any, '_dispose');
|
|
196
|
+
dt.dispose();
|
|
197
|
+
expect(spy).toHaveBeenCalled();
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe('_emit helper', () => {
|
|
202
|
+
it('_emit dispatches both internal and DOM CustomEvent', () => {
|
|
203
|
+
const { table } = createLocalDatatable();
|
|
204
|
+
const dt = new KTDataTable(table);
|
|
205
|
+
|
|
206
|
+
const handler = vi.fn();
|
|
207
|
+
dt.on('test-event', handler);
|
|
208
|
+
|
|
209
|
+
table.addEventListener('kt.datatable.test-event', ((e: CustomEvent) => {
|
|
210
|
+
expect(e.detail).toBeDefined();
|
|
211
|
+
}) as EventListener);
|
|
212
|
+
|
|
213
|
+
(dt as any)._emit('test-event', { foo: 'bar' });
|
|
214
|
+
expect(handler).toHaveBeenCalledWith({ foo: 'bar' });
|
|
215
|
+
|
|
216
|
+
dt.dispose();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('_emit with no listeners does not throw', () => {
|
|
220
|
+
const { table } = createLocalDatatable();
|
|
221
|
+
const dt = new KTDataTable(table);
|
|
222
|
+
expect(() => (dt as any)._emit('nonexistent-event')).not.toThrow();
|
|
223
|
+
dt.dispose();
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
describe('sort', () => {
|
|
228
|
+
it('sort(field, order) applies explicit direction without toggling', () => {
|
|
229
|
+
const { table } = createLocalDatatable();
|
|
230
|
+
const dt = new KTDataTable(table);
|
|
231
|
+
|
|
232
|
+
dt.sort(1, 'desc');
|
|
233
|
+
expect(dt.getState().sortField).toBe(1);
|
|
234
|
+
expect(dt.getState().sortOrder).toBe('desc');
|
|
235
|
+
|
|
236
|
+
dt.sort(1, 'asc');
|
|
237
|
+
expect(dt.getState().sortOrder).toBe('asc');
|
|
238
|
+
|
|
239
|
+
dt.sort(1, '');
|
|
240
|
+
expect(dt.getState().sortOrder).toBe('');
|
|
241
|
+
|
|
242
|
+
dt.dispose();
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
describe('initAllDataTables', () => {
|
|
247
|
+
it('initAllDataTables creates instances and assigns to window', () => {
|
|
248
|
+
const container = document.createElement('div');
|
|
249
|
+
container.innerHTML = `
|
|
250
|
+
<div data-kt-datatable="true">
|
|
251
|
+
<table data-kt-datatable-table="true">
|
|
252
|
+
<thead><tr><th>Name</th></tr></thead>
|
|
253
|
+
<tbody><tr><td>Test</td></tr></tbody>
|
|
254
|
+
</table>
|
|
255
|
+
</div>
|
|
256
|
+
`;
|
|
257
|
+
document.body.appendChild(container);
|
|
258
|
+
|
|
259
|
+
initAllDataTables();
|
|
260
|
+
|
|
261
|
+
const el = container.querySelector('[data-kt-datatable]') as HTMLElement;
|
|
262
|
+
const instance = KTDataTable.getInstance(el);
|
|
263
|
+
expect(instance).toBeDefined();
|
|
264
|
+
expect((window as any).KTDataTable).toBe(KTDataTable);
|
|
265
|
+
|
|
266
|
+
instance?.dispose();
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
});
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { createDataTableRegistry } from '../datatable-registry';
|
|
3
|
+
import KTData from '../../../helpers/data';
|
|
4
|
+
|
|
5
|
+
vi.mock('../../../helpers/data', () => ({
|
|
6
|
+
default: { remove: vi.fn() },
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
function createMockInstance() {
|
|
10
|
+
return {
|
|
11
|
+
dispose: vi.fn(),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('createDataTableRegistry', () => {
|
|
16
|
+
let registry: ReturnType<typeof createDataTableRegistry>;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
registry = createDataTableRegistry();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('register and get', () => {
|
|
23
|
+
it('register() stores instance in Map, get() retrieves it', () => {
|
|
24
|
+
const el = document.createElement('div');
|
|
25
|
+
const instance = createMockInstance();
|
|
26
|
+
registry.register(el, instance as any);
|
|
27
|
+
expect(registry.get(el)).toBe(instance);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('get() falls back to element.instance property when Map has no entry', () => {
|
|
31
|
+
const el = document.createElement('div') as any;
|
|
32
|
+
const instance = createMockInstance();
|
|
33
|
+
el.instance = instance;
|
|
34
|
+
expect(registry.get(el)).toBe(instance);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('get() returns undefined for unregistered element', () => {
|
|
38
|
+
const el = document.createElement('div');
|
|
39
|
+
expect(registry.get(el)).toBeUndefined();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('remove', () => {
|
|
44
|
+
it('remove() deletes from Map and removes element.instance property', () => {
|
|
45
|
+
const el = document.createElement('div') as any;
|
|
46
|
+
const instance = createMockInstance();
|
|
47
|
+
registry.register(el, instance as any);
|
|
48
|
+
expect(el.instance).toBe(instance);
|
|
49
|
+
|
|
50
|
+
registry.remove(el);
|
|
51
|
+
|
|
52
|
+
expect(registry.get(el)).toBeUndefined();
|
|
53
|
+
expect(el.instance).toBeUndefined();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('remove() on non-existent element does not throw', () => {
|
|
57
|
+
const el = document.createElement('div');
|
|
58
|
+
expect(() => registry.remove(el)).not.toThrow();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('clear', () => {
|
|
63
|
+
it('clear() removes all entries from Map (get falls back to element.instance)', () => {
|
|
64
|
+
const el1 = document.createElement('div');
|
|
65
|
+
const el2 = document.createElement('div');
|
|
66
|
+
const inst1 = createMockInstance();
|
|
67
|
+
const inst2 = createMockInstance();
|
|
68
|
+
registry.register(el1, inst1 as any);
|
|
69
|
+
registry.register(el2, inst2 as any);
|
|
70
|
+
|
|
71
|
+
registry.clear();
|
|
72
|
+
|
|
73
|
+
// get() falls back to element.instance property set by register()
|
|
74
|
+
// so we need to also delete that to verify Map was truly cleared
|
|
75
|
+
delete (el1 as any).instance;
|
|
76
|
+
delete (el2 as any).instance;
|
|
77
|
+
expect(registry.get(el1)).toBeUndefined();
|
|
78
|
+
expect(registry.get(el2)).toBeUndefined();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('createAll', () => {
|
|
83
|
+
it('createAll() finds [data-kt-datatable="true"] elements and creates instances', () => {
|
|
84
|
+
const table1 = document.createElement('div');
|
|
85
|
+
table1.setAttribute('data-kt-datatable', 'true');
|
|
86
|
+
const table2 = document.createElement('div');
|
|
87
|
+
table2.setAttribute('data-kt-datatable', 'true');
|
|
88
|
+
document.body.appendChild(table1);
|
|
89
|
+
document.body.appendChild(table2);
|
|
90
|
+
|
|
91
|
+
const factory = vi.fn(() => createMockInstance());
|
|
92
|
+
registry.createAll(factory);
|
|
93
|
+
|
|
94
|
+
expect(factory).toHaveBeenCalledTimes(2);
|
|
95
|
+
expect(registry.get(table1)).toBeDefined();
|
|
96
|
+
expect(registry.get(table2)).toBeDefined();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('createAll() skips elements with datatable-initialized class', () => {
|
|
100
|
+
const table = document.createElement('div');
|
|
101
|
+
table.setAttribute('data-kt-datatable', 'true');
|
|
102
|
+
table.classList.add('datatable-initialized');
|
|
103
|
+
document.body.appendChild(table);
|
|
104
|
+
|
|
105
|
+
const factory = vi.fn(() => createMockInstance());
|
|
106
|
+
registry.createAll(factory);
|
|
107
|
+
|
|
108
|
+
// Note: The code checks hasAttribute('data-kt-datatable') AND !classList.contains('datatable-initialized')
|
|
109
|
+
// But the condition is: if (element.hasAttribute('data-kt-datatable') && !element.classList.contains('datatable-initialized'))
|
|
110
|
+
// Since the element DOES have the attribute AND does NOT have the class... wait, it DOES have the class.
|
|
111
|
+
// So it should skip.
|
|
112
|
+
// Actually re-reading the code: the forEach iterates ALL elements matching [data-kt-datatable="true"]
|
|
113
|
+
// Then inside: if (element.hasAttribute('data-kt-datatable') && !element.classList.contains('datatable-initialized'))
|
|
114
|
+
// The element has both the attribute and the class, so the condition is false => skip
|
|
115
|
+
expect(factory).not.toHaveBeenCalled();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('createAll() does nothing when document is undefined (guard)', () => {
|
|
119
|
+
const originalDoc = globalThis.document;
|
|
120
|
+
// @ts-ignore
|
|
121
|
+
delete globalThis.document;
|
|
122
|
+
const factory = vi.fn(() => createMockInstance());
|
|
123
|
+
registry.createAll(factory);
|
|
124
|
+
expect(factory).not.toHaveBeenCalled();
|
|
125
|
+
globalThis.document = originalDoc;
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe('reinit', () => {
|
|
130
|
+
it('reinit() disposes existing instances, removes KTData, clears registry, then createAll', () => {
|
|
131
|
+
const table = document.createElement('div');
|
|
132
|
+
table.setAttribute('data-kt-datatable', 'true');
|
|
133
|
+
document.body.appendChild(table);
|
|
134
|
+
|
|
135
|
+
const instance = createMockInstance();
|
|
136
|
+
registry.register(table, instance as any);
|
|
137
|
+
|
|
138
|
+
const factory = vi.fn(() => createMockInstance());
|
|
139
|
+
registry.reinit(factory);
|
|
140
|
+
|
|
141
|
+
expect(instance.dispose).toHaveBeenCalled();
|
|
142
|
+
expect(KTData.remove).toHaveBeenCalledWith(table, 'datatable');
|
|
143
|
+
expect(factory).toHaveBeenCalled();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('reinit() handles per-element dispose errors gracefully', () => {
|
|
147
|
+
const table = document.createElement('div');
|
|
148
|
+
table.setAttribute('data-kt-datatable', 'true');
|
|
149
|
+
document.body.appendChild(table);
|
|
150
|
+
|
|
151
|
+
const instance = {
|
|
152
|
+
dispose: vi.fn(() => {
|
|
153
|
+
throw new Error('dispose error');
|
|
154
|
+
}),
|
|
155
|
+
};
|
|
156
|
+
registry.register(table, instance as any);
|
|
157
|
+
|
|
158
|
+
const factory = vi.fn(() => createMockInstance());
|
|
159
|
+
expect(() => registry.reinit(factory)).not.toThrow();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('reinit() does nothing when document is undefined', () => {
|
|
163
|
+
const originalDoc = globalThis.document;
|
|
164
|
+
// @ts-ignore
|
|
165
|
+
delete globalThis.document;
|
|
166
|
+
const factory = vi.fn(() => createMockInstance());
|
|
167
|
+
registry.reinit(factory);
|
|
168
|
+
expect(factory).not.toHaveBeenCalled();
|
|
169
|
+
globalThis.document = originalDoc;
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
});
|