@keenthemes/ktui 1.2.3 → 1.2.4

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.
Files changed (141) hide show
  1. package/dist/ktui.js +1681 -957
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +110 -1
  5. package/lib/cjs/components/context-menu/context-menu.d.ts +66 -0
  6. package/lib/cjs/components/context-menu/context-menu.d.ts.map +1 -0
  7. package/lib/cjs/components/context-menu/context-menu.js +423 -0
  8. package/lib/cjs/components/context-menu/context-menu.js.map +1 -0
  9. package/lib/cjs/components/context-menu/index.d.ts +7 -0
  10. package/lib/cjs/components/context-menu/index.d.ts.map +1 -0
  11. package/lib/cjs/components/context-menu/index.js +10 -0
  12. package/lib/cjs/components/context-menu/index.js.map +1 -0
  13. package/lib/cjs/components/context-menu/types.d.ts +30 -0
  14. package/lib/cjs/components/context-menu/types.d.ts.map +1 -0
  15. package/lib/cjs/components/context-menu/types.js +7 -0
  16. package/lib/cjs/components/context-menu/types.js.map +1 -0
  17. package/lib/cjs/components/datatable/datatable-contracts.d.ts +66 -0
  18. package/lib/cjs/components/datatable/datatable-contracts.d.ts.map +1 -0
  19. package/lib/cjs/components/datatable/datatable-contracts.js +7 -0
  20. package/lib/cjs/components/datatable/datatable-contracts.js.map +1 -0
  21. package/lib/cjs/components/datatable/datatable-event-adapter.d.ts +7 -0
  22. package/lib/cjs/components/datatable/datatable-event-adapter.d.ts.map +1 -0
  23. package/lib/cjs/components/datatable/datatable-event-adapter.js +16 -0
  24. package/lib/cjs/components/datatable/datatable-event-adapter.js.map +1 -0
  25. package/lib/cjs/components/datatable/datatable-local-provider.d.ts +25 -0
  26. package/lib/cjs/components/datatable/datatable-local-provider.d.ts.map +1 -0
  27. package/lib/cjs/components/datatable/datatable-local-provider.js +184 -0
  28. package/lib/cjs/components/datatable/datatable-local-provider.js.map +1 -0
  29. package/lib/cjs/components/datatable/datatable-pagination-renderer.d.ts +15 -0
  30. package/lib/cjs/components/datatable/datatable-pagination-renderer.d.ts.map +1 -0
  31. package/lib/cjs/components/datatable/datatable-pagination-renderer.js +128 -0
  32. package/lib/cjs/components/datatable/datatable-pagination-renderer.js.map +1 -0
  33. package/lib/cjs/components/datatable/datatable-remote-provider.d.ts +25 -0
  34. package/lib/cjs/components/datatable/datatable-remote-provider.d.ts.map +1 -0
  35. package/lib/cjs/components/datatable/datatable-remote-provider.js +188 -0
  36. package/lib/cjs/components/datatable/datatable-remote-provider.js.map +1 -0
  37. package/lib/cjs/components/datatable/datatable-state-store.d.ts +21 -0
  38. package/lib/cjs/components/datatable/datatable-state-store.d.ts.map +1 -0
  39. package/lib/cjs/components/datatable/datatable-state-store.js +81 -0
  40. package/lib/cjs/components/datatable/datatable-state-store.js.map +1 -0
  41. package/lib/cjs/components/datatable/datatable-table-renderer.d.ts +16 -0
  42. package/lib/cjs/components/datatable/datatable-table-renderer.d.ts.map +1 -0
  43. package/lib/cjs/components/datatable/datatable-table-renderer.js +133 -0
  44. package/lib/cjs/components/datatable/datatable-table-renderer.js.map +1 -0
  45. package/lib/cjs/components/datatable/datatable.d.ts +9 -87
  46. package/lib/cjs/components/datatable/datatable.d.ts.map +1 -1
  47. package/lib/cjs/components/datatable/datatable.js +114 -686
  48. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  49. package/lib/cjs/components/select/index.d.ts +1 -1
  50. package/lib/cjs/components/select/index.d.ts.map +1 -1
  51. package/lib/cjs/index.d.ts +5 -1
  52. package/lib/cjs/index.d.ts.map +1 -1
  53. package/lib/cjs/index.js +7 -7
  54. package/lib/cjs/index.js.map +1 -1
  55. package/lib/cjs/init-all.d.ts +6 -0
  56. package/lib/cjs/init-all.d.ts.map +1 -0
  57. package/lib/cjs/init-all.js +17 -0
  58. package/lib/cjs/init-all.js.map +1 -0
  59. package/lib/cjs/legacy.d.ts +8 -0
  60. package/lib/cjs/legacy.d.ts.map +1 -0
  61. package/lib/cjs/legacy.js +26 -0
  62. package/lib/cjs/legacy.js.map +1 -0
  63. package/lib/esm/components/context-menu/context-menu.d.ts +66 -0
  64. package/lib/esm/components/context-menu/context-menu.d.ts.map +1 -0
  65. package/lib/esm/components/context-menu/context-menu.js +420 -0
  66. package/lib/esm/components/context-menu/context-menu.js.map +1 -0
  67. package/lib/esm/components/context-menu/index.d.ts +7 -0
  68. package/lib/esm/components/context-menu/index.d.ts.map +1 -0
  69. package/lib/esm/components/context-menu/index.js +6 -0
  70. package/lib/esm/components/context-menu/index.js.map +1 -0
  71. package/lib/esm/components/context-menu/types.d.ts +30 -0
  72. package/lib/esm/components/context-menu/types.d.ts.map +1 -0
  73. package/lib/esm/components/context-menu/types.js +6 -0
  74. package/lib/esm/components/context-menu/types.js.map +1 -0
  75. package/lib/esm/components/datatable/datatable-contracts.d.ts +66 -0
  76. package/lib/esm/components/datatable/datatable-contracts.d.ts.map +1 -0
  77. package/lib/esm/components/datatable/datatable-contracts.js +6 -0
  78. package/lib/esm/components/datatable/datatable-contracts.js.map +1 -0
  79. package/lib/esm/components/datatable/datatable-event-adapter.d.ts +7 -0
  80. package/lib/esm/components/datatable/datatable-event-adapter.d.ts.map +1 -0
  81. package/lib/esm/components/datatable/datatable-event-adapter.js +13 -0
  82. package/lib/esm/components/datatable/datatable-event-adapter.js.map +1 -0
  83. package/lib/esm/components/datatable/datatable-local-provider.d.ts +25 -0
  84. package/lib/esm/components/datatable/datatable-local-provider.d.ts.map +1 -0
  85. package/lib/esm/components/datatable/datatable-local-provider.js +181 -0
  86. package/lib/esm/components/datatable/datatable-local-provider.js.map +1 -0
  87. package/lib/esm/components/datatable/datatable-pagination-renderer.d.ts +15 -0
  88. package/lib/esm/components/datatable/datatable-pagination-renderer.d.ts.map +1 -0
  89. package/lib/esm/components/datatable/datatable-pagination-renderer.js +125 -0
  90. package/lib/esm/components/datatable/datatable-pagination-renderer.js.map +1 -0
  91. package/lib/esm/components/datatable/datatable-remote-provider.d.ts +25 -0
  92. package/lib/esm/components/datatable/datatable-remote-provider.d.ts.map +1 -0
  93. package/lib/esm/components/datatable/datatable-remote-provider.js +185 -0
  94. package/lib/esm/components/datatable/datatable-remote-provider.js.map +1 -0
  95. package/lib/esm/components/datatable/datatable-state-store.d.ts +21 -0
  96. package/lib/esm/components/datatable/datatable-state-store.d.ts.map +1 -0
  97. package/lib/esm/components/datatable/datatable-state-store.js +78 -0
  98. package/lib/esm/components/datatable/datatable-state-store.js.map +1 -0
  99. package/lib/esm/components/datatable/datatable-table-renderer.d.ts +16 -0
  100. package/lib/esm/components/datatable/datatable-table-renderer.d.ts.map +1 -0
  101. package/lib/esm/components/datatable/datatable-table-renderer.js +130 -0
  102. package/lib/esm/components/datatable/datatable-table-renderer.js.map +1 -0
  103. package/lib/esm/components/datatable/datatable.d.ts +9 -87
  104. package/lib/esm/components/datatable/datatable.d.ts.map +1 -1
  105. package/lib/esm/components/datatable/datatable.js +114 -686
  106. package/lib/esm/components/datatable/datatable.js.map +1 -1
  107. package/lib/esm/components/select/index.d.ts +1 -1
  108. package/lib/esm/components/select/index.d.ts.map +1 -1
  109. package/lib/esm/index.d.ts +5 -1
  110. package/lib/esm/index.d.ts.map +1 -1
  111. package/lib/esm/index.js +4 -5
  112. package/lib/esm/index.js.map +1 -1
  113. package/lib/esm/init-all.d.ts +6 -0
  114. package/lib/esm/init-all.d.ts.map +1 -0
  115. package/lib/esm/init-all.js +13 -0
  116. package/lib/esm/init-all.js.map +1 -0
  117. package/lib/esm/legacy.d.ts +8 -0
  118. package/lib/esm/legacy.d.ts.map +1 -0
  119. package/lib/esm/legacy.js +8 -0
  120. package/lib/esm/legacy.js.map +1 -0
  121. package/package.json +34 -4
  122. package/src/__tests__/entrypoints.test.ts +71 -0
  123. package/src/components/context-menu/__tests__/context-menu.test.ts +117 -0
  124. package/src/components/context-menu/context-menu.css +32 -0
  125. package/src/components/context-menu/context-menu.ts +529 -0
  126. package/src/components/context-menu/index.ts +10 -0
  127. package/src/components/context-menu/types.ts +32 -0
  128. package/src/components/datatable/__tests__/architecture-boundaries.test.ts +259 -0
  129. package/src/components/datatable/datatable-contracts.ts +96 -0
  130. package/src/components/datatable/datatable-event-adapter.ts +21 -0
  131. package/src/components/datatable/datatable-local-provider.ts +194 -0
  132. package/src/components/datatable/datatable-pagination-renderer.ts +211 -0
  133. package/src/components/datatable/datatable-remote-provider.ts +175 -0
  134. package/src/components/datatable/datatable-state-store.ts +94 -0
  135. package/src/components/datatable/datatable-table-renderer.ts +206 -0
  136. package/src/components/datatable/datatable.ts +128 -839
  137. package/src/components/select/index.ts +1 -1
  138. package/src/index.ts +9 -5
  139. package/src/init-all.ts +15 -0
  140. package/src/legacy.ts +9 -0
  141. package/styles.css +1 -0
@@ -65,35 +65,20 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
65
65
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
66
66
  }
67
67
  };
68
- var __rest = (this && this.__rest) || function (s, e) {
69
- var t = {};
70
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
71
- t[p] = s[p];
72
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
73
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
74
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
75
- t[p[i]] = s[p[i]];
76
- }
77
- return t;
78
- };
79
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
80
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
81
- if (ar || !(i in from)) {
82
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
83
- ar[i] = from[i];
84
- }
85
- }
86
- return to.concat(ar || Array.prototype.slice.call(from));
87
- };
88
68
  Object.defineProperty(exports, "__esModule", { value: true });
89
69
  exports.KTDataTable = void 0;
90
70
  exports.initAllDataTables = initAllDataTables;
91
71
  var component_1 = require("../component");
92
- var utils_1 = require("../../helpers/utils");
93
72
  var index_1 = require("../../index");
94
73
  var data_1 = require("../../helpers/data");
95
74
  var datatable_checkbox_1 = require("./datatable-checkbox");
96
75
  var datatable_sort_1 = require("./datatable-sort");
76
+ var datatable_event_adapter_1 = require("./datatable-event-adapter");
77
+ var datatable_local_provider_1 = require("./datatable-local-provider");
78
+ var datatable_remote_provider_1 = require("./datatable-remote-provider");
79
+ var datatable_state_store_1 = require("./datatable-state-store");
80
+ var datatable_pagination_renderer_1 = require("./datatable-pagination-renderer");
81
+ var datatable_table_renderer_1 = require("./datatable-table-renderer");
97
82
  /**
98
83
  * Custom DataTable plugin class with server-side API, pagination, and sorting
99
84
  * @classdesc A custom KTComponent class that integrates server-side API, pagination, and sorting functionality into a table.
@@ -113,18 +98,9 @@ var KTDataTable = /** @class */ (function (_super) {
113
98
  _this._originalTheadClass = ''; // Store original thead class
114
99
  _this._originalTdClasses = []; // Store original td classes as a 2D array [row][col]
115
100
  _this._originalThClasses = []; // Store original th classes
101
+ _this._cleanupCallbacks = [];
116
102
  _this._data = [];
117
103
  _this._isFetching = false;
118
- /**
119
- * AbortController for cancelling previous fetch requests
120
- * Used to prevent race conditions when multiple requests are triggered rapidly
121
- */
122
- _this._abortController = null;
123
- /**
124
- * Request ID counter for tracking request sequence
125
- * Used to detect and ignore stale responses from older requests
126
- */
127
- _this._requestId = 0;
128
104
  if (data_1.default.has(element, _this._name)) {
129
105
  // Already initialized (e.g. by createInstances). Merge user config so columns/sortType etc. apply.
130
106
  var existing = KTDataTable.getInstance(element);
@@ -136,21 +112,22 @@ var KTDataTable = /** @class */ (function (_super) {
136
112
  _this._defaultConfig = _this._initDefaultConfig(config);
137
113
  _this._init(element);
138
114
  _this._buildConfig();
115
+ _this._stateStore = new datatable_state_store_1.KTDataTableConfigStateStore(_this._config);
116
+ _this._eventAdapter = (0, datatable_event_adapter_1.createDataTableEventAdapter)(_this._fireEvent.bind(_this), _this._dispatchEvent.bind(_this));
139
117
  // Store the instance directly on the element
140
118
  KTDataTable.asElementWithInstance(element).instance = _this;
141
119
  _this._initElements();
120
+ _this._tableRenderer = new datatable_table_renderer_1.KTDataTableDomTableRenderer();
121
+ _this._paginationRenderer = new datatable_pagination_renderer_1.KTDataTableDomPaginationRenderer();
122
+ _this._initDataProviders();
142
123
  // Initialize checkbox handler
143
- _this._checkbox = (0, datatable_checkbox_1.createCheckboxHandler)(_this._element, _this._config, function (eventName, eventData) {
144
- _this._fireEvent(eventName, eventData);
145
- _this._dispatchEvent(eventName, eventData);
146
- });
124
+ _this._checkbox = (0, datatable_checkbox_1.createCheckboxHandler)(_this._element, _this._config, _this._emit.bind(_this));
147
125
  // Initialize sort handler
148
126
  _this._sortHandler = (0, datatable_sort_1.createSortHandler)(_this._config, _this._theadElement, function () { return ({
149
127
  sortField: _this.getState().sortField,
150
128
  sortOrder: _this.getState().sortOrder,
151
129
  }); }, function (field, order) {
152
- _this._config._state.sortField = field;
153
- _this._config._state.sortOrder = order;
130
+ _this._stateStore.setSort(field, order);
154
131
  }, _this._fireEvent.bind(_this), _this._dispatchEvent.bind(_this), _this._updateData.bind(_this));
155
132
  _this._sortHandler.initSort();
156
133
  if (_this._config.stateSave === false) {
@@ -160,8 +137,7 @@ var KTDataTable = /** @class */ (function (_super) {
160
137
  _this._loadState();
161
138
  }
162
139
  _this._updateData();
163
- _this._fireEvent('init');
164
- _this._dispatchEvent('init');
140
+ _this._emit('init');
165
141
  return _this;
166
142
  }
167
143
  KTDataTable.asElementWithInstance = function (element) {
@@ -170,6 +146,30 @@ var KTDataTable = /** @class */ (function (_super) {
170
146
  KTDataTable.asSearchElementWithDebounce = function (element) {
171
147
  return element;
172
148
  };
149
+ KTDataTable.prototype._emit = function (eventName, eventData) {
150
+ this._eventAdapter.emit(eventName, eventData);
151
+ };
152
+ KTDataTable.prototype._initDataProviders = function () {
153
+ var _this = this;
154
+ this._localProvider = new datatable_local_provider_1.KTDataTableLocalDataProvider({
155
+ config: this._config,
156
+ elements: function () { return ({
157
+ tableElement: _this._tableElement,
158
+ tbodyElement: _this._tbodyElement,
159
+ theadElement: _this._theadElement,
160
+ }); },
161
+ getLogicalColumnCount: this._getLogicalColumnCount.bind(this),
162
+ storeOriginalClasses: this._storeOriginalClasses.bind(this),
163
+ stateStore: this._stateStore,
164
+ });
165
+ this._remoteProvider = new datatable_remote_provider_1.KTDataTableRemoteDataProvider({
166
+ config: this._config,
167
+ createUrl: this._createUrl.bind(this),
168
+ eventAdapter: this._eventAdapter,
169
+ noticeOnTable: this._noticeOnTable.bind(this),
170
+ stateStore: this._stateStore,
171
+ });
172
+ };
173
173
  /**
174
174
  * Initialize default configuration for the datatable
175
175
  * @param config User-provided configuration options
@@ -439,32 +439,39 @@ var KTDataTable = /** @class */ (function (_super) {
439
439
  */
440
440
  KTDataTable.prototype._updateData = function () {
441
441
  return __awaiter(this, void 0, void 0, function () {
442
- return __generator(this, function (_a) {
443
- switch (_a.label) {
442
+ var result, _a;
443
+ return __generator(this, function (_b) {
444
+ switch (_b.label) {
444
445
  case 0:
445
446
  if (this._isFetching)
446
447
  return [2 /*return*/]; // Prevent duplicate fetches
447
448
  this._isFetching = true;
448
- _a.label = 1;
449
+ _b.label = 1;
449
450
  case 1:
450
- _a.trys.push([1, , 8, 9]);
451
+ _b.trys.push([1, , 8, 9]);
451
452
  this._showSpinner(); // Show spinner before fetching data
452
- if (!(typeof this._config.apiEndpoint === 'undefined')) return [3 /*break*/, 4];
453
- return [4 /*yield*/, this._fetchDataFromLocal()];
454
- case 2:
455
- _a.sent();
456
- return [4 /*yield*/, this._finalize()];
453
+ this._emit('fetch');
454
+ if (!(typeof this._config.apiEndpoint === 'undefined')) return [3 /*break*/, 2];
455
+ _a = this._localProvider.fetchSync();
456
+ return [3 /*break*/, 4];
457
+ case 2: return [4 /*yield*/, this._remoteProvider.fetch()];
457
458
  case 3:
458
- _a.sent();
459
- return [3 /*break*/, 7];
460
- case 4: return [4 /*yield*/, this._fetchDataFromServer()];
459
+ _a = _b.sent();
460
+ _b.label = 4;
461
+ case 4:
462
+ result = _a;
463
+ if (!!result.skipped) return [3 /*break*/, 6];
464
+ this._data = result.data;
465
+ this._stateStore.patchState({ totalItems: result.totalItems });
466
+ return [4 /*yield*/, this._draw()];
461
467
  case 5:
462
- _a.sent();
463
- return [4 /*yield*/, this._finalize()];
464
- case 6:
465
- _a.sent();
466
- _a.label = 7;
467
- case 7: return [3 /*break*/, 9];
468
+ _b.sent();
469
+ this._emit('fetched');
470
+ _b.label = 6;
471
+ case 6: return [4 /*yield*/, this._finalize()];
472
+ case 7:
473
+ _b.sent();
474
+ return [3 /*break*/, 9];
468
475
  case 8:
469
476
  // Finally block now correctly executes after promises resolve, not immediately
470
477
  this._isFetching = false;
@@ -531,152 +538,6 @@ var KTDataTable = /** @class */ (function (_super) {
531
538
  searchElement.addEventListener('keyup', debouncedSearch);
532
539
  }
533
540
  };
534
- /**
535
- * Fetch data from the DOM
536
- * Fetch data from the table element and save it to the `originalData` state property.
537
- * This method is used when the data is not fetched from the server via an API endpoint.
538
- */
539
- KTDataTable.prototype._fetchDataFromLocal = function () {
540
- return __awaiter(this, void 0, void 0, function () {
541
- var _a, sortField, sortOrder, page, pageSize, search, originalData, _b, originalData_1, originalDataAttributes, _temp, searchTerm, startIndex, endIndex;
542
- var _c;
543
- return __generator(this, function (_d) {
544
- switch (_d.label) {
545
- case 0:
546
- this._fireEvent('fetch');
547
- this._dispatchEvent('fetch');
548
- _a = this.getState(), sortField = _a.sortField, sortOrder = _a.sortOrder, page = _a.page, pageSize = _a.pageSize, search = _a.search;
549
- originalData = this.getState().originalData;
550
- // If the table element or the original data is not defined, bail
551
- if (!this._tableElement ||
552
- originalData === undefined ||
553
- this._tableConfigInvalidate() ||
554
- this._localTableHeaderInvalidate() ||
555
- this._localTableContentInvalidate()) {
556
- this._deleteState();
557
- _b = this._localExtractTableContent(), originalData_1 = _b.originalData, originalDataAttributes = _b.originalDataAttributes;
558
- this._config._state.originalData = originalData_1;
559
- this._config._state.originalDataAttributes = originalDataAttributes;
560
- }
561
- // Update the original data variable
562
- originalData = this.getState().originalData;
563
- _temp = (this._data = __spreadArray([], originalData, true));
564
- if (search) {
565
- searchTerm = typeof search === 'string' ? search : '';
566
- _temp = this._data = this._config.search.callback.call(this, this._data, searchTerm);
567
- }
568
- // If sorting is defined, sort the data
569
- if (sortField !== undefined &&
570
- sortOrder !== undefined &&
571
- sortOrder !== '') {
572
- if (typeof this._config.sort.callback === 'function') {
573
- this._data = this._config.sort.callback.call(this, this._data, sortField, sortOrder);
574
- }
575
- }
576
- // If there is data, slice it to the current page size
577
- if (((_c = this._data) === null || _c === void 0 ? void 0 : _c.length) > 0) {
578
- startIndex = (page - 1) * pageSize;
579
- endIndex = startIndex + pageSize;
580
- this._data = this._data.slice(startIndex, endIndex);
581
- }
582
- // Determine number of total rows
583
- this._config._state.totalItems = _temp.length;
584
- // Draw the data
585
- return [4 /*yield*/, this._draw()];
586
- case 1:
587
- // Draw the data
588
- _d.sent();
589
- this._fireEvent('fetched');
590
- this._dispatchEvent('fetched');
591
- return [2 /*return*/];
592
- }
593
- });
594
- });
595
- };
596
- /**
597
- * Checks if the table content has been invalidated by comparing the current checksum of the table body
598
- * with the stored checksum in the state. If the checksums are different, the state is updated with the
599
- * new checksum and `true` is returned. Otherwise, `false` is returned.
600
- *
601
- * @returns {boolean} `true` if the table content has been invalidated, `false` otherwise.
602
- */
603
- KTDataTable.prototype._localTableContentInvalidate = function () {
604
- var checksum = utils_1.default.checksum(JSON.stringify(this._tbodyElement.innerHTML));
605
- if (this.getState()._contentChecksum !== checksum) {
606
- this._config._state._contentChecksum = checksum;
607
- return true;
608
- }
609
- return false;
610
- };
611
- KTDataTable.prototype._tableConfigInvalidate = function () {
612
- // Remove _data and _state from config
613
- var _a = this._config, _state = _a._state, restConfig = __rest(_a, ["_state"]);
614
- var checksum = utils_1.default.checksum(JSON.stringify(restConfig));
615
- if (_state._configChecksum !== checksum) {
616
- this._config._state._configChecksum = checksum;
617
- return true;
618
- }
619
- return false;
620
- };
621
- /**
622
- * Extract the table content and returns it as an object containing an array of original data and an array of original data attributes.
623
- *
624
- * @returns {{originalData: T[], originalDataAttributes: KTDataTableAttributeInterface[]}} - An object containing an array of original data and an array of original data attributes.
625
- */
626
- KTDataTable.prototype._localExtractTableContent = function () {
627
- var originalData = [];
628
- var originalDataAttributes = [];
629
- this._storeOriginalClasses();
630
- var rows = this._tbodyElement.querySelectorAll('tr');
631
- // Filter th elements to only include those with data-kt-datatable-column attribute
632
- var allThs = this._theadElement
633
- ? this._theadElement.querySelectorAll('th')
634
- : [];
635
- var ths = Array.from(allThs).filter(function (th) {
636
- return th.hasAttribute('data-kt-datatable-column');
637
- });
638
- rows.forEach(function (row) {
639
- var dataRow = {};
640
- var dataRowAttribute = {};
641
- row.querySelectorAll('td').forEach(function (td, index) {
642
- var _a, _b, _c;
643
- var colName = (_a = ths[index]) === null || _a === void 0 ? void 0 : _a.getAttribute('data-kt-datatable-column');
644
- if (colName) {
645
- dataRow[colName] = (_b = td.innerHTML) === null || _b === void 0 ? void 0 : _b.trim();
646
- }
647
- else {
648
- // Store the original HTML for fallback
649
- dataRow[index] = (_c = td.innerHTML) === null || _c === void 0 ? void 0 : _c.trim();
650
- }
651
- });
652
- if (Object.keys(dataRow).length > 0) {
653
- originalData.push(dataRow);
654
- originalDataAttributes.push(dataRowAttribute);
655
- }
656
- });
657
- return { originalData: originalData, originalDataAttributes: originalDataAttributes };
658
- };
659
- /**
660
- * Check if the table header is invalidated
661
- * @returns {boolean} - Returns true if the table header is invalidated, false otherwise
662
- */
663
- KTDataTable.prototype._localTableHeaderInvalidate = function () {
664
- var originalData = this.getState().originalData;
665
- var totalColumns = originalData.length
666
- ? Object.keys(originalData[0]).length
667
- : 0;
668
- // Count th elements with data-kt-datatable-column; when none (e.g. multi-row headers), use logical column count so we don't falsely invalidate
669
- var allThs = this._theadElement
670
- ? this._theadElement.querySelectorAll('th')
671
- : [];
672
- var thsWithColumn = Array.from(allThs).filter(function (th) {
673
- return th.hasAttribute('data-kt-datatable-column');
674
- });
675
- var currentTableHeaders = thsWithColumn.length > 0
676
- ? thsWithColumn.length
677
- : this._getLogicalColumnCount();
678
- return currentTableHeaders !== totalColumns;
679
- };
680
541
  /**
681
542
  * Returns the logical data column count (number of data columns), used for multi-row headers
682
543
  * where querySelectorAll('th') would overcount. Prefers state.originalData, then first tbody row td count.
@@ -695,162 +556,6 @@ var KTDataTable = /** @class */ (function (_super) {
695
556
  }
696
557
  return 0;
697
558
  };
698
- /**
699
- * Fetch data from the server
700
- */
701
- KTDataTable.prototype._fetchDataFromServer = function () {
702
- return __awaiter(this, void 0, void 0, function () {
703
- var currentRequestId, queryParams, response, error_1, responseData, error_2;
704
- return __generator(this, function (_a) {
705
- switch (_a.label) {
706
- case 0:
707
- currentRequestId = ++this._requestId;
708
- this._fireEvent('fetch');
709
- this._dispatchEvent('fetch');
710
- queryParams = this._getQueryParamsForFetchRequest();
711
- _a.label = 1;
712
- case 1:
713
- _a.trys.push([1, 3, , 4]);
714
- return [4 /*yield*/, this._performFetchRequest(queryParams)];
715
- case 2:
716
- response = _a.sent();
717
- return [3 /*break*/, 4];
718
- case 3:
719
- error_1 = _a.sent();
720
- // Silently ignore AbortError - request was cancelled
721
- if (error_1.name === 'AbortError') {
722
- return [2 /*return*/];
723
- }
724
- throw error_1;
725
- case 4:
726
- // Check if this response is stale (a newer request has been initiated)
727
- if (currentRequestId !== this._requestId) {
728
- // Ignore stale response - a more recent request is in progress or has completed
729
- return [2 /*return*/];
730
- }
731
- responseData = null;
732
- _a.label = 5;
733
- case 5:
734
- _a.trys.push([5, 7, , 8]);
735
- return [4 /*yield*/, response.json()];
736
- case 6:
737
- responseData = _a.sent();
738
- return [3 /*break*/, 8];
739
- case 7:
740
- error_2 = _a.sent();
741
- // Fire event with complete error context for application handling
742
- this._fireEvent('parseError', {
743
- response: response,
744
- error: String(error_2),
745
- status: response.status,
746
- statusText: response.statusText,
747
- });
748
- this._dispatchEvent('parseError', {
749
- response: response,
750
- error: String(error_2),
751
- status: response.status,
752
- statusText: response.statusText,
753
- });
754
- return [2 /*return*/];
755
- case 8:
756
- // Double-check request ID after JSON parsing (additional safety)
757
- if (currentRequestId !== this._requestId) {
758
- return [2 /*return*/];
759
- }
760
- this._fireEvent('fetched', { response: responseData });
761
- this._dispatchEvent('fetched', { response: responseData });
762
- // Use the mapResponse function to transform the data if provided
763
- if (typeof this._config.mapResponse === 'function') {
764
- responseData = this._config.mapResponse.call(this, responseData);
765
- }
766
- this._data = responseData.data;
767
- this._config._state.totalItems = responseData.totalCount;
768
- return [4 /*yield*/, this._draw()];
769
- case 9:
770
- _a.sent();
771
- this._fireEvent('fetched');
772
- this._dispatchEvent('fetched');
773
- return [2 /*return*/];
774
- }
775
- });
776
- });
777
- };
778
- /**
779
- * Get the query params for a fetch request
780
- * @returns The query params for the fetch request
781
- */
782
- KTDataTable.prototype._getQueryParamsForFetchRequest = function () {
783
- // Get the current state of the datatable
784
- var _a = this.getState(), page = _a.page, pageSize = _a.pageSize, sortField = _a.sortField, sortOrder = _a.sortOrder, filters = _a.filters, search = _a.search;
785
- // Create a new URLSearchParams object to store the query params
786
- var queryParams = new URLSearchParams();
787
- // Add the current page number and page size to the query params
788
- queryParams.set('page', String(page));
789
- queryParams.set('size', String(pageSize));
790
- // If there is a sort order and field set, add them to the query params
791
- if (sortOrder !== undefined) {
792
- queryParams.set('sortOrder', String(sortOrder));
793
- }
794
- if (sortField !== undefined) {
795
- queryParams.set('sortField', String(sortField));
796
- }
797
- // If there are any filters set, add them to the query params
798
- if (Array.isArray(filters) && filters.length) {
799
- queryParams.set('filters', JSON.stringify(filters.map(function (filter) { return ({
800
- // Map the filter object to a simpler object with just the necessary properties
801
- column: filter.column,
802
- type: filter.type,
803
- value: filter.value,
804
- }); })));
805
- }
806
- if (search) {
807
- queryParams.set('search', typeof search === 'object' ? JSON.stringify(search) : search);
808
- }
809
- // If a mapRequest function is provided, call it with the query params object
810
- if (typeof this._config.mapRequest === 'function') {
811
- queryParams = this._config.mapRequest.call(this, queryParams);
812
- }
813
- // Return the query params object
814
- return queryParams;
815
- };
816
- KTDataTable.prototype._performFetchRequest = function (queryParams) {
817
- return __awaiter(this, void 0, void 0, function () {
818
- var requestMethod, requestBody, apiEndpointWithQueryParams;
819
- var _this = this;
820
- return __generator(this, function (_a) {
821
- requestMethod = this._config.requestMethod;
822
- requestBody = undefined;
823
- // Cancel previous request to prevent race conditions
824
- if (this._abortController) {
825
- this._abortController.abort();
826
- }
827
- // Create new AbortController for this request
828
- this._abortController = new AbortController();
829
- // If the request method is POST, send the query params as the request body
830
- if (requestMethod === 'POST') {
831
- requestBody = queryParams;
832
- }
833
- else if (requestMethod === 'GET') {
834
- apiEndpointWithQueryParams = this._createUrl(this._config.apiEndpoint);
835
- apiEndpointWithQueryParams.search = queryParams.toString();
836
- this._config.apiEndpoint = apiEndpointWithQueryParams.toString();
837
- }
838
- return [2 /*return*/, fetch(this._config.apiEndpoint, __assign(__assign({ method: requestMethod, body: requestBody, headers: this._config.requestHeaders }, (this._config.requestCredentials && {
839
- credentials: this._config.requestCredentials,
840
- })), (this._abortController && { signal: this._abortController.signal }))).catch(function (error) {
841
- // Silently ignore AbortError - this is expected when requests are cancelled
842
- if (error.name === 'AbortError') {
843
- return Promise.reject(error);
844
- }
845
- // Trigger an error event for non-abort errors
846
- _this._fireEvent('error', { error: error });
847
- _this._dispatchEvent('error', { error: error });
848
- _this._noticeOnTable('Error performing fetch request: ' + String(error));
849
- throw error;
850
- })];
851
- });
852
- });
853
- };
854
559
  /**
855
560
  * Creates a complete URL from a relative path or a full URL.
856
561
  *
@@ -885,10 +590,10 @@ var KTDataTable = /** @class */ (function (_super) {
885
590
  KTDataTable.prototype._draw = function () {
886
591
  return __awaiter(this, void 0, void 0, function () {
887
592
  return __generator(this, function (_a) {
888
- this._config._state.totalPages =
889
- Math.ceil(this.getState().totalItems / this.getState().pageSize) || 0;
890
- this._fireEvent('draw');
891
- this._dispatchEvent('draw');
593
+ this._stateStore.patchState({
594
+ totalPages: Math.ceil(this.getState().totalItems / this.getState().pageSize) || 0,
595
+ });
596
+ this._emit('draw');
892
597
  this._dispose();
893
598
  // Update the table and pagination controls
894
599
  if (this._theadElement && this._tbodyElement) {
@@ -897,8 +602,7 @@ var KTDataTable = /** @class */ (function (_super) {
897
602
  if (this._infoElement && this._paginationElement) {
898
603
  this._updatePagination();
899
604
  }
900
- this._fireEvent('drew');
901
- this._dispatchEvent('drew');
605
+ this._emit('drew');
902
606
  // Spinner is hidden in _finalize() to ensure it stays visible until the entire request completes
903
607
  // Removed duplicate _hideSpinner() call here to prevent premature hiding
904
608
  if (this._config.stateSave) {
@@ -913,115 +617,18 @@ var KTDataTable = /** @class */ (function (_super) {
913
617
  * @returns {HTMLTableSectionElement} The new table body element
914
618
  */
915
619
  KTDataTable.prototype._updateTable = function () {
916
- // Clear the existing table contents using a more efficient method
917
- while (this._tableElement.tBodies.length) {
918
- this._tableElement.removeChild(this._tableElement.tBodies[0]);
919
- }
920
- // Create the table body with the new data
921
- var tbodyElement = this._tableElement.createTBody();
922
- // Apply the original class to the new tbody element
923
- if (this._originalTbodyClass) {
924
- tbodyElement.className = this._originalTbodyClass;
925
- }
926
- this._updateTableContent(tbodyElement);
927
- return tbodyElement;
928
- };
929
- /**
930
- * Update the table content
931
- * @param tbodyElement The table body element
932
- * @returns {HTMLTableSectionElement} The updated table body element
933
- */
934
- KTDataTable.prototype._updateTableContent = function (tbodyElement) {
935
- var _this = this;
936
- var fragment = document.createDocumentFragment();
937
- tbodyElement.textContent = ''; // Clear the tbody element
938
- if (this._data.length === 0) {
939
- this._noticeOnTable(this._config.infoEmpty || '');
940
- return tbodyElement;
941
- }
942
- // Filter th elements to only include those with data-kt-datatable-column attribute
943
- // This prevents creating blank td elements for merged header cells (colspan/rowspan)
944
- var allThs = this._theadElement
945
- ? this._theadElement.querySelectorAll('th')
946
- : [];
947
- var ths = Array.from(allThs).filter(function (th) {
948
- return th.hasAttribute('data-kt-datatable-column');
620
+ return this._tableRenderer.render({
621
+ config: this._config,
622
+ context: this,
623
+ data: this._data,
624
+ getLogicalColumnCount: this._getLogicalColumnCount.bind(this),
625
+ getState: this.getState.bind(this),
626
+ originalTbodyClass: this._originalTbodyClass,
627
+ originalTrClasses: this._originalTrClasses,
628
+ originalTdClasses: this._originalTdClasses,
629
+ tableElement: this._tableElement,
630
+ theadElement: this._theadElement,
949
631
  });
950
- // When no th has data-kt-datatable-column (e.g. multi-row headers), use logical column count from tbody so we don't overcount thead cells
951
- var columnsToRender = ths.length > 0 ? ths : [];
952
- var logicalColumnCount = ths.length > 0 ? ths.length : this._getLogicalColumnCount();
953
- this._data.forEach(function (item, rowIndex) {
954
- var row = document.createElement('tr');
955
- // Apply original tr class if available
956
- if (_this._originalTrClasses && _this._originalTrClasses[rowIndex]) {
957
- row.className = _this._originalTrClasses[rowIndex];
958
- }
959
- if (!_this._config.columns) {
960
- var dataRowAttributes = _this.getState().originalDataAttributes
961
- ? _this.getState().originalDataAttributes[rowIndex]
962
- : null;
963
- for (var colIndex = 0; colIndex < logicalColumnCount; colIndex++) {
964
- var th = columnsToRender[colIndex];
965
- var colName = th === null || th === void 0 ? void 0 : th.getAttribute('data-kt-datatable-column');
966
- var td = document.createElement('td');
967
- var value = void 0;
968
- if (colName && Object.prototype.hasOwnProperty.call(item, colName)) {
969
- value = item[colName];
970
- }
971
- else if (Object.prototype.hasOwnProperty.call(item, colIndex)) {
972
- value = item[colIndex];
973
- }
974
- else {
975
- value = '';
976
- }
977
- td.innerHTML = value;
978
- // Apply original td class if available
979
- if (_this._originalTdClasses &&
980
- _this._originalTdClasses[rowIndex] &&
981
- _this._originalTdClasses[rowIndex][colIndex]) {
982
- td.className = _this._originalTdClasses[rowIndex][colIndex];
983
- }
984
- if (dataRowAttributes && dataRowAttributes[colIndex]) {
985
- for (var attr in dataRowAttributes[colIndex]) {
986
- td.setAttribute(attr, dataRowAttributes[colIndex][attr]);
987
- }
988
- }
989
- row.appendChild(td);
990
- }
991
- }
992
- else {
993
- Object.keys(_this._config.columns).forEach(function (key, colIndex) {
994
- var td = document.createElement('td');
995
- var columnDef = _this._config.columns[key];
996
- // Apply original td class if available
997
- if (_this._originalTdClasses &&
998
- _this._originalTdClasses[rowIndex] &&
999
- _this._originalTdClasses[rowIndex][colIndex]) {
1000
- td.className = _this._originalTdClasses[rowIndex][colIndex];
1001
- }
1002
- if (typeof columnDef.render === 'function') {
1003
- var result = columnDef.render.call(_this, item[key], item, _this);
1004
- if (result instanceof HTMLElement ||
1005
- result instanceof DocumentFragment) {
1006
- td.appendChild(result);
1007
- }
1008
- else if (typeof result === 'string') {
1009
- td.innerHTML = result;
1010
- }
1011
- }
1012
- else {
1013
- td.textContent = item[key];
1014
- }
1015
- if (typeof columnDef.createdCell === 'function') {
1016
- columnDef.createdCell.call(_this, td, item[key], item, row);
1017
- }
1018
- row.appendChild(td);
1019
- });
1020
- }
1021
- fragment.appendChild(row);
1022
- });
1023
- tbodyElement.appendChild(fragment);
1024
- return tbodyElement;
1025
632
  };
1026
633
  /**
1027
634
  * Show a notice on the table
@@ -1030,66 +637,22 @@ var KTDataTable = /** @class */ (function (_super) {
1030
637
  */
1031
638
  KTDataTable.prototype._noticeOnTable = function (message) {
1032
639
  if (message === void 0) { message = ''; }
1033
- var row = this._tableElement.tBodies[0].insertRow();
1034
- var cell = row.insertCell();
1035
- var logicalCount = this._getLogicalColumnCount();
1036
- // Use logical column count so multi-row headers don't overcount; fallback to 1 when 0 so message still displays
1037
- cell.colSpan = logicalCount > 0 ? logicalCount : 1;
1038
- cell.innerHTML = message;
640
+ this._tableRenderer.notice(this._tableElement, this._getLogicalColumnCount.bind(this), message);
1039
641
  };
1040
642
  KTDataTable.prototype._updatePagination = function () {
1041
- this._removeChildElements(this._sizeElement);
1042
- this._createPageSizeControls(this._sizeElement);
1043
- this._removeChildElements(this._paginationElement);
1044
- this._createPaginationControls(this._infoElement, this._paginationElement);
1045
- };
1046
- /**
1047
- * Removes all child elements from the given container element.
1048
- * @param container The container element to remove the child elements from.
1049
- */
1050
- KTDataTable.prototype._removeChildElements = function (container) {
1051
- if (!container) {
1052
- return;
1053
- }
1054
- // Loop through all child elements of the container and remove them one by one
1055
- while (container.firstChild) {
1056
- // Remove the first child element (which is the first element in the list of child elements)
1057
- container.removeChild(container.firstChild);
1058
- }
1059
- };
1060
- /**
1061
- * Creates a container element for the items per page selector.
1062
- * @param _sizeElement The element to create the page size controls in.
1063
- * @returns The container element.
1064
- */
1065
- KTDataTable.prototype._createPageSizeControls = function (_sizeElement) {
1066
- var _this = this;
1067
- // If no element is provided, return early
1068
- if (!_sizeElement) {
1069
- return _sizeElement;
643
+ var cleanup = this._paginationRenderer.render({
644
+ config: this._config,
645
+ dataLength: this._data.length,
646
+ infoElement: this._infoElement,
647
+ paginateData: this._paginateData.bind(this),
648
+ paginationElement: this._paginationElement,
649
+ reloadPageSize: this._reloadPageSize.bind(this),
650
+ sizeElement: this._sizeElement,
651
+ state: this.getState(),
652
+ });
653
+ if (typeof cleanup === 'function') {
654
+ this._cleanupCallbacks.push(cleanup);
1070
655
  }
1071
- // Wait for the element to be attached to the DOM
1072
- setTimeout(function () {
1073
- // Create <option> elements for each page size option
1074
- var options = _this._config.pageSizes.map(function (size) {
1075
- var option = document.createElement('option');
1076
- option.value = String(size);
1077
- option.text = String(size);
1078
- option.selected = _this.getState().pageSize === size;
1079
- return option;
1080
- });
1081
- // Add the <option> elements to the provided element
1082
- _sizeElement.append.apply(_sizeElement, options);
1083
- }, 100);
1084
- // Create an event listener for the "change" event on the element
1085
- var _pageSizeControlsEvent = function (event) {
1086
- // When the element changes, reload the page with the new page size and page number 1
1087
- _this._reloadPageSize(Number(event.target.value), 1);
1088
- };
1089
- // Bind the event listener to the component instance
1090
- _sizeElement.onchange = _pageSizeControlsEvent.bind(this);
1091
- // Return the element
1092
- return _sizeElement;
1093
656
  };
1094
657
  /**
1095
658
  * Reloads the data with the specified page size and optional page number.
@@ -1099,120 +662,10 @@ var KTDataTable = /** @class */ (function (_super) {
1099
662
  KTDataTable.prototype._reloadPageSize = function (pageSize, page) {
1100
663
  if (page === void 0) { page = 1; }
1101
664
  // Update the page size and page number in the state
1102
- this._config._state.pageSize = pageSize;
1103
- this._config._state.page = page;
665
+ this._stateStore.setPageSize(pageSize, page);
1104
666
  // Update the data with the new page size and page number
1105
667
  this._updateData();
1106
668
  };
1107
- /**
1108
- * Creates the pagination controls for the component.
1109
- * @param _infoElement The element to set the info text in.
1110
- * @param _paginationElement The element to create the pagination controls in.
1111
- * @return {HTMLElement} The element containing the pagination controls.
1112
- */
1113
- KTDataTable.prototype._createPaginationControls = function (_infoElement, _paginationElement) {
1114
- if (!_infoElement || !_paginationElement || this._data.length === 0) {
1115
- return null;
1116
- }
1117
- this._setPaginationInfoText(_infoElement);
1118
- var paginationContainer = this._createPaginationContainer(_paginationElement);
1119
- if (paginationContainer) {
1120
- this._createPaginationButtons(paginationContainer);
1121
- }
1122
- return paginationContainer;
1123
- };
1124
- /**
1125
- * Sets the info text for the pagination controls.
1126
- * @param _infoElement The element to set the info text in.
1127
- */
1128
- KTDataTable.prototype._setPaginationInfoText = function (_infoElement) {
1129
- _infoElement.textContent = this._config.info
1130
- .replace('{start}', (this.getState().page - 1) * this.getState().pageSize + 1 + '')
1131
- .replace('{end}', Math.min(this.getState().page * this.getState().pageSize, this.getState().totalItems) + '')
1132
- .replace('{total}', this.getState().totalItems + '');
1133
- };
1134
- /**
1135
- * Creates the container element for the pagination controls.
1136
- * @param _paginationElement The element to create the pagination controls in.
1137
- * @return {HTMLElement} The container element.
1138
- */
1139
- KTDataTable.prototype._createPaginationContainer = function (_paginationElement) {
1140
- // No longer create a wrapping div. Just return the pagination element itself.
1141
- return _paginationElement;
1142
- };
1143
- /**
1144
- * Creates the pagination buttons for the component.
1145
- * @param paginationContainer The container element for the pagination controls.
1146
- */
1147
- KTDataTable.prototype._createPaginationButtons = function (paginationContainer) {
1148
- var _this = this;
1149
- var _a = this.getState(), currentPage = _a.page, totalPages = _a.totalPages;
1150
- var _b = this._config.pagination, previous = _b.previous, next = _b.next, number = _b.number, more = _b.more;
1151
- // Helper function to create a button
1152
- var createButton = function (text, className, disabled, handleClick) {
1153
- var button = document.createElement('button');
1154
- button.className = className;
1155
- button.innerHTML = text;
1156
- button.disabled = disabled;
1157
- button.onclick = handleClick;
1158
- return button;
1159
- };
1160
- // Add Previous Button
1161
- paginationContainer.appendChild(createButton(previous.text, "".concat(previous.class).concat(currentPage === 1 ? ' disabled' : ''), currentPage === 1, function () { return _this._paginateData(currentPage - 1); }));
1162
- // Calculate range of pages
1163
- var pageMoreEnabled = this._config.pageMore;
1164
- if (pageMoreEnabled) {
1165
- var maxButtons = this._config.pageMoreLimit;
1166
- var range_1 = this._calculatePageRange(currentPage, totalPages, maxButtons);
1167
- // Add start ellipsis
1168
- if (range_1.start > 1) {
1169
- paginationContainer.appendChild(createButton(more.text, more.class, false, function () {
1170
- return _this._paginateData(Math.max(1, range_1.start - 1));
1171
- }));
1172
- }
1173
- var _loop_1 = function (i) {
1174
- paginationContainer.appendChild(createButton(number.text.replace('{page}', i.toString()), "".concat(number.class).concat(currentPage === i ? ' active disabled' : ''), currentPage === i, function () { return _this._paginateData(i); }));
1175
- };
1176
- // Add page buttons
1177
- for (var i = range_1.start; i <= range_1.end; i++) {
1178
- _loop_1(i);
1179
- }
1180
- // Add end ellipsis
1181
- if (pageMoreEnabled && range_1.end < totalPages) {
1182
- paginationContainer.appendChild(createButton(more.text, more.class, false, function () {
1183
- return _this._paginateData(Math.min(totalPages, range_1.end + 1));
1184
- }));
1185
- }
1186
- }
1187
- else {
1188
- var _loop_2 = function (i) {
1189
- paginationContainer.appendChild(createButton(number.text.replace('{page}', i.toString()), "".concat(number.class).concat(currentPage === i ? ' active disabled' : ''), currentPage === i, function () { return _this._paginateData(i); }));
1190
- };
1191
- // Add page buttons
1192
- for (var i = 1; i <= totalPages; i++) {
1193
- _loop_2(i);
1194
- }
1195
- }
1196
- // Add Next Button
1197
- paginationContainer.appendChild(createButton(next.text, "".concat(next.class).concat(currentPage === totalPages ? ' disabled' : ''), currentPage === totalPages, function () { return _this._paginateData(currentPage + 1); }));
1198
- };
1199
- // New helper method to calculate page range
1200
- KTDataTable.prototype._calculatePageRange = function (currentPage, totalPages, maxButtons) {
1201
- var startPage, endPage;
1202
- var halfMaxButtons = Math.floor(maxButtons / 2);
1203
- if (totalPages <= maxButtons) {
1204
- startPage = 1;
1205
- endPage = totalPages;
1206
- }
1207
- else {
1208
- startPage = Math.max(currentPage - halfMaxButtons, 1);
1209
- endPage = Math.min(startPage + maxButtons - 1, totalPages);
1210
- if (endPage - startPage < maxButtons - 1) {
1211
- startPage = Math.max(endPage - maxButtons + 1, 1);
1212
- }
1213
- }
1214
- return { start: startPage, end: endPage };
1215
- };
1216
669
  /**
1217
670
  * Method for handling pagination
1218
671
  * @param page - The page number to navigate to
@@ -1221,10 +674,9 @@ var KTDataTable = /** @class */ (function (_super) {
1221
674
  if (page < 1 || !Number.isInteger(page)) {
1222
675
  return;
1223
676
  }
1224
- this._fireEvent('pagination', { page: page });
1225
- this._dispatchEvent('pagination', { page: page });
677
+ this._emit('pagination', { page: page });
1226
678
  if (page >= 1 && page <= this.getState().totalPages) {
1227
- this._config._state.page = page;
679
+ this._stateStore.setPage(page);
1228
680
  this._updateData();
1229
681
  }
1230
682
  };
@@ -1263,8 +715,7 @@ var KTDataTable = /** @class */ (function (_super) {
1263
715
  * @returns {void}
1264
716
  */
1265
717
  KTDataTable.prototype._saveState = function () {
1266
- this._fireEvent('stateSave');
1267
- this._dispatchEvent('stateSave');
718
+ this._emit('stateSave');
1268
719
  var ns = this._tableNamespace();
1269
720
  if (ns) {
1270
721
  localStorage.setItem(ns, JSON.stringify(this.getState()));
@@ -1281,7 +732,7 @@ var KTDataTable = /** @class */ (function (_super) {
1281
732
  try {
1282
733
  var state = JSON.parse(stateString);
1283
734
  if (state)
1284
- this._config._state = state;
735
+ this._stateStore.replaceState(state);
1285
736
  return state;
1286
737
  }
1287
738
  catch (_a) { }
@@ -1328,16 +779,17 @@ var KTDataTable = /** @class */ (function (_super) {
1328
779
  * This method is called before re-rendering or when disposing the component.
1329
780
  */
1330
781
  KTDataTable.prototype._dispose = function () {
782
+ this._cleanupCallbacks.forEach(function (cleanup) { return cleanup(); });
783
+ this._cleanupCallbacks = [];
1331
784
  // --- 1. Remove search input event listener (debounced) ---
1332
785
  var tableId = this._tableId();
1333
786
  var searchElement = document.querySelector("[data-kt-datatable-search=\"#".concat(tableId, "\"]"));
1334
787
  if (searchElement) {
1335
788
  var searchWithDebounce = KTDataTable.asSearchElementWithDebounce(searchElement);
1336
- if (!searchWithDebounce._debouncedSearch) {
1337
- return;
789
+ if (searchWithDebounce._debouncedSearch) {
790
+ searchElement.removeEventListener('keyup', searchWithDebounce._debouncedSearch);
791
+ delete searchWithDebounce._debouncedSearch;
1338
792
  }
1339
- searchElement.removeEventListener('keyup', searchWithDebounce._debouncedSearch);
1340
- delete searchWithDebounce._debouncedSearch;
1341
793
  }
1342
794
  // --- 2. Remove page size dropdown event listener ---
1343
795
  if (this._sizeElement && this._sizeElement.onchange) {
@@ -1405,23 +857,7 @@ var KTDataTable = /** @class */ (function (_super) {
1405
857
  * @returns {KTDataTableStateInterface} The current state of the table.
1406
858
  */
1407
859
  KTDataTable.prototype.getState = function () {
1408
- return __assign({
1409
- /**
1410
- * The current page number.
1411
- */
1412
- page: 1,
1413
- /**
1414
- * The field that the data is sorted by.
1415
- */
1416
- sortField: null,
1417
- /**
1418
- * The sort order (ascending or descending).
1419
- */
1420
- sortOrder: '',
1421
- /**
1422
- * The number of rows to display per page.
1423
- */
1424
- pageSize: this._config.pageSize, filters: [] }, this._config._state);
860
+ return this._stateStore.getState();
1425
861
  };
1426
862
  /**
1427
863
  * Sorts the data in the table by the specified field.
@@ -1432,10 +868,8 @@ var KTDataTable = /** @class */ (function (_super) {
1432
868
  var state = this.getState();
1433
869
  var sortOrder = this._sortHandler.toggleSortOrder(state.sortField, state.sortOrder, field);
1434
870
  this._sortHandler.setSortIcon(field, sortOrder);
1435
- this._config._state.sortField = field;
1436
- this._config._state.sortOrder = sortOrder;
1437
- this._fireEvent('sort', { field: field, order: sortOrder });
1438
- this._dispatchEvent('sort', { field: field, order: sortOrder });
871
+ this._stateStore.setSort(field, sortOrder);
872
+ this._emit('sort', { field: field, order: sortOrder });
1439
873
  this._updateData();
1440
874
  };
1441
875
  /**
@@ -1468,15 +902,13 @@ var KTDataTable = /** @class */ (function (_super) {
1468
902
  * Triggers the 'reload' event and the 'kt.datatable.reload' custom event.
1469
903
  */
1470
904
  KTDataTable.prototype.reload = function () {
1471
- this._fireEvent('reload');
1472
- this._dispatchEvent('reload');
905
+ this._emit('reload');
1473
906
  // Fetch the data from the server using the current sort and filter settings
1474
907
  this._updateData();
1475
908
  };
1476
909
  KTDataTable.prototype.redraw = function (page) {
1477
910
  if (page === void 0) { page = 1; }
1478
- this._fireEvent('redraw');
1479
- this._dispatchEvent('redraw');
911
+ this._emit('redraw');
1480
912
  this._paginateData(page);
1481
913
  };
1482
914
  /**
@@ -1505,18 +937,16 @@ var KTDataTable = /** @class */ (function (_super) {
1505
937
  * @throws Error if the filter object is null or undefined.
1506
938
  */
1507
939
  KTDataTable.prototype.setFilter = function (filter) {
1508
- this._config._state.filters = __spreadArray(__spreadArray([], (this.getState().filters || []).filter(function (f) { return f.column !== filter.column; }), true), [
1509
- filter,
1510
- ], false);
1511
- this._config._state.page = 1;
940
+ this._stateStore.setFilter(filter);
1512
941
  return this;
1513
942
  };
1514
943
  KTDataTable.prototype.dispose = function () {
944
+ var _a;
945
+ (_a = this._remoteProvider) === null || _a === void 0 ? void 0 : _a.dispose();
1515
946
  this._dispose();
1516
947
  };
1517
948
  KTDataTable.prototype.search = function (query) {
1518
- this._config._state.search = query;
1519
- this._config._state.page = 1;
949
+ this._stateStore.setSearch(query);
1520
950
  this.reload();
1521
951
  };
1522
952
  /**
@@ -1609,8 +1039,7 @@ var KTDataTable = /** @class */ (function (_super) {
1609
1039
  */
1610
1040
  KTDataTable.prototype.check = function () {
1611
1041
  this._checkbox.check();
1612
- this._fireEvent('checked');
1613
- this._dispatchEvent('checked');
1042
+ this._emit('checked');
1614
1043
  };
1615
1044
  /**
1616
1045
  * Uncheck all visible row checkboxes
@@ -1618,8 +1047,7 @@ var KTDataTable = /** @class */ (function (_super) {
1618
1047
  */
1619
1048
  KTDataTable.prototype.uncheck = function () {
1620
1049
  this._checkbox.uncheck();
1621
- this._fireEvent('unchecked');
1622
- this._dispatchEvent('unchecked');
1050
+ this._emit('unchecked');
1623
1051
  };
1624
1052
  /**
1625
1053
  * Get all checked row IDs (across all pages if preserveSelection is true)