vgapp 1.4.8 → 1.5.0

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 (86) 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 +29 -15
  11. package/app/modules/vgfiles/js/droppable.js +37 -31
  12. package/app/modules/vgfiles/js/vgfiles.js +10 -4
  13. package/app/modules/vgfiles/scss/_mixins.scss +12 -2
  14. package/app/modules/vgfiles/scss/_variables.scss +3 -1
  15. package/app/modules/vgfiles/scss/vgfiles.scss +55 -10
  16. package/app/modules/vgformsender/js/vgformsender.js +5 -2
  17. package/app/modules/vgloadmore/js/vgloadmore.js +35 -7
  18. package/app/modules/vgnestable/js/vgnestable.js +140 -0
  19. package/app/modules/vgnestable/scss/_variables.scss +16 -9
  20. package/app/modules/vgnestable/scss/vgnestable.scss +35 -2
  21. package/app/modules/vgtable/index.js +3 -0
  22. package/app/modules/vgtable/js/_columns.js +567 -0
  23. package/app/modules/vgtable/js/_expandable.js +242 -0
  24. package/app/modules/vgtable/js/_filters.js +264 -0
  25. package/app/modules/vgtable/js/_fixed-columns.js +249 -0
  26. package/app/modules/vgtable/js/_i18n.js +75 -0
  27. package/app/modules/vgtable/js/_options.js +428 -0
  28. package/app/modules/vgtable/js/_pagination.js +491 -0
  29. package/app/modules/vgtable/js/_panning.js +124 -0
  30. package/app/modules/vgtable/js/_params-groups.js +21 -0
  31. package/app/modules/vgtable/js/_remote.js +395 -0
  32. package/app/modules/vgtable/js/_row-reorder.js +268 -0
  33. package/app/modules/vgtable/js/_search.js +134 -0
  34. package/app/modules/vgtable/js/_selection.js +113 -0
  35. package/app/modules/vgtable/js/_skeleton.js +123 -0
  36. package/app/modules/vgtable/js/_sorting.js +340 -0
  37. package/app/modules/vgtable/js/_states.js +143 -0
  38. package/app/modules/vgtable/js/_sticky-header.js +218 -0
  39. package/app/modules/vgtable/js/_url-state.js +178 -0
  40. package/app/modules/vgtable/js/vgtable.js +1444 -0
  41. package/app/modules/vgtable/readme.md +922 -0
  42. package/app/modules/vgtable/scss/_columns.scss +52 -0
  43. package/app/modules/vgtable/scss/_expandable.scss +54 -0
  44. package/app/modules/vgtable/scss/_fixed-columns.scss +117 -0
  45. package/app/modules/vgtable/scss/_pagination.scss +191 -0
  46. package/app/modules/vgtable/scss/_row-reorder.scss +45 -0
  47. package/app/modules/vgtable/scss/_skeleton.scss +65 -0
  48. package/app/modules/vgtable/scss/_sorting.scss +89 -0
  49. package/app/modules/vgtable/scss/_states.scss +70 -0
  50. package/app/modules/vgtable/scss/_sticky-header.scss +127 -0
  51. package/app/modules/vgtable/scss/_variables.scss +296 -0
  52. package/app/modules/vgtable/scss/vgtable.scss +206 -0
  53. package/app/utils/js/components/placement.js +64 -10
  54. package/app/vgapp.js +3 -3
  55. package/build/vgapp.css +1 -1
  56. package/build/vgapp.css.map +1 -1
  57. package/build/vgapp.js +1 -1
  58. package/build/vgapp.js.map +1 -1
  59. package/index.js +1 -1
  60. package/index.scss +3 -3
  61. package/package.json +4 -4
  62. package/app/modules/vgdynamictable/index.js +0 -4
  63. package/app/modules/vgdynamictable/js/editable.js +0 -438
  64. package/app/modules/vgdynamictable/js/expandable.js +0 -248
  65. package/app/modules/vgdynamictable/js/filters.js +0 -450
  66. package/app/modules/vgdynamictable/js/fixed.js +0 -566
  67. package/app/modules/vgdynamictable/js/options.js +0 -650
  68. package/app/modules/vgdynamictable/js/pagination.js +0 -623
  69. package/app/modules/vgdynamictable/js/search.js +0 -82
  70. package/app/modules/vgdynamictable/js/skeleton.js +0 -144
  71. package/app/modules/vgdynamictable/js/sortable.js +0 -442
  72. package/app/modules/vgdynamictable/js/summary-footer.js +0 -284
  73. package/app/modules/vgdynamictable/js/table-remote.js +0 -821
  74. package/app/modules/vgdynamictable/js/table-state.js +0 -243
  75. package/app/modules/vgdynamictable/js/table-url-state.js +0 -444
  76. package/app/modules/vgdynamictable/js/utils/common.js +0 -48
  77. package/app/modules/vgdynamictable/js/vgdynamictable.js +0 -3870
  78. package/app/modules/vgdynamictable/js/viewport.js +0 -322
  79. package/app/modules/vgdynamictable/readme.md +0 -251
  80. package/app/modules/vgdynamictable/scss/_actions.scss +0 -196
  81. package/app/modules/vgdynamictable/scss/_pagination.scss +0 -186
  82. package/app/modules/vgdynamictable/scss/_skeleton.scss +0 -63
  83. package/app/modules/vgdynamictable/scss/_sortable.scss +0 -66
  84. package/app/modules/vgdynamictable/scss/_table.scss +0 -137
  85. package/app/modules/vgdynamictable/scss/_variables.scss +0 -138
  86. package/app/modules/vgdynamictable/scss/vgdynamictable.scss +0 -264
@@ -1,248 +0,0 @@
1
- class Expandable {
2
- constructor(table, params = {}) {
3
- this._table = table;
4
- this._params = params && typeof params === 'object' ? params : {};
5
- this._collapsed = new Set();
6
- this._boundClick = this._handleClick.bind(this);
7
- this._initialized = false;
8
- }
9
-
10
- init() {
11
- if (!this._isEnabled() || this._initialized) {
12
- return;
13
- }
14
- this._table.addEventListener('click', this._boundClick);
15
- this._initialized = true;
16
- this.refresh();
17
- }
18
-
19
- destroy() {
20
- if (!this._initialized) {
21
- return;
22
- }
23
- this._table.removeEventListener('click', this._boundClick);
24
- this._initialized = false;
25
- }
26
-
27
- refresh() {
28
- if (!this._isEnabled()) {
29
- return;
30
- }
31
-
32
- const rows = this._getRows();
33
- if (!rows.length) {
34
- return;
35
- }
36
-
37
- this._resetExpandHidden(rows);
38
- this._rememberBaseVisibility(rows);
39
-
40
- const idAttr = this._getIdAttr();
41
- const parentAttr = this._getParentAttr();
42
- const rowById = new Map();
43
- const parentById = new Map();
44
- const childrenByParent = new Map();
45
-
46
- rows.forEach((row, index) => {
47
- const fallbackId = `row-${index + 1}`;
48
- const rowId = String(row.getAttribute(idAttr) || fallbackId).trim() || fallbackId;
49
- row.setAttribute(idAttr, rowId);
50
- rowById.set(rowId, row);
51
-
52
- const parentId = String(row.getAttribute(parentAttr) || '').trim();
53
- parentById.set(rowId, parentId);
54
- if (parentId) {
55
- if (!childrenByParent.has(parentId)) {
56
- childrenByParent.set(parentId, []);
57
- }
58
- childrenByParent.get(parentId).push(rowId);
59
- }
60
- });
61
-
62
- const depthCache = new Map();
63
- const getDepth = (rowId) => {
64
- if (depthCache.has(rowId)) {
65
- return depthCache.get(rowId);
66
- }
67
- const parentId = String(parentById.get(rowId) || '').trim();
68
- if (!parentId) {
69
- depthCache.set(rowId, 0);
70
- return 0;
71
- }
72
- if (!rowById.has(parentId) || parentId === rowId) {
73
- depthCache.set(rowId, 0);
74
- return 0;
75
- }
76
- const depth = Math.max(0, getDepth(parentId) + 1);
77
- depthCache.set(rowId, depth);
78
- return depth;
79
- };
80
-
81
- const isAncestorCollapsed = (rowId) => {
82
- let parentId = String(parentById.get(rowId) || '').trim();
83
- while (parentId) {
84
- if (this._collapsed.has(parentId)) {
85
- return true;
86
- }
87
- parentId = String(parentById.get(parentId) || '').trim();
88
- }
89
- return false;
90
- };
91
-
92
- rowById.forEach((row, rowId) => {
93
- const depth = getDepth(rowId);
94
- row.setAttribute('data-expand-depth', String(depth));
95
- row.style.setProperty('--vgdt-expand-depth', String(depth));
96
-
97
- const hasChildren = childrenByParent.has(rowId) && childrenByParent.get(rowId).length > 0;
98
- const seeded = row.getAttribute('data-expand-seeded') === '1';
99
- if (hasChildren && !seeded) {
100
- if (this._isInitiallyCollapsed(row)) {
101
- this._collapsed.add(rowId);
102
- }
103
- row.setAttribute('data-expand-seeded', '1');
104
- }
105
- this._syncToggleNode(row, rowId, hasChildren);
106
-
107
- const baseHidden = row.getAttribute('data-expand-base-hidden') === '1';
108
- const collapseHidden = isAncestorCollapsed(rowId);
109
- const nextHidden = baseHidden || collapseHidden;
110
- row.hidden = nextHidden;
111
- if (collapseHidden) {
112
- row.setAttribute('data-expand-hidden', '1');
113
- } else {
114
- row.removeAttribute('data-expand-hidden');
115
- }
116
- });
117
- }
118
-
119
- _handleClick(event) {
120
- const toggleSelector = this._getToggleSelector();
121
- const rawTarget = event.target || null;
122
- const target = rawTarget && rawTarget.nodeType === 3 ? rawTarget.parentElement : rawTarget;
123
- const toggle = target && target.closest ? target.closest(toggleSelector) : null;
124
- if (!toggle || !this._table.contains(toggle)) {
125
- return;
126
- }
127
- event.preventDefault();
128
-
129
- const row = toggle.closest('tr');
130
- if (!row) {
131
- return;
132
- }
133
- const rowId = String(row.getAttribute(this._getIdAttr()) || '').trim();
134
- if (!rowId) {
135
- return;
136
- }
137
-
138
- const collapsed = !this._collapsed.has(rowId);
139
- if (collapsed) {
140
- this._collapsed.add(rowId);
141
- } else {
142
- this._collapsed.delete(rowId);
143
- }
144
- this.refresh();
145
-
146
- const payload = {
147
- id: rowId,
148
- collapsed,
149
- row,
150
- };
151
- if (typeof this._params.onToggle === 'function') {
152
- this._params.onToggle(payload);
153
- }
154
- }
155
-
156
- _syncToggleNode(row, rowId, hasChildren) {
157
- const selector = this._getToggleSelector();
158
- let toggle = row.querySelector(selector);
159
- if (!toggle && hasChildren) {
160
- const firstCell = row.cells && row.cells[0] ? row.cells[0] : null;
161
- if (firstCell) {
162
- toggle = document.createElement('button');
163
- toggle.type = 'button';
164
- toggle.className = 'vgdt-expand-toggle';
165
- toggle.setAttribute('data-expand-toggle', '1');
166
- firstCell.prepend(toggle);
167
- }
168
- }
169
- if (!toggle) {
170
- return;
171
- }
172
-
173
- // Keep visual spacing stable even if CSS bundle is outdated.
174
- toggle.style.marginInlineEnd = '10px';
175
- toggle.style.cursor = 'pointer';
176
-
177
- const nextNode = toggle.nextSibling;
178
- const hasLeadingSpace = nextNode
179
- && nextNode.nodeType === 3
180
- && /^\s/.test(String(nextNode.textContent || ''));
181
- if (!hasLeadingSpace) {
182
- toggle.after(document.createTextNode(' '));
183
- }
184
-
185
- toggle.setAttribute('data-expand-toggle', rowId);
186
- toggle.setAttribute('aria-expanded', this._collapsed.has(rowId) ? 'false' : 'true');
187
- toggle.hidden = !hasChildren;
188
- if (!hasChildren) {
189
- return;
190
- }
191
- const collapsed = this._collapsed.has(rowId);
192
- toggle.textContent = collapsed ? '+' : '−';
193
- }
194
-
195
- _getRows() {
196
- const body = this._table.tBodies && this._table.tBodies[0];
197
- if (!body) {
198
- return [];
199
- }
200
- return Array.from(body.rows).filter((row) => !row.querySelector('[data-table-state]'));
201
- }
202
-
203
- _resetExpandHidden(rows) {
204
- rows.forEach((row) => {
205
- if (row.getAttribute('data-expand-hidden') === '1') {
206
- row.hidden = false;
207
- row.removeAttribute('data-expand-hidden');
208
- }
209
- });
210
- }
211
-
212
- _rememberBaseVisibility(rows) {
213
- rows.forEach((row) => {
214
- row.setAttribute('data-expand-base-hidden', row.hidden ? '1' : '0');
215
- });
216
- }
217
-
218
- _isInitiallyCollapsed(row) {
219
- const attr = row.getAttribute('data-expand-collapsed');
220
- if (attr !== null) {
221
- return this._isTruthy(attr);
222
- }
223
- return Boolean(this._params.collapsed);
224
- }
225
-
226
- _isEnabled() {
227
- return Boolean(this._params.enable);
228
- }
229
-
230
- _getIdAttr() {
231
- return String(this._params.idAttr || 'data-expand-id').trim() || 'data-expand-id';
232
- }
233
-
234
- _getParentAttr() {
235
- return String(this._params.parentAttr || 'data-expand-parent-id').trim() || 'data-expand-parent-id';
236
- }
237
-
238
- _getToggleSelector() {
239
- return String(this._params.toggleSelector || '[data-expand-toggle]').trim() || '[data-expand-toggle]';
240
- }
241
-
242
- _isTruthy(value) {
243
- const normalized = String(value || '').toLowerCase().trim();
244
- return normalized !== '' && normalized !== '0' && normalized !== 'false' && normalized !== 'off' && normalized !== 'no';
245
- }
246
- }
247
-
248
- export default Expandable;
@@ -1,450 +0,0 @@
1
- import {normalizeNonNegativeInt, safeQuerySelector} from "./utils/common";
2
-
3
- class Filters {
4
- constructor(options = {}) {
5
- this._options = Object.assign({
6
- enabled: true,
7
- formSelector: '',
8
- formNode: null,
9
- debounceMs: 300,
10
- applyMode: 'auto', // auto | manual
11
- button: {
12
- apply: '[data-filter-apply]',
13
- reset: '[data-filter-reset]',
14
- },
15
- fieldAttr: 'data-filter-field',
16
- partAttr: 'data-filter-part',
17
- typeAttr: 'data-filter-type',
18
- valueAttr: 'data-filter-value',
19
- operatorAttr: 'data-filter-operator',
20
- defaultOperator: 'eq',
21
- skipEmpty: true,
22
- trimValues: true,
23
- emitOnInit: false,
24
- initialValues: {},
25
- onChange: null,
26
- onReset: null,
27
- }, options);
28
-
29
- this._form = null;
30
- this._timer = null;
31
- this._controls = [];
32
- this._boundInput = this._handleInput.bind(this);
33
- this._boundChange = this._handleChange.bind(this);
34
- this._boundClick = this._handleClick.bind(this);
35
- this._boundSubmit = this._handleSubmit.bind(this);
36
- }
37
-
38
- init() {
39
- if (!this._options.enabled) {
40
- return;
41
- }
42
-
43
- const form = this._resolveFormNode();
44
- if (!form) {
45
- return;
46
- }
47
-
48
- this._form = form;
49
- this._syncCachedNodes();
50
- this._form.addEventListener('input', this._boundInput);
51
- this._form.addEventListener('change', this._boundChange);
52
- this._form.addEventListener('click', this._boundClick);
53
- this._form.addEventListener('submit', this._boundSubmit);
54
-
55
- this.setValues(this._options.initialValues || {}, { emit: false });
56
- if (this._options.emitOnInit) {
57
- this._emit();
58
- }
59
- }
60
-
61
- destroy() {
62
- if (!this._form) {
63
- return;
64
- }
65
- this._form.removeEventListener('input', this._boundInput);
66
- this._form.removeEventListener('change', this._boundChange);
67
- this._form.removeEventListener('click', this._boundClick);
68
- this._form.removeEventListener('submit', this._boundSubmit);
69
- this._form = null;
70
- clearTimeout(this._timer);
71
- this._timer = null;
72
- this._controls = [];
73
- }
74
-
75
- getState() {
76
- return this._collectState();
77
- }
78
-
79
- getValues() {
80
- return this._collectState().params;
81
- }
82
-
83
- getFields() {
84
- const unique = new Set();
85
- this._getControls().forEach((control) => {
86
- const field = this._getField(control);
87
- if (field) {
88
- unique.add(field);
89
- }
90
- });
91
- return Array.from(unique);
92
- }
93
-
94
- setValues(nextValues = {}, options = {}) {
95
- if (!this._form) {
96
- return;
97
- }
98
- this._getControls().forEach((control) => {
99
- const field = this._getField(control);
100
- if (!field) {
101
- return;
102
- }
103
- const part = this._getPart(control);
104
- const key = part === 'operator' ? `${field}_op` : field;
105
- const hasOwn = Object.prototype.hasOwnProperty.call(nextValues, key);
106
- const nextValue = hasOwn ? nextValues[key] : '';
107
- this._setControlValue(control, nextValue);
108
- });
109
- if (options.emit) {
110
- this._emit();
111
- }
112
- }
113
-
114
- _resolveFormNode() {
115
- if (this._options.formNode && this._options.formNode.nodeType === 1) {
116
- return this._options.formNode;
117
- }
118
- const selector = String(this._options.formSelector || '').trim();
119
- if (!selector) {
120
- return null;
121
- }
122
- return safeQuerySelector(selector);
123
- }
124
-
125
- _handleInput(event) {
126
- if (!this._isFilterControl(event.target)) {
127
- return;
128
- }
129
- if (this._isManualMode()) {
130
- return;
131
- }
132
- const type = String(event.target.type || '').toLowerCase();
133
- if (type === 'checkbox' || type === 'radio' || event.target.tagName === 'SELECT') {
134
- this._emit();
135
- return;
136
- }
137
- clearTimeout(this._timer);
138
- this._timer = setTimeout(() => this._emit(), normalizeNonNegativeInt(this._options.debounceMs, 300));
139
- }
140
-
141
- _handleChange(event) {
142
- if (!this._isFilterControl(event.target)) {
143
- return;
144
- }
145
- if (this._isManualMode()) {
146
- return;
147
- }
148
- clearTimeout(this._timer);
149
- this._emit();
150
- }
151
-
152
- _handleClick(event) {
153
- if (!this._form) {
154
- return;
155
- }
156
- const button = this._options.button || {};
157
- const applySelector = String(button.apply || '[data-filter-apply]').trim();
158
- const resetSelector = String(button.reset || '[data-filter-reset]').trim();
159
-
160
- const applyButton = applySelector ? event.target.closest(applySelector) : null;
161
- if (applyButton) {
162
- event.preventDefault();
163
- clearTimeout(this._timer);
164
- this._emit();
165
- return;
166
- }
167
-
168
- const resetButton = resetSelector ? event.target.closest(resetSelector) : null;
169
- if (!resetButton) {
170
- return;
171
- }
172
- event.preventDefault();
173
- this._reset();
174
- if (typeof this._options.onReset === 'function') {
175
- this._options.onReset();
176
- }
177
- clearTimeout(this._timer);
178
- this._emit();
179
- }
180
-
181
- _handleSubmit(event) {
182
- if (!this._isManualMode()) {
183
- return;
184
- }
185
- event.preventDefault();
186
- clearTimeout(this._timer);
187
- this._emit();
188
- }
189
-
190
- _emit() {
191
- if (!this._form || typeof this._options.onChange !== 'function') {
192
- return;
193
- }
194
- this._options.onChange(this._collectState());
195
- }
196
-
197
- _collectState() {
198
- const groups = new Map();
199
- this._getControls().forEach((control) => {
200
- const field = this._getField(control);
201
- if (!field) {
202
- return;
203
- }
204
- if (!groups.has(field)) {
205
- groups.set(field, {
206
- field,
207
- type: this._getType(control),
208
- operator: this._getStaticOperator(control),
209
- value: '',
210
- values: [],
211
- });
212
- }
213
- const item = groups.get(field);
214
- const part = this._getPart(control);
215
- const value = this._readControlValue(control);
216
- const controlType = String(control.type || '').toLowerCase();
217
- if (part === 'operator') {
218
- item.operator = String(value || '').trim() || item.operator || this._getDefaultOperator();
219
- return;
220
- }
221
- if (part === 'type') {
222
- item.type = String(value || '').trim() || item.type || 'text';
223
- return;
224
- }
225
- // Ignore unchecked radio/checkbox values so they do not wipe selected values in a group.
226
- if ((controlType === 'checkbox' || controlType === 'radio') && value === '') {
227
- return;
228
- }
229
- if (Array.isArray(value)) {
230
- item.values = value.slice();
231
- item.value = item.values.join(',');
232
- return;
233
- }
234
- item.value = value;
235
- });
236
-
237
- const filters = {};
238
- const params = {};
239
- groups.forEach((item, field) => {
240
- const normalized = this._normalizeFilterItem(item);
241
- if (!normalized) {
242
- return;
243
- }
244
- filters[field] = normalized;
245
-
246
- if (normalized.values.length > 0) {
247
- params[field] = normalized.values.slice();
248
- } else {
249
- params[field] = normalized.value;
250
- }
251
- if (normalized.operator) {
252
- params[`${field}_op`] = normalized.operator;
253
- }
254
- });
255
-
256
- return {
257
- filters,
258
- params,
259
- fields: Object.keys(filters),
260
- meta: {
261
- count: Object.keys(filters).length,
262
- },
263
- };
264
- }
265
-
266
- _normalizeFilterItem(item) {
267
- const type = String(item.type || 'text').trim() || 'text';
268
- const operator = String(item.operator || this._getDefaultOperator()).trim();
269
- let value = item.value;
270
- let values = Array.isArray(item.values) ? item.values.slice() : [];
271
-
272
- if (this._options.trimValues) {
273
- if (typeof value === 'string') {
274
- value = value.trim();
275
- }
276
- values = values.map((entry) => String(entry || '').trim()).filter((entry) => entry !== '');
277
- }
278
-
279
- if (this._options.skipEmpty) {
280
- const isEmptyArray = values.length === 0;
281
- const isEmptyValue = value === undefined || value === null || String(value) === '';
282
- if (isEmptyArray && isEmptyValue) {
283
- return null;
284
- }
285
- }
286
-
287
- return {
288
- field: String(item.field || '').trim(),
289
- type,
290
- operator,
291
- value: value === undefined || value === null ? '' : value,
292
- values,
293
- };
294
- }
295
-
296
- _setControlValue(control, nextValue) {
297
- const type = String(control.type || '').toLowerCase();
298
- if (type === 'checkbox') {
299
- const normalized = String(nextValue || '').toLowerCase();
300
- control.checked = normalized === String(control.value || '').toLowerCase()
301
- || normalized === '1'
302
- || normalized === 'true'
303
- || normalized === 'on';
304
- return;
305
- }
306
- if (type === 'radio') {
307
- control.checked = String(control.value || '') === String(nextValue || '');
308
- return;
309
- }
310
- if (control.tagName === 'SELECT' && control.multiple) {
311
- const rawValues = Array.isArray(nextValue)
312
- ? nextValue
313
- : String(nextValue || '').split(',');
314
- const selected = new Set(rawValues
315
- .map((value) => String(value || '').trim())
316
- .filter((value) => value !== ''));
317
- Array.from(control.options || []).forEach((option) => {
318
- option.selected = selected.has(String(option.value || '').trim());
319
- });
320
- return;
321
- }
322
- control.value = String(nextValue || '');
323
- }
324
-
325
- _readControlValue(control) {
326
- if (control.tagName === 'SELECT' && control.multiple) {
327
- return Array.from(control.selectedOptions || [])
328
- .map((option) => String(option.value || '').trim())
329
- .filter((value) => value !== '');
330
- }
331
- const type = String(control.type || '').toLowerCase();
332
- if (type === 'checkbox') {
333
- return control.checked ? (control.value || '1') : '';
334
- }
335
- if (type === 'radio') {
336
- return control.checked ? (control.value || '') : '';
337
- }
338
- return String(control.value || '');
339
- }
340
-
341
- _syncCachedNodes() {
342
- if (!this._form) {
343
- this._controls = [];
344
- return;
345
- }
346
- const attr = this._getFieldAttr();
347
- this._controls = Array.from(this._form.querySelectorAll(`[${attr}]`))
348
- .filter((control) => this._isSupportedControl(control));
349
- }
350
-
351
- _getControls() {
352
- if (!this._form) {
353
- return [];
354
- }
355
- if (!Array.isArray(this._controls) || this._controls.length === 0) {
356
- this._syncCachedNodes();
357
- }
358
- return this._controls;
359
- }
360
-
361
- _reset() {
362
- this._getControls().forEach((control) => {
363
- const type = String(control.type || '').toLowerCase();
364
- if (type === 'checkbox' || type === 'radio') {
365
- control.checked = false;
366
- return;
367
- }
368
- if (control.tagName === 'SELECT') {
369
- if (control.multiple) {
370
- Array.from(control.options || []).forEach((option) => {
371
- option.selected = false;
372
- });
373
- return;
374
- }
375
- control.selectedIndex = 0;
376
- return;
377
- }
378
- control.value = '';
379
- });
380
- }
381
-
382
- _getFieldAttr() {
383
- return String(this._options.fieldAttr || 'data-filter-field').trim() || 'data-filter-field';
384
- }
385
-
386
- _getPartAttr() {
387
- return String(this._options.partAttr || 'data-filter-part').trim() || 'data-filter-part';
388
- }
389
-
390
- _getTypeAttr() {
391
- return String(this._options.typeAttr || 'data-filter-type').trim() || 'data-filter-type';
392
- }
393
-
394
- _getValueAttr() {
395
- return String(this._options.valueAttr || 'data-filter-value').trim() || 'data-filter-value';
396
- }
397
-
398
- _getOperatorAttr() {
399
- return String(this._options.operatorAttr || 'data-filter-operator').trim() || 'data-filter-operator';
400
- }
401
-
402
- _getDefaultOperator() {
403
- return String(this._options.defaultOperator || 'eq').trim() || 'eq';
404
- }
405
-
406
- _getField(control) {
407
- return String(control.getAttribute(this._getFieldAttr()) || '').trim();
408
- }
409
-
410
- _getPart(control) {
411
- const part = String(control.getAttribute(this._getPartAttr()) || 'value').toLowerCase().trim();
412
- if (part === 'operator' || part === 'type') {
413
- return part;
414
- }
415
- return 'value';
416
- }
417
-
418
- _getType(control) {
419
- const type = String(control.getAttribute(this._getTypeAttr()) || '').toLowerCase().trim();
420
- return type || 'text';
421
- }
422
-
423
- _getStaticOperator(control) {
424
- const operator = String(control.getAttribute(this._getOperatorAttr()) || '').trim();
425
- return operator || '';
426
- }
427
-
428
- _isFilterControl(node) {
429
- return Boolean(
430
- node
431
- && this._isSupportedControl(node)
432
- && typeof node.getAttribute === 'function'
433
- && String(node.getAttribute(this._getFieldAttr()) || '').trim() !== ''
434
- );
435
- }
436
-
437
- _isSupportedControl(node) {
438
- if (!node || typeof node.tagName !== 'string') {
439
- return false;
440
- }
441
- const tag = String(node.tagName || '').toUpperCase();
442
- return tag === 'INPUT' || tag === 'SELECT' || tag === 'TEXTAREA';
443
- }
444
- _isManualMode() {
445
- const mode = String(this._options.applyMode || 'auto').toLowerCase().trim();
446
- return mode === 'manual';
447
- }
448
- }
449
-
450
- export default Filters;