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.
- package/CHANGELOG.md +66 -7
- package/README.md +2 -1
- package/agents.md +2 -2
- package/app/modules/base-module.js +87 -10
- package/app/modules/vgalert/js/vgalert.js +133 -202
- package/app/modules/vgalert/readme.md +105 -46
- package/app/modules/vgalert/scss/vgalert.scss +18 -0
- package/app/modules/vgdynamictable/index.js +5 -0
- package/app/modules/vgdynamictable/js/editable.js +438 -0
- package/app/modules/vgdynamictable/js/expandable.js +248 -0
- package/app/modules/vgdynamictable/js/filters.js +450 -0
- package/app/modules/vgdynamictable/js/fixed.js +566 -0
- package/app/modules/vgdynamictable/js/options.js +646 -0
- package/app/modules/vgdynamictable/js/pagination.js +623 -0
- package/app/modules/vgdynamictable/js/search.js +82 -0
- package/app/modules/vgdynamictable/js/skeleton.js +136 -0
- package/app/modules/vgdynamictable/js/sortable.js +442 -0
- package/app/modules/vgdynamictable/js/summary-footer.js +284 -0
- package/app/modules/vgdynamictable/js/table-remote.js +821 -0
- package/app/modules/vgdynamictable/js/table-state.js +243 -0
- package/app/modules/vgdynamictable/js/table-url-state.js +444 -0
- package/app/modules/vgdynamictable/js/utils/common.js +48 -0
- package/app/modules/vgdynamictable/js/vgdynamictable.js +3829 -0
- package/app/modules/vgdynamictable/js/viewport.js +322 -0
- package/app/modules/vgdynamictable/readme.md +251 -0
- package/app/modules/vgdynamictable/scss/_actions.scss +193 -0
- package/app/modules/vgdynamictable/scss/_pagination.scss +183 -0
- package/app/modules/vgdynamictable/scss/_skeleton.scss +60 -0
- package/app/modules/vgdynamictable/scss/_sortable.scss +63 -0
- package/app/modules/vgdynamictable/scss/_table.scss +157 -0
- package/app/modules/vgdynamictable/scss/_variables.scss +130 -0
- package/app/modules/vgdynamictable/scss/vgdynamictable.scss +267 -0
- package/app/modules/vgrangeslider/index.js +3 -0
- package/app/modules/vgrangeslider/js/skins.js +222 -0
- package/app/modules/vgrangeslider/js/vgrangeslider.js +704 -0
- package/app/modules/vgrangeslider/readme.md +523 -0
- package/app/modules/vgrangeslider/scss/_variables.scss +53 -0
- package/app/modules/vgrangeslider/scss/vgrangeslider.scss +240 -0
- package/app/modules/vgtoast/js/vgtoast.js +111 -111
- package/app/modules/vgtooltip/index.js +3 -0
- package/app/modules/vgtooltip/js/vgtooltip.js +493 -0
- package/app/modules/vgtooltip/readme.md +181 -0
- package/app/modules/vgtooltip/scss/_variables.scss +15 -0
- package/app/modules/vgtooltip/scss/vgtooltip.scss +64 -0
- package/app/utils/js/components/ajax.js +116 -7
- package/app/utils/js/components/placement.js +112 -41
- package/build/vgapp.css +1 -1
- package/build/vgapp.css.map +1 -1
- package/index.js +20 -17
- package/index.scss +9 -0
- 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 {
|
|
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
|
-
|
|
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
|
|
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.
|
|
20
|
-
|
|
21
|
-
|
|
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 (
|
|
64
|
-
|
|
65
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
77
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
124
|
-
if (pos.
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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() {
|