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,64 @@
1
+ /**
2
+ *--------------------------------------------------------------------------
3
+ * Модуль: VGTooltip
4
+ * Автор: Vegas DEV
5
+ * Лицензия: смотри LICENSE
6
+ *--------------------------------------------------------------------------
7
+ **/
8
+
9
+ @import "../../../utils/scss/functions";
10
+ @import "../../../utils/scss/mixin";
11
+ @import "../../../utils/scss/variables";
12
+ @import "variables";
13
+
14
+ .vg-tooltip {
15
+ @include mix-vars('tooltip', $tooltip-map );
16
+ position: absolute;
17
+ z-index: var(--vg-tooltip-zindex);
18
+ pointer-events: none;
19
+ opacity: 0;
20
+ visibility: hidden;
21
+ transition: opacity .15s ease, transform .15s ease, visibility .15s ease;
22
+ transform: none !important;
23
+
24
+ &.show {
25
+ opacity: 1;
26
+ visibility: visible;
27
+ }
28
+
29
+ &-inner {
30
+ position: relative;
31
+ max-width: var(--vg-tooltip-max-width);
32
+ padding: var(--vg-tooltip-padding);
33
+ font-size: var(--vg-tooltip-font-size);
34
+ line-height: var(--vg-tooltip-line-height);
35
+ color: var(--vg-tooltip-color);
36
+ background: var(--vg-tooltip-background);
37
+ border-radius: var(--vg-tooltip-border-radius);
38
+ box-shadow: var(--vg-tooltip-box-shadow);
39
+ word-break: var(--vg-tooltip-word-break);
40
+ }
41
+
42
+ &-arrow {
43
+ position: absolute;
44
+ width: var(--vg-tooltip-arrow-width);
45
+ height: var(--vg-tooltip-arrow-height);
46
+ background: var(--vg-tooltip-background, #222);
47
+ transform: rotate(45deg);
48
+ }
49
+
50
+ &-popover {
51
+ .vg-tooltip-inner {
52
+ padding: 0;
53
+
54
+ &--title {
55
+ padding: var(--vg-tooltip-padding);
56
+ border-bottom: 1px solid var(--vg-tooltip-border-color);
57
+ }
58
+
59
+ &--content {
60
+ padding: var(--vg-tooltip-padding);
61
+ }
62
+ }
63
+ }
64
+ }
@@ -1,7 +1,117 @@
1
- import { mergeDeepObject, noop, normalizeData } from "../functions";
1
+ import { isObject, noop, normalizeData } from "../functions";
2
2
 
3
- class Ajax {
4
- /**
3
+ class Ajax {
4
+ static _toRouteQueryParamValue(value) {
5
+ if (!Array.isArray(value)) {
6
+ return value;
7
+ }
8
+
9
+ return value
10
+ .map((item) => String(item || '').trim())
11
+ .filter((item) => item !== '')
12
+ .join(',');
13
+ }
14
+
15
+ static buildRouteUrl(route, options = {}) {
16
+ const target = String(route || '').trim();
17
+ if (!target) {
18
+ throw new Error('Request endpoint is empty');
19
+ }
20
+
21
+ const baseParams = isObject(options.baseParams) ? options.baseParams : {};
22
+ const params = isObject(options.params) ? options.params : {};
23
+ const url = new URL(target, window.location.origin);
24
+ const merged = { ...baseParams, ...params };
25
+
26
+ Object.keys(merged).forEach((key) => {
27
+ const value = this._toRouteQueryParamValue(merged[key]);
28
+ if (value === undefined || value === null || value === '') {
29
+ return;
30
+ }
31
+
32
+ url.searchParams.set(key, String(value));
33
+ });
34
+
35
+ return url;
36
+ }
37
+
38
+ static async requestRoute(options = {}) {
39
+ const method = String(options.method || 'GET').toUpperCase().trim() || 'GET';
40
+ const headers = isObject(options.headers) ? { ...options.headers } : {};
41
+ const credentials = String(options.credentials || 'same-origin').trim() || 'same-origin';
42
+ const baseParams = isObject(options.baseParams) ? options.baseParams : {};
43
+ const params = isObject(options.params) ? options.params : {};
44
+ const hasBody = options.body !== undefined && options.body !== null;
45
+ const isGetLike = method === 'GET' || method === 'HEAD';
46
+ const route = String(options.route || options.endpoint || '').trim();
47
+ const url = this.buildRouteUrl(route, {
48
+ baseParams,
49
+ params: isGetLike ? params : {},
50
+ });
51
+ const requestOptions = {
52
+ method,
53
+ credentials,
54
+ headers,
55
+ signal: options.signal || undefined,
56
+ };
57
+
58
+ if (!isGetLike && hasBody) {
59
+ const body = options.body;
60
+ const isFormData = typeof FormData !== 'undefined' && body instanceof FormData;
61
+
62
+ if (isFormData) {
63
+ delete requestOptions.headers['Content-Type'];
64
+ requestOptions.body = body;
65
+ } else if (typeof body === 'string') {
66
+ if (!requestOptions.headers['Content-Type']) {
67
+ requestOptions.headers['Content-Type'] = 'application/json';
68
+ }
69
+ requestOptions.body = body;
70
+ } else {
71
+ if (!requestOptions.headers['Content-Type']) {
72
+ requestOptions.headers['Content-Type'] = 'application/json';
73
+ }
74
+ requestOptions.body = JSON.stringify(body);
75
+ }
76
+ }
77
+
78
+ const response = await fetch(url.toString(), requestOptions);
79
+ const contentType = String(response.headers.get('content-type') || '').toLowerCase();
80
+ const expectsJson = options.responseType === 'json'
81
+ || (options.responseType !== 'text' && contentType.includes('application/json'));
82
+ const payload = await (async () => {
83
+ if (expectsJson) {
84
+ try {
85
+ return await response.json();
86
+ } catch (error) {
87
+ return await response.text();
88
+ }
89
+ }
90
+
91
+ return response.text();
92
+ })();
93
+
94
+ if (!response.ok) {
95
+ const apiError = payload && typeof payload === 'object' && payload.error && typeof payload.error === 'object'
96
+ ? payload.error
97
+ : {};
98
+ const fallbackMessage = typeof payload === 'string' && payload.trim()
99
+ ? payload
100
+ : response.statusText;
101
+ const message = String(apiError.message || fallbackMessage || 'Request failed');
102
+ const error = new Error(message);
103
+ error.status = response.status;
104
+ error.code = apiError.code || 'REQUEST_FAILED';
105
+ error.details = Array.isArray(apiError.details) ? apiError.details : [];
106
+ error.requestId = apiError.request_id || response.headers.get('X-Request-Id') || '';
107
+ error.response = payload;
108
+ throw error;
109
+ }
110
+
111
+ return payload;
112
+ }
113
+
114
+ /**
5
115
  * Конфигурация запроса
6
116
  * @param {Object} options
7
117
  * @param {string} options.baseUrl - Базовый URL API (опционально)
@@ -121,7 +231,7 @@ class Ajax {
121
231
  method,
122
232
  headers,
123
233
  signal,
124
- withCredentials,
234
+ credentials: withCredentials ? 'include' : 'same-origin',
125
235
  ...(body !== undefined && { body }),
126
236
  };
127
237
 
@@ -157,8 +267,7 @@ class Ajax {
157
267
  () => {}
158
268
  );
159
269
  } else {
160
- console.log(data)
161
- onSuccess(data);
270
+ onSuccess(data);
162
271
  }
163
272
  })
164
273
  .catch((error) => {
@@ -284,4 +393,4 @@ class Ajax {
284
393
  }
285
394
  }
286
395
 
287
- export default Ajax;
396
+ export default Ajax;
@@ -1,9 +1,4 @@
1
- import {mergeDeepObject, normalizeData} from "../functions";
2
- import {Classes} from "../dom/manipulator";
3
-
4
- /**
5
- * Класс Placement, определяет и устанавливает местоположение элемента на странице.
6
- */
1
+ import {mergeDeepObject} from "../functions";
7
2
 
8
3
  class Placement {
9
4
  constructor(config) {
@@ -16,20 +11,9 @@ class Placement {
16
11
  this.placement = config.placement || 'bottom';
17
12
  this.fallbackPlacements = config.fallbackPlacements || [];
18
13
 
19
- this._builtInPlacements = {
20
- top: 'top',
21
- 'top-start': 'top-start',
22
- 'top-end': 'top-end',
23
- bottom: 'bottom',
24
- 'bottom-start': 'bottom-start',
25
- 'bottom-end': 'bottom-end',
26
- left: 'left',
27
- 'left-start': 'left-start',
28
- 'left-end': 'left-end',
29
- right: 'right',
30
- 'right-start': 'right-start',
31
- 'right-end': 'right-end'
32
- };
14
+ this.clamp = config.clamp === true;
15
+ this.clampPadding = config.clampPadding ?? 8;
16
+ this.isMerge = config.isMerge !== false;
33
17
  }
34
18
 
35
19
  _getPlacementRect(element) {
@@ -38,6 +22,7 @@ class Placement {
38
22
 
39
23
  _getViewportRect() {
40
24
  const doc = document.documentElement;
25
+
41
26
  return {
42
27
  width: doc.clientWidth,
43
28
  height: doc.clientHeight,
@@ -60,56 +45,102 @@ class Placement {
60
45
  const fallbacks = [this.placement, ...this.fallbackPlacements];
61
46
  let best = null;
62
47
 
63
- for (let p of fallbacks) {
64
- let pos = this._calculatePosition(p, refRect, dropRect, xOffset, yOffset);
65
- let overflow = this._calculateOverflow(pos, viewRect);
48
+ for (const p of fallbacks) {
49
+ const position = this._calculatePosition(p, refRect, dropRect, xOffset, yOffset);
50
+ const overflow = this._calculateOverflow(position, dropRect, viewRect);
66
51
 
67
52
  if (!best || overflow < best.overflow) {
68
- best = { placement: p, position: pos, overflow };
53
+ best = { placement: p, position, overflow };
54
+
69
55
  if (overflow === 0) break;
70
56
  }
71
57
  }
72
58
 
73
59
  placement = best.placement;
74
- this._setStyles(best.position);
60
+
61
+ const finalPosition = this.clamp
62
+ ? this._clampPosition(best.position, dropRect, viewRect)
63
+ : best.position;
64
+
65
+ this._setStyles(finalPosition);
75
66
  } else {
76
- const pos = this._calculatePosition(placement, refRect, dropRect, xOffset, yOffset);
77
- this._setStyles(pos);
67
+ const position = this._calculatePosition(placement, refRect, dropRect, xOffset, yOffset);
68
+
69
+ const finalPosition = this.clamp
70
+ ? this._clampPosition(position, dropRect, viewRect)
71
+ : position;
72
+
73
+ this._setStyles(finalPosition);
78
74
  }
79
75
 
80
76
  this.drop.setAttribute('data-vg-placement', placement);
81
77
  }
82
78
 
83
79
  _calculatePosition(placement, refRect, dropRect, xOffset = 0, yOffset = 0) {
84
- let top, left;
80
+ let top;
81
+ let left;
85
82
 
86
83
  switch (placement) {
87
84
  case 'top':
85
+ top = refRect.top - dropRect.height - yOffset;
86
+ left = refRect.left + (refRect.width - dropRect.width) / 2;
87
+ break;
88
+
88
89
  case 'top-start':
89
90
  top = refRect.top - dropRect.height - yOffset;
90
- left = placement === 'top-start' ? refRect.left + xOffset : refRect.left + (refRect.width - dropRect.width) / 2;
91
+ left = refRect.left + xOffset;
91
92
  break;
93
+
92
94
  case 'top-end':
93
95
  top = refRect.top - dropRect.height - yOffset;
94
96
  left = refRect.right - dropRect.width - xOffset;
95
97
  break;
98
+
96
99
  case 'bottom':
100
+ top = refRect.bottom + yOffset;
101
+ left = refRect.left + (refRect.width - dropRect.width) / 2;
102
+ break;
103
+
97
104
  case 'bottom-start':
98
105
  top = refRect.bottom + yOffset;
99
- left = placement === 'bottom-start' ? refRect.left + xOffset : refRect.left + (refRect.width - dropRect.width) / 2;
106
+ left = refRect.left + xOffset;
100
107
  break;
108
+
101
109
  case 'bottom-end':
102
110
  top = refRect.bottom + yOffset;
103
111
  left = refRect.right - dropRect.width - xOffset;
104
112
  break;
113
+
105
114
  case 'left':
106
115
  top = refRect.top + (refRect.height - dropRect.height) / 2;
107
116
  left = refRect.left - dropRect.width - xOffset;
108
117
  break;
118
+
119
+ case 'left-start':
120
+ top = refRect.top + yOffset;
121
+ left = refRect.left - dropRect.width - xOffset;
122
+ break;
123
+
124
+ case 'left-end':
125
+ top = refRect.bottom - dropRect.height - yOffset;
126
+ left = refRect.left - dropRect.width - xOffset;
127
+ break;
128
+
109
129
  case 'right':
110
130
  top = refRect.top + (refRect.height - dropRect.height) / 2;
111
131
  left = refRect.right + xOffset;
112
132
  break;
133
+
134
+ case 'right-start':
135
+ top = refRect.top + yOffset;
136
+ left = refRect.right + xOffset;
137
+ break;
138
+
139
+ case 'right-end':
140
+ top = refRect.bottom - dropRect.height - yOffset;
141
+ left = refRect.right + xOffset;
142
+ break;
143
+
113
144
  default:
114
145
  top = refRect.bottom + yOffset;
115
146
  left = refRect.left + xOffset;
@@ -118,22 +149,62 @@ class Placement {
118
149
  return { top, left };
119
150
  }
120
151
 
121
- _calculateOverflow(pos, viewRect) {
152
+ _calculateOverflow(pos, dropRect, viewRect) {
122
153
  let overflow = 0;
123
- if (pos.left < viewRect.left) overflow += viewRect.left - pos.left;
124
- if (pos.top < viewRect.top) overflow += viewRect.top - pos.top;
125
- if (pos.left + this.drop.offsetWidth > viewRect.right) overflow += (pos.left + this.drop.offsetWidth) - viewRect.right;
126
- if (pos.top + this.drop.offsetHeight > viewRect.bottom) overflow += (pos.top + this.drop.offsetHeight) - viewRect.bottom;
154
+
155
+ if (pos.left < viewRect.left) {
156
+ overflow += viewRect.left - pos.left;
157
+ }
158
+
159
+ if (pos.top < viewRect.top) {
160
+ overflow += viewRect.top - pos.top;
161
+ }
162
+
163
+ if (pos.left + dropRect.width > viewRect.right) {
164
+ overflow += (pos.left + dropRect.width) - viewRect.right;
165
+ }
166
+
167
+ if (pos.top + dropRect.height > viewRect.bottom) {
168
+ overflow += (pos.top + dropRect.height) - viewRect.bottom;
169
+ }
170
+
127
171
  return overflow;
128
172
  }
129
173
 
174
+ _clampPosition(pos, dropRect, viewRect) {
175
+ const padding = this.clampPadding;
176
+
177
+ const maxTop = viewRect.bottom - dropRect.height - padding;
178
+ const maxLeft = viewRect.right - dropRect.width - padding;
179
+
180
+ return {
181
+ top: Math.min(
182
+ Math.max(pos.top, viewRect.top + padding),
183
+ maxTop
184
+ ),
185
+ left: Math.min(
186
+ Math.max(pos.left, viewRect.left + padding),
187
+ maxLeft
188
+ )
189
+ };
190
+ }
191
+
130
192
  _setStyles(pos) {
131
- mergeDeepObject(this.drop.style, {
132
- position: 'absolute',
133
- top: `${pos.top}px`,
134
- left: `${pos.left}px`,
135
- margin: 0
136
- })
193
+ if (!pos || !this.drop) return;
194
+
195
+ if (this.isMerge) {
196
+ mergeDeepObject(this.drop.style, {
197
+ position: 'absolute',
198
+ top: `${pos.top + window.pageYOffset}px`,
199
+ left: `${pos.left + window.pageXOffset}px`,
200
+ margin: '0'
201
+ });
202
+ } else {
203
+ this.drop.style.position = 'absolute';
204
+ this.drop.style.top = `${pos.top + window.pageYOffset}px`;
205
+ this.drop.style.left = `${pos.left + window.pageXOffset}px`;
206
+ this.drop.style.margin = '0';
207
+ }
137
208
  }
138
209
 
139
210
  _setPlacement() {