@keenthemes/ktui 1.2.5 → 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 +1538 -786
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +85 -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 +7 -0
- package/lib/cjs/components/datatable/datatable-layout-plugin.d.ts.map +1 -0
- package/lib/cjs/components/datatable/datatable-layout-plugin.js +338 -0
- package/lib/cjs/components/datatable/datatable-layout-plugin.js.map +1 -0
- package/lib/cjs/components/datatable/datatable-local-provider.d.ts +2 -2
- package/lib/cjs/components/datatable/datatable-local-provider.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-local-provider.js +85 -27
- 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 +13 -13
- 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 +35 -34
- package/lib/cjs/components/datatable/datatable.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable.js +233 -497
- 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 +127 -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 +7 -0
- package/lib/esm/components/datatable/datatable-layout-plugin.d.ts.map +1 -0
- package/lib/esm/components/datatable/datatable-layout-plugin.js +334 -0
- package/lib/esm/components/datatable/datatable-layout-plugin.js.map +1 -0
- package/lib/esm/components/datatable/datatable-local-provider.d.ts +2 -2
- package/lib/esm/components/datatable/datatable-local-provider.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-local-provider.js +85 -27
- 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 +13 -13
- 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 +35 -34
- package/lib/esm/components/datatable/datatable.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable.js +235 -499
- 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 +127 -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__/locked-layout.test.ts +257 -0
- package/src/components/datatable/__tests__/multi-row-headers.test.ts +7 -7
- package/src/components/datatable/__tests__/pagination-reset.test.ts +147 -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 +139 -143
- 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 +459 -0
- package/src/components/datatable/datatable-local-provider.ts +106 -35
- package/src/components/datatable/datatable-pagination-renderer.ts +13 -15
- 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.css +98 -0
- package/src/components/datatable/datatable.ts +288 -583
- package/src/components/datatable/index.ts +8 -0
- package/src/components/datatable/types.ts +157 -23
- package/src/helpers/__tests__/dom.test.ts +776 -0
- package/src/helpers/__tests__/utils.test.ts +332 -0
- package/src/index.ts +15 -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
|
@@ -11,15 +11,20 @@ import {
|
|
|
11
11
|
KTDataTableSortOrderInterface,
|
|
12
12
|
KTDataTableStateInterface,
|
|
13
13
|
KTDataTableColumnFilterInterface,
|
|
14
|
+
KTDataTableLayoutPluginContextInterface,
|
|
15
|
+
KTDataTableLayoutPluginInterface,
|
|
16
|
+
OriginalTableClasses,
|
|
14
17
|
} from './types';
|
|
15
18
|
import { KTOptionType } from '../../types';
|
|
16
|
-
import KTComponents from '../../index';
|
|
17
19
|
import KTData from '../../helpers/data';
|
|
18
20
|
import {
|
|
19
|
-
|
|
21
|
+
KTDataTableCheckboxHandler,
|
|
20
22
|
KTDataTableCheckboxAPI,
|
|
21
23
|
} from './datatable-checkbox';
|
|
22
|
-
import {
|
|
24
|
+
import { KTDataTableSortHandler, KTDataTableSortAPI } from './datatable-sort';
|
|
25
|
+
import { createStickyLayoutPlugin } from './datatable-layout-plugin';
|
|
26
|
+
import { DATATABLE_DEFAULTS, DEFAULT_PAGE_SIZES, DEFAULT_SEARCH_DELAY } from './datatable-defaults';
|
|
27
|
+
import { getLogicalColumnCount } from './datatable-column-utils';
|
|
23
28
|
import {
|
|
24
29
|
KTDataTableCleanup,
|
|
25
30
|
KTDataTableEventAdapter,
|
|
@@ -27,12 +32,20 @@ import {
|
|
|
27
32
|
KTDataTableStateStore,
|
|
28
33
|
KTDataTableTableRenderer,
|
|
29
34
|
} from './datatable-contracts';
|
|
30
|
-
import { createDataTableEventAdapter } from './datatable-event-adapter';
|
|
31
35
|
import { KTDataTableLocalDataProvider } from './datatable-local-provider';
|
|
32
36
|
import { KTDataTableRemoteDataProvider } from './datatable-remote-provider';
|
|
33
37
|
import { KTDataTableConfigStateStore } from './datatable-state-store';
|
|
34
38
|
import { KTDataTableDomPaginationRenderer } from './datatable-pagination-renderer';
|
|
35
39
|
import { KTDataTableDomTableRenderer } from './datatable-table-renderer';
|
|
40
|
+
import KTUtils from '../../helpers/utils';
|
|
41
|
+
import { createSearchHandler } from './datatable-search-handler';
|
|
42
|
+
import {
|
|
43
|
+
createStatePersistence,
|
|
44
|
+
resolveTableNamespace,
|
|
45
|
+
} from './datatable-state-persistence';
|
|
46
|
+
import { createSpinner } from './datatable-spinner';
|
|
47
|
+
import { createDataTableRegistry } from './datatable-registry';
|
|
48
|
+
import { stripHtml } from './datatable-utils';
|
|
36
49
|
|
|
37
50
|
/**
|
|
38
51
|
* Custom DataTable plugin class with server-side API, pagination, and sorting
|
|
@@ -43,24 +56,14 @@ import { KTDataTableDomTableRenderer } from './datatable-table-renderer';
|
|
|
43
56
|
* @param {HTMLElement} element The table element
|
|
44
57
|
* @param {KTDataTableConfigInterface} [config] Additional configuration options
|
|
45
58
|
*/
|
|
59
|
+
const datatableRegistry = createDataTableRegistry<
|
|
60
|
+
KTDataTable<KTDataTableDataInterface>
|
|
61
|
+
>();
|
|
62
|
+
|
|
46
63
|
export class KTDataTable<T extends KTDataTableDataInterface>
|
|
47
64
|
extends KTComponent
|
|
48
65
|
implements KTDataTableInterface
|
|
49
66
|
{
|
|
50
|
-
private static asElementWithInstance(element: HTMLElement): HTMLElement & {
|
|
51
|
-
instance?: KTDataTable<KTDataTableDataInterface>;
|
|
52
|
-
} {
|
|
53
|
-
return element as HTMLElement & {
|
|
54
|
-
instance?: KTDataTable<KTDataTableDataInterface>;
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
private static asSearchElementWithDebounce(
|
|
59
|
-
element: HTMLInputElement,
|
|
60
|
-
): HTMLInputElement & { _debouncedSearch?: EventListener } {
|
|
61
|
-
return element as HTMLInputElement & { _debouncedSearch?: EventListener };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
67
|
protected override _name: string = 'datatable';
|
|
65
68
|
protected override _config: KTDataTableConfigInterface;
|
|
66
69
|
protected override _defaultConfig: KTDataTableConfigInterface;
|
|
@@ -68,11 +71,13 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
68
71
|
private _tableElement: HTMLTableElement;
|
|
69
72
|
private _tbodyElement: HTMLTableSectionElement;
|
|
70
73
|
private _theadElement: HTMLTableSectionElement;
|
|
71
|
-
private
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
private _originalClasses: OriginalTableClasses = {
|
|
75
|
+
tbody: '',
|
|
76
|
+
thead: '',
|
|
77
|
+
tr: [],
|
|
78
|
+
td: [],
|
|
79
|
+
th: [],
|
|
80
|
+
};
|
|
76
81
|
|
|
77
82
|
private _infoElement: HTMLElement | null = null;
|
|
78
83
|
private _sizeElement: HTMLSelectElement | null = null;
|
|
@@ -80,6 +85,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
80
85
|
|
|
81
86
|
private _checkbox: KTDataTableCheckboxAPI;
|
|
82
87
|
private _sortHandler: KTDataTableSortAPI<T>;
|
|
88
|
+
private _layoutPlugin: KTDataTableLayoutPluginInterface | null = null;
|
|
83
89
|
private _eventAdapter: KTDataTableEventAdapter;
|
|
84
90
|
private _stateStore: KTDataTableStateStore;
|
|
85
91
|
private _localProvider: KTDataTableLocalDataProvider<T>;
|
|
@@ -88,6 +94,10 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
88
94
|
private _paginationRenderer: KTDataTablePaginationRenderer;
|
|
89
95
|
private _cleanupCallbacks: KTDataTableCleanup[] = [];
|
|
90
96
|
|
|
97
|
+
private _searchHandler = createSearchHandler();
|
|
98
|
+
private _statePersistence = createStatePersistence();
|
|
99
|
+
private _spinner = createSpinner();
|
|
100
|
+
|
|
91
101
|
private _data: T[] = [];
|
|
92
102
|
private _isFetching: boolean = false;
|
|
93
103
|
|
|
@@ -95,10 +105,10 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
95
105
|
super();
|
|
96
106
|
|
|
97
107
|
if (KTData.has(element as HTMLElement, this._name)) {
|
|
98
|
-
// Already initialized (e.g. by createInstances). Merge
|
|
108
|
+
// Already initialized (e.g. by createInstances). Merge demo config and redraw once.
|
|
99
109
|
const existing = KTDataTable.getInstance(element as HTMLElement);
|
|
100
110
|
if (existing && config) {
|
|
101
|
-
existing.
|
|
111
|
+
existing._applyRuntimeConfig(config);
|
|
102
112
|
}
|
|
103
113
|
return;
|
|
104
114
|
}
|
|
@@ -109,43 +119,54 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
109
119
|
if (!this._element) {
|
|
110
120
|
return;
|
|
111
121
|
}
|
|
122
|
+
if (!this._element.hasAttribute('data-kt-datatable')) {
|
|
123
|
+
this._element.setAttribute('data-kt-datatable', 'true');
|
|
124
|
+
}
|
|
112
125
|
this._buildConfig();
|
|
126
|
+
this._normalizePageSizeConfig();
|
|
113
127
|
this._stateStore = new KTDataTableConfigStateStore(this._config);
|
|
114
|
-
this._eventAdapter =
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
128
|
+
this._eventAdapter = {
|
|
129
|
+
emit: (eventName: string, eventData?: object) => {
|
|
130
|
+
this._emit(eventName, eventData);
|
|
131
|
+
},
|
|
132
|
+
};
|
|
118
133
|
|
|
119
134
|
// Store the instance directly on the element
|
|
120
|
-
|
|
135
|
+
datatableRegistry.register(element, this);
|
|
121
136
|
|
|
122
137
|
this._initElements();
|
|
138
|
+
this._layoutPlugin = this._createLayoutPlugin();
|
|
123
139
|
this._tableRenderer = new KTDataTableDomTableRenderer<T>();
|
|
124
140
|
this._paginationRenderer = new KTDataTableDomPaginationRenderer();
|
|
125
141
|
this._initDataProviders();
|
|
126
142
|
|
|
127
143
|
// Initialize checkbox handler
|
|
128
|
-
this._checkbox =
|
|
144
|
+
this._checkbox = new KTDataTableCheckboxHandler(
|
|
129
145
|
this._element,
|
|
130
146
|
this._config,
|
|
131
147
|
this._emit.bind(this),
|
|
148
|
+
{
|
|
149
|
+
getState: () => this._stateStore.getState(),
|
|
150
|
+
setSelectedRows: (rows) => {
|
|
151
|
+
this._stateStore.patchState({ selectedRows: rows });
|
|
152
|
+
},
|
|
153
|
+
},
|
|
132
154
|
);
|
|
133
155
|
|
|
134
156
|
// Initialize sort handler
|
|
135
|
-
this._sortHandler =
|
|
136
|
-
this._config,
|
|
137
|
-
this._theadElement,
|
|
138
|
-
() => ({
|
|
157
|
+
this._sortHandler = new KTDataTableSortHandler({
|
|
158
|
+
config: this._config,
|
|
159
|
+
theadElement: this._theadElement,
|
|
160
|
+
getState: () => ({
|
|
139
161
|
sortField: this.getState().sortField,
|
|
140
162
|
sortOrder: this.getState().sortOrder,
|
|
141
163
|
}),
|
|
142
|
-
(field, order) => {
|
|
164
|
+
setState: (field, order) => {
|
|
143
165
|
this._stateStore.setSort(field as never, order);
|
|
144
166
|
},
|
|
145
|
-
this.
|
|
146
|
-
this.
|
|
147
|
-
|
|
148
|
-
);
|
|
167
|
+
emit: this._emit.bind(this),
|
|
168
|
+
updateData: this._updateData.bind(this),
|
|
169
|
+
});
|
|
149
170
|
|
|
150
171
|
this._sortHandler.initSort();
|
|
151
172
|
|
|
@@ -155,15 +176,15 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
155
176
|
|
|
156
177
|
if (this._config.stateSave) {
|
|
157
178
|
this._loadState();
|
|
179
|
+
this._normalizePageState();
|
|
158
180
|
}
|
|
159
181
|
|
|
160
182
|
this._updateData();
|
|
161
|
-
|
|
162
|
-
this._emit('init');
|
|
163
183
|
}
|
|
164
184
|
|
|
165
185
|
private _emit(eventName: string, eventData?: object): void {
|
|
166
|
-
this.
|
|
186
|
+
this._fireEvent(eventName, eventData);
|
|
187
|
+
this._dispatchEvent(`kt.datatable.${eventName}`, eventData);
|
|
167
188
|
}
|
|
168
189
|
|
|
169
190
|
private _initDataProviders(): void {
|
|
@@ -188,122 +209,111 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
188
209
|
});
|
|
189
210
|
}
|
|
190
211
|
|
|
212
|
+
private _createLayoutPlugin(): KTDataTableLayoutPluginInterface | null {
|
|
213
|
+
if (this._config.layoutPlugin) {
|
|
214
|
+
return this._config.layoutPlugin;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (this._config.lockedLayout) {
|
|
218
|
+
return createStickyLayoutPlugin();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Apply config from a late constructor call (e.g. docs demo script after auto-init).
|
|
226
|
+
*/
|
|
227
|
+
private _applyRuntimeConfig(config: KTDataTableConfigInterface): void {
|
|
228
|
+
this._mergeConfig(config);
|
|
229
|
+
this._normalizePageSizeConfig();
|
|
230
|
+
this._layoutPlugin = this._createLayoutPlugin();
|
|
231
|
+
this.reload();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private _normalizePageSizeConfig(): void {
|
|
235
|
+
const configuredPageSizes = Array.isArray(this._config.pageSizes)
|
|
236
|
+
? this._config.pageSizes
|
|
237
|
+
: [];
|
|
238
|
+
const pageSizes = configuredPageSizes
|
|
239
|
+
.map((size) => Number(size))
|
|
240
|
+
.filter((size) => Number.isFinite(size) && size > 0)
|
|
241
|
+
.map((size) => Math.floor(size));
|
|
242
|
+
const fallbackPageSizes: number[] = [...DEFAULT_PAGE_SIZES];
|
|
243
|
+
this._config.pageSizes =
|
|
244
|
+
pageSizes.length > 0 ? Array.from(new Set(pageSizes)) : fallbackPageSizes;
|
|
245
|
+
|
|
246
|
+
const configuredPageSize = Number(this._config.pageSize);
|
|
247
|
+
this._config.pageSize =
|
|
248
|
+
Number.isFinite(configuredPageSize) && configuredPageSize > 0
|
|
249
|
+
? Math.floor(configuredPageSize)
|
|
250
|
+
: this._config.pageSizes[0];
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private _normalizePageState(): void {
|
|
254
|
+
const statePageSize = Number(this._config._state.pageSize);
|
|
255
|
+
this._config._state.pageSize =
|
|
256
|
+
Number.isFinite(statePageSize) && statePageSize > 0
|
|
257
|
+
? Math.floor(statePageSize)
|
|
258
|
+
: this._config.pageSize;
|
|
259
|
+
|
|
260
|
+
const statePage = Number(this._config._state.page);
|
|
261
|
+
this._config._state.page =
|
|
262
|
+
Number.isFinite(statePage) && statePage > 0 ? Math.floor(statePage) : 1;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private _getLayoutPluginContext(): KTDataTableLayoutPluginContextInterface {
|
|
266
|
+
return {
|
|
267
|
+
rootElement: this._element,
|
|
268
|
+
tableElement: this._tableElement,
|
|
269
|
+
theadElement: this._theadElement,
|
|
270
|
+
tbodyElement: this._tbodyElement,
|
|
271
|
+
config: this._config,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
191
275
|
/**
|
|
192
276
|
* Initialize default configuration for the datatable
|
|
193
277
|
* @param config User-provided configuration options
|
|
194
278
|
* @returns Default configuration merged with user-provided options
|
|
195
279
|
*/
|
|
280
|
+
private _createDefaultSearchCallback(): (
|
|
281
|
+
data: KTDataTableDataInterface[],
|
|
282
|
+
search: string,
|
|
283
|
+
) => KTDataTableDataInterface[] {
|
|
284
|
+
return ((data: T[], search: string): T[] => {
|
|
285
|
+
if (!data || !search) {
|
|
286
|
+
return [];
|
|
287
|
+
}
|
|
288
|
+
const searchLower = search.toLowerCase();
|
|
289
|
+
return data.filter((item: T) => {
|
|
290
|
+
if (!item) {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
return Object.values(item).some((value: KTOptionType) => {
|
|
294
|
+
if (
|
|
295
|
+
typeof value !== 'string' &&
|
|
296
|
+
typeof value !== 'number' &&
|
|
297
|
+
typeof value !== 'boolean'
|
|
298
|
+
) {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
const valueText = stripHtml(value).toLowerCase();
|
|
302
|
+
return valueText.includes(searchLower);
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
}) as unknown as (data: KTDataTableDataInterface[], search: string) => KTDataTableDataInterface[];
|
|
306
|
+
}
|
|
307
|
+
|
|
196
308
|
private _initDefaultConfig(
|
|
197
309
|
config?: KTDataTableConfigInterface,
|
|
198
310
|
): KTDataTableConfigInterface {
|
|
199
311
|
return {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
requestMethod: 'GET',
|
|
204
|
-
/**
|
|
205
|
-
* Custom HTTP headers for the API request
|
|
206
|
-
*/
|
|
207
|
-
requestHeaders: {
|
|
208
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
209
|
-
},
|
|
210
|
-
/**
|
|
211
|
-
* Pagination info template
|
|
212
|
-
*/
|
|
213
|
-
info: '{start}-{end} of {total}',
|
|
214
|
-
/**
|
|
215
|
-
* Info text when there is no data
|
|
216
|
-
*/
|
|
217
|
-
infoEmpty: 'No records found',
|
|
218
|
-
/**
|
|
219
|
-
* Available page sizes
|
|
220
|
-
*/
|
|
221
|
-
pageSizes: [5, 10, 20, 30, 50],
|
|
222
|
-
/**
|
|
223
|
-
* Default page size
|
|
224
|
-
*/
|
|
225
|
-
pageSize: 10,
|
|
226
|
-
/**
|
|
227
|
-
* Enable or disable pagination more button
|
|
228
|
-
*/
|
|
229
|
-
pageMore: true,
|
|
230
|
-
/**
|
|
231
|
-
* Maximum number of pages before enabling pagination more button
|
|
232
|
-
*/
|
|
233
|
-
pageMoreLimit: 3,
|
|
234
|
-
/**
|
|
235
|
-
* Pagination button templates
|
|
236
|
-
*/
|
|
237
|
-
pagination: {
|
|
238
|
-
number: {
|
|
239
|
-
/**
|
|
240
|
-
* CSS classes to be added to the pagination button
|
|
241
|
-
*/
|
|
242
|
-
class: 'kt-datatable-pagination-button',
|
|
243
|
-
/**
|
|
244
|
-
* Text to be displayed in the pagination button
|
|
245
|
-
*/
|
|
246
|
-
text: '{page}',
|
|
247
|
-
},
|
|
248
|
-
previous: {
|
|
249
|
-
/**
|
|
250
|
-
* CSS classes to be added to the previous pagination button
|
|
251
|
-
*/
|
|
252
|
-
class: 'kt-datatable-pagination-button kt-datatable-pagination-prev',
|
|
253
|
-
/**
|
|
254
|
-
* Text to be displayed in the previous pagination button
|
|
255
|
-
*/
|
|
256
|
-
text: `
|
|
257
|
-
<svg class="rtl:transform rtl:rotate-180 size-3.5 shrink-0" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
258
|
-
<path d="M8.86501 16.7882V12.8481H21.1459C21.3724 12.8481 21.5897 12.7581 21.7498 12.5979C21.91 12.4378 22 12.2205 22 11.994C22 11.7675 21.91 11.5503 21.7498 11.3901C21.5897 11.2299 21.3724 11.1399 21.1459 11.1399H8.86501V7.2112C8.86628 7.10375 8.83517 6.9984 8.77573 6.90887C8.7163 6.81934 8.63129 6.74978 8.53177 6.70923C8.43225 6.66869 8.32283 6.65904 8.21775 6.68155C8.11267 6.70405 8.0168 6.75766 7.94262 6.83541L2.15981 11.6182C2.1092 11.668 2.06901 11.7274 2.04157 11.7929C2.01413 11.8584 2 11.9287 2 11.9997C2 12.0707 2.01413 12.141 2.04157 12.2065C2.06901 12.272 2.1092 12.3314 2.15981 12.3812L7.94262 17.164C8.0168 17.2417 8.11267 17.2953 8.21775 17.3178C8.32283 17.3403 8.43225 17.3307 8.53177 17.2902C8.63129 17.2496 8.7163 17.18 8.77573 17.0905C8.83517 17.001 8.86628 16.8956 8.86501 16.7882Z" fill="currentColor"/>
|
|
259
|
-
</svg>
|
|
260
|
-
`,
|
|
261
|
-
},
|
|
262
|
-
next: {
|
|
263
|
-
/**
|
|
264
|
-
* CSS classes to be added to the next pagination button
|
|
265
|
-
*/
|
|
266
|
-
class: 'kt-datatable-pagination-button kt-datatable-pagination-next',
|
|
267
|
-
/**
|
|
268
|
-
* Text to be displayed in the next pagination button
|
|
269
|
-
*/
|
|
270
|
-
text: `
|
|
271
|
-
<svg class="rtl:transform rtl:rotate-180 size-3.5 shrink-0" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
272
|
-
<path d="M15.135 7.21144V11.1516H2.85407C2.62756 11.1516 2.41032 11.2415 2.25015 11.4017C2.08998 11.5619 2 11.7791 2 12.0056C2 12.2321 2.08998 12.4494 2.25015 12.6096C2.41032 12.7697 2.62756 12.8597 2.85407 12.8597H15.135V16.7884C15.1337 16.8959 15.1648 17.0012 15.2243 17.0908C15.2837 17.1803 15.3687 17.2499 15.4682 17.2904C15.5677 17.3309 15.6772 17.3406 15.7822 17.3181C15.8873 17.2956 15.9832 17.242 16.0574 17.1642L21.8402 12.3814C21.8908 12.3316 21.931 12.2722 21.9584 12.2067C21.9859 12.1412 22 12.0709 22 11.9999C22 11.9289 21.9859 11.8586 21.9584 11.7931C21.931 11.7276 21.8908 11.6683 21.8402 11.6185L16.0574 6.83565C15.9832 6.75791 15.8873 6.70429 15.7822 6.68179C15.6772 6.65929 15.5677 6.66893 15.4682 6.70948C15.3687 6.75002 15.2837 6.81959 15.2243 6.90911C15.1648 6.99864 15.1337 7.10399 15.135 7.21144Z" fill="currentColor"/>
|
|
273
|
-
</svg>
|
|
274
|
-
`,
|
|
275
|
-
},
|
|
276
|
-
more: {
|
|
277
|
-
/**
|
|
278
|
-
* CSS classes to be added to the pagination more button
|
|
279
|
-
*/
|
|
280
|
-
class: 'kt-datatable-pagination-button kt-datatable-pagination-more',
|
|
281
|
-
/**
|
|
282
|
-
* Text to be displayed in the pagination more button
|
|
283
|
-
*/
|
|
284
|
-
text: '...',
|
|
285
|
-
},
|
|
286
|
-
},
|
|
287
|
-
/**
|
|
288
|
-
* Sorting options
|
|
289
|
-
*/
|
|
312
|
+
...DATATABLE_DEFAULTS,
|
|
313
|
+
// Per-instance state; DATATABLE_DEFAULTS._state is a shared singleton.
|
|
314
|
+
_state: {} as KTDataTableStateInterface,
|
|
290
315
|
sort: {
|
|
291
|
-
|
|
292
|
-
* CSS classes to be added to the sortable headers
|
|
293
|
-
*/
|
|
294
|
-
classes: {
|
|
295
|
-
base: 'kt-table-col',
|
|
296
|
-
asc: 'asc',
|
|
297
|
-
desc: 'desc',
|
|
298
|
-
},
|
|
299
|
-
/**
|
|
300
|
-
* Local sorting callback function
|
|
301
|
-
* Sorts the data array based on the sort field and order
|
|
302
|
-
* @param data Data array to be sorted
|
|
303
|
-
* @param sortField Property name of the data object to be sorted by
|
|
304
|
-
* @param sortOrder Sorting order (ascending or descending)
|
|
305
|
-
* @returns Sorted data array
|
|
306
|
-
*/
|
|
316
|
+
...DATATABLE_DEFAULTS.sort,
|
|
307
317
|
callback: (
|
|
308
318
|
data: T[],
|
|
309
319
|
sortField: keyof T | number,
|
|
@@ -315,110 +325,9 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
315
325
|
},
|
|
316
326
|
},
|
|
317
327
|
search: {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
* @default 500
|
|
321
|
-
*/
|
|
322
|
-
delay: 500, // ms
|
|
323
|
-
/**
|
|
324
|
-
* Local search callback function
|
|
325
|
-
* Filters the data array based on the search string
|
|
326
|
-
* @param data Data array to be filtered
|
|
327
|
-
* @param search Search string used to filter the data array
|
|
328
|
-
* @returns Filtered data array
|
|
329
|
-
*/
|
|
330
|
-
callback: (data: T[], search: string): T[] => {
|
|
331
|
-
if (!data || !search) {
|
|
332
|
-
return [];
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
return data.filter((item: T) => {
|
|
336
|
-
if (!item) {
|
|
337
|
-
return false;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return Object.values(item).some((value: KTOptionType) => {
|
|
341
|
-
if (
|
|
342
|
-
typeof value !== 'string' &&
|
|
343
|
-
typeof value !== 'number' &&
|
|
344
|
-
typeof value !== 'boolean'
|
|
345
|
-
) {
|
|
346
|
-
return false;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const valueText = String(value)
|
|
350
|
-
.replace(/<|>| /g, '')
|
|
351
|
-
.toLowerCase();
|
|
352
|
-
return valueText.includes(search.toLowerCase());
|
|
353
|
-
});
|
|
354
|
-
});
|
|
355
|
-
},
|
|
356
|
-
},
|
|
357
|
-
/**
|
|
358
|
-
* Loading spinner options
|
|
359
|
-
*/
|
|
360
|
-
loading: {
|
|
361
|
-
/**
|
|
362
|
-
* Template to be displayed during data fetching process
|
|
363
|
-
*/
|
|
364
|
-
template: `
|
|
365
|
-
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
|
366
|
-
<div class="kt-datatable-loading">
|
|
367
|
-
<svg class="animate-spin -ml-1 h-5 w-5 text-gray-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
368
|
-
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="3"></circle>
|
|
369
|
-
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
370
|
-
</svg>
|
|
371
|
-
{content}
|
|
372
|
-
</div>
|
|
373
|
-
</div>
|
|
374
|
-
`,
|
|
375
|
-
/**
|
|
376
|
-
* Loading text to be displayed in the template
|
|
377
|
-
*/
|
|
378
|
-
content: 'Loading...',
|
|
379
|
-
},
|
|
380
|
-
/**
|
|
381
|
-
* Selectors of the elements to be targeted
|
|
382
|
-
*/
|
|
383
|
-
attributes: {
|
|
384
|
-
/**
|
|
385
|
-
* Data table element
|
|
386
|
-
*/
|
|
387
|
-
table: 'table[data-kt-datatable-table="true"]',
|
|
388
|
-
/**
|
|
389
|
-
* Pagination info element
|
|
390
|
-
*/
|
|
391
|
-
info: '[data-kt-datatable-info="true"]',
|
|
392
|
-
/**
|
|
393
|
-
* Page size dropdown element
|
|
394
|
-
*/
|
|
395
|
-
size: '[data-kt-datatable-size="true"]',
|
|
396
|
-
/**
|
|
397
|
-
* Pagination element
|
|
398
|
-
*/
|
|
399
|
-
pagination: '[data-kt-datatable-pagination="true"]',
|
|
400
|
-
/**
|
|
401
|
-
* Spinner element
|
|
402
|
-
*/
|
|
403
|
-
spinner: '[data-kt-datatable-spinner="true"]',
|
|
404
|
-
/**
|
|
405
|
-
* Checkbox element
|
|
406
|
-
*/
|
|
407
|
-
check: '[data-kt-datatable-check="true"]',
|
|
408
|
-
checkbox: '[data-kt-datatable-row-check="true"]',
|
|
409
|
-
},
|
|
410
|
-
/**
|
|
411
|
-
* Enable or disable state saving
|
|
412
|
-
*/
|
|
413
|
-
stateSave: true,
|
|
414
|
-
checkbox: {
|
|
415
|
-
checkedClass: 'checked',
|
|
328
|
+
...DATATABLE_DEFAULTS.search,
|
|
329
|
+
callback: this._createDefaultSearchCallback(),
|
|
416
330
|
},
|
|
417
|
-
/**
|
|
418
|
-
* Private properties
|
|
419
|
-
*/
|
|
420
|
-
_state: {} as KTDataTableStateInterface,
|
|
421
|
-
loadingClass: 'loading',
|
|
422
331
|
...config,
|
|
423
332
|
} as KTDataTableConfigInterface;
|
|
424
333
|
}
|
|
@@ -431,7 +340,9 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
431
340
|
const root = this._element;
|
|
432
341
|
const attrs = this._config.attributes;
|
|
433
342
|
if (!root || !attrs?.table) {
|
|
434
|
-
throw new Error(
|
|
343
|
+
throw new Error(
|
|
344
|
+
'KTDataTable: root element and table selector are required',
|
|
345
|
+
);
|
|
435
346
|
}
|
|
436
347
|
|
|
437
348
|
const tableEl = root.querySelector<HTMLTableElement>(attrs.table);
|
|
@@ -466,17 +377,17 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
466
377
|
private _storeOriginalClasses(): void {
|
|
467
378
|
// Store tbody class
|
|
468
379
|
if (this._tbodyElement) {
|
|
469
|
-
this.
|
|
380
|
+
this._originalClasses.tbody = this._tbodyElement.className || '';
|
|
470
381
|
}
|
|
471
382
|
|
|
472
383
|
// Store thead class and th classes
|
|
473
384
|
if (this._theadElement) {
|
|
474
|
-
this.
|
|
385
|
+
this._originalClasses.thead = this._theadElement.className || '';
|
|
475
386
|
|
|
476
387
|
// Store th classes
|
|
477
388
|
const thElements =
|
|
478
389
|
this._theadElement.querySelectorAll<HTMLTableCellElement>('th');
|
|
479
|
-
this.
|
|
390
|
+
this._originalClasses.th = Array.from(thElements).map(
|
|
480
391
|
(th) => th.className || '',
|
|
481
392
|
);
|
|
482
393
|
}
|
|
@@ -485,15 +396,15 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
485
396
|
if (this._tbodyElement) {
|
|
486
397
|
const originalRows =
|
|
487
398
|
this._tbodyElement.querySelectorAll<HTMLTableRowElement>('tr');
|
|
488
|
-
this.
|
|
399
|
+
this._originalClasses.tr = Array.from(originalRows).map(
|
|
489
400
|
(row) => row.className || '',
|
|
490
401
|
);
|
|
491
402
|
|
|
492
403
|
// Store td classes as a 2D array
|
|
493
|
-
this.
|
|
404
|
+
this._originalClasses.td = [];
|
|
494
405
|
Array.from(originalRows).forEach((row, rowIndex) => {
|
|
495
406
|
const tdElements = row.querySelectorAll<HTMLTableCellElement>('td');
|
|
496
|
-
this.
|
|
407
|
+
this._originalClasses.td[rowIndex] = Array.from(tdElements).map(
|
|
497
408
|
(td) => td.className || '',
|
|
498
409
|
);
|
|
499
410
|
});
|
|
@@ -508,9 +419,8 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
508
419
|
if (this._isFetching) return; // Prevent duplicate fetches
|
|
509
420
|
this._isFetching = true;
|
|
510
421
|
try {
|
|
511
|
-
this.
|
|
422
|
+
this._spinner.show(this._element, this._config, this._tableElement); // Show spinner before fetching data
|
|
512
423
|
|
|
513
|
-
this._emit('fetch');
|
|
514
424
|
const result =
|
|
515
425
|
typeof this._config.apiEndpoint === 'undefined'
|
|
516
426
|
? this._localProvider.fetchSync()
|
|
@@ -520,10 +430,11 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
520
430
|
this._data = result.data;
|
|
521
431
|
this._stateStore.patchState({ totalItems: result.totalItems });
|
|
522
432
|
await this._draw();
|
|
523
|
-
this._emit('fetched');
|
|
524
433
|
}
|
|
525
434
|
|
|
526
435
|
await this._finalize();
|
|
436
|
+
|
|
437
|
+
this._emit('update');
|
|
527
438
|
} finally {
|
|
528
439
|
// Finally block now correctly executes after promises resolve, not immediately
|
|
529
440
|
this._isFetching = false;
|
|
@@ -545,63 +456,29 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
545
456
|
this._sortHandler.initSort();
|
|
546
457
|
}
|
|
547
458
|
|
|
548
|
-
this.
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
459
|
+
this._searchHandler.attach(
|
|
460
|
+
this._tableId(),
|
|
461
|
+
this.getState().search,
|
|
462
|
+
this._config.search?.delay ?? DEFAULT_SEARCH_DELAY,
|
|
463
|
+
(query) => this.search(query),
|
|
464
|
+
);
|
|
553
465
|
|
|
554
466
|
/**
|
|
555
467
|
* Hide spinner
|
|
556
468
|
*/
|
|
557
|
-
this.
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
);
|
|
570
|
-
|
|
571
|
-
// Get search state
|
|
572
|
-
const { search } = this.getState();
|
|
573
|
-
// Set search value
|
|
574
|
-
if (searchElement) {
|
|
575
|
-
searchElement.value =
|
|
576
|
-
search === undefined || search === null
|
|
577
|
-
? ''
|
|
578
|
-
: typeof search === 'string'
|
|
579
|
-
? search
|
|
580
|
-
: String(search);
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
if (searchElement) {
|
|
584
|
-
// Check if a debounced search function already exists
|
|
585
|
-
const searchWithDebounce =
|
|
586
|
-
KTDataTable.asSearchElementWithDebounce(searchElement);
|
|
587
|
-
if (searchWithDebounce._debouncedSearch) {
|
|
588
|
-
// Remove the existing debounced event listener
|
|
589
|
-
searchElement.removeEventListener(
|
|
590
|
-
'keyup',
|
|
591
|
-
searchWithDebounce._debouncedSearch,
|
|
592
|
-
);
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
// Create a new debounced search function
|
|
596
|
-
const debouncedSearch = this._debounce(() => {
|
|
597
|
-
this.search(searchElement.value);
|
|
598
|
-
}, this._config.search?.delay ?? 500);
|
|
599
|
-
|
|
600
|
-
// Store the new debounced function as a property of the element
|
|
601
|
-
searchWithDebounce._debouncedSearch = debouncedSearch;
|
|
602
|
-
|
|
603
|
-
// Add the new debounced event listener
|
|
604
|
-
searchElement.addEventListener('keyup', debouncedSearch);
|
|
469
|
+
this._spinner.hide(this._element, this._config);
|
|
470
|
+
|
|
471
|
+
// Update content checksum AFTER all DOM modifications (checkbox init
|
|
472
|
+
// adds checked-class to <tr> elements which changes tbody innerHTML).
|
|
473
|
+
// If we save the checksum earlier (in _draw), the next fetchSync()
|
|
474
|
+
// sees a mismatch, re-extracts from the DOM, and loses rows that
|
|
475
|
+
// were on other pages — making pagination show empty.
|
|
476
|
+
if (!this._config.apiEndpoint) {
|
|
477
|
+
this._stateStore.patchState({
|
|
478
|
+
_contentChecksum: KTUtils.checksum(
|
|
479
|
+
JSON.stringify(this._tbodyElement.innerHTML),
|
|
480
|
+
),
|
|
481
|
+
});
|
|
605
482
|
}
|
|
606
483
|
}
|
|
607
484
|
|
|
@@ -611,18 +488,11 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
611
488
|
* @returns {number} Number of data columns, or 0 if unknown
|
|
612
489
|
*/
|
|
613
490
|
private _getLogicalColumnCount(): number {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
const firstRow =
|
|
620
|
-
this._tbodyElement.querySelector<HTMLTableRowElement>('tr');
|
|
621
|
-
if (firstRow) {
|
|
622
|
-
return firstRow.querySelectorAll<HTMLTableCellElement>('td').length;
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
return 0;
|
|
491
|
+
return getLogicalColumnCount(
|
|
492
|
+
this._theadElement,
|
|
493
|
+
this._tbodyElement,
|
|
494
|
+
this.getState().originalData as Array<Record<string, unknown>> | undefined,
|
|
495
|
+
);
|
|
626
496
|
}
|
|
627
497
|
|
|
628
498
|
/**
|
|
@@ -698,14 +568,22 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
698
568
|
* @returns {Promise<void>} A promise that resolves when the table and pagination controls are updated
|
|
699
569
|
*/
|
|
700
570
|
private async _draw(): Promise<void> {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
571
|
+
const normalizedPageSize = Math.max(
|
|
572
|
+
1,
|
|
573
|
+
Number(this.getState().pageSize) || Number(this._config.pageSize) || 1,
|
|
574
|
+
);
|
|
575
|
+
const totalPages =
|
|
576
|
+
Math.ceil(this.getState().totalItems / normalizedPageSize) || 0;
|
|
577
|
+
const page =
|
|
578
|
+
totalPages > 0
|
|
579
|
+
? Math.min(Math.max(1, this.getState().page), totalPages)
|
|
580
|
+
: 1;
|
|
705
581
|
|
|
706
|
-
this.
|
|
582
|
+
this._stateStore.patchState({ totalPages, page });
|
|
707
583
|
|
|
708
|
-
this.
|
|
584
|
+
this._layoutPlugin?.beforeDraw?.(this._getLayoutPluginContext());
|
|
585
|
+
|
|
586
|
+
this._cleanupForRedraw();
|
|
709
587
|
|
|
710
588
|
// Update the table and pagination controls
|
|
711
589
|
if (this._theadElement && this._tbodyElement) {
|
|
@@ -716,7 +594,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
716
594
|
this._updatePagination();
|
|
717
595
|
}
|
|
718
596
|
|
|
719
|
-
this.
|
|
597
|
+
this._layoutPlugin?.afterDraw?.(this._getLayoutPluginContext());
|
|
720
598
|
|
|
721
599
|
// Spinner is hidden in _finalize() to ensure it stays visible until the entire request completes
|
|
722
600
|
// Removed duplicate _hideSpinner() call here to prevent premature hiding
|
|
@@ -731,18 +609,17 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
731
609
|
* @returns {HTMLTableSectionElement} The new table body element
|
|
732
610
|
*/
|
|
733
611
|
private _updateTable(): HTMLTableSectionElement {
|
|
734
|
-
|
|
612
|
+
this._tbodyElement = this._tableRenderer.render({
|
|
735
613
|
config: this._config,
|
|
736
614
|
context: this,
|
|
737
615
|
data: this._data,
|
|
738
616
|
getLogicalColumnCount: this._getLogicalColumnCount.bind(this),
|
|
739
617
|
getState: this.getState.bind(this),
|
|
740
|
-
|
|
741
|
-
originalTrClasses: this._originalTrClasses,
|
|
742
|
-
originalTdClasses: this._originalTdClasses,
|
|
618
|
+
originalClasses: this._originalClasses,
|
|
743
619
|
tableElement: this._tableElement,
|
|
744
620
|
theadElement: this._theadElement,
|
|
745
621
|
});
|
|
622
|
+
return this._tbodyElement;
|
|
746
623
|
}
|
|
747
624
|
|
|
748
625
|
/**
|
|
@@ -797,81 +674,21 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
797
674
|
return;
|
|
798
675
|
}
|
|
799
676
|
|
|
800
|
-
this._emit('pagination', { page: page });
|
|
801
|
-
|
|
802
677
|
if (page >= 1 && page <= this.getState().totalPages) {
|
|
803
678
|
this._stateStore.setPage(page);
|
|
804
679
|
this._updateData();
|
|
805
680
|
}
|
|
806
681
|
}
|
|
807
682
|
|
|
808
|
-
// Method to show the loading spinner
|
|
809
|
-
private _showSpinner(): void {
|
|
810
|
-
const root = this._element;
|
|
811
|
-
const spinnerSel = this._config.attributes?.spinner;
|
|
812
|
-
const fromDom =
|
|
813
|
-
root && spinnerSel
|
|
814
|
-
? root.querySelector<HTMLElement>(spinnerSel)
|
|
815
|
-
: null;
|
|
816
|
-
const spinner = fromDom ?? this._createSpinner();
|
|
817
|
-
if (spinner) {
|
|
818
|
-
spinner.style.display = 'block';
|
|
819
|
-
}
|
|
820
|
-
root?.classList.add(this._config.loadingClass ?? 'loading');
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
// Method to hide the loading spinner
|
|
824
|
-
private _hideSpinner(): void {
|
|
825
|
-
const root = this._element;
|
|
826
|
-
const spinnerSel = this._config.attributes?.spinner;
|
|
827
|
-
const spinner =
|
|
828
|
-
root && spinnerSel
|
|
829
|
-
? root.querySelector<HTMLElement>(spinnerSel)
|
|
830
|
-
: null;
|
|
831
|
-
if (spinner) {
|
|
832
|
-
spinner.style.display = 'none';
|
|
833
|
-
}
|
|
834
|
-
root?.classList.remove(this._config.loadingClass ?? 'loading');
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
// Method to create a spinner element if it doesn't exist
|
|
838
|
-
private _createSpinner(): HTMLElement | null {
|
|
839
|
-
const loading = this._config.loading;
|
|
840
|
-
if (!loading) {
|
|
841
|
-
return null;
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
const template = document.createElement('template');
|
|
845
|
-
template.innerHTML = loading.template
|
|
846
|
-
.trim()
|
|
847
|
-
.replace('{content}', loading.content);
|
|
848
|
-
const first = template.content.firstChild;
|
|
849
|
-
if (!first || !(first instanceof HTMLElement)) {
|
|
850
|
-
return null;
|
|
851
|
-
}
|
|
852
|
-
const spinner = first;
|
|
853
|
-
spinner.setAttribute('data-kt-datatable-spinner', 'true');
|
|
854
|
-
|
|
855
|
-
this._tableElement.appendChild(spinner);
|
|
856
|
-
|
|
857
|
-
return spinner;
|
|
858
|
-
}
|
|
859
|
-
|
|
860
683
|
/**
|
|
861
684
|
* Saves the current state of the table to local storage.
|
|
862
685
|
* @returns {void}
|
|
863
686
|
*/
|
|
864
687
|
private _saveState(): void {
|
|
865
|
-
this.
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
if (ns) {
|
|
870
|
-
localStorage.setItem(
|
|
871
|
-
ns,
|
|
872
|
-
JSON.stringify(this.getState() as KTDataTableStateInterface),
|
|
873
|
-
);
|
|
874
|
-
}
|
|
688
|
+
this._statePersistence.save(
|
|
689
|
+
this._tableNamespace(),
|
|
690
|
+
this.getState() as KTDataTableStateInterface,
|
|
691
|
+
);
|
|
875
692
|
}
|
|
876
693
|
|
|
877
694
|
/**
|
|
@@ -879,24 +696,16 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
879
696
|
* @returns {Object} The saved state of the table, or null if no saved state exists.
|
|
880
697
|
*/
|
|
881
698
|
private _loadState(): KTDataTableStateInterface | null {
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
const state = JSON.parse(stateString) as KTDataTableStateInterface;
|
|
887
|
-
if (state) this._stateStore.replaceState(state);
|
|
888
|
-
return state;
|
|
889
|
-
} catch {}
|
|
890
|
-
|
|
891
|
-
return null;
|
|
699
|
+
const ns = this._tableNamespace();
|
|
700
|
+
const saved = this._statePersistence.load(ns);
|
|
701
|
+
if (saved) this._stateStore.replaceState(saved);
|
|
702
|
+
return saved;
|
|
892
703
|
}
|
|
893
704
|
|
|
894
705
|
private _deleteState(): void {
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
localStorage.removeItem(ns);
|
|
899
|
-
}
|
|
706
|
+
this._statePersistence.remove(
|
|
707
|
+
this._tableNamespace(),
|
|
708
|
+
);
|
|
900
709
|
}
|
|
901
710
|
|
|
902
711
|
/**
|
|
@@ -908,13 +717,12 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
908
717
|
* @returns {string} The namespace for the table's state.
|
|
909
718
|
*/
|
|
910
719
|
private _tableNamespace(): string {
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
return this._tableId() ?? this._name;
|
|
720
|
+
return resolveTableNamespace(
|
|
721
|
+
this._config,
|
|
722
|
+
this._tableElement,
|
|
723
|
+
this._element,
|
|
724
|
+
this._name,
|
|
725
|
+
);
|
|
918
726
|
}
|
|
919
727
|
|
|
920
728
|
private _tableId(): string {
|
|
@@ -933,106 +741,51 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
933
741
|
* Clean up all event listeners, handlers, and DOM nodes created by this instance.
|
|
934
742
|
* This method is called before re-rendering or when disposing the component.
|
|
935
743
|
*/
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
744
|
+
/**
|
|
745
|
+
* Clean up event listeners and DOM artifacts for a redraw cycle.
|
|
746
|
+
* Does NOT remove the instance from the registry — the datatable
|
|
747
|
+
* remains accessible via getInstance() during the redraw window.
|
|
748
|
+
*/
|
|
749
|
+
private _cleanupForRedraw(): void {
|
|
750
|
+
this._layoutPlugin?.dispose?.(this._getLayoutPluginContext());
|
|
751
|
+
|
|
752
|
+
if (!this._element) {
|
|
939
753
|
return;
|
|
940
754
|
}
|
|
941
755
|
|
|
942
756
|
this._cleanupCallbacks.forEach((cleanup) => cleanup());
|
|
943
757
|
this._cleanupCallbacks = [];
|
|
944
758
|
|
|
945
|
-
|
|
946
|
-
const tableId: string = this._tableId();
|
|
947
|
-
const searchElement: HTMLInputElement | null =
|
|
948
|
-
document.querySelector<HTMLInputElement>(
|
|
949
|
-
`[data-kt-datatable-search="#${tableId}"]`,
|
|
950
|
-
);
|
|
951
|
-
if (searchElement) {
|
|
952
|
-
const searchWithDebounce =
|
|
953
|
-
KTDataTable.asSearchElementWithDebounce(searchElement);
|
|
954
|
-
if (searchWithDebounce._debouncedSearch) {
|
|
955
|
-
searchElement.removeEventListener(
|
|
956
|
-
'keyup',
|
|
957
|
-
searchWithDebounce._debouncedSearch,
|
|
958
|
-
);
|
|
959
|
-
delete searchWithDebounce._debouncedSearch;
|
|
960
|
-
}
|
|
961
|
-
}
|
|
759
|
+
this._searchHandler.detach(this._tableId());
|
|
962
760
|
|
|
963
|
-
// --- 2. Remove page size dropdown event listener ---
|
|
964
761
|
if (this._sizeElement && this._sizeElement.onchange) {
|
|
965
762
|
this._sizeElement.onchange = null;
|
|
966
763
|
}
|
|
967
764
|
|
|
968
|
-
// --- 3. Remove all pagination button event listeners ---
|
|
969
765
|
if (this._paginationElement) {
|
|
970
|
-
// Remove all child nodes (buttons) to ensure no lingering listeners
|
|
971
766
|
while (this._paginationElement.firstChild) {
|
|
972
767
|
this._paginationElement.removeChild(this._paginationElement.firstChild);
|
|
973
768
|
}
|
|
974
769
|
}
|
|
975
770
|
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
const checkboxWithDispose = this._checkbox as KTDataTableCheckboxAPI & {
|
|
979
|
-
dispose?: () => void;
|
|
980
|
-
};
|
|
981
|
-
if (this._checkbox && typeof checkboxWithDispose.dispose === 'function') {
|
|
982
|
-
checkboxWithDispose.dispose();
|
|
983
|
-
} else {
|
|
984
|
-
const checkSel = this._config.attributes?.check;
|
|
985
|
-
if (checkSel) {
|
|
986
|
-
const headerCheckElement = root.querySelector<HTMLInputElement>(checkSel);
|
|
987
|
-
if (headerCheckElement) {
|
|
988
|
-
headerCheckElement.replaceWith(headerCheckElement.cloneNode(true));
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
// KTDataTableSortAPI does not have a dispose method, but we can remove th click listeners by replacing them
|
|
993
|
-
if (this._theadElement) {
|
|
994
|
-
const ths = this._theadElement.querySelectorAll('th');
|
|
995
|
-
ths.forEach((th) => {
|
|
996
|
-
th.replaceWith(th.cloneNode(true));
|
|
997
|
-
});
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
// --- 5. Remove spinner DOM node if it exists ---
|
|
1001
|
-
const spinnerSel = this._config.attributes?.spinner;
|
|
1002
|
-
if (spinnerSel) {
|
|
1003
|
-
const spinner = root.querySelector<HTMLElement>(spinnerSel);
|
|
1004
|
-
if (spinner?.parentNode) {
|
|
1005
|
-
spinner.parentNode.removeChild(spinner);
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
root.classList.remove(this._config.loadingClass ?? 'loading');
|
|
1009
|
-
|
|
1010
|
-
// --- 6. Remove instance reference from the DOM element ---
|
|
1011
|
-
const elementWithInstance = KTDataTable.asElementWithInstance(root);
|
|
1012
|
-
if (elementWithInstance.instance) {
|
|
1013
|
-
delete elementWithInstance.instance;
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
KTData.remove(root, this._name);
|
|
771
|
+
this._checkbox.dispose();
|
|
772
|
+
this._sortHandler.dispose();
|
|
1017
773
|
|
|
1018
|
-
|
|
1019
|
-
// Uncomment the following line if you want to clear state on dispose:
|
|
1020
|
-
// this._deleteState();
|
|
774
|
+
this._spinner.remove(this._element, this._config);
|
|
1021
775
|
}
|
|
1022
776
|
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
};
|
|
777
|
+
/**
|
|
778
|
+
* Full disposal — cleans up listeners AND removes the instance from
|
|
779
|
+
* the registry. Only called when the component is being destroyed.
|
|
780
|
+
*/
|
|
781
|
+
private _dispose(): void {
|
|
782
|
+
this._cleanupForRedraw();
|
|
783
|
+
|
|
784
|
+
const root = this._element;
|
|
785
|
+
if (root) {
|
|
786
|
+
datatableRegistry.remove(root);
|
|
787
|
+
KTData.remove(root, this._name);
|
|
788
|
+
}
|
|
1036
789
|
}
|
|
1037
790
|
|
|
1038
791
|
/**
|
|
@@ -1045,16 +798,22 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
1045
798
|
|
|
1046
799
|
/**
|
|
1047
800
|
* Sorts the data in the table by the specified field.
|
|
801
|
+
* When `order` is provided, applies that sort direction instead of toggling.
|
|
1048
802
|
* @param field The field to sort by.
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
803
|
+
* @param order Optional sort direction (`asc`, `desc`, or `''` to clear).
|
|
804
|
+
*/
|
|
805
|
+
public sort(
|
|
806
|
+
field: keyof T | number,
|
|
807
|
+
order?: KTDataTableSortOrderInterface,
|
|
808
|
+
): void {
|
|
809
|
+
const sortOrder =
|
|
810
|
+
order !== undefined
|
|
811
|
+
? order
|
|
812
|
+
: this._sortHandler.toggleSortOrder(
|
|
813
|
+
this.getState().sortField,
|
|
814
|
+
this.getState().sortOrder,
|
|
815
|
+
field,
|
|
816
|
+
);
|
|
1058
817
|
this._sortHandler.setSortIcon(field as keyof T, sortOrder);
|
|
1059
818
|
this._stateStore.setSort(field as never, sortOrder);
|
|
1060
819
|
this._emit('sort', { field, order: sortOrder });
|
|
@@ -1091,19 +850,15 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
1091
850
|
}
|
|
1092
851
|
|
|
1093
852
|
/**
|
|
1094
|
-
* Reloads the data from the
|
|
1095
|
-
*
|
|
853
|
+
* Reloads the data from the source (API or DOM) and redraws the table.
|
|
854
|
+
* @returns {Promise<void>}
|
|
1096
855
|
*/
|
|
1097
856
|
public reload(): void {
|
|
1098
|
-
this._emit('reload');
|
|
1099
|
-
|
|
1100
857
|
// Fetch the data from the server using the current sort and filter settings
|
|
1101
858
|
this._updateData();
|
|
1102
859
|
}
|
|
1103
860
|
|
|
1104
861
|
public redraw(page: number = 1): void {
|
|
1105
|
-
this._emit('redraw');
|
|
1106
|
-
|
|
1107
862
|
this._paginateData(page);
|
|
1108
863
|
}
|
|
1109
864
|
|
|
@@ -1111,20 +866,14 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
1111
866
|
* Show the loading spinner of the data table.
|
|
1112
867
|
*/
|
|
1113
868
|
public showSpinner(): void {
|
|
1114
|
-
|
|
1115
|
-
* Show the loading spinner of the data table.
|
|
1116
|
-
*/
|
|
1117
|
-
this._showSpinner();
|
|
869
|
+
this._spinner.show(this._element, this._config, this._tableElement);
|
|
1118
870
|
}
|
|
1119
871
|
|
|
1120
872
|
/**
|
|
1121
873
|
* Hide the loading spinner of the data table.
|
|
1122
874
|
*/
|
|
1123
875
|
public hideSpinner(): void {
|
|
1124
|
-
|
|
1125
|
-
* Hide the loading spinner of the data table.
|
|
1126
|
-
*/
|
|
1127
|
-
this._hideSpinner();
|
|
876
|
+
this._spinner.hide(this._element, this._config);
|
|
1128
877
|
}
|
|
1129
878
|
|
|
1130
879
|
/**
|
|
@@ -1149,37 +898,12 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
1149
898
|
this.reload();
|
|
1150
899
|
}
|
|
1151
900
|
|
|
1152
|
-
/**
|
|
1153
|
-
* Static variables
|
|
1154
|
-
*/
|
|
1155
|
-
private static _instances = new Map<
|
|
1156
|
-
HTMLElement,
|
|
1157
|
-
KTDataTable<KTDataTableDataInterface>
|
|
1158
|
-
>();
|
|
1159
|
-
|
|
1160
901
|
/**
|
|
1161
902
|
* Create KTDataTable instances for all elements with a data-kt-datatable="true" attribute.
|
|
1162
903
|
* This function is now browser-guarded and must be called explicitly.
|
|
1163
904
|
*/
|
|
1164
905
|
public static createInstances(): void {
|
|
1165
|
-
|
|
1166
|
-
const elements = document.querySelectorAll<HTMLElement>(
|
|
1167
|
-
'[data-kt-datatable="true"]',
|
|
1168
|
-
);
|
|
1169
|
-
|
|
1170
|
-
elements.forEach((element) => {
|
|
1171
|
-
if (
|
|
1172
|
-
element.hasAttribute('data-kt-datatable') &&
|
|
1173
|
-
!element.classList.contains('datatable-initialized')
|
|
1174
|
-
) {
|
|
1175
|
-
/**
|
|
1176
|
-
* Create an instance of KTDataTable for the given element
|
|
1177
|
-
* @param element The element to create an instance for
|
|
1178
|
-
*/
|
|
1179
|
-
const instance = new KTDataTable(element);
|
|
1180
|
-
this._instances.set(element, instance);
|
|
1181
|
-
}
|
|
1182
|
-
});
|
|
906
|
+
datatableRegistry.createAll((el) => new KTDataTable(el));
|
|
1183
907
|
}
|
|
1184
908
|
|
|
1185
909
|
/**
|
|
@@ -1191,14 +915,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
1191
915
|
public static getInstance(
|
|
1192
916
|
element: HTMLElement,
|
|
1193
917
|
): KTDataTable<KTDataTableDataInterface> | undefined {
|
|
1194
|
-
|
|
1195
|
-
const instanceFromMap = this._instances.get(element);
|
|
1196
|
-
if (instanceFromMap) {
|
|
1197
|
-
return instanceFromMap;
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
// Fallback to element's instance property (for manually created instances)
|
|
1201
|
-
return KTDataTable.asElementWithInstance(element).instance;
|
|
918
|
+
return datatableRegistry.get(element);
|
|
1202
919
|
}
|
|
1203
920
|
|
|
1204
921
|
/**
|
|
@@ -1206,7 +923,6 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
1206
923
|
* This function is now browser-guarded and must be called explicitly.
|
|
1207
924
|
*/
|
|
1208
925
|
public static init(): void {
|
|
1209
|
-
if (typeof document === 'undefined') return;
|
|
1210
926
|
KTDataTable.createInstances();
|
|
1211
927
|
}
|
|
1212
928
|
|
|
@@ -1215,25 +931,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
1215
931
|
* Useful for Livewire wire:navigate where the DOM is replaced and new tables need to be initialized.
|
|
1216
932
|
*/
|
|
1217
933
|
public static reinit(): void {
|
|
1218
|
-
|
|
1219
|
-
const elements = document.querySelectorAll<HTMLElement>(
|
|
1220
|
-
'[data-kt-datatable="true"]',
|
|
1221
|
-
);
|
|
1222
|
-
elements.forEach((element) => {
|
|
1223
|
-
try {
|
|
1224
|
-
const instance = KTDataTable.getInstance(element);
|
|
1225
|
-
if (instance && typeof instance.dispose === 'function') {
|
|
1226
|
-
instance.dispose();
|
|
1227
|
-
}
|
|
1228
|
-
KTData.remove(element, 'datatable');
|
|
1229
|
-
element.removeAttribute('data-kt-datatable-initialized');
|
|
1230
|
-
element.classList.remove('datatable-initialized');
|
|
1231
|
-
} catch {
|
|
1232
|
-
// ignore per-element errors
|
|
1233
|
-
}
|
|
1234
|
-
});
|
|
1235
|
-
KTDataTable._instances.clear();
|
|
1236
|
-
KTDataTable.createInstances();
|
|
934
|
+
datatableRegistry.reinit((el) => new KTDataTable(el));
|
|
1237
935
|
}
|
|
1238
936
|
|
|
1239
937
|
/**
|
|
@@ -1279,13 +977,20 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
1279
977
|
}
|
|
1280
978
|
|
|
1281
979
|
/**
|
|
1282
|
-
*
|
|
980
|
+
* Re-apply checkbox checked states to visible rows after a redraw or pagination change.
|
|
1283
981
|
* @returns {void}
|
|
1284
982
|
*/
|
|
1285
|
-
public
|
|
983
|
+
public refreshCheckboxes(): void {
|
|
1286
984
|
this._checkbox.updateState();
|
|
1287
985
|
}
|
|
1288
986
|
|
|
987
|
+
/**
|
|
988
|
+
* @deprecated Use {@link refreshCheckboxes} instead.
|
|
989
|
+
*/
|
|
990
|
+
public update(): void {
|
|
991
|
+
this.refreshCheckboxes();
|
|
992
|
+
}
|
|
993
|
+
|
|
1289
994
|
// Other plugin methods can be added here
|
|
1290
995
|
}
|
|
1291
996
|
|