vgapp 1.2.4 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +66 -7
  2. package/README.md +2 -1
  3. package/agents.md +2 -2
  4. package/app/modules/base-module.js +87 -10
  5. package/app/modules/vgalert/js/vgalert.js +133 -202
  6. package/app/modules/vgalert/readme.md +105 -46
  7. package/app/modules/vgalert/scss/vgalert.scss +18 -0
  8. package/app/modules/vgdynamictable/index.js +5 -0
  9. package/app/modules/vgdynamictable/js/editable.js +438 -0
  10. package/app/modules/vgdynamictable/js/expandable.js +248 -0
  11. package/app/modules/vgdynamictable/js/filters.js +450 -0
  12. package/app/modules/vgdynamictable/js/fixed.js +566 -0
  13. package/app/modules/vgdynamictable/js/options.js +646 -0
  14. package/app/modules/vgdynamictable/js/pagination.js +623 -0
  15. package/app/modules/vgdynamictable/js/search.js +82 -0
  16. package/app/modules/vgdynamictable/js/skeleton.js +136 -0
  17. package/app/modules/vgdynamictable/js/sortable.js +442 -0
  18. package/app/modules/vgdynamictable/js/summary-footer.js +284 -0
  19. package/app/modules/vgdynamictable/js/table-remote.js +821 -0
  20. package/app/modules/vgdynamictable/js/table-state.js +243 -0
  21. package/app/modules/vgdynamictable/js/table-url-state.js +444 -0
  22. package/app/modules/vgdynamictable/js/utils/common.js +48 -0
  23. package/app/modules/vgdynamictable/js/vgdynamictable.js +3829 -0
  24. package/app/modules/vgdynamictable/js/viewport.js +322 -0
  25. package/app/modules/vgdynamictable/readme.md +251 -0
  26. package/app/modules/vgdynamictable/scss/_actions.scss +193 -0
  27. package/app/modules/vgdynamictable/scss/_pagination.scss +183 -0
  28. package/app/modules/vgdynamictable/scss/_skeleton.scss +60 -0
  29. package/app/modules/vgdynamictable/scss/_sortable.scss +63 -0
  30. package/app/modules/vgdynamictable/scss/_table.scss +157 -0
  31. package/app/modules/vgdynamictable/scss/_variables.scss +130 -0
  32. package/app/modules/vgdynamictable/scss/vgdynamictable.scss +267 -0
  33. package/app/modules/vgrangeslider/index.js +3 -0
  34. package/app/modules/vgrangeslider/js/skins.js +222 -0
  35. package/app/modules/vgrangeslider/js/vgrangeslider.js +704 -0
  36. package/app/modules/vgrangeslider/readme.md +523 -0
  37. package/app/modules/vgrangeslider/scss/_variables.scss +53 -0
  38. package/app/modules/vgrangeslider/scss/vgrangeslider.scss +240 -0
  39. package/app/modules/vgtoast/js/vgtoast.js +111 -111
  40. package/app/modules/vgtooltip/index.js +3 -0
  41. package/app/modules/vgtooltip/js/vgtooltip.js +493 -0
  42. package/app/modules/vgtooltip/readme.md +181 -0
  43. package/app/modules/vgtooltip/scss/_variables.scss +15 -0
  44. package/app/modules/vgtooltip/scss/vgtooltip.scss +64 -0
  45. package/app/utils/js/components/ajax.js +116 -7
  46. package/app/utils/js/components/placement.js +112 -41
  47. package/build/vgapp.css +1 -1
  48. package/build/vgapp.css.map +1 -1
  49. package/index.js +20 -17
  50. package/index.scss +9 -0
  51. package/package.json +1 -1
@@ -0,0 +1,243 @@
1
+ const tableStateMethods = {
2
+ _renderRemoteRows(rows) {
3
+ const body = this._getBody();
4
+
5
+ if (!rows.length) {
6
+ const message = this._getTableMessage('stateEmpty', 'Ничего нет');
7
+ this._renderStateRow(message, 'empty');
8
+ return;
9
+ }
10
+
11
+ this._setFixedColumnsSuppressed(false);
12
+ this._clearStateMode();
13
+ body.innerHTML = rows.map((row) => {
14
+ const cells = this._fields.map((field) => {
15
+ const rawValue = row && Object.prototype.hasOwnProperty.call(row, field) ? row[field] : '';
16
+ const prepared = this._formatFieldValue(field, rawValue);
17
+ return `<td>${this._escapeHtml(prepared)}</td>`;
18
+ });
19
+ return `<tr>${cells.join('')}</tr>`;
20
+ }).join('');
21
+ this._updatePanHintVisibility();
22
+ },
23
+
24
+ _renderStateRow(message, state) {
25
+ const body = this._getBody();
26
+ const columns = this._getRenderedColumnsCount();
27
+ const retryButton = state === 'error'
28
+ ? `<div class="vgdt-state-actions"><button type="button" class="vgdt-state-reset" data-state-retry>${this._escapeHtml(this._getTableMessage('retry', 'Retry'))}</button></div>`
29
+ : '';
30
+ const illustration = this._buildStateIllustrationMarkup(state);
31
+ body.innerHTML = `<tr><td colspan="${columns}" data-table-state="${state}"><div class="vgdt-state">${illustration}<div class="vgdt-state-text">${this._escapeHtml(message)}</div>${retryButton}</div></td></tr>`;
32
+ const stateCell = body.querySelector('[data-table-state]');
33
+ this._setFixedColumnsSuppressed(true);
34
+ this._setStateMode(state);
35
+ this._ensureStateRowVisible(stateCell);
36
+ this._announce(message);
37
+ this._clearFooter();
38
+ this._updatePanHintVisibility();
39
+ this._refreshStickyAndFixedLayout();
40
+ },
41
+
42
+ _hasRenderableRowsInBody(body) {
43
+ if (!body || !body.rows || !body.rows.length) {
44
+ return false;
45
+ }
46
+ return Array.from(body.rows).some((row) => {
47
+ const cells = Array.from(row.cells || []);
48
+ if (!cells.length) {
49
+ return false;
50
+ }
51
+ return cells.some((cell) => {
52
+ if (!cell) {
53
+ return false;
54
+ }
55
+ const text = String(cell.textContent || '').trim();
56
+ return text !== '' || cell.children.length > 0;
57
+ });
58
+ });
59
+ },
60
+
61
+ _setFixedColumnsSuppressed(value) {
62
+ this._fixedColumnsSuppressed = Boolean(value);
63
+ },
64
+
65
+ _setStateMode(state) {
66
+ if (!this._parent) {
67
+ return;
68
+ }
69
+ this._parent.setAttribute('data-state-mode', String(state || ''));
70
+ },
71
+
72
+ _clearStateMode() {
73
+ if (!this._parent) {
74
+ return;
75
+ }
76
+ this._parent.removeAttribute('data-state-mode');
77
+ },
78
+
79
+ _buildStateIllustrationMarkup(state) {
80
+ const stateOptions = this._params.state && typeof this._params.state === 'object'
81
+ ? this._params.state
82
+ : {};
83
+ const optionKey = state === 'error' ? 'errorIllustration' : 'emptyIllustration';
84
+ const attrName = state === 'error'
85
+ ? 'data-state-error-illustration'
86
+ : 'data-state-empty-illustration';
87
+ const optionValue = stateOptions[optionKey] || '';
88
+ const attrValue = this._element ? this._element.getAttribute(attrName) : '';
89
+ const src = String(optionValue || attrValue || '').trim();
90
+ if (!src) {
91
+ return '<div class="vgdt-state-illustration" aria-hidden="true"></div>';
92
+ }
93
+ const inlineSvg = this._extractInlineSvgMarkup(src);
94
+ if (inlineSvg) {
95
+ return `<div class="vgdt-state-illustration" aria-hidden="true">${inlineSvg}</div>`;
96
+ }
97
+ const alt = state === 'error' ? 'Error' : 'Empty';
98
+ return `<div class="vgdt-state-illustration"><img src="${this._escapeHtml(src)}" alt="${alt}" loading="lazy"></div>`;
99
+ },
100
+
101
+ _extractInlineSvgMarkup(value) {
102
+ const raw = String(value || '').trim();
103
+ if (!raw) {
104
+ return '';
105
+ }
106
+ if (/^<svg[\s>]/i.test(raw)) {
107
+ return raw;
108
+ }
109
+
110
+ const decoded = this._decodeHtmlEntities(raw);
111
+ if (/^<svg[\s>]/i.test(decoded)) {
112
+ return decoded;
113
+ }
114
+ return '';
115
+ },
116
+
117
+ _decodeHtmlEntities(value) {
118
+ return String(value || '')
119
+ .replace(/&lt;/g, '<')
120
+ .replace(/&gt;/g, '>')
121
+ .replace(/&quot;/g, '"')
122
+ .replace(/&#39;/g, '\'')
123
+ .replace(/&amp;/g, '&');
124
+ },
125
+
126
+ _ensureStateRowVisible(stateCell) {
127
+ if (!stateCell) {
128
+ return;
129
+ }
130
+ const minHeight = this._getStateBlockMinHeight();
131
+ stateCell.style.minHeight = `${minHeight}px`;
132
+ if (this._tableViewport) {
133
+ this._tableViewport.scrollTop = 0;
134
+ this._tableViewport.scrollLeft = 0;
135
+ }
136
+ if (typeof window === 'undefined') {
137
+ return;
138
+ }
139
+ const rect = stateCell.getBoundingClientRect();
140
+ const vh = window.innerHeight || 0;
141
+ if (rect.top < 0 || (vh > 0 && rect.bottom > vh)) {
142
+ stateCell.scrollIntoView({ block: 'center', inline: 'nearest' });
143
+ }
144
+ },
145
+
146
+ _getStateBlockMinHeight() {
147
+ if (typeof window === 'undefined') {
148
+ return 180;
149
+ }
150
+ const vh = window.innerHeight || 0;
151
+ const isMobile = (window.innerWidth || 0) <= 768;
152
+ const ratio = isMobile ? 0.52 : 0.34;
153
+ const computed = vh > 0 ? Math.round(vh * ratio) : 0;
154
+ return Math.max(160, computed);
155
+ },
156
+
157
+ _bindTableStateActions() {
158
+ this._element.addEventListener('click', (event) => {
159
+ const reset = event.target.closest('[data-state-reset]');
160
+ if (reset) {
161
+ event.preventDefault();
162
+ this._resetFiltersAndSearch();
163
+ return;
164
+ }
165
+ const retry = event.target.closest('[data-state-retry]');
166
+ if (retry) {
167
+ event.preventDefault();
168
+ this._reloadCurrentPage();
169
+ }
170
+ });
171
+ },
172
+
173
+ _resetFiltersAndSearch() {
174
+ if (!this._isRemote) {
175
+ return;
176
+ }
177
+
178
+ this._remoteParams = {};
179
+ this._activeFilters = {};
180
+ this._sortState = Object.assign({}, this._sortState, { field: '', dir: 'asc', columnIndex: -1, sorts: [] });
181
+ if (this._sortable) {
182
+ this._sortable.setState({ sorts: [] });
183
+ }
184
+
185
+ const searchSelector = this._getSearchInputSelector();
186
+ if (searchSelector) {
187
+ const searchInput = this._getSearchInputNode(searchSelector);
188
+ if (searchInput) {
189
+ searchInput.value = '';
190
+ }
191
+ }
192
+
193
+ if (this._filters && typeof this._filters.setValues === 'function') {
194
+ this._filters.setValues({}, { emit: false });
195
+ }
196
+
197
+ const perPage = this._pageState.perPage || this._normalizePositiveInt(this._params.pagination.perPage, 10);
198
+ this._pageState = { page: 1, perPage };
199
+ this._emitAction('reset', {
200
+ page: 1,
201
+ perPage,
202
+ });
203
+ this._loadRemotePage(1, perPage);
204
+ },
205
+
206
+ _reloadCurrentPage() {
207
+ if (!this._isRemote) {
208
+ return;
209
+ }
210
+ const page = this._pageState.page || 1;
211
+ const perPage = this._pageState.perPage || this._normalizePositiveInt(this._params.pagination.perPage, 10);
212
+ this._loadRemotePage(page, perPage);
213
+ },
214
+
215
+ _hasActiveRemoteFilters() {
216
+ if (!this._isRemote) {
217
+ return false;
218
+ }
219
+ return Object.keys(this._remoteParams || {}).length > 0;
220
+ },
221
+
222
+ _ensureLiveRegion() {
223
+ if (this._liveRegion || !this._parent) {
224
+ return;
225
+ }
226
+ const node = document.createElement('div');
227
+ node.className = 'vgdt-live-region';
228
+ node.setAttribute('aria-live', 'polite');
229
+ node.setAttribute('aria-atomic', 'true');
230
+ this._parent.appendChild(node);
231
+ this._liveRegion = node;
232
+ },
233
+
234
+ _announce(message) {
235
+ if (!this._liveRegion) {
236
+ return;
237
+ }
238
+ this._liveRegion.textContent = String(message || '');
239
+ },
240
+ };
241
+
242
+ export default tableStateMethods;
243
+
@@ -0,0 +1,444 @@
1
+ import {normalizeBooleanOption, normalizeEnabledFlag, safeQuerySelector, toQueryParamValue} from "./utils/common";
2
+
3
+ const tableUrlStateMethods = {
4
+ _syncUrlState() {
5
+ if (!this._isFiltersUrlStateEnabled() || !this._isFiltersUrlStateWriteOnChange()) {
6
+ return;
7
+ }
8
+ if (typeof window === 'undefined' || !window.history || !window.location) {
9
+ return;
10
+ }
11
+
12
+ let url;
13
+ try {
14
+ url = new URL(window.location.href);
15
+ } catch (error) {
16
+ this._emitAction('urlstateerror', {
17
+ source: 'write',
18
+ error,
19
+ });
20
+ return;
21
+ }
22
+
23
+ const nextState = this._collectUrlState();
24
+ const managedKeys = this._getManagedUrlStateKeys();
25
+ managedKeys.forEach((key) => {
26
+ url.searchParams.delete(key);
27
+ });
28
+
29
+ Object.keys(nextState).forEach((key) => {
30
+ const rawValue = nextState[key];
31
+ const value = toQueryParamValue(rawValue);
32
+ if (value === undefined || value === null || value === '') {
33
+ return;
34
+ }
35
+ url.searchParams.set(key, String(value));
36
+ });
37
+
38
+ const nextUrl = `${url.pathname}${url.search}${url.hash}`;
39
+ const currentUrl = `${window.location.pathname}${window.location.search}${window.location.hash}`;
40
+ if (nextUrl === currentUrl) {
41
+ return;
42
+ }
43
+
44
+ const mode = this._getUrlStateMode();
45
+ if (mode === 'push') {
46
+ window.history.pushState({}, '', nextUrl);
47
+ } else {
48
+ window.history.replaceState({}, '', nextUrl);
49
+ }
50
+
51
+ this._emitAction('urlstatewrite', {
52
+ mode,
53
+ state: Object.assign({}, nextState),
54
+ url: nextUrl,
55
+ });
56
+ },
57
+
58
+ _collectUrlState() {
59
+ const next = {};
60
+ const config = this._getFiltersUrlStateConfig();
61
+ const prefix = this._getFiltersUrlPrefix();
62
+ const searchParam = this._getSearchParamName();
63
+
64
+ if (searchParam && Object.prototype.hasOwnProperty.call(this._remoteParams || {}, searchParam)) {
65
+ next[searchParam] = this._remoteParams[searchParam];
66
+ }
67
+
68
+ this._getFilterFieldKeys().forEach((field) => {
69
+ const valueKey = field;
70
+ const operatorKey = `${field}_op`;
71
+ const urlValueKey = this._prefixFilterParamKey(valueKey, prefix);
72
+ const urlOperatorKey = this._prefixFilterParamKey(operatorKey, prefix);
73
+ if (Object.prototype.hasOwnProperty.call(this._remoteParams || {}, valueKey)) {
74
+ next[urlValueKey] = this._remoteParams[valueKey];
75
+ }
76
+ if (Object.prototype.hasOwnProperty.call(this._remoteParams || {}, operatorKey)) {
77
+ next[urlOperatorKey] = this._remoteParams[operatorKey];
78
+ }
79
+ });
80
+
81
+ if (this._isPaginationEnabled()) {
82
+ const page = this._normalizePositiveInt(this._pageState.page, 1);
83
+ const fallbackPerPage = this._normalizePositiveInt(this._params.pagination.perPage, 10);
84
+ const perPage = this._normalizePositiveInt(this._pageState.perPage, fallbackPerPage);
85
+ next[String(config.pageKey || 'page')] = page;
86
+ next[String(config.perPageKey || 'perPage')] = perPage;
87
+ }
88
+
89
+ if (this._params.sortable && this._params.sortable.enable) {
90
+ const sorts = this._getNormalizedSorts(this._sortState.sorts || []);
91
+ const valid = sorts
92
+ .filter((item) => String(item.field || '').trim() !== '')
93
+ .map((item) => `${item.field}:${this._normalizeSortDir(item.dir)}`);
94
+ if (valid.length > 0) {
95
+ next[String(config.sortKey || 'sort')] = valid.join(',');
96
+ }
97
+ }
98
+
99
+ return next;
100
+ },
101
+
102
+ _getManagedUrlStateKeys() {
103
+ const keys = new Set();
104
+ const config = this._getFiltersUrlStateConfig();
105
+ const prefix = this._getFiltersUrlPrefix();
106
+
107
+ keys.add(this._getSearchParamName());
108
+ this._getFilterFieldKeys().forEach((field) => {
109
+ keys.add(this._prefixFilterParamKey(field, prefix));
110
+ keys.add(this._prefixFilterParamKey(`${field}_op`, prefix));
111
+ });
112
+
113
+ if (this._isPaginationEnabled()) {
114
+ keys.add(String(config.pageKey || 'page'));
115
+ keys.add(String(config.perPageKey || 'perPage'));
116
+ }
117
+ if (this._params.sortable && this._params.sortable.enable) {
118
+ keys.add(String(config.sortKey || 'sort'));
119
+ }
120
+
121
+ return Array.from(keys).filter(Boolean);
122
+ },
123
+
124
+ _isUrlStateEnabled() {
125
+ return this._isFiltersUrlStateEnabled();
126
+ },
127
+
128
+ _getUrlStateMode() {
129
+ const config = this._getFiltersUrlStateConfig();
130
+ const attr = this._element.getAttribute('data-filters-urlstate-history-mode');
131
+ const mode = String(attr !== null ? attr : (config.historyMode || 'replace')).toLowerCase().trim();
132
+ return mode === 'push' ? 'push' : 'replace';
133
+ },
134
+
135
+ _isUrlStateIncludePagination() {
136
+ return this._isPaginationEnabled();
137
+ },
138
+
139
+ _isUrlStateIncludeSort() {
140
+ return Boolean(this._params.sortable && this._params.sortable.enable);
141
+ },
142
+
143
+ _bindPopState() {
144
+ if (!this._isRemote || !this._isFiltersUrlStateEnabled()) {
145
+ return;
146
+ }
147
+ if (typeof window === 'undefined' || !window.addEventListener) {
148
+ return;
149
+ }
150
+ const listen = this._isUrlStatePopStateEnabled();
151
+ if (!listen) {
152
+ return;
153
+ }
154
+ window.removeEventListener('popstate', this._boundPopState);
155
+ window.addEventListener('popstate', this._boundPopState);
156
+ },
157
+
158
+ async _handlePopState() {
159
+ if (!this._isRemote) {
160
+ return;
161
+ }
162
+
163
+ this._remoteParams = this._getInitialRemoteParams();
164
+ this._sortState = this._getInitialSortState();
165
+ if (this._sortable) {
166
+ this._sortable.setState({
167
+ sorts: this._sortState.sorts,
168
+ });
169
+ }
170
+
171
+ this._syncControlsFromState();
172
+
173
+ const page = this._getInitialPage();
174
+ const perPage = this._getInitialPerPage();
175
+ this._pageState = { page, perPage };
176
+ if (this._pagination) {
177
+ this._pagination.setMeta({
178
+ page,
179
+ perPage,
180
+ });
181
+ }
182
+
183
+ const filtersRequestMeta = this._getFiltersRequestMetaIfActive();
184
+ await this._loadRemotePage(page, perPage, null, filtersRequestMeta);
185
+ },
186
+
187
+ _syncControlsFromState() {
188
+ const searchParam = this._getSearchParamName();
189
+ const searchSelector = this._getSearchInputSelector();
190
+ if (searchSelector) {
191
+ const input = this._getSearchInputNode(searchSelector);
192
+ if (input) {
193
+ input.value = String(this._remoteParams[searchParam] || '');
194
+ }
195
+ }
196
+
197
+ if (this._filters && typeof this._filters.setValues === 'function') {
198
+ this._filters.setValues(this._getInitialFilterValues(), { emit: false });
199
+ }
200
+ },
201
+
202
+ _isUrlStatePopStateEnabled() {
203
+ const attr = this._element.getAttribute('data-filters-urlstate-listen-popstate');
204
+ return normalizeEnabledFlag(attr, true);
205
+ },
206
+
207
+ _getInitialRemoteParams() {
208
+ const requestOptions = this._params.request || {};
209
+ const requestParams = requestOptions.params || {};
210
+ const nextParams = {};
211
+ const reserved = new Set(['page', 'per_page', 'sort', 'dir']);
212
+
213
+ Object.keys(requestParams).forEach((key) => {
214
+ if (reserved.has(key)) {
215
+ return;
216
+ }
217
+ const value = requestParams[key];
218
+ if (value === undefined || value === null || value === '') {
219
+ return;
220
+ }
221
+ nextParams[key] = value;
222
+ });
223
+
224
+ if (!this._isFiltersUrlStateEnabled() || !this._isFiltersUrlStateReadOnInit()) {
225
+ return nextParams;
226
+ }
227
+
228
+ const config = this._getFiltersUrlStateConfig();
229
+ const prefix = this._getFiltersUrlPrefix();
230
+ const urlParams = this._getUrlParams();
231
+ const searchParam = this._getSearchParamName();
232
+ const filterFields = this._getFilterFieldKeys();
233
+
234
+ if (searchParam && urlParams.has(searchParam)) {
235
+ const value = String(urlParams.get(searchParam) || '').trim();
236
+ if (value) {
237
+ nextParams[searchParam] = value;
238
+ } else {
239
+ delete nextParams[searchParam];
240
+ }
241
+ }
242
+
243
+ filterFields.forEach((field) => {
244
+ const valueKey = this._prefixFilterParamKey(field, prefix);
245
+ const operatorKey = this._prefixFilterParamKey(`${field}_op`, prefix);
246
+ if (urlParams.has(valueKey)) {
247
+ const value = String(urlParams.get(valueKey) || '').trim();
248
+ if (value) {
249
+ nextParams[field] = value.includes(',') ? value.split(',').map((item) => String(item || '').trim()).filter(Boolean) : value;
250
+ } else {
251
+ delete nextParams[field];
252
+ }
253
+ }
254
+ if (urlParams.has(operatorKey)) {
255
+ const operator = String(urlParams.get(operatorKey) || '').trim();
256
+ if (operator) {
257
+ nextParams[`${field}_op`] = operator;
258
+ } else {
259
+ delete nextParams[`${field}_op`];
260
+ }
261
+ }
262
+ });
263
+
264
+ const sortKey = String(config.sortKey || 'sort');
265
+ if (urlParams.has(sortKey)) {
266
+ const rawSort = String(urlParams.get(sortKey) || '').trim();
267
+ if (rawSort) {
268
+ const items = rawSort.split(',').map((item) => String(item || '').trim()).filter(Boolean);
269
+ const fields = [];
270
+ const dirs = [];
271
+ items.forEach((item) => {
272
+ const parts = item.split(':').map((part) => String(part || '').trim()).filter(Boolean);
273
+ if (!parts.length) {
274
+ return;
275
+ }
276
+ fields.push(parts[0]);
277
+ dirs.push(parts[1] === 'desc' ? 'desc' : 'asc');
278
+ });
279
+ if (fields.length) {
280
+ nextParams.sort = fields.join(',');
281
+ nextParams.dir = dirs.join(',');
282
+ }
283
+ }
284
+ }
285
+
286
+ this._emitAction('urlstateread', {
287
+ state: Object.assign({}, nextParams),
288
+ });
289
+
290
+ return nextParams;
291
+ },
292
+
293
+ _prefixFilterParamKey(key, prefix) {
294
+ const rawKey = String(key || '').trim();
295
+ if (!rawKey) {
296
+ return '';
297
+ }
298
+ const rawPrefix = String(prefix || '').trim();
299
+ if (!rawPrefix || rawKey.startsWith(rawPrefix)) {
300
+ return rawKey;
301
+ }
302
+ return `${rawPrefix}${rawKey}`;
303
+ },
304
+
305
+ _getUrlParams() {
306
+ try {
307
+ return new URLSearchParams(window.location.search || '');
308
+ } catch (error) {
309
+ this._emitAction('urlstateerror', {
310
+ source: 'read',
311
+ error,
312
+ });
313
+ return new URLSearchParams();
314
+ }
315
+ },
316
+
317
+ _getSearchParamName() {
318
+ const searchOptions = this._params.search || {};
319
+ const attrParam = this._element.getAttribute('data-search-param') || '';
320
+ return String(searchOptions.param || attrParam || 'q').trim() || 'q';
321
+ },
322
+
323
+ _getFilterFieldKeys() {
324
+ const form = this._getFiltersFormNode();
325
+ if (!form) {
326
+ return [];
327
+ }
328
+
329
+ if (Array.isArray(this._filterParamKeysCache)) {
330
+ return this._filterParamKeysCache.slice();
331
+ }
332
+
333
+ const options = this._params.filters || {};
334
+ const fieldAttr = String(options.fieldAttr || 'data-filter-field').trim() || 'data-filter-field';
335
+ const unique = new Set();
336
+ Array.from(form.querySelectorAll(`[${fieldAttr}]`)).forEach((node) => {
337
+ const key = String(node.getAttribute(fieldAttr) || '').trim();
338
+ if (key) {
339
+ unique.add(key);
340
+ }
341
+ });
342
+ this._filterParamKeysCache = Array.from(unique);
343
+ return this._filterParamKeysCache.slice();
344
+ },
345
+
346
+ _getInitialFilterValues() {
347
+ const keys = this._getFilterFieldKeys();
348
+ if (!keys.length) {
349
+ return {};
350
+ }
351
+ const values = {};
352
+ keys.forEach((key) => {
353
+ if (Object.prototype.hasOwnProperty.call(this._remoteParams, key)) {
354
+ values[key] = this._remoteParams[key];
355
+ }
356
+ if (Object.prototype.hasOwnProperty.call(this._remoteParams, `${key}_op`)) {
357
+ values[`${key}_op`] = this._remoteParams[`${key}_op`];
358
+ }
359
+ });
360
+ return values;
361
+ },
362
+
363
+ _getFiltersFormSelector() {
364
+ const filterOptions = this._params.filters || {};
365
+ if (typeof filterOptions.form === 'string') {
366
+ return String(filterOptions.form).trim();
367
+ }
368
+ const attrSelector = this._element.getAttribute('data-filters-form') || '';
369
+ return String(attrSelector).trim();
370
+ },
371
+
372
+ _getFiltersFormNode() {
373
+ const filterOptions = this._params.filters || {};
374
+ const optionForm = filterOptions.form;
375
+ if (optionForm && optionForm.nodeType === 1) {
376
+ const shouldRefreshByNode = this._filtersFormCacheNode !== optionForm
377
+ || this._filtersFormCacheSelector !== '';
378
+ if (shouldRefreshByNode) {
379
+ this._filtersFormCacheSelector = '';
380
+ this._filtersFormCacheNode = optionForm;
381
+ this._filterParamKeysCache = null;
382
+ }
383
+ if (!optionForm.isConnected) {
384
+ return null;
385
+ }
386
+ return this._filtersFormCacheNode;
387
+ }
388
+
389
+ const selector = this._getFiltersFormSelector();
390
+ if (!selector) {
391
+ this._filtersFormCacheSelector = '';
392
+ this._filtersFormCacheNode = null;
393
+ this._filterParamKeysCache = null;
394
+ return null;
395
+ }
396
+ const shouldRefresh = this._filtersFormCacheSelector !== selector
397
+ || !this._filtersFormCacheNode
398
+ || !this._filtersFormCacheNode.isConnected;
399
+ if (shouldRefresh) {
400
+ this._filtersFormCacheSelector = selector;
401
+ this._filtersFormCacheNode = safeQuerySelector(selector);
402
+ this._filterParamKeysCache = null;
403
+ }
404
+ return this._filtersFormCacheNode;
405
+ },
406
+
407
+ _getFiltersUrlStateConfig() {
408
+ const filters = this._params.filters || {};
409
+ const urlState = filters.urlState && typeof filters.urlState === 'object'
410
+ ? filters.urlState
411
+ : {};
412
+ return urlState;
413
+ },
414
+
415
+ _getFiltersUrlPrefix() {
416
+ const config = this._getFiltersUrlStateConfig();
417
+ const attr = this._element.getAttribute('data-filters-urlstate-prefix');
418
+ const raw = attr !== null ? attr : config.paramPrefix;
419
+ return String(raw || 'f.').trim() || 'f.';
420
+ },
421
+
422
+ _isFiltersUrlStateEnabled() {
423
+ const config = this._getFiltersUrlStateConfig();
424
+ const attr = this._element.getAttribute('data-filters-urlstate-enable');
425
+ const raw = attr !== null ? attr : config.enable;
426
+ return normalizeBooleanOption(raw, false);
427
+ },
428
+
429
+ _isFiltersUrlStateReadOnInit() {
430
+ const config = this._getFiltersUrlStateConfig();
431
+ const attr = this._element.getAttribute('data-filters-urlstate-read-on-init');
432
+ const raw = attr !== null ? attr : config.readOnInit;
433
+ return normalizeEnabledFlag(raw, true);
434
+ },
435
+
436
+ _isFiltersUrlStateWriteOnChange() {
437
+ const config = this._getFiltersUrlStateConfig();
438
+ const attr = this._element.getAttribute('data-filters-urlstate-write-on-change');
439
+ const raw = attr !== null ? attr : config.writeOnChange;
440
+ return normalizeEnabledFlag(raw, true);
441
+ },
442
+ };
443
+
444
+ export default tableUrlStateMethods;