@syncfusion/ej2-treegrid 31.2.12 → 32.1.19

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 (156) hide show
  1. package/dist/ej2-treegrid.min.js +1 -10
  2. package/dist/ej2-treegrid.umd.min.js +1 -10
  3. package/dist/ej2-treegrid.umd.min.js.map +1 -1
  4. package/dist/es6/ej2-treegrid.es2015.js +1069 -324
  5. package/dist/es6/ej2-treegrid.es2015.js.map +1 -1
  6. package/dist/es6/ej2-treegrid.es5.js +1075 -327
  7. package/dist/es6/ej2-treegrid.es5.js.map +1 -1
  8. package/dist/global/ej2-treegrid.min.js +1 -10
  9. package/dist/global/ej2-treegrid.min.js.map +1 -1
  10. package/dist/global/index.d.ts +0 -9
  11. package/package.json +5 -5
  12. package/src/treegrid/actions/batch-edit.js +22 -4
  13. package/src/treegrid/actions/context-menu.d.ts +1 -0
  14. package/src/treegrid/actions/context-menu.js +16 -0
  15. package/src/treegrid/actions/crud-actions.js +12 -5
  16. package/src/treegrid/actions/edit.d.ts +4 -1
  17. package/src/treegrid/actions/edit.js +59 -3
  18. package/src/treegrid/actions/freeze-column.js +1 -1
  19. package/src/treegrid/actions/rowdragdrop.js +3 -0
  20. package/src/treegrid/actions/selection.d.ts +226 -8
  21. package/src/treegrid/actions/selection.js +759 -288
  22. package/src/treegrid/actions/summary.js +1 -1
  23. package/src/treegrid/actions/virtual-scroll.js +6 -3
  24. package/src/treegrid/base/data.js +2 -1
  25. package/src/treegrid/base/treegrid-model.d.ts +16 -0
  26. package/src/treegrid/base/treegrid.d.ts +50 -4
  27. package/src/treegrid/base/treegrid.js +158 -19
  28. package/src/treegrid/models/column.d.ts +24 -0
  29. package/src/treegrid/models/column.js +12 -0
  30. package/src/treegrid/renderer/virtual-tree-content-render.d.ts +5 -0
  31. package/src/treegrid/renderer/virtual-tree-content-render.js +24 -2
  32. package/styles/bds-lite.scss +17 -18
  33. package/styles/bds.scss +18 -19
  34. package/styles/bootstrap-dark-lite.scss +17 -18
  35. package/styles/bootstrap-dark.scss +18 -19
  36. package/styles/bootstrap-lite.scss +17 -18
  37. package/styles/bootstrap.scss +18 -19
  38. package/styles/bootstrap4-lite.scss +17 -18
  39. package/styles/bootstrap4.scss +18 -19
  40. package/styles/bootstrap5-dark-lite.scss +17 -18
  41. package/styles/bootstrap5-dark.scss +18 -19
  42. package/styles/bootstrap5-lite.scss +18 -18
  43. package/styles/bootstrap5.3-lite.css +81 -1
  44. package/styles/bootstrap5.3-lite.scss +18 -18
  45. package/styles/bootstrap5.3.css +81 -1
  46. package/styles/bootstrap5.3.scss +19 -19
  47. package/styles/bootstrap5.scss +19 -19
  48. package/styles/fabric-dark-lite.scss +18 -18
  49. package/styles/fabric-dark.scss +19 -19
  50. package/styles/fabric-lite.scss +18 -18
  51. package/styles/fabric.scss +19 -19
  52. package/styles/fluent-dark-lite.scss +18 -18
  53. package/styles/fluent-dark.scss +19 -19
  54. package/styles/fluent-lite.scss +18 -18
  55. package/styles/fluent.scss +19 -19
  56. package/styles/fluent2-lite.css +152 -4
  57. package/styles/fluent2-lite.scss +18 -18
  58. package/styles/fluent2.css +152 -4
  59. package/styles/fluent2.scss +19 -19
  60. package/styles/highcontrast-light-lite.scss +18 -18
  61. package/styles/highcontrast-light.scss +19 -19
  62. package/styles/highcontrast-lite.scss +18 -18
  63. package/styles/highcontrast.scss +19 -19
  64. package/styles/material-dark-lite.scss +18 -18
  65. package/styles/material-dark.scss +19 -19
  66. package/styles/material-lite.scss +17 -18
  67. package/styles/material.scss +18 -19
  68. package/styles/material3-dark-lite.css +140 -1
  69. package/styles/material3-dark-lite.scss +18 -18
  70. package/styles/material3-dark.css +140 -1
  71. package/styles/material3-dark.scss +19 -21
  72. package/styles/material3-lite.css +140 -1
  73. package/styles/material3-lite.scss +18 -18
  74. package/styles/material3.css +140 -1
  75. package/styles/material3.scss +19 -21
  76. package/styles/tailwind-dark-lite.scss +18 -18
  77. package/styles/tailwind-dark.scss +19 -19
  78. package/styles/tailwind-lite.scss +18 -18
  79. package/styles/tailwind.scss +19 -19
  80. package/styles/tailwind3-lite.css +119 -1
  81. package/styles/tailwind3-lite.scss +18 -18
  82. package/styles/tailwind3.css +119 -1
  83. package/styles/tailwind3.scss +19 -19
  84. package/styles/treegrid/_all.scss +2 -2
  85. package/styles/treegrid/_bds-definition.scss +2 -0
  86. package/styles/treegrid/_bigger.scss +2 -0
  87. package/styles/treegrid/_bootstrap-dark-definition.scss +2 -0
  88. package/styles/treegrid/_bootstrap-definition.scss +2 -0
  89. package/styles/treegrid/_bootstrap4-definition.scss +2 -0
  90. package/styles/treegrid/_bootstrap5-dark-definition.scss +26 -1
  91. package/styles/treegrid/_bootstrap5-definition.scss +2 -0
  92. package/styles/treegrid/_bootstrap5.3-definition.scss +2 -0
  93. package/styles/treegrid/_fabric-dark-definition.scss +2 -0
  94. package/styles/treegrid/_fabric-definition.scss +2 -0
  95. package/styles/treegrid/_fluent-dark-definition.scss +27 -1
  96. package/styles/treegrid/_fluent-definition.scss +2 -0
  97. package/styles/treegrid/_fluent2-definition.scss +2 -0
  98. package/styles/treegrid/_highcontrast-definition.scss +2 -0
  99. package/styles/treegrid/_highcontrast-light-definition.scss +2 -0
  100. package/styles/treegrid/_layout.scss +5 -2
  101. package/styles/treegrid/_material-dark-definition.scss +2 -0
  102. package/styles/treegrid/_material-definition.scss +2 -0
  103. package/styles/treegrid/_material3-dark-definition.scss +26 -1
  104. package/styles/treegrid/_material3-definition.scss +2 -0
  105. package/styles/treegrid/_tailwind-dark-definition.scss +26 -1
  106. package/styles/treegrid/_tailwind-definition.scss +2 -0
  107. package/styles/treegrid/_tailwind3-definition.scss +2 -0
  108. package/styles/treegrid/_theme-variables.scss +1 -0
  109. package/styles/treegrid/bds.scss +19 -19
  110. package/styles/treegrid/bootstrap-dark.scss +19 -19
  111. package/styles/treegrid/bootstrap.scss +19 -19
  112. package/styles/treegrid/bootstrap4.scss +19 -19
  113. package/styles/treegrid/bootstrap5-dark.scss +19 -19
  114. package/styles/treegrid/bootstrap5.3.css +81 -1
  115. package/styles/treegrid/bootstrap5.3.scss +19 -19
  116. package/styles/treegrid/bootstrap5.scss +19 -19
  117. package/styles/treegrid/fabric-dark.scss +19 -19
  118. package/styles/treegrid/fabric.scss +19 -19
  119. package/styles/treegrid/fluent-dark.scss +19 -19
  120. package/styles/treegrid/fluent.scss +19 -19
  121. package/styles/treegrid/fluent2.css +152 -4
  122. package/styles/treegrid/fluent2.scss +19 -19
  123. package/styles/treegrid/highcontrast-light.scss +19 -19
  124. package/styles/treegrid/highcontrast.scss +19 -19
  125. package/styles/treegrid/icons/_bds.scss +1 -0
  126. package/styles/treegrid/icons/_bootstrap-dark.scss +1 -0
  127. package/styles/treegrid/icons/_bootstrap.scss +1 -0
  128. package/styles/treegrid/icons/_bootstrap4.scss +1 -0
  129. package/styles/treegrid/icons/_bootstrap5-dark.scss +1 -1
  130. package/styles/treegrid/icons/_bootstrap5.3.scss +1 -0
  131. package/styles/treegrid/icons/_bootstrap5.scss +1 -0
  132. package/styles/treegrid/icons/_fabric-dark.scss +1 -0
  133. package/styles/treegrid/icons/_fabric.scss +1 -0
  134. package/styles/treegrid/icons/_fluent-dark.scss +1 -1
  135. package/styles/treegrid/icons/_fluent.scss +1 -0
  136. package/styles/treegrid/icons/_fluent2.scss +1 -0
  137. package/styles/treegrid/icons/_fusionnew.scss +1 -0
  138. package/styles/treegrid/icons/_highcontrast-light.scss +1 -0
  139. package/styles/treegrid/icons/_highcontrast.scss +1 -0
  140. package/styles/treegrid/icons/_material-dark.scss +1 -0
  141. package/styles/treegrid/icons/_material.scss +1 -0
  142. package/styles/treegrid/icons/_material3-dark.scss +1 -1
  143. package/styles/treegrid/icons/_material3.scss +1 -0
  144. package/styles/treegrid/icons/_tailwind-dark.scss +1 -0
  145. package/styles/treegrid/icons/_tailwind.scss +1 -0
  146. package/styles/treegrid/icons/_tailwind3.scss +1 -0
  147. package/styles/treegrid/material-dark.scss +19 -19
  148. package/styles/treegrid/material.scss +19 -19
  149. package/styles/treegrid/material3-dark.css +140 -1
  150. package/styles/treegrid/material3-dark.scss +19 -20
  151. package/styles/treegrid/material3.css +140 -1
  152. package/styles/treegrid/material3.scss +19 -20
  153. package/styles/treegrid/tailwind-dark.scss +19 -19
  154. package/styles/treegrid/tailwind.scss +19 -19
  155. package/styles/treegrid/tailwind3.css +119 -1
  156. package/styles/treegrid/tailwind3.scss +19 -19
@@ -2,7 +2,7 @@ import { isNullOrUndefined, removeClass } from '@syncfusion/ej2-base';
2
2
  import { createCheckBox } from '@syncfusion/ej2-buttons';
3
3
  import { parentsUntil, getObject } from '@syncfusion/ej2-grids';
4
4
  import * as events from '../base/constant';
5
- import { getParentData, isRemoteData, isCheckboxcolumn, findChildrenRecords } from '../utils';
5
+ import { getParentData, isRemoteData, isCheckboxcolumn } from '../utils';
6
6
  /**
7
7
  * TreeGrid Selection module
8
8
  *
@@ -10,27 +10,56 @@ import { getParentData, isRemoteData, isCheckboxcolumn, findChildrenRecords } fr
10
10
  */
11
11
  var Selection = /** @class */ (function () {
12
12
  /**
13
- * Constructor for Selection module
13
+ * Creates an instance of Selection.
14
14
  *
15
- * @param {TreeGrid} parent - Tree Grid instance
15
+ * @param {TreeGrid} parent - The TreeGrid instance this selection module is associated with.
16
16
  */
17
17
  function Selection(parent) {
18
+ this.headerCheckboxFrameEl = null;
19
+ this.checkboxColIndexCache = -2;
20
+ this.parentSelectionCounters = {};
21
+ this.selectedUidMap = new Map(); // Quick lookup for whether an item is selected
22
+ this.totalSelectableCount = 0;
23
+ this.headerSelectionState = 'uncheck';
24
+ this.checkedItemCount = 0;
25
+ this.visibleUidIndex = {};
18
26
  this.parent = parent;
19
27
  this.selectedItems = [];
20
- this.selectedIndexes = [];
28
+ this.selectedIndexes = []; // Initialize here
21
29
  this.filteredList = [];
22
30
  this.searchingRecords = [];
23
31
  this.addEventListener();
24
32
  }
25
33
  /**
26
- * For internal use only - Get the module name.
34
+ * Gets the module name.
27
35
  *
28
- * @private
29
- * @returns {string} Returns Selection module name
36
+ * @returns {string} The name of the module ('selection').
37
+ */
38
+ Selection.prototype.getModuleName = function () { return 'selection'; };
39
+ /**
40
+ * Builds a map from visible record uniqueID to its visible index.
41
+ * This map is crucial for finding the *current visible index* of a record.
42
+ *
43
+ * @returns {void}
30
44
  */
31
- Selection.prototype.getModuleName = function () {
32
- return 'selection';
45
+ Selection.prototype.buildVisibleUidMap = function () {
46
+ this.visibleUidIndex = {};
47
+ var view = this.parent.grid.currentViewData;
48
+ if (!view) {
49
+ return;
50
+ }
51
+ for (var i = 0, len = view.length; i < len; i++) {
52
+ var rec = view[parseInt(i.toString(), 10)];
53
+ if (rec && rec.uniqueID) {
54
+ this.visibleUidIndex[rec.uniqueID] = i; // Map uid -> visible row index
55
+ }
56
+ }
33
57
  };
58
+ /**
59
+ * Adds required event listeners for selection handling.
60
+ *
61
+ * @returns {void}
62
+ */
34
63
  Selection.prototype.addEventListener = function () {
35
64
  this.parent.on('dataBoundArg', this.headerCheckbox, this);
36
65
  this.parent.on('columnCheckbox', this.columnCheckbox, this);
@@ -38,6 +67,11 @@ var Selection = /** @class */ (function () {
38
67
  this.parent.grid.on('colgroup-refresh', this.headerCheckbox, this);
39
68
  this.parent.on('checkboxSelection', this.checkboxSelection, this);
40
69
  };
70
+ /**
71
+ * Removes previously added event listeners.
72
+ *
73
+ * @returns {void}
74
+ */
41
75
  Selection.prototype.removeEventListener = function () {
42
76
  if (this.parent.isDestroyed) {
43
77
  return;
@@ -49,14 +83,20 @@ var Selection = /** @class */ (function () {
49
83
  this.parent.off('updateGridActions', this.updateGridActions);
50
84
  };
51
85
  /**
52
- * To destroy the Selection
86
+ * Destroys the selection module and clears internal caches.
53
87
  *
54
88
  * @returns {void}
55
- * @hidden
56
89
  */
57
90
  Selection.prototype.destroy = function () {
91
+ this.resetSelectionCaches();
58
92
  this.removeEventListener();
59
93
  };
94
+ /**
95
+ * Handles checkbox click events from the DOM and dispatches selection logic.
96
+ *
97
+ * @param {Object} args - Event args containing the click target.
98
+ * @returns {void}
99
+ */
60
100
  Selection.prototype.checkboxSelection = function (args) {
61
101
  var _a;
62
102
  var target = getObject('target', args);
@@ -65,16 +105,23 @@ var Selection = /** @class */ (function () {
65
105
  if (checkWrap && checkWrap.querySelectorAll('.e-treecheckselect').length > 0) {
66
106
  checkBox = checkWrap.querySelector('input[type="checkbox"]');
67
107
  var rowIndex = [];
68
- rowIndex.push(target.closest('tr').rowIndex);
108
+ if (this.parent.frozenRows) {
109
+ rowIndex.push(parseInt(target.closest('tr').getAttribute('aria-rowindex'), 10) - 1);
110
+ }
111
+ else {
112
+ rowIndex.push(target.closest('tr').rowIndex);
113
+ }
69
114
  this.selectCheckboxes(rowIndex);
70
- this.triggerChkChangeEvent(checkBox, checkBox.nextElementSibling.classList.contains('e-check'), target.closest('tr'));
115
+ var newCheckState = checkBox.nextElementSibling.classList.contains('e-check');
116
+ this.triggerChkChangeEvent(checkBox, newCheckState, target.closest('tr'));
71
117
  }
72
118
  else if (checkWrap && checkWrap.querySelectorAll('.e-treeselectall').length > 0 && this.parent.autoCheckHierarchy) {
73
- var checkBoxvalue = !checkWrap.querySelector('.e-frame').classList.contains('e-check')
74
- && !checkWrap.querySelector('.e-frame').classList.contains('e-stop');
75
- this.headerSelection(checkBoxvalue);
119
+ var frame = checkWrap.querySelector('.e-frame');
120
+ var currentStateIsUncheck = !frame.classList.contains('e-check') && !frame.classList.contains('e-stop');
121
+ var targetState = currentStateIsUncheck; // If currently uncheck, target state is to check all.
122
+ this.headerSelection(targetState);
76
123
  checkBox = checkWrap.querySelector('input[type="checkbox"]');
77
- this.triggerChkChangeEvent(checkBox, checkBoxvalue, target.closest('tr'));
124
+ this.triggerChkChangeEvent(checkBox, targetState, target.closest('tr'));
78
125
  }
79
126
  if (!isNullOrUndefined(this.parent['parentQuery']) && this.parent.selectionSettings.persistSelection
80
127
  && this.parent['columnModel'].filter(function (col) { return col.type === 'checkbox'; }).length > 0
@@ -85,63 +132,99 @@ var Selection = /** @class */ (function () {
85
132
  }
86
133
  }
87
134
  };
135
+ /**
136
+ * Triggers the checkboxChange event with the appropriate arguments.
137
+ *
138
+ * @param {HTMLInputElement} checkBox - The checkbox input element that changed.
139
+ * @param {boolean} checkState - The new checked state.
140
+ * @param {HTMLTableRowElement} rowElement - The row element where the change occurred.
141
+ * @returns {void}
142
+ */
88
143
  Selection.prototype.triggerChkChangeEvent = function (checkBox, checkState, rowElement) {
89
144
  var data = this.parent.getCurrentViewRecords()[rowElement.rowIndex];
90
- var args = { checked: checkState, target: checkBox, rowElement: rowElement,
145
+ var args = {
146
+ checked: checkState, target: checkBox, rowElement: rowElement,
91
147
  rowData: checkBox.classList.contains('e-treeselectall')
92
- ? this.parent.getCheckedRecords() : data };
148
+ ? this.parent.getCheckedRecords() : data
149
+ };
93
150
  this.parent.trigger(events.checkboxChange, args);
94
151
  };
152
+ /**
153
+ * Determines the index of the checkbox column in the header.
154
+ *
155
+ * @returns {number} The index of the checkbox column, or -1 if not found.
156
+ */
95
157
  Selection.prototype.getCheckboxcolumnIndex = function () {
158
+ if (this.checkboxColIndexCache !== -2) {
159
+ return this.checkboxColIndexCache;
160
+ }
96
161
  var mappingUid;
97
- var columnIndex;
162
+ var columnIndex = -1;
98
163
  var stackedHeader = 'stackedHeader';
99
164
  var columnModel = 'columnModel';
100
165
  var columns = this.parent["" + stackedHeader] ? this.parent["" + columnModel] : (this.parent.columns);
101
166
  for (var col = 0; col < columns.length; col++) {
102
167
  if (columns[parseInt(col.toString(), 10)].showCheckbox) {
103
168
  mappingUid = columns[parseInt(col.toString(), 10)].uid;
169
+ break;
104
170
  }
105
171
  }
106
- var headerCelllength = this.parent.getHeaderContent().querySelectorAll('.e-headercelldiv').length;
107
- for (var j = 0; j < headerCelllength; j++) {
108
- var headercell = this.parent.getHeaderContent().querySelectorAll('.e-headercelldiv')[parseInt(j.toString(), 10)];
172
+ var headerDivs = this.parent.getHeaderContent().querySelectorAll('.e-headercelldiv');
173
+ for (var j = 0; j < headerDivs.length; j++) {
174
+ var headercell = headerDivs[parseInt(j.toString(), 10)];
109
175
  if (headercell.getAttribute('data-mappinguid') === mappingUid) {
110
176
  columnIndex = j;
177
+ break;
111
178
  }
112
179
  }
113
- return columnIndex;
180
+ this.checkboxColIndexCache = isNullOrUndefined(columnIndex) ? -1 : columnIndex;
181
+ return this.checkboxColIndexCache;
114
182
  };
183
+ /**
184
+ * Renders and initializes the header checkbox element.
185
+ *
186
+ * @returns {void}
187
+ */
115
188
  Selection.prototype.headerCheckbox = function () {
189
+ this.buildVisibleUidMap();
190
+ this.totalSelectableCount = this.countSelectableRecords(this.resolveHeaderSelectionList(true)); // Use all flatData for initial count
116
191
  this.columnIndex = this.getCheckboxcolumnIndex();
117
- if (this.columnIndex > -1 && this.parent.getHeaderContent().querySelectorAll('.e-treeselectall').length === 0) {
192
+ if (this.columnIndex > -1) {
118
193
  var headerElement = this.parent.getHeaderContent().querySelectorAll('.e-headercelldiv')[this.columnIndex];
119
- var value = false;
120
- var rowChkBox = this.parent.createElement('input', { className: 'e-treeselectall', attrs: { 'type': 'checkbox' } });
121
- var checkWrap = createCheckBox(this.parent.createElement, false, { checked: value, label: ' ' });
122
- checkWrap.classList.add('e-hierarchycheckbox');
123
- checkWrap.insertBefore(rowChkBox.cloneNode(), checkWrap.firstChild);
124
- if (!isNullOrUndefined(headerElement)) {
125
- headerElement.insertBefore(checkWrap, headerElement.firstChild);
126
- }
127
- if (this.parent.autoCheckHierarchy) {
128
- this.headerSelection();
194
+ if (headerElement && headerElement.querySelectorAll('.e-treeselectall').length === 0) {
195
+ var value = false; // Initial state can be false.
196
+ var rowChkBox = this.parent.createElement('input', { className: 'e-treeselectall', attrs: { 'type': 'checkbox' } });
197
+ var checkWrap = createCheckBox(this.parent.createElement, false, { checked: value, label: ' ' });
198
+ checkWrap.classList.add('e-hierarchycheckbox');
199
+ checkWrap.insertBefore(rowChkBox.cloneNode(), checkWrap.firstChild);
200
+ if (!isNullOrUndefined(headerElement)) {
201
+ headerElement.insertBefore(checkWrap, headerElement.firstChild);
202
+ }
203
+ this.headerCheckboxFrameEl = checkWrap.querySelector('.e-frame'); // Assign the frame element
204
+ if (this.parent.autoCheckHierarchy) {
205
+ this.headerSelection();
206
+ } // Update header state based on data
129
207
  }
130
- }
131
- else if (this.columnIndex > -1 && this.parent.getHeaderContent().querySelectorAll('.e-treeselectall').length > 0) {
132
- var checkWrap = this.parent.getHeaderContent().querySelectorAll('.e-checkbox-wrapper')[0];
133
- var checkBoxvalue = checkWrap.querySelector('.e-frame').classList.contains('e-check');
134
- if (this.parent.autoCheckHierarchy && checkBoxvalue) {
135
- this.headerSelection(checkBoxvalue);
208
+ else if (headerElement && headerElement.querySelectorAll('.e-treeselectall').length > 0) {
209
+ this.headerCheckboxFrameEl = headerElement.querySelector('.e-frame');
210
+ if (this.parent.autoCheckHierarchy) {
211
+ this.headerSelection();
212
+ } // Update status based on current selections
136
213
  }
137
214
  }
138
215
  };
216
+ /**
217
+ * Renders a checkbox element for a column cell.
218
+ *
219
+ * @param {QueryCellInfoEventArgs} args - The QueryCellInfoEventArgs for the cell.
220
+ * @returns {Element} The rendered checkbox wrapper element.
221
+ */
139
222
  Selection.prototype.renderColumnCheckbox = function (args) {
140
223
  var rowChkBox = this.parent.createElement('input', { className: 'e-treecheckselect', attrs: { 'type': 'checkbox', 'aria-label': 'checkbox' } });
141
224
  var data = args.data;
142
225
  args.cell.classList.add('e-treegridcheckbox');
143
226
  args.cell.setAttribute('aria-label', 'checkbox');
144
- var value = (isNullOrUndefined(data.checkboxState) || data.checkboxState === 'uncheck') ? false : true;
227
+ var value = (data.checkboxState === 'check');
145
228
  var checkWrap = createCheckBox(this.parent.createElement, false, { checked: value, label: ' ' });
146
229
  checkWrap.classList.add('e-hierarchycheckbox');
147
230
  if (this.parent.allowTextWrap) {
@@ -152,9 +235,25 @@ var Selection = /** @class */ (function () {
152
235
  removeClass([checkbox], ['e-check', 'e-stop', 'e-uncheck']);
153
236
  checkWrap.querySelector('.e-frame').classList.add('e-stop');
154
237
  }
238
+ else if (data.checkboxState === 'uncheck') {
239
+ var checkbox = checkWrap.querySelectorAll('.e-frame')[0];
240
+ removeClass([checkbox], ['e-check', 'e-stop', 'e-uncheck']);
241
+ checkWrap.querySelector('.e-frame').classList.add('e-uncheck');
242
+ }
243
+ else if (data.checkboxState === 'check') {
244
+ var checkbox = checkWrap.querySelectorAll('.e-frame')[0];
245
+ removeClass([checkbox], ['e-check', 'e-stop', 'e-uncheck']);
246
+ checkWrap.querySelector('.e-frame').classList.add('e-check');
247
+ }
155
248
  checkWrap.insertBefore(rowChkBox.cloneNode(), checkWrap.firstChild);
156
249
  return checkWrap;
157
250
  };
251
+ /**
252
+ * Injects the checkbox into a column cell during QueryCellInfo.
253
+ *
254
+ * @param {QueryCellInfoEventArgs} container - The cell event args.
255
+ * @returns {void}
256
+ */
158
257
  Selection.prototype.columnCheckbox = function (container) {
159
258
  var checkWrap = this.renderColumnCheckbox(container);
160
259
  var containerELe = container.cell.querySelector('.e-treecolumn-container');
@@ -174,54 +273,105 @@ var Selection = /** @class */ (function () {
174
273
  container.cell.appendChild(divEle);
175
274
  }
176
275
  };
276
+ /**
277
+ * Selects or toggles checkboxes for the provided row indexes.
278
+ *
279
+ * @param {number[]} rowIndexes - Array of row indexes to toggle selection for.
280
+ * @returns {void}
281
+ */
177
282
  Selection.prototype.selectCheckboxes = function (rowIndexes) {
178
- if (isNullOrUndefined(rowIndexes)) {
179
- var error = 'The provided value for the rowIndexes is undefined. Please ensure the rowIndexes contains number.';
180
- this.parent.trigger(events.actionFailure, { error: error });
181
- }
182
283
  for (var i = 0; i < rowIndexes.length; i++) {
183
- var record = this.parent.getCurrentViewRecords()[rowIndexes[parseInt(i.toString(), 10)]];
184
- var flatRecord = getParentData(this.parent, record.uniqueID);
185
- record = flatRecord;
186
- var checkboxState = (record.checkboxState === 'uncheck') ? 'check' : 'uncheck';
187
- record.checkboxState = checkboxState;
188
- var keys = Object.keys(record);
189
- for (var j = 0; j < keys.length; j++) {
190
- if (Object.prototype.hasOwnProperty.call(flatRecord, keys[parseInt(j.toString(), 10)])) {
191
- flatRecord[keys[parseInt(j.toString(), 10)]] = record[keys[parseInt(j.toString(), 10)]];
192
- }
193
- }
194
- this.traverSelection(record, checkboxState, false);
195
- if (this.parent.autoCheckHierarchy) {
196
- this.headerSelection();
197
- }
284
+ var viewRec = this.parent.getCurrentViewRecords()[rowIndexes[parseInt(i.toString(), 10)]];
285
+ var flatRec = getParentData(this.parent, viewRec.uniqueID);
286
+ var nextState = (flatRec.checkboxState === 'check') ? 'uncheck' : 'check';
287
+ flatRec.checkboxState = nextState;
288
+ this.traverSelection(flatRec, nextState, false);
198
289
  }
199
290
  };
200
- Selection.prototype.traverSelection = function (record, checkboxState, ischildItem) {
201
- var length = 0;
202
- this.updateSelectedItems(record, checkboxState);
203
- if (!ischildItem && record.parentItem && this.parent.autoCheckHierarchy) {
204
- this.updateParentSelection(record.parentItem);
205
- }
206
- if (record.childRecords && this.parent.autoCheckHierarchy) {
207
- var childRecords = record.childRecords;
208
- if (!isNullOrUndefined(this.parent.filterModule) &&
209
- this.parent.filterModule.filteredResult.length > 0 && this.parent.autoCheckHierarchy) {
210
- childRecords = this.getFilteredChildRecords(childRecords);
211
- }
212
- length = childRecords.length;
213
- for (var count = 0; count < length; count++) {
214
- if (!childRecords[parseInt(count.toString(), 10)].isSummaryRow) {
215
- if (childRecords[parseInt(count.toString(), 10)].hasChildRecords) {
216
- this.traverSelection(childRecords[parseInt(count.toString(), 10)], checkboxState, true);
217
- }
218
- else {
219
- this.updateSelectedItems(childRecords[parseInt(count.toString(), 10)], checkboxState);
220
- }
291
+ /**
292
+ * Traverses selection for a record and cascades selections to children/parents as necessary.
293
+ *
294
+ * @param {ITreeData} record - The record to process.
295
+ * @param {string} checkboxState - The desired checkbox state ('check'|'uncheck'|'indeterminate').
296
+ * @param {boolean} isChildItem - True if this invocation is for a child during recursion.
297
+ * @returns {void}
298
+ */
299
+ Selection.prototype.traverSelection = function (record, checkboxState, isChildItem) {
300
+ var previousState = record.checkboxState;
301
+ if (!isChildItem) {
302
+ this.buildVisibleUidMap();
303
+ }
304
+ var effectiveChildren = Array.isArray(record.childRecords) ? record.childRecords : [];
305
+ if ((!effectiveChildren || effectiveChildren.length === 0) && this.parent.autoCheckHierarchy) {
306
+ effectiveChildren = this.getChildrenFromFlat(record);
307
+ }
308
+ if (this.parent.filterModule && this.parent.filterModule.filteredResult.length > 0
309
+ && effectiveChildren && effectiveChildren.length) {
310
+ effectiveChildren = this.getFilteredChildRecords(effectiveChildren);
311
+ }
312
+ if (!this.parent.autoCheckHierarchy || !effectiveChildren || effectiveChildren.length === 0) {
313
+ this.updateSelectedItems(record, checkboxState);
314
+ if (!isChildItem) {
315
+ if (record.parentItem && this.parent.autoCheckHierarchy) {
316
+ this.updateParentSelection(record.parentItem);
317
+ }
318
+ this.updateSelectedCollectionsAfterBulk(this.resolveHeaderSelectionList(), '');
319
+ this.refreshVisibleCheckboxes();
320
+ if (this.parent.autoCheckHierarchy) {
321
+ this.updateHeaderCheckboxState();
221
322
  }
222
323
  }
324
+ return;
325
+ }
326
+ var childCount = 0;
327
+ var checkedCount = 0;
328
+ var indeterminateCount = 0;
329
+ for (var i = 0; i < effectiveChildren.length; i++) {
330
+ var child = effectiveChildren[parseInt(i.toString(), 10)];
331
+ if (!child || child.isSummaryRow) {
332
+ continue;
333
+ }
334
+ childCount++;
335
+ this.updateSelectedItems(child, checkboxState, true);
336
+ if (child.hasChildRecords) {
337
+ this.traverSelection(child, checkboxState, true);
338
+ }
339
+ if (child.checkboxState === 'check') {
340
+ checkedCount++;
341
+ }
342
+ else if (child.checkboxState === 'indeterminate') {
343
+ indeterminateCount++;
344
+ }
345
+ }
346
+ if (record.uniqueID) {
347
+ this.parentSelectionCounters[record.uniqueID] = {
348
+ total: childCount,
349
+ checked: checkedCount,
350
+ indeterminate: indeterminateCount
351
+ };
352
+ }
353
+ var summary = this.parentSelectionCounters[record.uniqueID];
354
+ var finalState = this.deriveParentState(record, summary);
355
+ if (checkboxState === 'check' && summary.total > 0 && summary.checked === summary.total && summary.indeterminate === 0) {
356
+ finalState = 'check';
357
+ }
358
+ this.updateSelectedItems(record, finalState);
359
+ if (!isChildItem && record.parentItem && this.parent.autoCheckHierarchy) {
360
+ this.updateParentSelection(record.parentItem, previousState, finalState);
361
+ }
362
+ if (!isChildItem) {
363
+ var bulkList = this.resolveHeaderSelectionList();
364
+ this.updateSelectedCollectionsAfterBulk(bulkList, ''); // This will rebuild selectedItems & selectedIndexes based on total state
365
+ this.refreshVisibleCheckboxes();
366
+ this.updateHeaderCheckboxState();
223
367
  }
224
368
  };
369
+ /**
370
+ * Filters provided child records against the current filter result.
371
+ *
372
+ * @param {ITreeData[]} childRecords - The array of child records to filter.
373
+ * @returns {ITreeData[]} The filtered child records array.
374
+ */
225
375
  Selection.prototype.getFilteredChildRecords = function (childRecords) {
226
376
  var _this = this;
227
377
  var filteredChildRecords = childRecords.filter(function (e) {
@@ -229,59 +379,142 @@ var Selection = /** @class */ (function () {
229
379
  });
230
380
  return filteredChildRecords;
231
381
  };
232
- Selection.prototype.updateParentSelection = function (parentRecord) {
233
- var length = 0;
234
- var childRecords = [];
235
- var record = getParentData(this.parent, parentRecord.uniqueID);
236
- if (record && record.childRecords) {
237
- childRecords = record.childRecords;
238
- }
239
- if (!isNullOrUndefined(this.parent.filterModule) &&
240
- this.parent.filterModule.filteredResult.length > 0 && this.parent.autoCheckHierarchy) {
241
- childRecords = this.getFilteredChildRecords(childRecords);
242
- }
243
- length = childRecords && childRecords.length;
244
- var indeter = 0;
245
- var checkChildRecords = 0;
246
- if (!isNullOrUndefined(record)) {
247
- for (var i = 0; i < childRecords.length; i++) {
248
- var currentRecord = getParentData(this.parent, childRecords[parseInt(i.toString(), 10)].uniqueID);
249
- var checkBoxRecord = currentRecord;
250
- if (!isNullOrUndefined(checkBoxRecord)) {
251
- if (checkBoxRecord.checkboxState === 'indeterminate') {
252
- indeter++;
253
- }
254
- else if (checkBoxRecord.checkboxState === 'check') {
255
- checkChildRecords++;
256
- }
257
- }
258
- }
259
- if (indeter > 0 || (checkChildRecords > 0 && checkChildRecords !== length)) {
260
- record.checkboxState = 'indeterminate';
382
+ /**
383
+ * Derives children for a record from flatData using the parentItem link.
384
+ * Used when childRecords is missing or empty.
385
+ *
386
+ * @param {ITreeData} record - The record for which to find child elements.
387
+ * @returns {ITreeData[]} An array of child records derived from flatData.
388
+ */
389
+ Selection.prototype.getChildrenFromFlat = function (record) {
390
+ var all = (this.parent.flatData);
391
+ if (!all || !record) {
392
+ return [];
393
+ }
394
+ var pid = record.uniqueID;
395
+ var out = [];
396
+ for (var i = 0; i < all.length; i++) {
397
+ var r = all[parseInt(i.toString(), 10)];
398
+ if (!r || r.isSummaryRow) {
399
+ continue;
261
400
  }
262
- else if (checkChildRecords === 0 && (!record.hasFilteredChildRecords || isNullOrUndefined(record.hasFilteredChildRecords)) && !isNullOrUndefined(this.parent['dataResults']['actionArgs']) &&
263
- (this.parent['dataResults']['actionArgs'].requestType === 'searching' || this.parent['dataResults']['actionArgs'].requestType === 'filtering') && record.checkboxState === 'check') {
264
- record.checkboxState = 'check';
401
+ var p = r.parentItem;
402
+ if (p && p.uniqueID === pid) {
403
+ out.push(r);
265
404
  }
266
- else if ((checkChildRecords === 0 && indeter === 0) || (checkChildRecords === 0 && record.hasFilteredChildRecords && !isNullOrUndefined(this.parent['dataResults']['actionArgs']) &&
267
- (this.parent['dataResults']['actionArgs'].requestType === 'searching' || this.parent['dataResults']['actionArgs'].requestType === 'filtering') && record.checkboxState === 'check')) {
268
- record.checkboxState = 'uncheck';
405
+ }
406
+ return out;
407
+ };
408
+ /**
409
+ * Updates parent selection by rebuilding summary and applying deltas, then bubbling up if required.
410
+ *
411
+ * @param {ITreeData} parentRecord - The parent record reference.
412
+ * @param {string} [previousChildState] - Previous state of the child that changed.
413
+ * @param {string} [nextChildState] - Next state of the child that changed.
414
+ * @returns {void}
415
+ */
416
+ Selection.prototype.updateParentSelection = function (parentRecord, previousChildState, nextChildState) {
417
+ var parent = getParentData(this.parent, parentRecord.uniqueID);
418
+ if (!parent) {
419
+ return;
420
+ }
421
+ var summary = this.buildSelectionSummary(parent);
422
+ if (previousChildState) {
423
+ this.applySummaryDelta(summary, previousChildState, -1);
424
+ }
425
+ if (nextChildState) {
426
+ this.applySummaryDelta(summary, nextChildState, 1);
427
+ }
428
+ if (parent.uniqueID) {
429
+ this.parentSelectionCounters[parent.uniqueID] = summary;
430
+ }
431
+ var desiredState = this.deriveParentState(parent, summary);
432
+ if (parent.checkboxState === desiredState) {
433
+ return;
434
+ }
435
+ var parentPrev = parent.checkboxState;
436
+ parent.checkboxState = desiredState;
437
+ this.updateSelectedItems(parent, desiredState);
438
+ if (parent.parentItem) {
439
+ this.updateParentSelection(parent.parentItem, parentPrev, desiredState);
440
+ }
441
+ };
442
+ /**
443
+ * Builds a selection summary for a record's children.
444
+ *
445
+ * @param {Object} record - The record whose children should be summarized.
446
+ * @param {boolean} [ignoreFilter] - If true, ignore current filter when computing summary.
447
+ * @returns {{ total: number, checked: number, indeterminate: number }} The computed summary.
448
+ */
449
+ Selection.prototype.buildSelectionSummary = function (record, ignoreFilter) {
450
+ var summary = { total: 0, checked: 0, indeterminate: 0 };
451
+ var children = [];
452
+ if (record && Array.isArray(record.childRecords) && record.childRecords.length) {
453
+ children = record.childRecords;
454
+ }
455
+ else {
456
+ children = this.getChildrenFromFlat(record);
457
+ }
458
+ if (!ignoreFilter && this.parent.filterModule && this.parent.filterModule.filteredResult.length > 0) {
459
+ children = this.getFilteredChildRecords(children);
460
+ }
461
+ for (var i = 0; i < children.length; i++) {
462
+ var child = children[parseInt(i.toString(), 10)];
463
+ if (!child || child.isSummaryRow) {
464
+ continue;
269
465
  }
270
- else {
271
- record.checkboxState = 'check';
466
+ summary.total++;
467
+ if (child.checkboxState === 'check') {
468
+ summary.checked++;
272
469
  }
273
- this.updateSelectedItems(record, record.checkboxState);
274
- if (record.parentItem) {
275
- this.updateParentSelection(record.parentItem);
470
+ else if (child.checkboxState === 'indeterminate') {
471
+ summary.indeterminate++;
276
472
  }
277
473
  }
474
+ return summary;
475
+ };
476
+ /**
477
+ * Applies a delta to a selection summary based on a state change.
478
+ *
479
+ * @param {Object} summary - The summary to modify. Object with numeric properties: total, checked, indeterminate.
480
+ * @param {string} state - The state that changed ('check' | 'indeterminate').
481
+ * @param {number} delta - The delta to apply (e.g. +1 or -1).
482
+ * @returns {void}
483
+ */
484
+ Selection.prototype.applySummaryDelta = function (summary, state, delta) {
485
+ if (state === 'check') {
486
+ summary.checked = Math.max(0, summary.checked + delta);
487
+ }
488
+ else if (state === 'indeterminate') {
489
+ summary.indeterminate = Math.max(0, summary.indeterminate + delta);
490
+ }
278
491
  };
492
+ /**
493
+ * Derives the parent's checkbox state based on children summary counts.
494
+ *
495
+ * @param {ITreeData} record The parent record.
496
+ * @param {{ total: number, checked: number, indeterminate: number }} summary The children summary.
497
+ * @returns {'check'|'indeterminate'|'uncheck'} The derived checkbox state.
498
+ */
499
+ Selection.prototype.deriveParentState = function (record, summary) {
500
+ var total = summary.total;
501
+ var checked = summary.checked;
502
+ var indeterminate = summary.indeterminate;
503
+ if (indeterminate > 0 || (checked > 0 && checked !== total)) {
504
+ return 'indeterminate';
505
+ }
506
+ if (checked === total && total > 0) {
507
+ return 'check';
508
+ }
509
+ return 'uncheck';
510
+ };
511
+ /**
512
+ * Handles header checkbox (select all / clear all) behavior.
513
+ *
514
+ * @param {boolean} [checkAll] - Optional explicit flag to check or uncheck all.
515
+ * @returns {void}
516
+ */
279
517
  Selection.prototype.headerSelection = function (checkAll) {
280
- var _this = this;
281
- var index = -1;
282
- var length = 0;
283
- //This property used to maintain the check state of the currentview data after clear filtering
284
- var multiFilterCheckState = false;
285
518
  if (!isNullOrUndefined(this.parent.filterModule) && this.parent.filterModule.filteredResult.length > 0) {
286
519
  var filterResult = this.parent.filterModule.filteredResult;
287
520
  if (this.filteredList.length === 0) {
@@ -291,161 +524,401 @@ var Selection = /** @class */ (function () {
291
524
  this.searchingRecords = filterResult;
292
525
  }
293
526
  else {
294
- if (this.filteredList !== filterResult) {
527
+ if (this.filteredList !== filterResult && !this.parent.grid.searchSettings.key.length) {
295
528
  this.filteredList = filterResult;
296
- multiFilterCheckState = true;
297
- }
298
- else {
299
- multiFilterCheckState = false;
529
+ this.searchingRecords = [];
300
530
  }
301
531
  }
302
532
  }
303
- if (this.filteredList.length > 0) {
304
- if (!this.parent.filterSettings.columns.length && this.filteredList.length && !this.parent.grid.searchSettings.key.length) {
305
- this.filteredList = [];
533
+ if (this.searchingRecords.length > 0 && !isNullOrUndefined(checkAll)) {
534
+ this.filteredList = this.searchingRecords;
535
+ }
536
+ else if (this.filteredList.length > 0 && !this.parent.filterSettings.columns.length
537
+ && !this.parent.grid.searchSettings.key.length) {
538
+ this.filteredList = [];
539
+ }
540
+ var records = this.resolveHeaderSelectionList(true);
541
+ if (!isNullOrUndefined(checkAll)) {
542
+ this.resetSelectionCaches();
543
+ var targetState = checkAll ? 'check' : 'uncheck';
544
+ this.headerSelectionState = targetState;
545
+ this.processHeaderSelection(records, targetState);
546
+ this.finalizeParentsAfterBulk(records);
547
+ this.updateSelectedCollectionsAfterBulk(records, '');
548
+ this.refreshVisibleCheckboxes();
549
+ this.updateHeaderCheckboxState();
550
+ return;
551
+ }
552
+ this.totalSelectableCount = this.countSelectableRecords(records);
553
+ this.updateHeaderCheckboxState();
554
+ };
555
+ /**
556
+ * Finalizes parent states after a bulk header operation (e.g., Select All).
557
+ * This ensures parent states (checked/indeterminate) are correct after cascades.
558
+ *
559
+ * @param {ITreeData[]} records - The records that were processed in the bulk operation.
560
+ * @returns {void}
561
+ */
562
+ Selection.prototype.finalizeParentsAfterBulk = function (records) {
563
+ var all = records;
564
+ for (var i = 0; i < all.length; i++) {
565
+ var rec = all[parseInt(i.toString(), 10)];
566
+ if (!rec || !rec.hasChildRecords) {
567
+ continue;
306
568
  }
307
- if (this.searchingRecords.length && !isNullOrUndefined(checkAll)) {
308
- this.filteredList = this.searchingRecords;
569
+ var summary = this.buildSelectionSummary(rec, true);
570
+ this.parentSelectionCounters[rec.uniqueID] = summary;
571
+ var finalState = this.deriveParentState(rec, summary);
572
+ if (this.headerSelectionState === 'check' &&
573
+ summary.total > 0 && summary.checked === summary.total && summary.indeterminate === 0) {
574
+ finalState = 'check';
575
+ }
576
+ else if (this.headerSelectionState === 'uncheck') {
577
+ finalState = 'uncheck';
578
+ }
579
+ if (rec.checkboxState !== finalState) {
580
+ this.updateSelectedItems(rec, finalState);
309
581
  }
310
582
  }
311
- var data;
312
- if (!(isNullOrUndefined(this.parent.filterModule)) &&
313
- this.parent.filterModule.filteredResult.length === 0 && this.parent.getCurrentViewRecords().length === 0 &&
314
- this.parent.filterSettings.columns.length > 0) {
315
- data = this.filteredList;
316
- }
317
- else {
318
- data = (!isNullOrUndefined(this.parent.filterModule) &&
319
- (this.filteredList.length > 0)) ? this.filteredList : this.parent.flatData;
583
+ };
584
+ /**
585
+ * Processes header selection for each record, setting their state silently in the data model.
586
+ * Called during bulk operations like "select all".
587
+ *
588
+ * @param {ITreeData[]} records - The records to process.
589
+ * @param {string} targetState - The target state to set on each record.
590
+ * @returns {void}
591
+ */
592
+ Selection.prototype.processHeaderSelection = function (records, targetState) {
593
+ for (var i = 0; i < records.length; i++) {
594
+ var record = records[parseInt(i.toString(), 10)];
595
+ if (!record) {
596
+ continue;
597
+ }
598
+ var previousState = record.checkboxState;
599
+ if (previousState === targetState) {
600
+ continue;
601
+ }
602
+ record.checkboxState = targetState;
603
+ this.updateSelectedItems(record, targetState, true);
320
604
  }
321
- data = isRemoteData(this.parent) ? this.parent.getCurrentViewRecords() : data;
322
- if (!isNullOrUndefined(checkAll)) {
323
- for (var i = 0; i < data.length; i++) {
324
- if (checkAll) {
325
- if (data[parseInt(i.toString(), 10)].checkboxState === 'check') {
605
+ };
606
+ /**
607
+ * Rebuilds `selectedItems`, `selectedUidMap`, and `selectedIndexes` based on the current data states in the model.
608
+ * This method is called after bulk operations (like headerSelection, grid actions, etc.) to synchronize internal collections.
609
+ * It ensures `selectedItems` retains original selection order *as much as possible* for currently checked items
610
+ * and `selectedIndexes` reflects their *current visible order*.
611
+ *
612
+ * @param {ITreeData[]} records - The records that were processed (or the full data set if re-evaluating everything).
613
+ * @param {string} requestType - The data action type such as filtering, searching, refresh,etc.
614
+ * @returns {void}
615
+ */
616
+ Selection.prototype.updateSelectedCollectionsAfterBulk = function (records, requestType) {
617
+ var hasFilter = !!(this.parent.filterModule && this.parent.filterModule.filteredResult &&
618
+ this.parent.filterModule.filteredResult.length);
619
+ var hasSearch = !!(this.parent.grid && this.parent.grid.searchSettings &&
620
+ this.parent.grid.searchSettings.key && this.parent.grid.searchSettings.key.length);
621
+ var isFilterOrSearch = hasFilter || hasSearch || requestType === 'refresh' || requestType === 'searching';
622
+ var currentlySelectedItemsInOrder = isFilterOrSearch ? records : this.selectedItems.slice();
623
+ var newSelectedItems = [];
624
+ var newSelectedUidMap = new Map();
625
+ var newSelectedIndexes = [];
626
+ for (var _i = 0, currentlySelectedItemsInOrder_1 = currentlySelectedItemsInOrder; _i < currentlySelectedItemsInOrder_1.length; _i++) {
627
+ var item = currentlySelectedItemsInOrder_1[_i];
628
+ if (item.hasChildRecords && isFilterOrSearch && item.level === 0) {
629
+ this.updateParentSelection(item);
630
+ }
631
+ if (item.uniqueID && item.checkboxState === 'check') {
632
+ newSelectedItems.push(item);
633
+ newSelectedUidMap.set(item.uniqueID, true);
634
+ }
635
+ }
636
+ if (!isFilterOrSearch) {
637
+ var allFlatData = this.parent.flatData;
638
+ if (allFlatData) {
639
+ for (var _a = 0, allFlatData_1 = allFlatData; _a < allFlatData_1.length; _a++) {
640
+ var record = allFlatData_1[_a];
641
+ if (!record || record.isSummaryRow) {
326
642
  continue;
327
643
  }
328
- if (multiFilterCheckState) {
329
- continue;
644
+ if (record.uniqueID && record.checkboxState === 'check' && !newSelectedUidMap.has(record.uniqueID)) {
645
+ newSelectedItems.push(record);
646
+ newSelectedUidMap.set(record.uniqueID, true);
330
647
  }
331
- data[parseInt(i.toString(), 10)].checkboxState = 'check';
332
- this.updateSelectedItems(data[parseInt(i.toString(), 10)], data[parseInt(i.toString(), 10)].checkboxState);
333
648
  }
334
- else {
335
- index = this.selectedItems.indexOf(data[parseInt(i.toString(), 10)]);
336
- if (index > -1) {
337
- data[parseInt(i.toString(), 10)].checkboxState = 'uncheck';
338
- this.updateSelectedItems(data[parseInt(i.toString(), 10)], data[parseInt(i.toString(), 10)].checkboxState);
339
- if (this.parent.autoCheckHierarchy) {
340
- this.updateParentSelection(data[parseInt(i.toString(), 10)]);
341
- }
649
+ }
650
+ }
651
+ this.selectedItems = newSelectedItems;
652
+ this.selectedUidMap = newSelectedUidMap;
653
+ this.buildVisibleUidMap();
654
+ for (var _b = 0, _c = this.selectedItems; _b < _c.length; _b++) {
655
+ var item = _c[_b];
656
+ var visibleIdx = this.visibleUidIndex[item.uniqueID];
657
+ if (visibleIdx !== undefined) {
658
+ newSelectedIndexes.push(visibleIdx);
659
+ }
660
+ }
661
+ this.selectedIndexes = newSelectedIndexes;
662
+ this.checkedItemCount = this.selectedItems.length;
663
+ this.totalSelectableCount =
664
+ this.countSelectableRecords(records);
665
+ };
666
+ /**
667
+ * Refreshes visible checkbox DOM elements to reflect the current data state.
668
+ * This method exclusively updates the UI representation of checkboxes.
669
+ *
670
+ * @returns {void}
671
+ */
672
+ Selection.prototype.refreshVisibleCheckboxes = function () {
673
+ this.buildVisibleUidMap();
674
+ var data = this.parent.getCurrentViewRecords();
675
+ var uidMap = this.parent.uniqueIDCollection;
676
+ for (var i = 0; data && i < data.length; i++) {
677
+ var viewRec = data[parseInt(i.toString(), 10)];
678
+ if (!viewRec) {
679
+ continue;
680
+ }
681
+ var uid = viewRec.uniqueID;
682
+ var srcRec = (uidMap && uid != null) ? uidMap[String(uid)] : viewRec;
683
+ var state = (srcRec && srcRec.checkboxState) ? srcRec.checkboxState : 'uncheck';
684
+ var rowEl = null;
685
+ var rowUid = viewRec.uid;
686
+ if (rowUid) {
687
+ rowEl = this.parent.grid.getRowElementByUID(rowUid);
688
+ }
689
+ if (!rowEl) {
690
+ var rows = this.parent.getRows();
691
+ rowEl = rows && rows[parseInt(i.toString(), 10)];
692
+ if ((this.parent.frozenRows || this.parent.getFrozenColumns()) && !rowEl) {
693
+ var movableRows = this.parent.getDataRows();
694
+ rowEl = movableRows && movableRows[parseInt(i.toString(), 10)];
695
+ }
696
+ }
697
+ if (rowEl) {
698
+ var frame = rowEl.querySelector('.e-hierarchycheckbox .e-frame');
699
+ if (frame) {
700
+ removeClass([frame], ['e-check', 'e-stop', 'e-uncheck']);
701
+ frame.classList.add(state === 'indeterminate' ? 'e-stop' : ('e-' + state));
702
+ var input = rowEl.querySelector('.e-treecheckselect');
703
+ if (input) {
704
+ input.setAttribute('aria-checked', state === 'check' ? 'true' :
705
+ (state === 'uncheck' ? 'false' : 'mixed'));
342
706
  }
343
707
  }
344
708
  }
345
709
  }
346
- if (checkAll === false && this.parent.enableVirtualization) {
347
- this.selectedItems = [];
348
- this.selectedIndexes = [];
349
- data.filter(function (rec) {
350
- rec.checkboxState = 'uncheck';
351
- _this.updateSelectedItems(rec, rec.checkboxState);
352
- });
710
+ };
711
+ /**
712
+ * Resets internal selection caches to their initial state.
713
+ * This is usually called before a bulk selection operation (like "select all").
714
+ *
715
+ * @returns {void}
716
+ */
717
+ Selection.prototype.resetSelectionCaches = function () {
718
+ this.parentSelectionCounters = {};
719
+ this.selectedUidMap = new Map();
720
+ this.selectedItems = [];
721
+ this.selectedIndexes = [];
722
+ this.totalSelectableCount = 0;
723
+ this.headerSelectionState = 'uncheck';
724
+ this.checkedItemCount = 0;
725
+ };
726
+ /**
727
+ * Counts selectable (non-summary) records in the provided array.
728
+ *
729
+ * @param {ITreeData[]} records - The records to count.
730
+ * @returns {number} The number of selectable records.
731
+ */
732
+ Selection.prototype.countSelectableRecords = function (records) {
733
+ var count = 0;
734
+ if (!records) {
735
+ return count;
736
+ }
737
+ for (var i = 0; i < records.length; i++) {
738
+ var rec = records[parseInt(i.toString(), 10)];
739
+ if (rec && !rec.isSummaryRow) {
740
+ count++;
741
+ }
353
742
  }
354
- length = this.selectedItems.length;
355
- var checkbox = this.parent.getHeaderContent().querySelectorAll('.e-frame')[0];
356
- if (length > 0 && data.length > 0) {
357
- if (length !== data.length && !checkAll) {
358
- removeClass([checkbox], ['e-check']);
359
- checkbox.classList.add('e-stop');
743
+ return count;
744
+ };
745
+ /**
746
+ * Resolves the list of records used for header selection operations (e.g., for `select all`).
747
+ *
748
+ * @param {boolean} [includeAll] - If true and data is local, returns flatData (all records for full dataset actions).
749
+ * @returns {ITreeData[]} The array of records to consider for header operations.
750
+ */
751
+ Selection.prototype.resolveHeaderSelectionList = function (includeAll) {
752
+ var dataToProcess = [];
753
+ if (!isRemoteData(this.parent)) {
754
+ var hasFilter = !!(this.parent.filterModule &&
755
+ this.parent.filterModule.filteredResult &&
756
+ this.parent.filterModule.filteredResult.length);
757
+ var hasSearch = !!(this.parent.grid &&
758
+ this.parent.grid.searchSettings &&
759
+ this.parent.grid.searchSettings.key &&
760
+ this.parent.grid.searchSettings.key.length);
761
+ if (includeAll) {
762
+ if (hasFilter) {
763
+ dataToProcess = this.filteredList && this.filteredList.length
764
+ ? this.filteredList
765
+ : this.parent.filterModule.filteredResult;
766
+ }
767
+ else if (hasSearch && this.searchingRecords && this.searchingRecords.length) {
768
+ dataToProcess = this.searchingRecords;
769
+ }
770
+ else {
771
+ dataToProcess = this.parent.flatData;
772
+ }
360
773
  }
361
774
  else {
362
- removeClass([checkbox], ['e-stop']);
363
- checkbox.classList.add('e-check');
775
+ if (hasFilter) {
776
+ dataToProcess = this.filteredList && this.filteredList.length
777
+ ? this.filteredList
778
+ : this.parent.filterModule.filteredResult;
779
+ }
780
+ else if (hasSearch && this.searchingRecords && this.searchingRecords.length) {
781
+ dataToProcess = this.searchingRecords;
782
+ }
783
+ else {
784
+ dataToProcess = this.parent.flatData;
785
+ }
364
786
  }
365
787
  }
366
788
  else {
367
- removeClass([checkbox], ['e-check', 'e-stop']);
789
+ dataToProcess = this.parent.getCurrentViewRecords();
368
790
  }
791
+ return dataToProcess;
369
792
  };
370
- Selection.prototype.updateSelectedItems = function (currentRecord, checkState) {
371
- var record = this.parent.grid.currentViewData.filter(function (e) {
372
- return e.uniqueID === currentRecord.uniqueID;
373
- });
374
- var checkedRecord;
375
- var recordIndex = this.parent.grid.currentViewData.indexOf(record[0]);
376
- var checkboxRecord = getParentData(this.parent, currentRecord.uniqueID);
377
- var tr = this.parent.getRows()[parseInt(recordIndex.toString(), 10)];
378
- var checkbox;
379
- if (recordIndex > -1) {
380
- var movableTr = void 0;
381
- if (this.parent.frozenRows || this.parent.getFrozenColumns()) {
382
- movableTr = this.parent.getDataRows()[parseInt(recordIndex.toString(), 10)];
383
- }
384
- checkbox = tr.querySelectorAll('.e-hierarchycheckbox .e-frame')[0] ? tr.querySelectorAll('.e-hierarchycheckbox .e-frame')[0]
385
- : movableTr.querySelectorAll('.e-hierarchycheckbox .e-frame')[0];
386
- if (!isNullOrUndefined(checkbox)) {
387
- removeClass([checkbox], ['e-check', 'e-stop', 'e-uncheck']);
793
+ /**
794
+ * Updates the header checkbox state (checked/indeterminate/unchecked) based on current selections.
795
+ *
796
+ * @returns {void}
797
+ */
798
+ Selection.prototype.updateHeaderCheckboxState = function () {
799
+ var frame = this.headerCheckboxFrameEl;
800
+ if (!frame) {
801
+ return;
802
+ }
803
+ var recordsForHeaderLogic = this.resolveHeaderSelectionList(true);
804
+ this.totalSelectableCount = this.countSelectableRecords(recordsForHeaderLogic);
805
+ var checkedCountForHeaderLogic = 0;
806
+ for (var _i = 0, recordsForHeaderLogic_1 = recordsForHeaderLogic; _i < recordsForHeaderLogic_1.length; _i++) {
807
+ var record = recordsForHeaderLogic_1[_i];
808
+ if (record && !record.isSummaryRow && record.checkboxState === 'check') {
809
+ checkedCountForHeaderLogic++;
388
810
  }
389
811
  }
390
- checkedRecord = checkboxRecord;
391
- if (isNullOrUndefined(checkedRecord)) {
392
- checkedRecord = currentRecord;
812
+ removeClass([frame], ['e-check', 'e-stop', 'e-uncheck']);
813
+ if (this.totalSelectableCount === 0) {
814
+ frame.classList.add('e-uncheck');
393
815
  }
394
- checkedRecord.checkboxState = checkState;
395
- if (checkState === 'check' && isNullOrUndefined(currentRecord.isSummaryRow)) {
396
- if (recordIndex !== -1 && this.selectedIndexes.indexOf(recordIndex) === -1) {
397
- this.selectedIndexes.push(recordIndex);
398
- }
399
- if (this.selectedItems.indexOf(checkedRecord) === -1 && (recordIndex !== -1 &&
400
- (!isNullOrUndefined(this.parent.filterModule) && this.parent.filterModule.filteredResult.length > 0))) {
401
- this.selectedItems.push(checkedRecord);
402
- }
403
- if (this.selectedItems.indexOf(checkedRecord) === -1 && (this.parent.enableVirtualization || this.parent.allowPaging) && ((!isNullOrUndefined(this.parent.filterModule) && this.parent.filterModule.filteredResult.length > 0))) {
404
- this.selectedItems.push(checkedRecord);
405
- }
406
- if (this.selectedItems.indexOf(checkedRecord) === -1 && (!isNullOrUndefined(this.parent.filterModule) &&
407
- this.parent.filterModule.filteredResult.length === 0)) {
408
- this.selectedItems.push(checkedRecord);
816
+ else if (checkedCountForHeaderLogic === 0) {
817
+ frame.classList.add('e-uncheck');
818
+ }
819
+ else if (checkedCountForHeaderLogic === this.totalSelectableCount) {
820
+ frame.classList.add('e-check');
821
+ }
822
+ else {
823
+ frame.classList.add('e-stop');
824
+ }
825
+ };
826
+ /**
827
+ * Updates selection arrays (selectedItems, selectedUidMap, selectedIndexes) and visible DOM for a single record.
828
+ * This is the core method for managing the state of a single checkbox.
829
+ *
830
+ * @param {ITreeData} currentRecord - The record to update.
831
+ * @param {string} checkState - The new checkbox state ('check' | 'uncheck' | 'indeterminate').
832
+ * @param {boolean} [silent] - If true, update is silent (only updates data model, no collection management or DOM update).
833
+ * @returns {void}
834
+ */
835
+ Selection.prototype.updateSelectedItems = function (currentRecord, checkState, silent) {
836
+ this.buildVisibleUidMap();
837
+ var uid = currentRecord.uniqueID;
838
+ var uidMap = this.parent.uniqueIDCollection;
839
+ var checkboxRecord = (uidMap && uid != null) ? (uidMap[String(uid)] ?
840
+ uidMap[String(uid)] : currentRecord) : currentRecord;
841
+ var isSummary = currentRecord.isSummaryRow === true;
842
+ var previousState = checkboxRecord.checkboxState;
843
+ var currentVisibleIndex = this.visibleUidIndex[String(uid)];
844
+ checkboxRecord.checkboxState = checkState;
845
+ if (silent) {
846
+ return;
847
+ }
848
+ if (!isSummary && previousState !== checkState) {
849
+ if (checkState === 'check') {
850
+ this.checkedItemCount++;
851
+ if (!this.selectedUidMap.has(String(uid))) {
852
+ if (checkboxRecord.uniqueID) {
853
+ this.selectedUidMap.set(String(checkboxRecord.uniqueID), true);
854
+ }
855
+ this.selectedItems.push(checkboxRecord);
856
+ if (currentVisibleIndex !== undefined && this.selectedIndexes.indexOf(currentVisibleIndex) === -1) {
857
+ this.selectedIndexes.push(currentVisibleIndex);
858
+ }
859
+ }
409
860
  }
410
- if (this.selectedItems.indexOf(checkedRecord) === -1 && isNullOrUndefined(this.parent.filterModule)) {
411
- this.selectedItems.push(checkedRecord);
861
+ else if (previousState === 'check' || previousState === 'indeterminate') {
862
+ if (this.checkedItemCount > 0) {
863
+ this.checkedItemCount--;
864
+ }
865
+ if (checkboxRecord && checkboxRecord.uniqueID && this.selectedUidMap.has(String(checkboxRecord.uniqueID))) {
866
+ this.selectedUidMap.delete(String(checkboxRecord.uniqueID));
867
+ var itemIdx = this.selectedItems.indexOf(checkboxRecord);
868
+ if (itemIdx !== -1) {
869
+ this.selectedItems.splice(itemIdx, 1);
870
+ }
871
+ if (currentVisibleIndex !== undefined) {
872
+ var indexInSelectedIndexes = this.selectedIndexes.indexOf(currentVisibleIndex);
873
+ if (indexInSelectedIndexes > -1) {
874
+ this.selectedIndexes.splice(indexInSelectedIndexes, 1);
875
+ }
876
+ }
877
+ }
412
878
  }
413
879
  }
414
- else if ((checkState === 'uncheck' || checkState === 'indeterminate') && isNullOrUndefined(currentRecord.isSummaryRow)) {
415
- var index = this.selectedItems.indexOf(checkedRecord);
416
- if (index !== -1) {
417
- this.selectedItems.splice(index, 1);
418
- }
419
- if (this.selectedIndexes.indexOf(recordIndex) !== -1) {
420
- var checkedIndex = this.selectedIndexes.indexOf(recordIndex);
421
- this.selectedIndexes.splice(checkedIndex, 1);
880
+ var rowEl = null;
881
+ var rowUid = currentRecord.uid;
882
+ if (rowUid) {
883
+ rowEl = this.parent.grid.getRowElementByUID(rowUid);
884
+ }
885
+ if (!rowEl) {
886
+ var recordVisibleIndex = currentVisibleIndex !== undefined ? currentVisibleIndex : (typeof this.visibleUidIndex[String(uid)] === 'number' ? this.visibleUidIndex[String(uid)] : -1);
887
+ if (recordVisibleIndex > -1) {
888
+ rowEl = this.parent.getRows()[parseInt(recordVisibleIndex.toString(), 10)];
889
+ if (!rowEl && (this.parent.frozenRows || this.parent.getFrozenColumns())) {
890
+ rowEl = this.parent.getDataRows()[parseInt(recordVisibleIndex.toString(), 10)];
891
+ }
422
892
  }
423
893
  }
424
- var checkBoxclass = checkState === 'indeterminate' ? 'e-stop' : 'e-' + checkState;
425
- if (recordIndex > -1) {
426
- if (!isNullOrUndefined(checkbox)) {
427
- checkbox.classList.add(checkBoxclass);
428
- tr.querySelector('.e-treecheckselect').setAttribute('aria-checked', checkState === 'check' ? 'true' : checkState === 'uncheck' ? 'false' : 'mixed');
894
+ if (rowEl) {
895
+ var frame = rowEl.querySelector('.e-hierarchycheckbox .e-frame');
896
+ if (frame) {
897
+ removeClass([frame], ['e-check', 'e-stop', 'e-uncheck']);
898
+ frame.classList.add(checkState === 'indeterminate' ? 'e-stop' : ('e-' + checkState));
899
+ }
900
+ var input = rowEl.querySelector('.e-treecheckselect');
901
+ if (input) {
902
+ input.setAttribute('aria-checked', checkState === 'check' ? 'true' :
903
+ (checkState === 'uncheck' ? 'false' : 'mixed'));
429
904
  }
430
905
  }
431
906
  };
907
+ /**
908
+ * Handles various grid actions and updates selection state accordingly.
909
+ * This method ensures that selection state is maintained and UI is refreshed after grid operations.
910
+ *
911
+ * @param {CellSaveEventArgs} args - Action arguments containing requestType and data.
912
+ * @returns {void}
913
+ */
432
914
  Selection.prototype.updateGridActions = function (args) {
433
- var _this = this;
434
915
  var requestType = args.requestType;
435
- var childData;
436
- var childLength;
437
916
  if (isCheckboxcolumn(this.parent)) {
438
917
  if (this.parent.autoCheckHierarchy) {
439
918
  if ((requestType === 'sorting' || requestType === 'paging')) {
440
- var rows = this.parent.grid.getRows();
441
- childData = this.parent.getCurrentViewRecords();
442
- childLength = childData.length;
443
- this.selectedIndexes = [];
444
- for (var i = 0; i < childLength; i++) {
445
- if (!rows[parseInt(i.toString(), 10)].classList.contains('e-summaryrow')) {
446
- this.updateSelectedItems(childData[parseInt(i.toString(), 10)], childData[parseInt(i.toString(), 10)].checkboxState);
447
- }
448
- }
919
+ this.updateSelectedCollectionsAfterBulk(this.resolveHeaderSelectionList(), '');
920
+ this.refreshVisibleCheckboxes();
921
+ this.updateHeaderCheckboxState();
449
922
  }
450
923
  else if (requestType === 'delete' || args.action === 'add') {
451
924
  var updatedData = [];
@@ -457,71 +930,69 @@ var Selection = /** @class */ (function () {
457
930
  }
458
931
  for (var i = 0; i < updatedData.length; i++) {
459
932
  if (requestType === 'delete') {
460
- var index = this.parent.flatData.indexOf(updatedData[parseInt(i.toString(), 10)]);
461
- var checkedIndex = this.selectedIndexes.indexOf(index);
462
- this.selectedIndexes.splice(checkedIndex, 1);
463
- this.updateSelectedItems(updatedData[parseInt(i.toString(), 10)], 'uncheck');
933
+ this.updateSelectedItems(updatedData[parseInt(i.toString(), 10)], 'uncheck', false);
464
934
  }
465
935
  if (!isNullOrUndefined(updatedData[parseInt(i.toString(), 10)].parentItem)) {
466
936
  this.updateParentSelection(updatedData[parseInt(i.toString(), 10)].parentItem);
467
937
  }
468
938
  }
939
+ this.updateSelectedCollectionsAfterBulk(this.resolveHeaderSelectionList(true), '');
940
+ this.refreshVisibleCheckboxes();
941
+ if (this.parent.autoCheckHierarchy) {
942
+ this.updateHeaderCheckboxState();
943
+ }
469
944
  }
470
945
  else if (args.requestType === 'add' && this.parent.autoCheckHierarchy) {
471
946
  args.data.checkboxState = 'uncheck';
472
947
  }
473
- else if (requestType === 'filtering' || requestType === 'searching' || requestType === 'refresh'
474
- && !isRemoteData(this.parent)) {
475
- this.selectedItems = [];
476
- this.selectedIndexes = [];
477
- childData = (!isNullOrUndefined(this.parent.filterModule) && this.parent.filterModule.filteredResult.length > 0) ?
478
- this.parent.filterModule.filteredResult : this.parent.flatData;
479
- childData.forEach(function (record) {
480
- if (_this.parent.enableVirtualization) {
481
- if (record.hasChildRecords && record.childRecords.length > 0) {
482
- _this.updateParentSelection(record);
483
- }
484
- else {
485
- _this.updateSelectedItems(record, record.checkboxState);
486
- }
487
- var child = findChildrenRecords(record);
488
- child = _this.getFilteredChildRecords(child);
489
- for (var i = 0; i < child.length; i++) {
490
- if (child[parseInt(i.toString(), 10)].hasChildRecords) {
491
- _this.updateParentSelection(child[parseInt(i.toString(), 10)]);
492
- }
493
- else if (!(child[parseInt(i.toString(), 10)].hasChildRecords) &&
494
- !isNullOrUndefined(child[parseInt(i.toString(), 10)])) {
495
- _this.updateSelectedItems(child[parseInt(i.toString(), 10)], child[parseInt(i.toString(), 10)].checkboxState);
496
- }
497
- }
498
- }
499
- else {
500
- if (record.hasChildRecords) {
501
- _this.updateParentSelection(record);
502
- }
503
- else {
504
- _this.updateSelectedItems(record, record.checkboxState);
505
- }
506
- }
507
- });
508
- this.headerSelection();
948
+ else if (requestType === 'filtering' || requestType === 'searching' || requestType === 'refresh') {
949
+ this.updateSelectedCollectionsAfterBulk(this.resolveHeaderSelectionList(), requestType);
950
+ this.refreshVisibleCheckboxes();
951
+ if (this.parent.autoCheckHierarchy) {
952
+ this.updateHeaderCheckboxState();
953
+ }
509
954
  }
510
955
  }
511
956
  else {
512
- if ((requestType === 'filtering' || requestType === 'searching' || requestType === 'refresh')
513
- && !isRemoteData(this.parent)) {
957
+ if ((requestType === 'filtering' || requestType === 'searching' || requestType === 'refresh' ||
958
+ requestType === 'sorting' || requestType === 'paging' || requestType === 'expanding' ||
959
+ requestType === 'expand' || requestType === 'collapsing' || requestType === 'collapse') && !isRemoteData(this.parent)) {
514
960
  this.selectedItems = [];
961
+ this.selectedUidMap = new Map();
515
962
  this.selectedIndexes = [];
963
+ this.refreshVisibleCheckboxes();
964
+ if (this.parent.autoCheckHierarchy) {
965
+ this.updateHeaderCheckboxState();
966
+ }
516
967
  }
517
968
  }
518
969
  }
519
970
  };
520
- Selection.prototype.getCheckedrecords = function () {
521
- return this.selectedItems;
522
- };
971
+ /**
972
+ * Retrieves checked record objects.
973
+ * This array maintains the `ITreeData` objects in the order they were selected.
974
+ *
975
+ * @returns {ITreeData[]} Array of checked records.
976
+ */
977
+ Selection.prototype.getCheckedrecords = function () { return this.selectedItems; };
978
+ /**
979
+ * Retrieves visible indexes of checked rows in the current view, in the order they were selected.
980
+ * This method dynamically generates the list of visible indexes by iterating through `selectedItems`
981
+ * (which preserves selection order) and finding their *current* visible index.
982
+ *
983
+ * @returns {number[]} Array of checked row indexes in selection order.
984
+ */
523
985
  Selection.prototype.getCheckedRowIndexes = function () {
524
- return this.selectedIndexes;
986
+ this.buildVisibleUidMap();
987
+ var orderedVisibleIndexes = [];
988
+ for (var _i = 0, _a = this.selectedItems; _i < _a.length; _i++) {
989
+ var selectedItem = _a[_i];
990
+ var uid = selectedItem.uniqueID;
991
+ if (uid !== undefined && this.visibleUidIndex[uid] !== undefined) {
992
+ orderedVisibleIndexes.push(this.visibleUidIndex[uid]);
993
+ }
994
+ }
995
+ return orderedVisibleIndexes;
525
996
  };
526
997
  return Selection;
527
998
  }());