vgapp 1.4.7 → 1.4.9

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 (85) hide show
  1. package/README.md +24 -2
  2. package/app/modules/base-module.js +14 -2
  3. package/app/modules/module-fn.js +5 -4
  4. package/app/modules/vgalert/js/vgalert.js +21 -1
  5. package/app/modules/vgalert/scss/vgalert.scss +48 -0
  6. package/app/modules/vgdropdown/js/vgdropdown.js +58 -27
  7. package/app/modules/vgfilepreview/js/renderers/video-modal.js +5 -1
  8. package/app/modules/vgfilepreview/js/renderers/video.js +6 -1
  9. package/app/modules/vgfilepreview/js/vgfilepreview.js +5 -1
  10. package/app/modules/vgfiles/js/base.js +14 -5
  11. package/app/modules/vgfiles/js/droppable.js +37 -31
  12. package/app/modules/vgfiles/js/vgfiles.js +5 -2
  13. package/app/modules/vgfiles/scss/_variables.scss +3 -1
  14. package/app/modules/vgfiles/scss/vgfiles.scss +55 -10
  15. package/app/modules/vgformsender/js/vgformsender.js +5 -2
  16. package/app/modules/vgloadmore/js/vgloadmore.js +35 -7
  17. package/app/modules/vgnestable/js/vgnestable.js +140 -0
  18. package/app/modules/vgnestable/scss/_variables.scss +16 -9
  19. package/app/modules/vgnestable/scss/vgnestable.scss +35 -2
  20. package/app/modules/vgtable/index.js +3 -0
  21. package/app/modules/vgtable/js/_columns.js +567 -0
  22. package/app/modules/vgtable/js/_expandable.js +242 -0
  23. package/app/modules/vgtable/js/_filters.js +264 -0
  24. package/app/modules/vgtable/js/_fixed-columns.js +249 -0
  25. package/app/modules/vgtable/js/_i18n.js +75 -0
  26. package/app/modules/vgtable/js/_options.js +428 -0
  27. package/app/modules/vgtable/js/_pagination.js +491 -0
  28. package/app/modules/vgtable/js/_panning.js +124 -0
  29. package/app/modules/vgtable/js/_params-groups.js +21 -0
  30. package/app/modules/vgtable/js/_remote.js +395 -0
  31. package/app/modules/vgtable/js/_row-reorder.js +268 -0
  32. package/app/modules/vgtable/js/_search.js +134 -0
  33. package/app/modules/vgtable/js/_selection.js +113 -0
  34. package/app/modules/vgtable/js/_skeleton.js +123 -0
  35. package/app/modules/vgtable/js/_sorting.js +340 -0
  36. package/app/modules/vgtable/js/_states.js +143 -0
  37. package/app/modules/vgtable/js/_sticky-header.js +193 -0
  38. package/app/modules/vgtable/js/_url-state.js +178 -0
  39. package/app/modules/vgtable/js/vgtable.js +1444 -0
  40. package/app/modules/vgtable/readme.md +922 -0
  41. package/app/modules/vgtable/scss/_columns.scss +52 -0
  42. package/app/modules/vgtable/scss/_expandable.scss +54 -0
  43. package/app/modules/vgtable/scss/_fixed-columns.scss +117 -0
  44. package/app/modules/vgtable/scss/_pagination.scss +191 -0
  45. package/app/modules/vgtable/scss/_row-reorder.scss +45 -0
  46. package/app/modules/vgtable/scss/_skeleton.scss +65 -0
  47. package/app/modules/vgtable/scss/_sorting.scss +89 -0
  48. package/app/modules/vgtable/scss/_states.scss +70 -0
  49. package/app/modules/vgtable/scss/_sticky-header.scss +121 -0
  50. package/app/modules/vgtable/scss/_variables.scss +296 -0
  51. package/app/modules/vgtable/scss/vgtable.scss +206 -0
  52. package/app/utils/js/components/placement.js +64 -10
  53. package/app/vgapp.js +3 -3
  54. package/build/vgapp.css +1 -1
  55. package/build/vgapp.css.map +1 -1
  56. package/build/vgapp.js +1 -1
  57. package/build/vgapp.js.map +1 -1
  58. package/index.js +1 -1
  59. package/index.scss +3 -3
  60. package/package.json +5 -5
  61. package/app/modules/vgdynamictable/index.js +0 -4
  62. package/app/modules/vgdynamictable/js/editable.js +0 -438
  63. package/app/modules/vgdynamictable/js/expandable.js +0 -248
  64. package/app/modules/vgdynamictable/js/filters.js +0 -450
  65. package/app/modules/vgdynamictable/js/fixed.js +0 -566
  66. package/app/modules/vgdynamictable/js/options.js +0 -650
  67. package/app/modules/vgdynamictable/js/pagination.js +0 -623
  68. package/app/modules/vgdynamictable/js/search.js +0 -82
  69. package/app/modules/vgdynamictable/js/skeleton.js +0 -144
  70. package/app/modules/vgdynamictable/js/sortable.js +0 -442
  71. package/app/modules/vgdynamictable/js/summary-footer.js +0 -284
  72. package/app/modules/vgdynamictable/js/table-remote.js +0 -821
  73. package/app/modules/vgdynamictable/js/table-state.js +0 -243
  74. package/app/modules/vgdynamictable/js/table-url-state.js +0 -444
  75. package/app/modules/vgdynamictable/js/utils/common.js +0 -48
  76. package/app/modules/vgdynamictable/js/vgdynamictable.js +0 -3870
  77. package/app/modules/vgdynamictable/js/viewport.js +0 -322
  78. package/app/modules/vgdynamictable/readme.md +0 -251
  79. package/app/modules/vgdynamictable/scss/_actions.scss +0 -196
  80. package/app/modules/vgdynamictable/scss/_pagination.scss +0 -186
  81. package/app/modules/vgdynamictable/scss/_skeleton.scss +0 -63
  82. package/app/modules/vgdynamictable/scss/_sortable.scss +0 -66
  83. package/app/modules/vgdynamictable/scss/_table.scss +0 -137
  84. package/app/modules/vgdynamictable/scss/_variables.scss +0 -138
  85. package/app/modules/vgdynamictable/scss/vgdynamictable.scss +0 -264
@@ -1,144 +0,0 @@
1
- const skeletonMethods = {
2
- _renderLoadingSkeleton() {
3
- const body = this._getBody();
4
- const columns = this._getRenderedColumnsCount();
5
- const columnWidths = this._getCurrentColumnWidthsPx();
6
- const rowsCount = this._getSkeletonRowsCount();
7
- const rowHeight = this._getSkeletonRowHeightPx();
8
- const rowHeightStyle = Number.isFinite(rowHeight) && rowHeight > 0
9
- ? `height:${rowHeight}px;--vgdt-skeleton-row-height:${rowHeight}px;`
10
- : '';
11
-
12
- const rowHtml = Array.from({ length: rowsCount }).map((_, rowIndex) => {
13
- const cells = Array.from({ length: columns }).map((_, columnIndex) => {
14
- const width = Number.isFinite(columnWidths[columnIndex]) ? Math.round(columnWidths[columnIndex]) : 0;
15
- const widthStyle = width > 0
16
- ? ` style="width:${width}px;min-width:${width}px;max-width:${width}px;"`
17
- : '';
18
- return `<td${widthStyle}><div class="skeleton-cell"><div class="skeleton-line"></div></div></td>`;
19
- }).join('');
20
- return `<tr class="skeleton-row" style="${rowHeightStyle}--skeleton-delay:${(rowIndex * 0.08).toFixed(2)}s">${cells}</tr>`;
21
- }).join('');
22
-
23
- body.innerHTML = rowHtml;
24
- this._updatePanHintVisibility();
25
- this._refreshStickyAndFixedLayout();
26
- },
27
-
28
- _getRenderedColumnsCount() {
29
- const headerCount = this._getHeaderCells().length;
30
- const fieldsCount = this._fields.length;
31
- const resolved = Math.max(headerCount, fieldsCount);
32
- return resolved > 0 ? resolved : 1;
33
- },
34
-
35
- _getCurrentColumnWidthsPx() {
36
- const headers = this._getHeaderCells();
37
- const headerWidths = headers.map((header) => {
38
- if (!header || typeof header.getBoundingClientRect !== 'function') {
39
- return 0;
40
- }
41
- const rect = header.getBoundingClientRect();
42
- return rect && Number.isFinite(rect.width) && rect.width > 0 ? rect.width : 0;
43
- });
44
-
45
- if (headerWidths.some((width) => width > 0)) {
46
- return headerWidths;
47
- }
48
-
49
- const body = this._getBody();
50
- const firstRow = body && body.rows && body.rows.length ? body.rows[0] : null;
51
- if (!firstRow || !firstRow.cells || !firstRow.cells.length) {
52
- return [];
53
- }
54
-
55
- return Array.from(firstRow.cells).map((cell) => {
56
- if (!cell || typeof cell.getBoundingClientRect !== 'function') {
57
- return 0;
58
- }
59
- const rect = cell.getBoundingClientRect();
60
- return rect && Number.isFinite(rect.width) && rect.width > 0 ? rect.width : 0;
61
- });
62
- },
63
-
64
- _getSkeletonRowsCount() {
65
- const renderedRows = this._getRenderedDataRows();
66
- if (renderedRows.length > 0) {
67
- return renderedRows.length;
68
- }
69
-
70
- const body = this._getBody();
71
- const currentSkeletonRows = Array.from(body.rows || []).filter((row) => {
72
- return row && row.classList.contains('skeleton-row');
73
- });
74
- if (currentSkeletonRows.length > 0) {
75
- return currentSkeletonRows.length;
76
- }
77
-
78
- const loadingOptions = this._params.loading || {};
79
- const explicit = Number.parseInt(loadingOptions.skeleton, 10);
80
- if (Number.isFinite(explicit) && explicit > 0) {
81
- return explicit;
82
- }
83
-
84
- const fromPerPageControl = this._getPerPageControlValue();
85
- if (Number.isFinite(fromPerPageControl) && fromPerPageControl > 0) {
86
- return fromPerPageControl;
87
- }
88
-
89
- const fromState = Number.parseInt(this._pageState && this._pageState.perPage, 10);
90
- if (Number.isFinite(fromState) && fromState > 0) {
91
- return fromState;
92
- }
93
-
94
- const pagination = this._params.pagination || {};
95
- const fromParams = Number.parseInt(pagination.perPage, 10);
96
- if (Number.isFinite(fromParams) && fromParams > 0) {
97
- return fromParams;
98
- }
99
-
100
- return 5;
101
- },
102
-
103
- _getPerPageControlValue() {
104
- if (!this._parent) {
105
- return NaN;
106
- }
107
- const perPageControl = this._parent.querySelector('[data-per-page]');
108
- if (!perPageControl) {
109
- return NaN;
110
- }
111
- const value = Number.parseInt(perPageControl.value, 10);
112
- return Number.isFinite(value) ? this._clampPerPage(value, 10) : NaN;
113
- },
114
-
115
- _getSkeletonRowHeightPx() {
116
- const renderedRows = this._getRenderedDataRows();
117
- if (!renderedRows.length) {
118
- return null;
119
- }
120
-
121
- const firstRow = renderedRows[0];
122
- const rect = firstRow.getBoundingClientRect();
123
- if (!rect || !Number.isFinite(rect.height) || rect.height <= 0) {
124
- return null;
125
- }
126
-
127
- return Math.round(rect.height);
128
- },
129
-
130
- _getRenderedDataRows() {
131
- const body = this._getBody();
132
- return Array.from(body.rows || []).filter((row) => {
133
- if (!row || row.classList.contains('skeleton-row')) {
134
- return false;
135
- }
136
- if (row.querySelector('[data-table-state]')) {
137
- return false;
138
- }
139
- return true;
140
- });
141
- },
142
- };
143
-
144
- export default skeletonMethods;
@@ -1,442 +0,0 @@
1
- class Sortable {
2
- constructor(table, options = {}) {
3
- this._table = table;
4
- this._options = Object.assign({
5
- initialField: '',
6
- initialDir: 'asc',
7
- directions: ['asc', 'desc'],
8
- ascLabel: 'Сортировка по возрастанию',
9
- descLabel: 'Сортировка по убыванию',
10
- isColumnSortable: null,
11
- onChange: null,
12
- multiSort: false,
13
- multiSortWithShift: true,
14
- hideUnsortedArrows: false,
15
- }, options);
16
-
17
- this._headers = [];
18
- this._sorts = [];
19
- this._headerControls = new WeakMap();
20
- this._boundClick = this._handleClick.bind(this);
21
- this._boundKeyDown = this._handleKeyDown.bind(this);
22
- }
23
-
24
- init() {
25
- this._headers = this._getHeaders();
26
- if (!this._headers.length) {
27
- return;
28
- }
29
- this._syncControlsVisibilityMode();
30
-
31
- this._headers.forEach((header, index) => {
32
- if (!this._isSortable(header, index)) {
33
- header.setAttribute('aria-sort', 'none');
34
- return;
35
- }
36
-
37
- header.dataset.sortable = '1';
38
- header.tabIndex = 0;
39
- header.setAttribute('role', 'button');
40
- header.setAttribute('aria-sort', 'none');
41
- this._decorateHeader(header);
42
- });
43
-
44
- this._table.addEventListener('click', this._boundClick);
45
- this._table.addEventListener('keydown', this._boundKeyDown);
46
- this._applyInitialState();
47
- }
48
-
49
- setState(payload = {}) {
50
- if (Array.isArray(payload.sorts)) {
51
- const normalized = this._normalizeSorts(payload.sorts);
52
- this._setSorts(normalized, false);
53
- return;
54
- }
55
-
56
- const index = this._resolveIndex(payload);
57
- if (index < 0) {
58
- this._setSorts([], false);
59
- return;
60
- }
61
- if (!this._isSortable(this._headers[index], index)) {
62
- return;
63
- }
64
- this._setSorts([{ index, dir: this._normalizeDir(payload.dir) }], false);
65
- }
66
-
67
- refresh(payload = {}) {
68
- this._headers = this._getHeaders();
69
- if (!this._headers.length) {
70
- return;
71
- }
72
- this._syncControlsVisibilityMode();
73
-
74
- this._headers.forEach((header, index) => {
75
- if (!this._isSortable(header, index)) {
76
- header.removeAttribute('data-sortable');
77
- header.removeAttribute('data-sort-direction');
78
- header.removeAttribute('data-sort-priority');
79
- header.setAttribute('aria-sort', 'none');
80
- return;
81
- }
82
-
83
- header.dataset.sortable = '1';
84
- header.tabIndex = 0;
85
- header.setAttribute('role', 'button');
86
- if (!header.hasAttribute('aria-sort')) {
87
- header.setAttribute('aria-sort', 'none');
88
- }
89
- this._decorateHeader(header);
90
- });
91
-
92
- if (Array.isArray(payload.sorts)) {
93
- this._setSorts(this._normalizeSorts(payload.sorts), false);
94
- return;
95
- }
96
-
97
- this._setSorts(this._normalizeSorts(this._sorts), false);
98
- }
99
-
100
- _applyInitialState() {
101
- const index = this._resolveIndex({
102
- field: this._options.initialField,
103
- columnIndex: -1,
104
- });
105
- if (index < 0 || !this._isSortable(this._headers[index], index)) {
106
- this._setSorts([], false);
107
- return;
108
- }
109
- this._setSorts([{ index, dir: this._normalizeDir(this._options.initialDir) }], false);
110
- }
111
-
112
- _getHeaders() {
113
- const head = this._table.tHead || this._table.querySelector('thead');
114
- if (!head || !head.rows.length) {
115
- return [];
116
- }
117
- return Array.from(head.rows[0].cells);
118
- }
119
-
120
- _isSortable(header, index) {
121
- if (typeof this._options.isColumnSortable === 'function') {
122
- return Boolean(this._options.isColumnSortable(header, index));
123
- }
124
- return true;
125
- }
126
-
127
- _handleClick(event) {
128
- const header = event.target.closest('th');
129
- if (!header || !this._table.contains(header)) {
130
- return;
131
- }
132
-
133
- const index = this._headers.indexOf(header);
134
- if (index < 0 || !this._isSortable(header, index)) {
135
- return;
136
- }
137
-
138
- const arrow = event.target.closest('[data-sort-arrow]');
139
- const multiMode = this._isMultiMode(event);
140
- if (arrow && header.contains(arrow)) {
141
- const dir = this._normalizeDir(arrow.getAttribute('data-sort-arrow'));
142
- this._applyColumnDirection(index, dir, multiMode, true);
143
- return;
144
- }
145
-
146
- this._cycleColumn(index, multiMode);
147
- }
148
-
149
- _handleKeyDown(event) {
150
- if (event.key !== 'Enter' && event.key !== ' ') {
151
- return;
152
- }
153
-
154
- const header = event.target.closest('th');
155
- if (!header || !this._table.contains(header)) {
156
- return;
157
- }
158
-
159
- const index = this._headers.indexOf(header);
160
- if (index < 0 || !this._isSortable(header, index)) {
161
- return;
162
- }
163
-
164
- event.preventDefault();
165
- this._cycleColumn(index, this._isMultiMode(event));
166
- }
167
-
168
- _isMultiMode(event) {
169
- if (!this._options.multiSort) {
170
- return false;
171
- }
172
- if (!this._options.multiSortWithShift) {
173
- return true;
174
- }
175
- return Boolean(event && event.shiftKey);
176
- }
177
-
178
- _cycleColumn(index, multiMode) {
179
- const current = this._sorts.find((item) => item.index === index) || null;
180
- const directions = this._getDirections();
181
- const firstDir = directions[0];
182
- const secondDir = directions[1] || firstDir;
183
-
184
- if (!current) {
185
- this._applyColumnDirection(index, firstDir, multiMode, true);
186
- return;
187
- }
188
- if (current.dir === firstDir) {
189
- this._applyColumnDirection(index, secondDir, multiMode, true);
190
- return;
191
- }
192
- this._removeColumnDirection(index, multiMode, true);
193
- }
194
-
195
- _applyColumnDirection(index, dir, multiMode, emit) {
196
- let next = this._sorts.slice();
197
- next = next.filter((item) => item.index !== index);
198
- if (!multiMode) {
199
- next = [];
200
- }
201
- next.push({ index, dir: this._normalizeDir(dir) });
202
- this._setSorts(next, emit);
203
- }
204
-
205
- _removeColumnDirection(index, multiMode, emit) {
206
- let next = this._sorts.slice();
207
- next = next.filter((item) => item.index !== index);
208
- if (!multiMode) {
209
- next = [];
210
- }
211
- this._setSorts(next, emit);
212
- }
213
-
214
- _setSorts(nextSorts, emit) {
215
- this._sorts = this._normalizeSorts(nextSorts);
216
- const sortByIndex = new Map();
217
- this._sorts.forEach((item, index) => {
218
- sortByIndex.set(item.index, {
219
- dir: item.dir,
220
- priority: index + 1,
221
- });
222
- });
223
-
224
- this._headers.forEach((header, headerIndex) => {
225
- const sort = sortByIndex.has(headerIndex) ? sortByIndex.get(headerIndex) : null;
226
- if (!this._isSortable(header, headerIndex)) {
227
- header.removeAttribute('data-sort-direction');
228
- header.removeAttribute('data-sort-priority');
229
- header.setAttribute('aria-sort', 'none');
230
- return;
231
- }
232
-
233
- const controls = this._getHeaderControls(header);
234
- const controlsNode = controls.controlsNode;
235
- const ascButton = controls.ascButton;
236
- const descButton = controls.descButton;
237
- const shouldHideControls = Boolean(this._options.hideUnsortedArrows && !sort);
238
-
239
- if (controlsNode) {
240
- controlsNode.hidden = shouldHideControls;
241
- }
242
-
243
- if (sort) {
244
- header.dataset.sortDirection = sort.dir;
245
- header.dataset.sortPriority = String(sort.priority);
246
- header.setAttribute('aria-sort', sort.dir === 'asc' ? 'ascending' : 'descending');
247
- if (ascButton) ascButton.setAttribute('aria-pressed', sort.dir === 'asc' ? 'true' : 'false');
248
- if (descButton) descButton.setAttribute('aria-pressed', sort.dir === 'desc' ? 'true' : 'false');
249
- } else {
250
- header.removeAttribute('data-sort-direction');
251
- header.removeAttribute('data-sort-priority');
252
- header.setAttribute('aria-sort', 'none');
253
- if (ascButton) ascButton.setAttribute('aria-pressed', 'false');
254
- if (descButton) descButton.setAttribute('aria-pressed', 'false');
255
- }
256
- });
257
- this._syncSortedColumnsHighlight();
258
-
259
- if (!emit || typeof this._options.onChange !== 'function') {
260
- return;
261
- }
262
-
263
- const first = this._sorts[0] || null;
264
- this._options.onChange({
265
- field: first ? this._getFieldByIndex(first.index) : '',
266
- dir: first ? first.dir : this._normalizeDir(this._options.initialDir),
267
- columnIndex: first ? first.index : -1,
268
- sorts: this._sorts.map((item) => ({
269
- field: this._getFieldByIndex(item.index),
270
- dir: item.dir,
271
- columnIndex: item.index,
272
- })),
273
- });
274
- }
275
-
276
- _normalizeSorts(items) {
277
- const unique = [];
278
- const seen = new Set();
279
- (Array.isArray(items) ? items : []).forEach((item) => {
280
- const index = Number.parseInt(item.index ?? item.columnIndex, 10);
281
- if (!Number.isInteger(index) || index < 0 || index >= this._headers.length) {
282
- return;
283
- }
284
- if (!this._isSortable(this._headers[index], index)) {
285
- return;
286
- }
287
- if (seen.has(index)) {
288
- return;
289
- }
290
- seen.add(index);
291
- unique.push({
292
- index,
293
- dir: this._normalizeDir(item.dir),
294
- });
295
- });
296
- return unique;
297
- }
298
-
299
- _syncSortedColumnsHighlight() {
300
- const rows = this._getAllRows();
301
- if (!rows.length) {
302
- return;
303
- }
304
-
305
- rows.forEach((row) => {
306
- Array.from(row.cells || []).forEach((cell) => {
307
- cell.removeAttribute('data-sorted-column');
308
- cell.removeAttribute('data-sorted-priority');
309
- });
310
- });
311
-
312
- this._sorts.forEach((sort, index) => {
313
- rows.forEach((row) => {
314
- const cell = row.cells && row.cells[sort.index] ? row.cells[sort.index] : null;
315
- if (!cell) {
316
- return;
317
- }
318
- cell.setAttribute('data-sorted-column', '1');
319
- cell.setAttribute('data-sorted-priority', String(index + 1));
320
- });
321
- });
322
- }
323
-
324
- _getAllRows() {
325
- const rows = [];
326
- const sections = ['tHead', 'tBodies', 'tFoot'];
327
-
328
- sections.forEach((section) => {
329
- const value = this._table[section];
330
- if (!value) {
331
- return;
332
- }
333
- if (section === 'tBodies') {
334
- Array.from(value).forEach((body) => {
335
- rows.push(...Array.from(body.rows || []));
336
- });
337
- return;
338
- }
339
- rows.push(...Array.from(value.rows || []));
340
- });
341
-
342
- return rows;
343
- }
344
-
345
- _decorateHeader(header) {
346
- if (header.querySelector('.vgdt-sort-controls')) {
347
- this._headerControls.delete(header);
348
- return;
349
- }
350
-
351
- const label = document.createElement('span');
352
- label.className = 'vgdt-sort-label';
353
- while (header.firstChild) {
354
- label.appendChild(header.firstChild);
355
- }
356
-
357
- const controls = document.createElement('span');
358
- controls.className = 'vgdt-sort-controls';
359
- controls.innerHTML = `
360
- <button type="button" class="vgdt-sort-arrow vgdt-sort-arrow--asc" data-sort-arrow="asc" aria-label="${this._escapeAttr(this._options.ascLabel)}" aria-pressed="false">&#9650;</button>
361
- <button type="button" class="vgdt-sort-arrow vgdt-sort-arrow--desc" data-sort-arrow="desc" aria-label="${this._escapeAttr(this._options.descLabel)}" aria-pressed="false">&#9660;</button>
362
- `;
363
-
364
- label.appendChild(controls);
365
- header.appendChild(label);
366
- this._headerControls.delete(header);
367
- }
368
-
369
- _getHeaderControls(header) {
370
- if (this._headerControls.has(header)) {
371
- return this._headerControls.get(header);
372
- }
373
- const controls = {
374
- controlsNode: header.querySelector('.vgdt-sort-controls'),
375
- ascButton: header.querySelector('[data-sort-arrow="asc"]'),
376
- descButton: header.querySelector('[data-sort-arrow="desc"]'),
377
- };
378
- this._headerControls.set(header, controls);
379
- return controls;
380
- }
381
-
382
- _getFieldByIndex(index) {
383
- const header = this._headers[index];
384
- if (!header) {
385
- return '';
386
- }
387
- return (header.getAttribute('data-field') || '').trim();
388
- }
389
-
390
- _resolveIndex(payload = {}) {
391
- const field = (payload.field || '').toString().trim();
392
- if (field) {
393
- const byField = this._headers.findIndex((header) => {
394
- return (header.getAttribute('data-field') || '').trim() === field;
395
- });
396
- if (byField >= 0) {
397
- return byField;
398
- }
399
- }
400
-
401
- const byIndex = Number.parseInt(payload.columnIndex, 10);
402
- if (Number.isInteger(byIndex) && byIndex >= 0 && byIndex < this._headers.length) {
403
- return byIndex;
404
- }
405
-
406
- return -1;
407
- }
408
-
409
- _normalizeDir(dir) {
410
- const normalized = String(dir).toLowerCase();
411
- const directions = this._getDirections();
412
- return directions.includes(normalized) ? normalized : directions[0];
413
- }
414
-
415
- _getDirections() {
416
- const list = Array.isArray(this._options.directions) ? this._options.directions : ['asc', 'desc'];
417
- const normalized = list
418
- .map((item) => String(item).toLowerCase().trim())
419
- .filter((item) => item === 'asc' || item === 'desc');
420
- return normalized.length ? Array.from(new Set(normalized)) : ['asc', 'desc'];
421
- }
422
-
423
- _syncControlsVisibilityMode() {
424
- if (this._options.hideUnsortedArrows) {
425
- this._table.setAttribute('data-sort-hide-unsorted-arrows', '1');
426
- return;
427
- }
428
- this._table.removeAttribute('data-sort-hide-unsorted-arrows');
429
- }
430
-
431
- _escapeAttr(value) {
432
- return String(value)
433
- .replace(/&/g, '&amp;')
434
- .replace(/"/g, '&quot;')
435
- .replace(/</g, '&lt;')
436
- .replace(/>/g, '&gt;');
437
- }
438
- }
439
-
440
- export default Sortable;
441
-
442
-