vgapp 1.3.4 → 1.3.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 (88) hide show
  1. package/app/langs/en/buttons.json +17 -17
  2. package/app/langs/en/messages.json +36 -36
  3. package/app/langs/ru/buttons.json +17 -17
  4. package/app/langs/ru/messages.json +36 -36
  5. package/app/modules/base-module.js +111 -111
  6. package/app/modules/vgalert/js/vgalert.js +52 -52
  7. package/app/modules/vgalert/readme.md +105 -105
  8. package/app/modules/vgdynamictable/index.js +5 -5
  9. package/app/modules/vgdynamictable/js/editable.js +19 -19
  10. package/app/modules/vgdynamictable/js/filters.js +21 -21
  11. package/app/modules/vgdynamictable/js/fixed.js +179 -179
  12. package/app/modules/vgdynamictable/js/pagination.js +1 -1
  13. package/app/modules/vgdynamictable/js/search.js +12 -12
  14. package/app/modules/vgdynamictable/js/sortable.js +71 -71
  15. package/app/modules/vgdynamictable/js/summary-footer.js +28 -28
  16. package/app/modules/vgdynamictable/js/table-remote.js +79 -79
  17. package/app/modules/vgdynamictable/js/table-url-state.js +31 -31
  18. package/app/modules/vgdynamictable/js/utils/common.js +48 -48
  19. package/app/modules/vgdynamictable/js/vgdynamictable.js +268 -268
  20. package/app/modules/vgdynamictable/readme.md +250 -250
  21. package/app/modules/vgdynamictable/scss/_skeleton.scss +6 -6
  22. package/app/modules/vgdynamictable/scss/_sortable.scss +24 -24
  23. package/app/modules/vgdynamictable/scss/_table.scss +4 -4
  24. package/app/modules/vgdynamictable/scss/_variables.scss +79 -79
  25. package/app/modules/vgdynamictable/scss/vgdynamictable.scss +27 -27
  26. package/app/modules/vgfilepreview/js/i18n.js +56 -56
  27. package/app/modules/vgfilepreview/js/renderers/image-modal.js +145 -145
  28. package/app/modules/vgfilepreview/js/renderers/image.js +92 -92
  29. package/app/modules/vgfilepreview/js/renderers/index.js +19 -19
  30. package/app/modules/vgfilepreview/js/renderers/office-modal.js +168 -168
  31. package/app/modules/vgfilepreview/js/renderers/office.js +79 -79
  32. package/app/modules/vgfilepreview/js/renderers/pdf-modal.js +260 -260
  33. package/app/modules/vgfilepreview/js/renderers/pdf.js +76 -76
  34. package/app/modules/vgfilepreview/js/renderers/playlist.js +71 -71
  35. package/app/modules/vgfilepreview/js/renderers/text-modal.js +343 -343
  36. package/app/modules/vgfilepreview/js/renderers/text.js +83 -83
  37. package/app/modules/vgfilepreview/js/renderers/video-modal.js +272 -272
  38. package/app/modules/vgfilepreview/js/renderers/video.js +80 -80
  39. package/app/modules/vgfilepreview/js/renderers/zip-modal.js +522 -522
  40. package/app/modules/vgfilepreview/js/renderers/zip.js +89 -89
  41. package/app/modules/vgfilepreview/js/vgfilepreview.js +7 -7
  42. package/app/modules/vgfilepreview/readme.md +68 -68
  43. package/app/modules/vgfilepreview/scss/_variables.scss +113 -113
  44. package/app/modules/vgfilepreview/scss/vgfilepreview.scss +464 -464
  45. package/app/modules/vgfiles/js/base.js +26 -26
  46. package/app/modules/vgfiles/js/droppable.js +260 -260
  47. package/app/modules/vgfiles/js/render.js +153 -153
  48. package/app/modules/vgfiles/js/vgfiles.js +104 -104
  49. package/app/modules/vgfiles/readme.md +123 -123
  50. package/app/modules/vgfiles/scss/_variables.scss +18 -18
  51. package/app/modules/vgfiles/scss/vgfiles.scss +148 -148
  52. package/app/modules/vgformsender/js/hideshowpass.js +16 -16
  53. package/app/modules/vgformsender/scss/vgformsender.scss +34 -34
  54. package/app/modules/vgmodal/js/vgmodal.drag.js +332 -332
  55. package/app/modules/vgmodal/js/vgmodal.js +188 -188
  56. package/app/modules/vgmodal/js/vgmodal.resize.js +27 -27
  57. package/app/modules/vgmodal/scss/vgmodal.scss +14 -14
  58. package/app/modules/vgnav/js/vgnav.js +135 -135
  59. package/app/modules/vgnav/readme.md +67 -67
  60. package/app/modules/vgnestable/README.md +307 -307
  61. package/app/modules/vgnestable/scss/_variables.scss +60 -60
  62. package/app/modules/vgnestable/scss/vgnestable.scss +163 -163
  63. package/app/modules/vgrangeslider/js/skins.js +222 -222
  64. package/app/modules/vgrangeslider/js/vgrangeslider.js +704 -704
  65. package/app/modules/vgrangeslider/readme.md +523 -523
  66. package/app/modules/vgrangeslider/scss/_variables.scss +53 -53
  67. package/app/modules/vgrangeslider/scss/vgrangeslider.scss +240 -240
  68. package/app/modules/vgselect/js/vgselect.js +39 -39
  69. package/app/modules/vgselect/scss/vgselect.scss +22 -22
  70. package/app/modules/vgspy/readme.md +28 -28
  71. package/app/modules/vgtoast/readme.md +18 -18
  72. package/app/modules/vgtoast/scss/vgtoast.scss +48 -48
  73. package/app/modules/vgtooltip/js/vgtooltip.js +89 -89
  74. package/app/modules/vgtooltip/readme.md +181 -181
  75. package/app/utils/js/components/ajax.js +117 -117
  76. package/app/utils/js/components/audio-metadata.js +240 -240
  77. package/app/utils/js/components/backdrop.js +17 -17
  78. package/app/utils/js/components/file-icon.js +109 -109
  79. package/app/utils/js/components/file-preview.js +304 -304
  80. package/app/utils/js/components/sanitize.js +150 -150
  81. package/app/utils/js/components/video-metadata.js +140 -140
  82. package/app/vgapp.js +46 -46
  83. package/build/vgapp.css +1 -1
  84. package/build/vgapp.css.map +1 -1
  85. package/build/vgapp.js +1 -1
  86. package/build/vgapp.js.map +1 -1
  87. package/index.js +14 -14
  88. package/package.json +3 -1
@@ -1,6 +1,6 @@
1
- import {normalizeBooleanOption, normalizeEnabledFlag, safeQuerySelector} from "./utils/common";
2
-
3
- const summaryFooterMethods = {
1
+ import {normalizeBooleanOption, normalizeEnabledFlag, safeQuerySelector} from "./utils/common";
2
+
3
+ const summaryFooterMethods = {
4
4
  _renderSummary(meta = {}) {
5
5
  if (!this._isSummaryEnabled() || !this._summaryNode || !this._isRemote) {
6
6
  return;
@@ -28,14 +28,14 @@ const summaryFooterMethods = {
28
28
  this._summaryNode.hidden = false;
29
29
  },
30
30
 
31
- _isSummaryEnabled() {
32
- const options = this._params.summary || {};
33
- if (options.enable !== undefined && options.enable !== null) {
34
- return normalizeBooleanOption(options.enable, false);
35
- }
36
-
37
- const attr = this._element.getAttribute('data-summary-enable');
38
- return normalizeEnabledFlag(attr, false);
31
+ _isSummaryEnabled() {
32
+ const options = this._params.summary || {};
33
+ if (options.enable !== undefined && options.enable !== null) {
34
+ return normalizeBooleanOption(options.enable, false);
35
+ }
36
+
37
+ const attr = this._element.getAttribute('data-summary-enable');
38
+ return normalizeEnabledFlag(attr, false);
39
39
  },
40
40
 
41
41
  _getActiveCriteria() {
@@ -69,14 +69,14 @@ const summaryFooterMethods = {
69
69
  return '';
70
70
  }
71
71
 
72
- const shouldRefreshFormCache = this._filtersFormCacheSelector !== selector
73
- || !this._filtersFormCacheNode
74
- || !this._filtersFormCacheNode.isConnected;
75
- if (shouldRefreshFormCache) {
76
- this._filtersFormCacheSelector = selector;
77
- this._filtersFormCacheNode = safeQuerySelector(selector);
78
- this._filtersLabelCache = {};
79
- }
72
+ const shouldRefreshFormCache = this._filtersFormCacheSelector !== selector
73
+ || !this._filtersFormCacheNode
74
+ || !this._filtersFormCacheNode.isConnected;
75
+ if (shouldRefreshFormCache) {
76
+ this._filtersFormCacheSelector = selector;
77
+ this._filtersFormCacheNode = safeQuerySelector(selector);
78
+ this._filtersLabelCache = {};
79
+ }
80
80
 
81
81
  const form = this._filtersFormCacheNode;
82
82
  if (!form) {
@@ -237,15 +237,15 @@ const summaryFooterMethods = {
237
237
  `;
238
238
  },
239
239
 
240
- _isFooterEnabled() {
241
- const options = this._params.footer || {};
242
- if (options.enable !== undefined && options.enable !== null) {
243
- return normalizeBooleanOption(options.enable, false);
244
- }
245
-
246
- const attr = this._element.getAttribute('data-footer-enable');
247
- return normalizeEnabledFlag(attr, false);
248
- },
240
+ _isFooterEnabled() {
241
+ const options = this._params.footer || {};
242
+ if (options.enable !== undefined && options.enable !== null) {
243
+ return normalizeBooleanOption(options.enable, false);
244
+ }
245
+
246
+ const attr = this._element.getAttribute('data-footer-enable');
247
+ return normalizeEnabledFlag(attr, false);
248
+ },
249
249
 
250
250
  _applyFooterVisibility() {
251
251
  const foot = this._element.tFoot || this._element.querySelector('tfoot');
@@ -1,43 +1,43 @@
1
- const tableRemoteMethods = {
2
- _getRemoteRouteRequestConfig(route = '') {
3
- const requestOptions = this._params.request || {};
4
- const attrMethod = this._element.getAttribute('data-request-method');
5
- const attrCredentials = this._element.getAttribute('data-request-credentials');
6
- const attrParams = this._element.getAttribute('data-request-params');
7
- let paramsFromAttr = {};
8
-
9
- if (attrParams !== null && String(attrParams).trim() !== '') {
10
- try {
11
- const parsed = JSON.parse(attrParams);
12
- if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
13
- paramsFromAttr = parsed;
14
- }
15
- } catch (error) {
16
- paramsFromAttr = {};
17
- }
18
- }
19
-
20
- return {
21
- route: route || this._getRemoteDataRoute(),
22
- method: attrMethod !== null ? attrMethod : requestOptions.method,
23
- credentials: attrCredentials !== null ? attrCredentials : requestOptions.credentials,
24
- headers: requestOptions.headers && typeof requestOptions.headers === 'object'
25
- ? Object.assign({}, requestOptions.headers)
26
- : { 'Accept': 'application/json' },
27
- baseParams: Object.assign(
28
- {},
29
- requestOptions.params && typeof requestOptions.params === 'object' ? requestOptions.params : {},
30
- paramsFromAttr
31
- ),
32
- responseType: 'json',
33
- };
34
- },
35
-
36
- _isRemoteCacheEnabled() {
37
- const requestOptions = this._params.request || {};
38
- const requestCacheOptions = requestOptions.cache && typeof requestOptions.cache === 'object'
39
- ? requestOptions.cache
40
- : {};
1
+ const tableRemoteMethods = {
2
+ _getRemoteRouteRequestConfig(route = '') {
3
+ const requestOptions = this._params.request || {};
4
+ const attrMethod = this._element.getAttribute('data-request-method');
5
+ const attrCredentials = this._element.getAttribute('data-request-credentials');
6
+ const attrParams = this._element.getAttribute('data-request-params');
7
+ let paramsFromAttr = {};
8
+
9
+ if (attrParams !== null && String(attrParams).trim() !== '') {
10
+ try {
11
+ const parsed = JSON.parse(attrParams);
12
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
13
+ paramsFromAttr = parsed;
14
+ }
15
+ } catch (error) {
16
+ paramsFromAttr = {};
17
+ }
18
+ }
19
+
20
+ return {
21
+ route: route || this._getRemoteDataRoute(),
22
+ method: attrMethod !== null ? attrMethod : requestOptions.method,
23
+ credentials: attrCredentials !== null ? attrCredentials : requestOptions.credentials,
24
+ headers: requestOptions.headers && typeof requestOptions.headers === 'object'
25
+ ? Object.assign({}, requestOptions.headers)
26
+ : { 'Accept': 'application/json' },
27
+ baseParams: Object.assign(
28
+ {},
29
+ requestOptions.params && typeof requestOptions.params === 'object' ? requestOptions.params : {},
30
+ paramsFromAttr
31
+ ),
32
+ responseType: 'json',
33
+ };
34
+ },
35
+
36
+ _isRemoteCacheEnabled() {
37
+ const requestOptions = this._params.request || {};
38
+ const requestCacheOptions = requestOptions.cache && typeof requestOptions.cache === 'object'
39
+ ? requestOptions.cache
40
+ : {};
41
41
  const attr = this._element.getAttribute('data-request-cache-enable');
42
42
  if (attr !== null) {
43
43
  return this._isTruthy(attr);
@@ -321,11 +321,11 @@ const tableRemoteMethods = {
321
321
  return requestParams;
322
322
  },
323
323
 
324
- exportRemote(format = 'csv', options = {}) {
325
- if (!this._isRemote) {
326
- return '';
327
- }
328
- const requestOptions = this._params.request || {};
324
+ exportRemote(format = 'csv', options = {}) {
325
+ if (!this._isRemote) {
326
+ return '';
327
+ }
328
+ const requestOptions = this._params.request || {};
329
329
 
330
330
  const normalizedFormat = String(format || 'csv').toLowerCase().trim() === 'xlsx'
331
331
  ? 'xlsx'
@@ -346,17 +346,17 @@ const tableRemoteMethods = {
346
346
  options.endpoint
347
347
  || (requestOptions.export && requestOptions.export.route)
348
348
  || this._element.getAttribute('data-request-export-route')
349
- || this._getRemoteDataRoute()
350
- ).trim();
351
- const exportEndpoint = endpoint || this._getRemoteDataRoute();
352
- const exportUrl = this._buildRouteUrl(
353
- mappedRequestParams,
354
- exportEndpoint,
355
- this._getRemoteRouteRequestConfig(exportEndpoint)
356
- ).toString();
357
- if (options.open !== false && typeof window !== 'undefined' && typeof window.open === 'function') {
358
- window.open(exportUrl, '_blank', 'noopener');
359
- }
349
+ || this._getRemoteDataRoute()
350
+ ).trim();
351
+ const exportEndpoint = endpoint || this._getRemoteDataRoute();
352
+ const exportUrl = this._buildRouteUrl(
353
+ mappedRequestParams,
354
+ exportEndpoint,
355
+ this._getRemoteRouteRequestConfig(exportEndpoint)
356
+ ).toString();
357
+ if (options.open !== false && typeof window !== 'undefined' && typeof window.open === 'function') {
358
+ window.open(exportUrl, '_blank', 'noopener');
359
+ }
360
360
 
361
361
  this._emitAction('export', {
362
362
  format: normalizedFormat,
@@ -366,13 +366,13 @@ const tableRemoteMethods = {
366
366
  url: exportUrl,
367
367
  });
368
368
  return exportUrl;
369
- },
370
-
371
- async _loadRemotePage(page, perPage, userOnChange = null, requestMeta = null) {
372
- if (!this._isRemote) {
373
- return;
374
- }
375
-
369
+ },
370
+
371
+ async _loadRemotePage(page, perPage, userOnChange = null, requestMeta = null) {
372
+ if (!this._isRemote) {
373
+ return;
374
+ }
375
+
376
376
  const safePage = this._normalizePositiveInt(page, 1);
377
377
  const safePerPage = this._clampPerPage(perPage, this._getInitialPerPage());
378
378
  const requestToken = ++this._requestToken;
@@ -450,22 +450,22 @@ const tableRemoteMethods = {
450
450
  if (!cachedResponse) {
451
451
  this._renderLoadingSkeleton();
452
452
  }
453
-
454
- try {
455
- const response = cachedResponse || await this._route(Object.assign(
456
- {},
457
- this._getRemoteRouteRequestConfig(endpoint),
458
- {
459
- route: endpoint,
460
- method: 'GET',
461
- params: mappedRequestParams,
462
- signal: requestAbortController ? requestAbortController.signal : undefined,
463
- responseType: 'json',
464
- }
465
- ));
466
- if (!cachedResponse) {
467
- await this._waitMinLoadingDelay(requestStartedAt);
468
- }
453
+
454
+ try {
455
+ const response = cachedResponse || await this._route(Object.assign(
456
+ {},
457
+ this._getRemoteRouteRequestConfig(endpoint),
458
+ {
459
+ route: endpoint,
460
+ method: 'GET',
461
+ params: mappedRequestParams,
462
+ signal: requestAbortController ? requestAbortController.signal : undefined,
463
+ responseType: 'json',
464
+ }
465
+ ));
466
+ if (!cachedResponse) {
467
+ await this._waitMinLoadingDelay(requestStartedAt);
468
+ }
469
469
 
470
470
  if (requestToken !== this._requestToken) {
471
471
  this._emitAction('staleresponse', {
@@ -1,6 +1,6 @@
1
- import {normalizeBooleanOption, normalizeEnabledFlag, safeQuerySelector, toQueryParamValue} from "./utils/common";
2
-
3
- const tableUrlStateMethods = {
1
+ import {normalizeBooleanOption, normalizeEnabledFlag, safeQuerySelector, toQueryParamValue} from "./utils/common";
2
+
3
+ const tableUrlStateMethods = {
4
4
  _syncUrlState() {
5
5
  if (!this._isFiltersUrlStateEnabled() || !this._isFiltersUrlStateWriteOnChange()) {
6
6
  return;
@@ -26,12 +26,12 @@ const tableUrlStateMethods = {
26
26
  url.searchParams.delete(key);
27
27
  });
28
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
- }
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
35
  url.searchParams.set(key, String(value));
36
36
  });
37
37
 
@@ -200,8 +200,8 @@ const tableUrlStateMethods = {
200
200
  },
201
201
 
202
202
  _isUrlStatePopStateEnabled() {
203
- const attr = this._element.getAttribute('data-filters-urlstate-listen-popstate');
204
- return normalizeEnabledFlag(attr, true);
203
+ const attr = this._element.getAttribute('data-filters-urlstate-listen-popstate');
204
+ return normalizeEnabledFlag(attr, true);
205
205
  },
206
206
 
207
207
  _getInitialRemoteParams() {
@@ -393,15 +393,15 @@ const tableUrlStateMethods = {
393
393
  this._filterParamKeysCache = null;
394
394
  return null;
395
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;
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
405
  },
406
406
 
407
407
  _getFiltersUrlStateConfig() {
@@ -421,24 +421,24 @@ const tableUrlStateMethods = {
421
421
 
422
422
  _isFiltersUrlStateEnabled() {
423
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);
424
+ const attr = this._element.getAttribute('data-filters-urlstate-enable');
425
+ const raw = attr !== null ? attr : config.enable;
426
+ return normalizeBooleanOption(raw, false);
427
427
  },
428
428
 
429
429
  _isFiltersUrlStateReadOnInit() {
430
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);
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
434
  },
435
435
 
436
436
  _isFiltersUrlStateWriteOnChange() {
437
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
- };
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
443
 
444
444
  export default tableUrlStateMethods;
@@ -1,48 +1,48 @@
1
- export function normalizeNonNegativeInt(value, fallback = 0) {
2
- const parsed = Number.parseInt(value, 10);
3
- return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
4
- }
5
-
6
- export function normalizeBooleanOption(value, fallback = false) {
7
- if (value === undefined || value === null) {
8
- return fallback;
9
- }
10
- const normalized = String(value).toLowerCase().trim();
11
- if (normalized === 'true' || normalized === '1') {
12
- return true;
13
- }
14
- if (normalized === 'false' || normalized === '0') {
15
- return false;
16
- }
17
- return Boolean(value);
18
- }
19
-
20
- export function normalizeEnabledFlag(value, fallback = true) {
21
- if (value === undefined || value === null) {
22
- return fallback;
23
- }
24
- const normalized = String(value).toLowerCase().trim();
25
- return normalized !== 'false' && normalized !== '0';
26
- }
27
-
28
- export function safeQuerySelector(selector, root = document) {
29
- const normalized = String(selector || '').trim();
30
- if (!normalized || !root || typeof root.querySelector !== 'function') {
31
- return null;
32
- }
33
- try {
34
- return root.querySelector(normalized);
35
- } catch (error) {
36
- return null;
37
- }
38
- }
39
-
40
- export function toQueryParamValue(value) {
41
- if (!Array.isArray(value)) {
42
- return value;
43
- }
44
- return value
45
- .map((item) => String(item || '').trim())
46
- .filter((item) => item !== '')
47
- .join(',');
48
- }
1
+ export function normalizeNonNegativeInt(value, fallback = 0) {
2
+ const parsed = Number.parseInt(value, 10);
3
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
4
+ }
5
+
6
+ export function normalizeBooleanOption(value, fallback = false) {
7
+ if (value === undefined || value === null) {
8
+ return fallback;
9
+ }
10
+ const normalized = String(value).toLowerCase().trim();
11
+ if (normalized === 'true' || normalized === '1') {
12
+ return true;
13
+ }
14
+ if (normalized === 'false' || normalized === '0') {
15
+ return false;
16
+ }
17
+ return Boolean(value);
18
+ }
19
+
20
+ export function normalizeEnabledFlag(value, fallback = true) {
21
+ if (value === undefined || value === null) {
22
+ return fallback;
23
+ }
24
+ const normalized = String(value).toLowerCase().trim();
25
+ return normalized !== 'false' && normalized !== '0';
26
+ }
27
+
28
+ export function safeQuerySelector(selector, root = document) {
29
+ const normalized = String(selector || '').trim();
30
+ if (!normalized || !root || typeof root.querySelector !== 'function') {
31
+ return null;
32
+ }
33
+ try {
34
+ return root.querySelector(normalized);
35
+ } catch (error) {
36
+ return null;
37
+ }
38
+ }
39
+
40
+ export function toQueryParamValue(value) {
41
+ if (!Array.isArray(value)) {
42
+ return value;
43
+ }
44
+ return value
45
+ .map((item) => String(item || '').trim())
46
+ .filter((item) => item !== '')
47
+ .join(',');
48
+ }