vgapp 0.8.1 → 0.8.2
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 +10 -0
- package/app/langs/en/buttons.json +8 -0
- package/app/langs/en/messages.json +3 -0
- package/app/langs/en/titles.json +3 -0
- package/app/langs/ru/buttons.json +8 -0
- package/app/langs/ru/messages.json +3 -0
- package/app/langs/ru/titles.json +3 -0
- package/app/modules/vgloadmore/js/vgloadmore.js +159 -8
- package/app/modules/vgrollup/js/vgrollup.js +328 -160
- package/app/modules/vgrollup/readme.md +196 -0
- package/app/modules/vgselect/js/handlers.js +220 -0
- package/app/modules/vgselect/js/vgselect.js +783 -298
- package/app/modules/vgselect/readme.md +180 -0
- package/app/modules/vgselect/scss/_variables.scss +20 -0
- package/app/modules/vgselect/scss/vgselect.scss +42 -2
- package/app/modules/vgsidebar/js/vgsidebar.js +194 -84
- package/app/modules/vgsidebar/readme.md +157 -0
- package/app/modules/vgspy/js/vgspy.js +236 -132
- package/app/modules/vgspy/readme.md +105 -0
- package/app/modules/vgtabs/js/vgtabs.js +290 -182
- package/app/modules/vgtabs/readme.md +156 -0
- package/app/modules/vgtoast/js/vgtoast.js +260 -156
- package/app/modules/vgtoast/readme.md +145 -0
- package/build/vgapp.css +1 -1
- package/build/vgapp.css.map +1 -1
- package/package.json +1 -1
|
@@ -5,26 +5,76 @@ import {execute, isDisabled, makeRandomString, mergeDeepObject} from "../../../u
|
|
|
5
5
|
import Selectors from "../../../utils/js/dom/selectors";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* @constant {string} NAME - Имя модуля.
|
|
9
9
|
*/
|
|
10
10
|
const NAME = 'toast';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @constant {string} NAME_KEY - Пространство имён для событий.
|
|
14
|
+
*/
|
|
11
15
|
const NAME_KEY = 'vg.toast';
|
|
12
|
-
const SELECTOR_DATA_TOGGLE= '[data-vg-toggle="toast"]';
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
/**
|
|
18
|
+
* @constant {string} SELECTOR_DATA_TOGGLE - Селектор для активации через data-атрибут.
|
|
19
|
+
*/
|
|
20
|
+
const SELECTOR_DATA_TOGGLE = '[data-vg-toggle="toast"]';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @constant {string} CLASS_NAME_OPEN - Класс, добавляемый к body при открытии любого тоста.
|
|
24
|
+
*/
|
|
25
|
+
const CLASS_NAME_OPEN = 'vg-toast-open';
|
|
17
26
|
|
|
27
|
+
/**
|
|
28
|
+
* @constant {string} CLASS_NAME_SHOW - Класс, показывающий, что тост видим.
|
|
29
|
+
*/
|
|
30
|
+
const CLASS_NAME_SHOW = 'show';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @constant {string} CLASS_NAME_SHOWN - Класс, добавляемый после завершения анимации появления.
|
|
34
|
+
*/
|
|
35
|
+
const CLASS_NAME_SHOWN = 'shown';
|
|
36
|
+
|
|
37
|
+
// События
|
|
18
38
|
const EVENT_KEY_HIDE = `${NAME_KEY}.hide`;
|
|
19
39
|
const EVENT_KEY_HIDDEN = `${NAME_KEY}.hidden`;
|
|
20
40
|
const EVENT_KEY_SHOW = `${NAME_KEY}.show`;
|
|
21
41
|
const EVENT_KEY_SHOWN = `${NAME_KEY}.shown`;
|
|
22
42
|
const EVENT_KEY_LOADED = `${NAME_KEY}.loaded`;
|
|
23
|
-
|
|
24
43
|
const EVENT_KEY_KEYDOWN_DISMISS = `keydown.dismiss.${NAME_KEY}`;
|
|
25
44
|
const EVENT_KEY_HIDE_PREVENTED = `hidePrevented.${NAME_KEY}`;
|
|
26
45
|
const EVENT_KEY_CLICK_DATA_API = `click.${NAME_KEY}.data.api`;
|
|
27
46
|
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {Object} ToastParams
|
|
49
|
+
* @property {boolean} static - Сохранять ли тост в DOM после скрытия.
|
|
50
|
+
* @property {string} placement - Расположение: 'top left', 'bottom center' и т.д.
|
|
51
|
+
* @property {boolean} autohide - Автоматически скрывать.
|
|
52
|
+
* @property {number} delay - Задержка перед авто-скрытием (мс).
|
|
53
|
+
* @property {boolean} enableClickToast - Закрывать по клику на тост.
|
|
54
|
+
* @property {boolean} enableButtonClose - Добавить кнопку закрытия.
|
|
55
|
+
* @property {boolean} keyboard - Закрывать по Esc.
|
|
56
|
+
* @property {string} theme - Тема: 'dark', 'light' и т.д.
|
|
57
|
+
* @property {Object} stack - Настройки стека уведомлений.
|
|
58
|
+
* @property {boolean} stack.enable - Разрешить стек.
|
|
59
|
+
* @property {number} stack.max - Макс. количество тостов одновременно.
|
|
60
|
+
* @property {Object} animation - Анимация.
|
|
61
|
+
* @property {boolean} animation.enable - Включить анимацию.
|
|
62
|
+
* @property {string} animation.in - Анимация входа (Animate.css).
|
|
63
|
+
* @property {string} animation.out - Анимация выхода.
|
|
64
|
+
* @property {number} animation.delay - Длительность анимации.
|
|
65
|
+
* @property {Object} ajax - Настройки AJAX.
|
|
66
|
+
* @property {string} ajax.route - URL для загрузки.
|
|
67
|
+
* @property {string} ajax.target - Селектор контейнера.
|
|
68
|
+
* @property {string} ajax.method - HTTP-метод.
|
|
69
|
+
* @property {boolean} ajax.loader - Показывать лоадер.
|
|
70
|
+
* @property {boolean} ajax.once - Загружать один раз.
|
|
71
|
+
* @property {boolean} ajax.output - Выводить результат.
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Параметры по умолчанию
|
|
76
|
+
* @type {ToastParams}
|
|
77
|
+
*/
|
|
28
78
|
const defaultParams = {
|
|
29
79
|
static: true,
|
|
30
80
|
placement: 'bottom center',
|
|
@@ -54,59 +104,95 @@ const defaultParams = {
|
|
|
54
104
|
}
|
|
55
105
|
};
|
|
56
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Класс VGToast — модуль уведомлений (тосты)
|
|
109
|
+
* Поддерживает стек, анимации, авто-скрытие, AJAX-контент, горячие клавиши.
|
|
110
|
+
*/
|
|
57
111
|
class VGToast extends BaseModule {
|
|
112
|
+
/**
|
|
113
|
+
* Создаёт экземпляр VGToast
|
|
114
|
+
* @param {Element} element - HTML-элемент тоста.
|
|
115
|
+
* @param {Partial<ToastParams>} params - Пользовательские параметры.
|
|
116
|
+
*/
|
|
58
117
|
constructor(element, params = {}) {
|
|
59
118
|
super(element, params);
|
|
60
119
|
|
|
120
|
+
/** @private */
|
|
61
121
|
this._params = this._getParams(element, mergeDeepObject(defaultParams, params));
|
|
62
122
|
this._animation(this._element, VGToast.NAME_KEY, this._params.animation);
|
|
63
123
|
this._dismissElement();
|
|
64
124
|
this._addEventListeners();
|
|
65
125
|
|
|
126
|
+
/** @private */
|
|
66
127
|
this._timeout = null;
|
|
67
128
|
}
|
|
68
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Имя модуля
|
|
132
|
+
* @returns {string}
|
|
133
|
+
*/
|
|
69
134
|
static get NAME() {
|
|
70
135
|
return NAME;
|
|
71
136
|
}
|
|
72
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Пространство имён событий
|
|
140
|
+
* @returns {string}
|
|
141
|
+
*/
|
|
73
142
|
static get NAME_KEY() {
|
|
74
|
-
return NAME_KEY
|
|
143
|
+
return NAME_KEY;
|
|
75
144
|
}
|
|
76
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Глобальный метод для быстрого создания тоста
|
|
148
|
+
* @param {string|Array<string>} text - Текст или [заголовок, тело].
|
|
149
|
+
* @param {Partial<ToastParams>} [params] - Параметры.
|
|
150
|
+
* @param {Function} [callback] - Вызывается после создания.
|
|
151
|
+
* @returns {VGToast}
|
|
152
|
+
*/
|
|
77
153
|
static run(text, params = {}, callback) {
|
|
78
154
|
return VGToast.build(text, params, callback);
|
|
79
155
|
}
|
|
80
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Создаёт и показывает новый тост
|
|
159
|
+
* @param {string|Array<string>} text - Текст уведомления.
|
|
160
|
+
* @param {Partial<ToastParams>} [params] - Параметры.
|
|
161
|
+
* @param {Function} [callback] - Вызывается после появления.
|
|
162
|
+
* @returns {VGToast}
|
|
163
|
+
*/
|
|
81
164
|
static build(text, params, callback) {
|
|
82
|
-
params = mergeDeepObject(defaultParams, {static: false, autohide: true}, params);
|
|
165
|
+
params = mergeDeepObject(defaultParams, { static: false, autohide: true }, params);
|
|
83
166
|
|
|
84
|
-
|
|
167
|
+
const id = 'vg-toast-' + makeRandomString();
|
|
168
|
+
const target = document.createElement('div');
|
|
85
169
|
target.classList.add('vg-toast');
|
|
86
|
-
target.id =
|
|
170
|
+
target.id = id;
|
|
87
171
|
|
|
88
|
-
|
|
89
|
-
|
|
172
|
+
// Тема
|
|
173
|
+
if (params.theme) {
|
|
174
|
+
target.classList.add(`vg-toast-${params.theme}`);
|
|
90
175
|
}
|
|
91
176
|
|
|
92
|
-
|
|
93
|
-
|
|
177
|
+
// Позиция
|
|
178
|
+
if (params.placement) {
|
|
179
|
+
params.placement.split(' ').forEach(cls => target.classList.add(cls));
|
|
94
180
|
}
|
|
95
181
|
|
|
96
|
-
|
|
182
|
+
const wrapper = document.createElement('div');
|
|
97
183
|
wrapper.classList.add('vg-toast-wrapper');
|
|
98
184
|
|
|
99
|
-
|
|
100
|
-
|
|
185
|
+
// Иконка (если задан тип)
|
|
186
|
+
if (params.type) {
|
|
187
|
+
const icon = document.createElement('div');
|
|
101
188
|
icon.classList.add('vg-toast-icon');
|
|
102
|
-
|
|
103
189
|
wrapper.append(icon);
|
|
104
190
|
}
|
|
105
191
|
|
|
106
|
-
|
|
192
|
+
const content = document.createElement('div');
|
|
107
193
|
content.classList.add('vg-toast-content');
|
|
108
194
|
|
|
109
|
-
|
|
195
|
+
const body = document.createElement('div');
|
|
110
196
|
body.classList.add('vg-toast-body');
|
|
111
197
|
|
|
112
198
|
if (typeof text === 'string') {
|
|
@@ -114,23 +200,20 @@ class VGToast extends BaseModule {
|
|
|
114
200
|
content.append(body);
|
|
115
201
|
} else if (Array.isArray(text)) {
|
|
116
202
|
if (text.length > 1) {
|
|
117
|
-
|
|
203
|
+
const header = document.createElement('div');
|
|
118
204
|
header.classList.add('vg-toast-header');
|
|
119
205
|
header.innerHTML = text[0];
|
|
120
206
|
content.append(header);
|
|
121
|
-
|
|
122
|
-
body.innerHTML = text[1];
|
|
123
|
-
content.append(body);
|
|
124
|
-
} else {
|
|
125
|
-
body.innerHTML = text[0];
|
|
126
|
-
content.append(body);
|
|
127
207
|
}
|
|
208
|
+
body.innerHTML = text[1];
|
|
209
|
+
content.append(body);
|
|
128
210
|
}
|
|
129
211
|
|
|
130
212
|
wrapper.append(content);
|
|
131
213
|
|
|
132
|
-
|
|
133
|
-
|
|
214
|
+
// Кнопка закрытия
|
|
215
|
+
if (params.enableButtonClose) {
|
|
216
|
+
const button = document.createElement('div');
|
|
134
217
|
button.classList.add('vg-toast-button');
|
|
135
218
|
button.innerHTML = '<button class="vg-btn-close" data-vg-dismiss="toast"></button>';
|
|
136
219
|
wrapper.append(button);
|
|
@@ -139,34 +222,45 @@ class VGToast extends BaseModule {
|
|
|
139
222
|
target.append(wrapper);
|
|
140
223
|
document.body.append(target);
|
|
141
224
|
|
|
142
|
-
|
|
143
|
-
if (
|
|
225
|
+
const instance = VGToast.getOrCreateInstance(target, params);
|
|
226
|
+
if (params.animation) {
|
|
144
227
|
instance._animation(target, VGToast.NAME_KEY, params.animation);
|
|
145
228
|
}
|
|
146
229
|
|
|
147
230
|
execute(callback, [instance]);
|
|
148
231
|
instance.show();
|
|
232
|
+
|
|
233
|
+
return instance;
|
|
149
234
|
}
|
|
150
235
|
|
|
236
|
+
/**
|
|
237
|
+
* Переключает состояние (показать/скрыть)
|
|
238
|
+
* @param {Element} [relatedTarget] - Элемент, вызвавший тост.
|
|
239
|
+
* @returns {VGToast}
|
|
240
|
+
*/
|
|
151
241
|
toggle(relatedTarget) {
|
|
152
|
-
return
|
|
242
|
+
return this._isShown() ? this.hide() : this.show(relatedTarget);
|
|
153
243
|
}
|
|
154
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Показывает тост
|
|
247
|
+
* @param {Element} [relatedTarget] - Элемент, инициировавший показ.
|
|
248
|
+
* @returns {void}
|
|
249
|
+
*/
|
|
155
250
|
show(relatedTarget) {
|
|
156
251
|
if (isDisabled(this._element)) return;
|
|
157
252
|
|
|
158
253
|
this._clearTimeout();
|
|
159
254
|
|
|
160
255
|
this._params = this._getParams(relatedTarget || {}, this._params);
|
|
161
|
-
this._route(
|
|
162
|
-
EventHandler.trigger(this._element, EVENT_KEY_LOADED, {stats: status, data
|
|
256
|
+
this._route((status, data) => {
|
|
257
|
+
EventHandler.trigger(this._element, EVENT_KEY_LOADED, { stats: status, data });
|
|
163
258
|
});
|
|
164
259
|
|
|
165
|
-
const showEvent = EventHandler.trigger(this._element, EVENT_KEY_SHOW, { relatedTarget })
|
|
260
|
+
const showEvent = EventHandler.trigger(this._element, EVENT_KEY_SHOW, { relatedTarget });
|
|
166
261
|
if (showEvent.defaultPrevented) return;
|
|
167
262
|
|
|
168
|
-
this._element
|
|
169
|
-
|
|
263
|
+
this._element.classList.remove(CLASS_NAME_SHOWN);
|
|
170
264
|
this._element.classList.add(CLASS_NAME_SHOW);
|
|
171
265
|
document.body.classList.add(CLASS_NAME_OPEN);
|
|
172
266
|
|
|
@@ -176,20 +270,25 @@ class VGToast extends BaseModule {
|
|
|
176
270
|
this._element.classList.add(CLASS_NAME_SHOWN);
|
|
177
271
|
this._scheduleHide();
|
|
178
272
|
EventHandler.trigger(this._element, EVENT_KEY_SHOWN, { relatedTarget });
|
|
179
|
-
}
|
|
273
|
+
};
|
|
274
|
+
|
|
180
275
|
this._queueCallback(completeCallBack, this._element, true, this._params.animation.delay);
|
|
181
276
|
}
|
|
182
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Скрывает тост
|
|
280
|
+
* @returns {void}
|
|
281
|
+
*/
|
|
183
282
|
hide() {
|
|
184
283
|
if (isDisabled(this._element)) return;
|
|
185
284
|
|
|
186
285
|
const hideEvent = EventHandler.trigger(this._element, EVENT_KEY_HIDE);
|
|
187
286
|
if (hideEvent.defaultPrevented) return;
|
|
188
287
|
|
|
189
|
-
this._element
|
|
288
|
+
this._element.classList.remove(CLASS_NAME_SHOWN);
|
|
190
289
|
|
|
191
290
|
setTimeout(() => {
|
|
192
|
-
this._element
|
|
291
|
+
this._element.classList.remove(CLASS_NAME_SHOW);
|
|
193
292
|
|
|
194
293
|
const completeCallback = () => {
|
|
195
294
|
document.body.classList.remove(CLASS_NAME_OPEN);
|
|
@@ -202,181 +301,186 @@ class VGToast extends BaseModule {
|
|
|
202
301
|
if (!this._params.static) {
|
|
203
302
|
this.dispose();
|
|
204
303
|
}
|
|
205
|
-
}
|
|
304
|
+
};
|
|
305
|
+
|
|
206
306
|
this._queueCallback(completeCallback, this._element, false, this._params.animation.delay);
|
|
207
307
|
}, this._params.animation.delay);
|
|
208
308
|
}
|
|
209
309
|
|
|
310
|
+
/**
|
|
311
|
+
* Удаляет тост из DOM и снимает обработчики
|
|
312
|
+
* @override
|
|
313
|
+
*/
|
|
210
314
|
dispose() {
|
|
211
315
|
this._clearTimeout();
|
|
212
|
-
if (this._isShown()) {
|
|
213
|
-
this._element.classList.remove(CLASS_NAME_SHOW);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
316
|
if (!this._params.static) {
|
|
217
317
|
this._element.remove();
|
|
218
318
|
}
|
|
219
|
-
|
|
220
319
|
super.dispose();
|
|
221
320
|
}
|
|
222
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Устанавливает таймер на скрытие
|
|
324
|
+
* @private
|
|
325
|
+
*/
|
|
223
326
|
_scheduleHide() {
|
|
224
|
-
if (!this._params.autohide)
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
327
|
+
if (!this._params.autohide) return;
|
|
227
328
|
|
|
228
|
-
this._timeout = setTimeout(() =>
|
|
229
|
-
this.hide();
|
|
230
|
-
}, this._params.delay);
|
|
329
|
+
this._timeout = setTimeout(() => this.hide(), this._params.delay);
|
|
231
330
|
}
|
|
232
331
|
|
|
332
|
+
/**
|
|
333
|
+
* Проверяет, показан ли тост
|
|
334
|
+
* @private
|
|
335
|
+
* @returns {boolean}
|
|
336
|
+
*/
|
|
233
337
|
_isShown() {
|
|
234
338
|
return this._element.classList.contains(CLASS_NAME_SHOW);
|
|
235
339
|
}
|
|
236
340
|
|
|
237
|
-
|
|
238
|
-
|
|
341
|
+
/**
|
|
342
|
+
* Возвращает список активных тостов с вертикальными смещениями
|
|
343
|
+
* Учитывает стек и максимальное количество
|
|
344
|
+
* @private
|
|
345
|
+
* @returns {Array<{el: Element, top: number}>}
|
|
346
|
+
*/
|
|
347
|
+
_enableStack() {
|
|
348
|
+
const placement = this._params.placement;
|
|
349
|
+
const isVerticalCenter = placement.includes('center');
|
|
350
|
+
const isTop = placement.includes('top');
|
|
351
|
+
const isBottom = !isTop; // по умолчанию снизу
|
|
352
|
+
|
|
353
|
+
// Фильтруем тосты с таким же направлением (top или bottom)
|
|
354
|
+
const stackClass = isTop ? 'top' : 'bottom';
|
|
355
|
+
const elmsShown = Selectors.findAll(`.vg-toast.show.${stackClass}`)
|
|
356
|
+
.filter(el => {
|
|
357
|
+
const instance = VGToast.getInstance(el);
|
|
358
|
+
return instance?._params.stack.enable;
|
|
359
|
+
});
|
|
239
360
|
|
|
240
|
-
if (this._params.stack.enable) {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
361
|
+
if (!this._params.stack.enable) {
|
|
362
|
+
// Скрываем другие тосты, если стек выключен
|
|
363
|
+
elmsShown
|
|
364
|
+
.filter(el => el !== this._element)
|
|
365
|
+
.forEach(el => VGToast.getInstance(el).hide());
|
|
366
|
+
return [{ el: this._element, top: 0 }];
|
|
245
367
|
}
|
|
246
368
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
isPlacementClassCenter = elm.el.classList.contains('center');
|
|
253
|
-
|
|
254
|
-
if (!isPlacementClassTop &&
|
|
255
|
-
!isPlacementClassBottom &&
|
|
256
|
-
!isPlacementClassCenter &&
|
|
257
|
-
!isPlacementClassRight &&
|
|
258
|
-
!isPlacementClassLeft
|
|
259
|
-
) {
|
|
260
|
-
isPlacementClassBottom = true;
|
|
261
|
-
isPlacementClassCenter = true;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (isPlacementClassCenter) {
|
|
265
|
-
if (isPlacementClassLeft) {
|
|
266
|
-
elm.el.style.left = 0;
|
|
267
|
-
elm.el.style.bottom = 'calc(50% - ('+ elm.top +'px))';
|
|
268
|
-
} else if (isPlacementClassRight) {
|
|
269
|
-
elm.el.style.right = 0;
|
|
270
|
-
elm.el.style.bottom = 'calc(50% - ('+ elm.top +'px))';
|
|
271
|
-
} else if (isPlacementClassBottom) {
|
|
272
|
-
elm.el.style.left = 'calc(50% - ('+ elm.el.clientWidth +'px) / 2)';
|
|
273
|
-
elm.el.style.bottom = elm.top + 'px';
|
|
274
|
-
} else if (isPlacementClassTop) {
|
|
275
|
-
elm.el.style.left = 'calc(50% - ('+ elm.el.clientWidth +'px) / 2)';
|
|
276
|
-
elm.el.style.top = elm.top + 'px';
|
|
277
|
-
} else {
|
|
278
|
-
elm.el.style.left = 'calc(50% - ('+ elm.el.clientHeight +'px) / 2)';
|
|
279
|
-
elm.el.style.bottom = 'calc(50% - '+ elm.top +'px)';
|
|
280
|
-
}
|
|
281
|
-
} else {
|
|
282
|
-
if (isPlacementClassLeft) elm.el.style.left = 0;
|
|
283
|
-
if (isPlacementClassBottom) elm.el.style.bottom = elm.top + 'px';
|
|
284
|
-
if (isPlacementClassTop) elm.el.style.top = elm.top + 'px';
|
|
285
|
-
if (isPlacementClassRight) elm.el.style.right = 0;
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
}
|
|
369
|
+
// Ограничиваем по max
|
|
370
|
+
if (elmsShown.length >= this._params.stack.max) {
|
|
371
|
+
const excess = elmsShown.slice(0, elmsShown.length - this._params.stack.max + 1);
|
|
372
|
+
excess.forEach(el => VGToast.getInstance(el).hide());
|
|
373
|
+
}
|
|
289
374
|
|
|
290
|
-
|
|
291
|
-
|
|
375
|
+
// Вычисляем смещение (по высоте)
|
|
376
|
+
const prevEls = elmsShown.filter(el => el !== this._element);
|
|
377
|
+
const offset = prevEls.reduce((sum, el) => sum + el.clientHeight, 0);
|
|
292
378
|
|
|
293
|
-
|
|
294
|
-
elmsShown.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
379
|
+
return elmsShown.includes(this._element)
|
|
380
|
+
? elmsShown.map((el, index) => {
|
|
381
|
+
const heightSum = elmsShown.slice(0, index).reduce((sum, e) => sum + e.clientHeight, 0);
|
|
382
|
+
return { el, top: heightSum };
|
|
298
383
|
})
|
|
384
|
+
: [{ el: this._element, top: offset }];
|
|
385
|
+
}
|
|
299
386
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
387
|
+
/**
|
|
388
|
+
* Устанавливает позицию тостов с учётом стека
|
|
389
|
+
* @private
|
|
390
|
+
*/
|
|
391
|
+
_setPlacement() {
|
|
392
|
+
const elms = this._enableStack();
|
|
393
|
+
const isCenter = this._params.placement.includes('center');
|
|
394
|
+
const isLeft = this._params.placement.includes('left');
|
|
395
|
+
const isRight = this._params.placement.includes('right');
|
|
396
|
+
const isTop = this._params.placement.includes('top');
|
|
397
|
+
|
|
398
|
+
const stackClass = isTop ? 'top' : 'bottom';
|
|
399
|
+
|
|
400
|
+
elms.forEach(({ el, top }) => {
|
|
401
|
+
const style = el.style;
|
|
402
|
+
style.left = '';
|
|
403
|
+
style.right = '';
|
|
404
|
+
style.top = '';
|
|
405
|
+
style.bottom = '';
|
|
406
|
+
style.transform = '';
|
|
407
|
+
|
|
408
|
+
if (isCenter) {
|
|
409
|
+
style.left = '50%';
|
|
410
|
+
style.transform = 'translateX(-50%)';
|
|
411
|
+
} else if (isLeft) {
|
|
412
|
+
style.left = '0';
|
|
413
|
+
} else if (isRight) {
|
|
414
|
+
style.right = '0';
|
|
415
|
+
} else {
|
|
416
|
+
// по умолчанию: центрирование
|
|
417
|
+
style.left = '50%';
|
|
418
|
+
style.transform = 'translateX(-50%)';
|
|
310
419
|
}
|
|
311
|
-
});
|
|
312
420
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
return {
|
|
316
|
-
el: value.el,
|
|
317
|
-
top: 0
|
|
318
|
-
}
|
|
421
|
+
if (isTop) {
|
|
422
|
+
style.top = top + 'px';
|
|
319
423
|
} else {
|
|
320
|
-
top
|
|
321
|
-
|
|
322
|
-
return {
|
|
323
|
-
el: value.el,
|
|
324
|
-
top: top
|
|
325
|
-
}
|
|
424
|
+
style.bottom = top + 'px';
|
|
326
425
|
}
|
|
327
426
|
});
|
|
328
427
|
}
|
|
329
428
|
|
|
429
|
+
/**
|
|
430
|
+
* Очищает таймер
|
|
431
|
+
* @private
|
|
432
|
+
*/
|
|
330
433
|
_clearTimeout() {
|
|
331
|
-
|
|
332
|
-
|
|
434
|
+
if (this._timeout) {
|
|
435
|
+
clearTimeout(this._timeout);
|
|
436
|
+
this._timeout = null;
|
|
437
|
+
}
|
|
333
438
|
}
|
|
334
439
|
|
|
440
|
+
/**
|
|
441
|
+
* Назначает обработчики событий
|
|
442
|
+
* @private
|
|
443
|
+
*/
|
|
335
444
|
_addEventListeners() {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
EventHandler.trigger(this._element, EVENT_KEY_HIDE_PREVENTED)
|
|
345
|
-
});
|
|
445
|
+
// Закрытие по Esc
|
|
446
|
+
if (this._params.keyboard) {
|
|
447
|
+
EventHandler.on(document, EVENT_KEY_KEYDOWN_DISMISS, event => {
|
|
448
|
+
if (event.key === 'Escape' && this._isShown()) {
|
|
449
|
+
this.hide();
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
}
|
|
346
453
|
|
|
454
|
+
// Закрытие по клику на тост
|
|
347
455
|
if (this._params.enableClickToast) {
|
|
348
456
|
this._element.classList.add('vg-toast-pointer');
|
|
349
|
-
|
|
350
|
-
EventHandler.on(document, EVENT_KEY_CLICK_DATA_API, '#' + this._element.id, () => {
|
|
457
|
+
EventHandler.on(document, EVENT_KEY_CLICK_DATA_API, `#${this._element.id}`, () => {
|
|
351
458
|
this.hide();
|
|
352
|
-
})
|
|
459
|
+
});
|
|
353
460
|
}
|
|
354
461
|
}
|
|
355
462
|
}
|
|
356
463
|
|
|
464
|
+
// Автоматическое закрытие по data-vg-dismiss
|
|
357
465
|
dismissTrigger(VGToast);
|
|
358
466
|
|
|
359
467
|
/**
|
|
360
|
-
* Data API
|
|
468
|
+
* Реализация Data API
|
|
361
469
|
*/
|
|
362
470
|
EventHandler.on(document, EVENT_KEY_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
|
|
363
471
|
const target = Selectors.getElementFromSelector(this);
|
|
364
|
-
|
|
365
472
|
if (['A', 'AREA'].includes(this.tagName)) {
|
|
366
|
-
event.preventDefault()
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
if (isDisabled(this)) {
|
|
370
|
-
return
|
|
473
|
+
event.preventDefault();
|
|
371
474
|
}
|
|
475
|
+
if (isDisabled(this)) return;
|
|
372
476
|
|
|
373
|
-
this.setAttribute('aria-expanded', true);
|
|
477
|
+
this.setAttribute('aria-expanded', 'true');
|
|
374
478
|
EventHandler.one(target, EVENT_KEY_HIDDEN, () => {
|
|
375
|
-
this.setAttribute('aria-expanded', false);
|
|
479
|
+
this.setAttribute('aria-expanded', 'false');
|
|
376
480
|
});
|
|
377
481
|
|
|
378
482
|
const data = VGToast.getOrCreateInstance(target);
|
|
379
483
|
data.toggle(this);
|
|
380
484
|
});
|
|
381
485
|
|
|
382
|
-
export default VGToast;
|
|
486
|
+
export default VGToast;
|