@keenthemes/ktui 1.2.4 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ktui.js +2551 -2817
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +136 -40
- package/lib/cjs/components/datatable/datatable-checkbox.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-checkbox.js +34 -15
- package/lib/cjs/components/datatable/datatable-checkbox.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-contracts.d.ts +3 -3
- package/lib/cjs/components/datatable/datatable-contracts.d.ts.map +1 -1
- 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 +328 -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 +18 -10
- 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 +40 -25
- package/lib/cjs/components/datatable/datatable-pagination-renderer.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-remote-provider.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-remote-provider.js +3 -0
- package/lib/cjs/components/datatable/datatable-remote-provider.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-table-renderer.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-table-renderer.js +14 -6
- package/lib/cjs/components/datatable/datatable-table-renderer.js.map +1 -1
- package/lib/cjs/components/datatable/datatable.d.ts +9 -0
- package/lib/cjs/components/datatable/datatable.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable.js +200 -61
- 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 +27 -0
- package/lib/cjs/components/datatable/types.d.ts.map +1 -1
- package/lib/cjs/components/dropdown/dropdown.d.ts +2 -2
- package/lib/cjs/components/dropdown/dropdown.d.ts.map +1 -1
- package/lib/cjs/components/dropdown/dropdown.js +68 -31
- package/lib/cjs/components/dropdown/dropdown.js.map +1 -1
- package/lib/cjs/components/input-number/index.d.ts +7 -0
- package/lib/cjs/components/input-number/index.d.ts.map +1 -0
- package/lib/cjs/components/input-number/index.js +10 -0
- package/lib/cjs/components/input-number/index.js.map +1 -0
- package/lib/cjs/components/input-number/input-number.d.ts +40 -0
- package/lib/cjs/components/input-number/input-number.d.ts.map +1 -0
- package/lib/cjs/components/input-number/input-number.js +248 -0
- package/lib/cjs/components/input-number/input-number.js.map +1 -0
- package/lib/cjs/components/input-number/types.d.ts +30 -0
- package/lib/cjs/components/input-number/types.d.ts.map +1 -0
- package/lib/cjs/components/input-number/types.js +7 -0
- package/lib/cjs/components/input-number/types.js.map +1 -0
- package/lib/cjs/components/select/config.d.ts +1 -0
- package/lib/cjs/components/select/config.d.ts.map +1 -1
- package/lib/cjs/components/select/config.js +2 -1
- package/lib/cjs/components/select/config.js.map +1 -1
- package/lib/cjs/components/select/select.d.ts +8 -1
- package/lib/cjs/components/select/select.d.ts.map +1 -1
- package/lib/cjs/components/select/select.js +14 -1
- package/lib/cjs/components/select/select.js.map +1 -1
- package/lib/cjs/components/select/tags.d.ts.map +1 -1
- package/lib/cjs/components/select/tags.js +10 -0
- package/lib/cjs/components/select/tags.js.map +1 -1
- package/lib/cjs/index.d.ts +5 -1
- package/lib/cjs/index.d.ts.map +1 -1
- package/lib/cjs/index.js +5 -1
- package/lib/cjs/index.js.map +1 -1
- package/lib/esm/components/datatable/datatable-checkbox.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-checkbox.js +34 -15
- package/lib/esm/components/datatable/datatable-checkbox.js.map +1 -1
- package/lib/esm/components/datatable/datatable-contracts.d.ts +3 -3
- package/lib/esm/components/datatable/datatable-contracts.d.ts.map +1 -1
- 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 +324 -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 +18 -10
- 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 +40 -25
- package/lib/esm/components/datatable/datatable-pagination-renderer.js.map +1 -1
- package/lib/esm/components/datatable/datatable-remote-provider.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-remote-provider.js +3 -0
- package/lib/esm/components/datatable/datatable-remote-provider.js.map +1 -1
- package/lib/esm/components/datatable/datatable-table-renderer.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-table-renderer.js +14 -6
- package/lib/esm/components/datatable/datatable-table-renderer.js.map +1 -1
- package/lib/esm/components/datatable/datatable.d.ts +9 -0
- package/lib/esm/components/datatable/datatable.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable.js +200 -61
- 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 +27 -0
- package/lib/esm/components/datatable/types.d.ts.map +1 -1
- package/lib/esm/components/dropdown/dropdown.d.ts +2 -2
- package/lib/esm/components/dropdown/dropdown.d.ts.map +1 -1
- package/lib/esm/components/dropdown/dropdown.js +68 -31
- package/lib/esm/components/dropdown/dropdown.js.map +1 -1
- package/lib/esm/components/input-number/index.d.ts +7 -0
- package/lib/esm/components/input-number/index.d.ts.map +1 -0
- package/lib/esm/components/input-number/index.js +6 -0
- package/lib/esm/components/input-number/index.js.map +1 -0
- package/lib/esm/components/input-number/input-number.d.ts +40 -0
- package/lib/esm/components/input-number/input-number.d.ts.map +1 -0
- package/lib/esm/components/input-number/input-number.js +245 -0
- package/lib/esm/components/input-number/input-number.js.map +1 -0
- package/lib/esm/components/input-number/types.d.ts +30 -0
- package/lib/esm/components/input-number/types.d.ts.map +1 -0
- package/lib/esm/components/input-number/types.js +6 -0
- package/lib/esm/components/input-number/types.js.map +1 -0
- package/lib/esm/components/select/config.d.ts +1 -0
- package/lib/esm/components/select/config.d.ts.map +1 -1
- package/lib/esm/components/select/config.js +2 -1
- package/lib/esm/components/select/config.js.map +1 -1
- package/lib/esm/components/select/select.d.ts +8 -1
- package/lib/esm/components/select/select.d.ts.map +1 -1
- package/lib/esm/components/select/select.js +14 -1
- package/lib/esm/components/select/select.js.map +1 -1
- package/lib/esm/components/select/tags.d.ts.map +1 -1
- package/lib/esm/components/select/tags.js +11 -1
- package/lib/esm/components/select/tags.js.map +1 -1
- package/lib/esm/index.d.ts +5 -1
- package/lib/esm/index.d.ts.map +1 -1
- package/lib/esm/index.js +3 -0
- package/lib/esm/index.js.map +1 -1
- package/package.json +5 -11
- package/src/components/datatable/__tests__/locked-layout.test.ts +257 -0
- package/src/components/datatable/__tests__/pagination-reset.test.ts +18 -0
- package/src/components/datatable/datatable-checkbox.ts +35 -27
- package/src/components/datatable/datatable-contracts.ts +3 -3
- package/src/components/datatable/datatable-layout-plugin.ts +449 -0
- package/src/components/datatable/datatable-local-provider.ts +21 -14
- package/src/components/datatable/datatable-pagination-renderer.ts +40 -29
- package/src/components/datatable/datatable-remote-provider.ts +3 -0
- package/src/components/datatable/datatable-table-renderer.ts +40 -32
- package/src/components/datatable/datatable.css +98 -0
- package/src/components/datatable/datatable.ts +223 -86
- package/src/components/datatable/index.ts +5 -0
- package/src/components/datatable/types.ts +33 -0
- package/src/components/dropdown/dropdown.ts +86 -58
- package/src/components/input/input-group.css +14 -1
- package/src/components/input-number/__tests__/input-number.test.ts +278 -0
- package/src/components/input-number/index.ts +11 -0
- package/src/components/input-number/input-number.ts +267 -0
- package/src/components/input-number/types.ts +32 -0
- package/src/components/select/__tests__/ux-behaviors.test.ts +72 -0
- package/src/components/select/config.ts +3 -1
- package/src/components/select/select.css +23 -20
- package/src/components/select/select.ts +15 -1
- package/src/components/select/tags.ts +14 -1
- package/src/index.ts +14 -0
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
KTDataTableSortOrderInterface,
|
|
12
12
|
KTDataTableStateInterface,
|
|
13
13
|
KTDataTableColumnFilterInterface,
|
|
14
|
+
KTDataTableLayoutPluginContextInterface,
|
|
15
|
+
KTDataTableLayoutPluginInterface,
|
|
14
16
|
} from './types';
|
|
15
17
|
import { KTOptionType } from '../../types';
|
|
16
18
|
import KTComponents from '../../index';
|
|
@@ -20,6 +22,7 @@ import {
|
|
|
20
22
|
KTDataTableCheckboxAPI,
|
|
21
23
|
} from './datatable-checkbox';
|
|
22
24
|
import { createSortHandler, KTDataTableSortAPI } from './datatable-sort';
|
|
25
|
+
import { createStickyLayoutPlugin } from './datatable-layout-plugin';
|
|
23
26
|
import {
|
|
24
27
|
KTDataTableCleanup,
|
|
25
28
|
KTDataTableEventAdapter,
|
|
@@ -33,6 +36,7 @@ import { KTDataTableRemoteDataProvider } from './datatable-remote-provider';
|
|
|
33
36
|
import { KTDataTableConfigStateStore } from './datatable-state-store';
|
|
34
37
|
import { KTDataTableDomPaginationRenderer } from './datatable-pagination-renderer';
|
|
35
38
|
import { KTDataTableDomTableRenderer } from './datatable-table-renderer';
|
|
39
|
+
import KTUtils from '../../helpers/utils';
|
|
36
40
|
|
|
37
41
|
/**
|
|
38
42
|
* Custom DataTable plugin class with server-side API, pagination, and sorting
|
|
@@ -74,12 +78,13 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
74
78
|
private _originalTdClasses: string[][] = []; // Store original td classes as a 2D array [row][col]
|
|
75
79
|
private _originalThClasses: string[] = []; // Store original th classes
|
|
76
80
|
|
|
77
|
-
private _infoElement: HTMLElement;
|
|
78
|
-
private _sizeElement: HTMLSelectElement;
|
|
79
|
-
private _paginationElement: HTMLElement;
|
|
81
|
+
private _infoElement: HTMLElement | null = null;
|
|
82
|
+
private _sizeElement: HTMLSelectElement | null = null;
|
|
83
|
+
private _paginationElement: HTMLElement | null = null;
|
|
80
84
|
|
|
81
85
|
private _checkbox: KTDataTableCheckboxAPI;
|
|
82
86
|
private _sortHandler: KTDataTableSortAPI<T>;
|
|
87
|
+
private _layoutPlugin: KTDataTableLayoutPluginInterface | null = null;
|
|
83
88
|
private _eventAdapter: KTDataTableEventAdapter;
|
|
84
89
|
private _stateStore: KTDataTableStateStore;
|
|
85
90
|
private _localProvider: KTDataTableLocalDataProvider<T>;
|
|
@@ -95,10 +100,10 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
95
100
|
super();
|
|
96
101
|
|
|
97
102
|
if (KTData.has(element as HTMLElement, this._name)) {
|
|
98
|
-
// Already initialized (e.g. by createInstances). Merge
|
|
103
|
+
// Already initialized (e.g. by createInstances). Merge demo config and redraw once.
|
|
99
104
|
const existing = KTDataTable.getInstance(element as HTMLElement);
|
|
100
105
|
if (existing && config) {
|
|
101
|
-
existing.
|
|
106
|
+
existing._applyRuntimeConfig(config);
|
|
102
107
|
}
|
|
103
108
|
return;
|
|
104
109
|
}
|
|
@@ -106,7 +111,14 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
106
111
|
this._defaultConfig = this._initDefaultConfig(config);
|
|
107
112
|
|
|
108
113
|
this._init(element);
|
|
114
|
+
if (!this._element) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (!this._element.hasAttribute('data-kt-datatable')) {
|
|
118
|
+
this._element.setAttribute('data-kt-datatable', 'true');
|
|
119
|
+
}
|
|
109
120
|
this._buildConfig();
|
|
121
|
+
this._normalizePageSizeConfig();
|
|
110
122
|
this._stateStore = new KTDataTableConfigStateStore(this._config);
|
|
111
123
|
this._eventAdapter = createDataTableEventAdapter(
|
|
112
124
|
this._fireEvent.bind(this),
|
|
@@ -117,6 +129,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
117
129
|
KTDataTable.asElementWithInstance(element).instance = this;
|
|
118
130
|
|
|
119
131
|
this._initElements();
|
|
132
|
+
this._layoutPlugin = this._createLayoutPlugin();
|
|
120
133
|
this._tableRenderer = new KTDataTableDomTableRenderer<T>();
|
|
121
134
|
this._paginationRenderer = new KTDataTableDomPaginationRenderer();
|
|
122
135
|
this._initDataProviders();
|
|
@@ -152,6 +165,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
152
165
|
|
|
153
166
|
if (this._config.stateSave) {
|
|
154
167
|
this._loadState();
|
|
168
|
+
this._normalizePageState();
|
|
155
169
|
}
|
|
156
170
|
|
|
157
171
|
this._updateData();
|
|
@@ -185,6 +199,69 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
185
199
|
});
|
|
186
200
|
}
|
|
187
201
|
|
|
202
|
+
private _createLayoutPlugin(): KTDataTableLayoutPluginInterface | null {
|
|
203
|
+
if (this._config.layoutPlugin) {
|
|
204
|
+
return this._config.layoutPlugin;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (this._config.lockedLayout) {
|
|
208
|
+
return createStickyLayoutPlugin();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Apply config from a late constructor call (e.g. docs demo script after auto-init).
|
|
216
|
+
*/
|
|
217
|
+
private _applyRuntimeConfig(config: KTDataTableConfigInterface): void {
|
|
218
|
+
this._mergeConfig(config);
|
|
219
|
+
this._normalizePageSizeConfig();
|
|
220
|
+
this._layoutPlugin = this._createLayoutPlugin();
|
|
221
|
+
this.reload();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private _normalizePageSizeConfig(): void {
|
|
225
|
+
const configuredPageSizes = Array.isArray(this._config.pageSizes)
|
|
226
|
+
? this._config.pageSizes
|
|
227
|
+
: [];
|
|
228
|
+
const pageSizes = configuredPageSizes
|
|
229
|
+
.map((size) => Number(size))
|
|
230
|
+
.filter((size) => Number.isFinite(size) && size > 0)
|
|
231
|
+
.map((size) => Math.floor(size));
|
|
232
|
+
const fallbackPageSizes = [5, 10, 20, 30, 50];
|
|
233
|
+
this._config.pageSizes =
|
|
234
|
+
pageSizes.length > 0 ? Array.from(new Set(pageSizes)) : fallbackPageSizes;
|
|
235
|
+
|
|
236
|
+
const configuredPageSize = Number(this._config.pageSize);
|
|
237
|
+
this._config.pageSize =
|
|
238
|
+
Number.isFinite(configuredPageSize) && configuredPageSize > 0
|
|
239
|
+
? Math.floor(configuredPageSize)
|
|
240
|
+
: this._config.pageSizes[0];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private _normalizePageState(): void {
|
|
244
|
+
const statePageSize = Number(this._config._state.pageSize);
|
|
245
|
+
this._config._state.pageSize =
|
|
246
|
+
Number.isFinite(statePageSize) && statePageSize > 0
|
|
247
|
+
? Math.floor(statePageSize)
|
|
248
|
+
: this._config.pageSize;
|
|
249
|
+
|
|
250
|
+
const statePage = Number(this._config._state.page);
|
|
251
|
+
this._config._state.page =
|
|
252
|
+
Number.isFinite(statePage) && statePage > 0 ? Math.floor(statePage) : 1;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private _getLayoutPluginContext(): KTDataTableLayoutPluginContextInterface {
|
|
256
|
+
return {
|
|
257
|
+
rootElement: this._element,
|
|
258
|
+
tableElement: this._tableElement,
|
|
259
|
+
theadElement: this._theadElement,
|
|
260
|
+
tbodyElement: this._tbodyElement,
|
|
261
|
+
config: this._config,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
188
265
|
/**
|
|
189
266
|
* Initialize default configuration for the datatable
|
|
190
267
|
* @param config User-provided configuration options
|
|
@@ -425,43 +502,37 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
425
502
|
* @returns {void}
|
|
426
503
|
*/
|
|
427
504
|
private _initElements(): void {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
505
|
+
const root = this._element;
|
|
506
|
+
const attrs = this._config.attributes;
|
|
507
|
+
if (!root || !attrs?.table) {
|
|
508
|
+
throw new Error(
|
|
509
|
+
'KTDataTable: root element and table selector are required',
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const tableEl = root.querySelector<HTMLTableElement>(attrs.table);
|
|
514
|
+
if (!tableEl) {
|
|
515
|
+
throw new Error(`KTDataTable: table element not found (${attrs.table})`);
|
|
516
|
+
}
|
|
517
|
+
this._tableElement = tableEl;
|
|
518
|
+
|
|
437
519
|
this._tbodyElement =
|
|
438
520
|
this._tableElement.tBodies[0] || this._tableElement.createTBody();
|
|
439
|
-
/**
|
|
440
|
-
* Table head element
|
|
441
|
-
*/
|
|
442
|
-
this._theadElement = this._tableElement.tHead!;
|
|
443
521
|
|
|
444
|
-
|
|
522
|
+
this._theadElement =
|
|
523
|
+
this._tableElement.tHead ?? this._tableElement.createTHead();
|
|
524
|
+
|
|
445
525
|
this._storeOriginalClasses();
|
|
446
526
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
this.
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
this._sizeElement = this._element.querySelector<HTMLSelectElement>(
|
|
457
|
-
this._config.attributes.size,
|
|
458
|
-
)!;
|
|
459
|
-
/**
|
|
460
|
-
* Pagination element
|
|
461
|
-
*/
|
|
462
|
-
this._paginationElement = this._element.querySelector<HTMLElement>(
|
|
463
|
-
this._config.attributes.pagination,
|
|
464
|
-
)!;
|
|
527
|
+
this._infoElement = attrs.info
|
|
528
|
+
? root.querySelector<HTMLElement>(attrs.info)
|
|
529
|
+
: null;
|
|
530
|
+
this._sizeElement = attrs.size
|
|
531
|
+
? root.querySelector<HTMLSelectElement>(attrs.size)
|
|
532
|
+
: null;
|
|
533
|
+
this._paginationElement = attrs.pagination
|
|
534
|
+
? root.querySelector<HTMLElement>(attrs.pagination)
|
|
535
|
+
: null;
|
|
465
536
|
}
|
|
466
537
|
|
|
467
538
|
/**
|
|
@@ -540,7 +611,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
540
611
|
* @returns {void}
|
|
541
612
|
*/
|
|
542
613
|
private _finalize(): void {
|
|
543
|
-
this._element
|
|
614
|
+
this._element?.classList.add('datatable-initialized');
|
|
544
615
|
|
|
545
616
|
// Initialize checkbox logic
|
|
546
617
|
this._checkbox.init();
|
|
@@ -600,7 +671,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
600
671
|
// Create a new debounced search function
|
|
601
672
|
const debouncedSearch = this._debounce(() => {
|
|
602
673
|
this.search(searchElement.value);
|
|
603
|
-
}, this._config.search
|
|
674
|
+
}, this._config.search?.delay ?? 500);
|
|
604
675
|
|
|
605
676
|
// Store the new debounced function as a property of the element
|
|
606
677
|
searchWithDebounce._debouncedSearch = debouncedSearch;
|
|
@@ -647,7 +718,9 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
647
718
|
|
|
648
719
|
private _createUrl(
|
|
649
720
|
pathOrUrl: string,
|
|
650
|
-
baseUrl: string | null = window
|
|
721
|
+
baseUrl: string | null = typeof window !== 'undefined'
|
|
722
|
+
? window.location.origin
|
|
723
|
+
: null,
|
|
651
724
|
): URL {
|
|
652
725
|
// Regular expression to check if the input is a full URL
|
|
653
726
|
const isFullUrl = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(pathOrUrl);
|
|
@@ -661,7 +734,39 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
661
734
|
? pathOrUrl
|
|
662
735
|
: `/${pathOrUrl}`;
|
|
663
736
|
|
|
664
|
-
|
|
737
|
+
// Opaque origins (e.g. srcdoc iframes) serialize as the string "null", which is not a valid URL base.
|
|
738
|
+
const bases: string[] = [];
|
|
739
|
+
if (baseUrl && baseUrl !== 'null') {
|
|
740
|
+
bases.push(baseUrl);
|
|
741
|
+
}
|
|
742
|
+
if (typeof window !== 'undefined') {
|
|
743
|
+
const href = window.location.href;
|
|
744
|
+
if (href && !bases.includes(href)) {
|
|
745
|
+
bases.push(href);
|
|
746
|
+
}
|
|
747
|
+
try {
|
|
748
|
+
if (window.parent !== window && window.parent.location?.href) {
|
|
749
|
+
const parentHref = window.parent.location.href;
|
|
750
|
+
if (parentHref && !bases.includes(parentHref)) {
|
|
751
|
+
bases.push(parentHref);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
} catch {
|
|
755
|
+
// parent is cross-origin
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
for (const base of bases) {
|
|
760
|
+
try {
|
|
761
|
+
return new URL(normalizedPath, base);
|
|
762
|
+
} catch {
|
|
763
|
+
// try next base
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
throw new Error(
|
|
768
|
+
`KTDataTable: cannot resolve relative apiEndpoint "${pathOrUrl}" (no valid base URL; use an absolute apiEndpoint).`,
|
|
769
|
+
);
|
|
665
770
|
}
|
|
666
771
|
|
|
667
772
|
/**
|
|
@@ -669,11 +774,20 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
669
774
|
* @returns {Promise<void>} A promise that resolves when the table and pagination controls are updated
|
|
670
775
|
*/
|
|
671
776
|
private async _draw(): Promise<void> {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
777
|
+
const normalizedPageSize = Math.max(
|
|
778
|
+
1,
|
|
779
|
+
Number(this.getState().pageSize) || Number(this._config.pageSize) || 1,
|
|
780
|
+
);
|
|
781
|
+
const totalPages =
|
|
782
|
+
Math.ceil(this.getState().totalItems / normalizedPageSize) || 0;
|
|
783
|
+
const page =
|
|
784
|
+
totalPages > 0
|
|
785
|
+
? Math.min(Math.max(1, this.getState().page), totalPages)
|
|
786
|
+
: 1;
|
|
787
|
+
|
|
788
|
+
this._stateStore.patchState({ totalPages, page });
|
|
676
789
|
|
|
790
|
+
this._layoutPlugin?.beforeDraw?.(this._getLayoutPluginContext());
|
|
677
791
|
this._emit('draw');
|
|
678
792
|
|
|
679
793
|
this._dispose();
|
|
@@ -683,10 +797,19 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
683
797
|
this._updateTable();
|
|
684
798
|
}
|
|
685
799
|
|
|
686
|
-
if (this._infoElement
|
|
800
|
+
if (this._infoElement || this._sizeElement || this._paginationElement) {
|
|
687
801
|
this._updatePagination();
|
|
688
802
|
}
|
|
689
803
|
|
|
804
|
+
this._layoutPlugin?.afterDraw?.(this._getLayoutPluginContext());
|
|
805
|
+
if (!this._config.apiEndpoint) {
|
|
806
|
+
this._stateStore.patchState({
|
|
807
|
+
_contentChecksum: KTUtils.checksum(
|
|
808
|
+
JSON.stringify(this._tbodyElement.innerHTML),
|
|
809
|
+
),
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
|
|
690
813
|
this._emit('drew');
|
|
691
814
|
|
|
692
815
|
// Spinner is hidden in _finalize() to ensure it stays visible until the entire request completes
|
|
@@ -702,7 +825,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
702
825
|
* @returns {HTMLTableSectionElement} The new table body element
|
|
703
826
|
*/
|
|
704
827
|
private _updateTable(): HTMLTableSectionElement {
|
|
705
|
-
|
|
828
|
+
this._tbodyElement = this._tableRenderer.render({
|
|
706
829
|
config: this._config,
|
|
707
830
|
context: this,
|
|
708
831
|
data: this._data,
|
|
@@ -714,6 +837,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
714
837
|
tableElement: this._tableElement,
|
|
715
838
|
theadElement: this._theadElement,
|
|
716
839
|
});
|
|
840
|
+
return this._tbodyElement;
|
|
717
841
|
}
|
|
718
842
|
|
|
719
843
|
/**
|
|
@@ -778,38 +902,45 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
778
902
|
|
|
779
903
|
// Method to show the loading spinner
|
|
780
904
|
private _showSpinner(): void {
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
905
|
+
const root = this._element;
|
|
906
|
+
const spinnerSel = this._config.attributes?.spinner;
|
|
907
|
+
const fromDom =
|
|
908
|
+
root && spinnerSel ? root.querySelector<HTMLElement>(spinnerSel) : null;
|
|
909
|
+
const spinner = fromDom ?? this._createSpinner();
|
|
785
910
|
if (spinner) {
|
|
786
911
|
spinner.style.display = 'block';
|
|
787
912
|
}
|
|
788
|
-
|
|
913
|
+
root?.classList.add(this._config.loadingClass ?? 'loading');
|
|
789
914
|
}
|
|
790
915
|
|
|
791
916
|
// Method to hide the loading spinner
|
|
792
917
|
private _hideSpinner(): void {
|
|
793
|
-
const
|
|
794
|
-
|
|
795
|
-
|
|
918
|
+
const root = this._element;
|
|
919
|
+
const spinnerSel = this._config.attributes?.spinner;
|
|
920
|
+
const spinner =
|
|
921
|
+
root && spinnerSel ? root.querySelector<HTMLElement>(spinnerSel) : null;
|
|
796
922
|
if (spinner) {
|
|
797
923
|
spinner.style.display = 'none';
|
|
798
924
|
}
|
|
799
|
-
|
|
925
|
+
root?.classList.remove(this._config.loadingClass ?? 'loading');
|
|
800
926
|
}
|
|
801
927
|
|
|
802
928
|
// Method to create a spinner element if it doesn't exist
|
|
803
|
-
private _createSpinner(): HTMLElement {
|
|
804
|
-
|
|
929
|
+
private _createSpinner(): HTMLElement | null {
|
|
930
|
+
const loading = this._config.loading;
|
|
931
|
+
if (!loading) {
|
|
805
932
|
return null;
|
|
806
933
|
}
|
|
807
934
|
|
|
808
935
|
const template = document.createElement('template');
|
|
809
|
-
template.innerHTML =
|
|
936
|
+
template.innerHTML = loading.template
|
|
810
937
|
.trim()
|
|
811
|
-
.replace('{content}',
|
|
812
|
-
const
|
|
938
|
+
.replace('{content}', loading.content);
|
|
939
|
+
const first = template.content.firstChild;
|
|
940
|
+
if (!first || !(first instanceof HTMLElement)) {
|
|
941
|
+
return null;
|
|
942
|
+
}
|
|
943
|
+
const spinner = first;
|
|
813
944
|
spinner.setAttribute('data-kt-datatable-spinner', 'true');
|
|
814
945
|
|
|
815
946
|
this._tableElement.appendChild(spinner);
|
|
@@ -878,18 +1009,15 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
878
1009
|
}
|
|
879
1010
|
|
|
880
1011
|
private _tableId(): string {
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
id = this._tableElement.getAttribute('id') as string;
|
|
1012
|
+
const tableIdAttr = this._tableElement?.getAttribute('id');
|
|
1013
|
+
if (tableIdAttr) {
|
|
1014
|
+
return tableIdAttr;
|
|
885
1015
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
id = this._element.getAttribute('id') as string;
|
|
1016
|
+
const rootIdAttr = this._element?.getAttribute('id');
|
|
1017
|
+
if (rootIdAttr) {
|
|
1018
|
+
return rootIdAttr;
|
|
890
1019
|
}
|
|
891
|
-
|
|
892
|
-
return id;
|
|
1020
|
+
return '';
|
|
893
1021
|
}
|
|
894
1022
|
|
|
895
1023
|
/**
|
|
@@ -897,6 +1025,13 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
897
1025
|
* This method is called before re-rendering or when disposing the component.
|
|
898
1026
|
*/
|
|
899
1027
|
private _dispose() {
|
|
1028
|
+
this._layoutPlugin?.dispose?.(this._getLayoutPluginContext());
|
|
1029
|
+
|
|
1030
|
+
const root = this._element;
|
|
1031
|
+
if (!root) {
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
900
1035
|
this._cleanupCallbacks.forEach((cleanup) => cleanup());
|
|
901
1036
|
this._cleanupCallbacks = [];
|
|
902
1037
|
|
|
@@ -939,12 +1074,13 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
939
1074
|
if (this._checkbox && typeof checkboxWithDispose.dispose === 'function') {
|
|
940
1075
|
checkboxWithDispose.dispose();
|
|
941
1076
|
} else {
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1077
|
+
const checkSel = this._config.attributes?.check;
|
|
1078
|
+
if (checkSel) {
|
|
1079
|
+
const headerCheckElement =
|
|
1080
|
+
root.querySelector<HTMLInputElement>(checkSel);
|
|
1081
|
+
if (headerCheckElement) {
|
|
1082
|
+
headerCheckElement.replaceWith(headerCheckElement.cloneNode(true));
|
|
1083
|
+
}
|
|
948
1084
|
}
|
|
949
1085
|
}
|
|
950
1086
|
// KTDataTableSortAPI does not have a dispose method, but we can remove th click listeners by replacing them
|
|
@@ -956,22 +1092,23 @@ export class KTDataTable<T extends KTDataTableDataInterface>
|
|
|
956
1092
|
}
|
|
957
1093
|
|
|
958
1094
|
// --- 5. Remove spinner DOM node if it exists ---
|
|
959
|
-
const
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1095
|
+
const spinnerSel = this._config.attributes?.spinner;
|
|
1096
|
+
if (spinnerSel) {
|
|
1097
|
+
const spinner = root.querySelector<HTMLElement>(spinnerSel);
|
|
1098
|
+
if (spinner?.parentNode) {
|
|
1099
|
+
spinner.parentNode.removeChild(spinner);
|
|
1100
|
+
}
|
|
964
1101
|
}
|
|
965
|
-
|
|
1102
|
+
root.classList.remove(this._config.loadingClass ?? 'loading');
|
|
966
1103
|
|
|
967
1104
|
// --- 6. Remove instance reference from the DOM element ---
|
|
968
|
-
const elementWithInstance = KTDataTable.asElementWithInstance(
|
|
969
|
-
this._element,
|
|
970
|
-
);
|
|
1105
|
+
const elementWithInstance = KTDataTable.asElementWithInstance(root);
|
|
971
1106
|
if (elementWithInstance.instance) {
|
|
972
1107
|
delete elementWithInstance.instance;
|
|
973
1108
|
}
|
|
974
1109
|
|
|
1110
|
+
KTData.remove(root, this._name);
|
|
1111
|
+
|
|
975
1112
|
// --- 7. (Optional) Clear localStorage state ---
|
|
976
1113
|
// Uncomment the following line if you want to clear state on dispose:
|
|
977
1114
|
// this._deleteState();
|
|
@@ -16,4 +16,9 @@ export type {
|
|
|
16
16
|
KTDataTableCheckConfigInterface,
|
|
17
17
|
KTDataTableCheckInterface,
|
|
18
18
|
KTDataTableCheckChangePayloadInterface,
|
|
19
|
+
KTDataTableLockedRowsConfigInterface,
|
|
20
|
+
KTDataTableLockedColumnsConfigInterface,
|
|
21
|
+
KTDataTableLockedLayoutConfigInterface,
|
|
22
|
+
KTDataTableLayoutPluginContextInterface,
|
|
23
|
+
KTDataTableLayoutPluginInterface,
|
|
19
24
|
} from './types';
|
|
@@ -69,6 +69,36 @@ export interface KTDataTableResponseDataInterface {
|
|
|
69
69
|
totalCount: number;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
export interface KTDataTableLockedRowsConfigInterface {
|
|
73
|
+
top?: number;
|
|
74
|
+
bottom?: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface KTDataTableLockedColumnsConfigInterface {
|
|
78
|
+
left?: string[];
|
|
79
|
+
right?: string[];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface KTDataTableLockedLayoutConfigInterface {
|
|
83
|
+
stickyHeader?: boolean;
|
|
84
|
+
stickyRows?: KTDataTableLockedRowsConfigInterface;
|
|
85
|
+
stickyColumns?: KTDataTableLockedColumnsConfigInterface;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface KTDataTableLayoutPluginContextInterface {
|
|
89
|
+
rootElement: HTMLElement;
|
|
90
|
+
tableElement: HTMLTableElement;
|
|
91
|
+
theadElement: HTMLTableSectionElement;
|
|
92
|
+
tbodyElement: HTMLTableSectionElement;
|
|
93
|
+
config: KTDataTableConfigInterface;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface KTDataTableLayoutPluginInterface {
|
|
97
|
+
beforeDraw?: (ctx: KTDataTableLayoutPluginContextInterface) => void;
|
|
98
|
+
afterDraw?: (ctx: KTDataTableLayoutPluginContextInterface) => void;
|
|
99
|
+
dispose?: (ctx: KTDataTableLayoutPluginContextInterface) => void;
|
|
100
|
+
}
|
|
101
|
+
|
|
72
102
|
// Define the DataTable options type
|
|
73
103
|
export interface KTDataTableConfigInterface {
|
|
74
104
|
requestMethod?: string;
|
|
@@ -187,6 +217,9 @@ export interface KTDataTableConfigInterface {
|
|
|
187
217
|
preserveSelection?: boolean;
|
|
188
218
|
};
|
|
189
219
|
|
|
220
|
+
lockedLayout?: KTDataTableLockedLayoutConfigInterface;
|
|
221
|
+
layoutPlugin?: KTDataTableLayoutPluginInterface;
|
|
222
|
+
|
|
190
223
|
_state?: KTDataTableStateInterface;
|
|
191
224
|
_data?: KTDataTableDataInterface[];
|
|
192
225
|
|