vgapp 1.5.6 → 1.5.7
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/app/modules/vgalert/js/vgalert.js +7 -4
- package/app/modules/vgfiles/js/base.js +25 -30
- package/app/modules/vgmodal/js/vgmodal.js +9 -3
- package/app/modules/vgselect/js/handlers.js +6 -53
- package/app/modules/vgselect/js/vgselect.js +107 -63
- package/app/modules/vgselect/scss/vgselect.scss +1 -1
- package/app/modules/vgsidebar/js/vgsidebar.js +21 -10
- package/app/modules/vgspy/js/vgspy.js +43 -22
- package/app/modules/vgtabs/js/vgtabs.js +91 -66
- package/app/modules/vgtoast/js/vgtoast.js +11 -5
- package/app/modules/vgtooltip/js/vgtooltip.js +19 -9
- package/app/utils/js/components/file-icon.js +7 -2
- package/build/vgapp.css +1 -1
- package/build/vgapp.css.map +1 -1
- package/build/vgapp.js +1 -1
- package/build/vgapp.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Описание: отслеживание активных секций и навигация по якорям.
|
|
3
|
+
* Возможности: Data API, нативная и виртуальная прокрутка, вложенные меню и обновление секций.
|
|
4
|
+
*/
|
|
5
|
+
import BaseModule from "../../base-module";
|
|
6
|
+
import { getElement, isDisabled, isVisible, normalizeData } from "../../../utils/js/functions";
|
|
3
7
|
import EventHandler from "../../../utils/js/dom/event";
|
|
4
8
|
import Selectors from "../../../utils/js/dom/selectors";
|
|
5
9
|
|
|
@@ -52,7 +56,7 @@ class VGSpy extends BaseModule {
|
|
|
52
56
|
* @property {number[]|string} threshold - пороги видимости (0.1, 0.5, 1)
|
|
53
57
|
*/
|
|
54
58
|
this._params = this._configAfterMerge(
|
|
55
|
-
|
|
59
|
+
Object.assign(
|
|
56
60
|
{
|
|
57
61
|
offset: null, // Устаревшее, для обратной совместимости
|
|
58
62
|
rootMargin: '0px 0px -25%',
|
|
@@ -60,7 +64,8 @@ class VGSpy extends BaseModule {
|
|
|
60
64
|
target: this._element,
|
|
61
65
|
threshold: [0.1, 0.5, 1],
|
|
62
66
|
},
|
|
63
|
-
params
|
|
67
|
+
params,
|
|
68
|
+
this._getDataOptions()
|
|
64
69
|
)
|
|
65
70
|
);
|
|
66
71
|
|
|
@@ -130,15 +135,27 @@ class VGSpy extends BaseModule {
|
|
|
130
135
|
* Ключ модуля (для хранения в data)
|
|
131
136
|
* @returns {string}
|
|
132
137
|
*/
|
|
133
|
-
static get NAME_KEY() {
|
|
134
|
-
return NAME_KEY;
|
|
135
|
-
}
|
|
138
|
+
static get NAME_KEY() {
|
|
139
|
+
return NAME_KEY;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
_getDataOptions() {
|
|
143
|
+
const options = {};
|
|
144
|
+
for (const name of ['target', 'offset', 'rootMargin', 'smoothScroll', 'threshold']) {
|
|
145
|
+
const attribute = `data-${name.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`)}`;
|
|
146
|
+
if (this._element.hasAttribute(attribute)) {
|
|
147
|
+
options[name] = normalizeData(this._element.getAttribute(attribute));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return options;
|
|
151
|
+
}
|
|
136
152
|
|
|
137
153
|
/**
|
|
138
154
|
* Инициализирует или перезапускает модуль: находит ссылки и секции, создаёт observer
|
|
139
155
|
*/
|
|
140
|
-
refresh() {
|
|
141
|
-
this.
|
|
156
|
+
refresh() {
|
|
157
|
+
this._process(null);
|
|
158
|
+
this._initializeTargetsAndObservables();
|
|
142
159
|
this._updateRootElement();
|
|
143
160
|
this._maybeEnableSmoothScroll();
|
|
144
161
|
|
|
@@ -163,8 +180,8 @@ class VGSpy extends BaseModule {
|
|
|
163
180
|
|
|
164
181
|
// Smooth Scrollbar can be initialized after the spy; retry once on the next tick.
|
|
165
182
|
if (this._rootElement && !this._isScrollableSelf(this._rootElement) && window.Scrollbar) {
|
|
166
|
-
setTimeout(() => {
|
|
167
|
-
if (this._scrollbar) return;
|
|
183
|
+
setTimeout(() => {
|
|
184
|
+
if (!this._element || this._scrollbar) return;
|
|
168
185
|
this._updateSmoothScrollbar();
|
|
169
186
|
if (this._scrollbar) this._setupScrollbarTracking();
|
|
170
187
|
}, 0);
|
|
@@ -356,7 +373,9 @@ class VGSpy extends BaseModule {
|
|
|
356
373
|
return window.scrollY || document.documentElement.scrollTop || 0;
|
|
357
374
|
}
|
|
358
375
|
|
|
359
|
-
dispose() {
|
|
376
|
+
dispose() {
|
|
377
|
+
if (!this._element) return;
|
|
378
|
+
this._process(null);
|
|
360
379
|
if (this._observer) {
|
|
361
380
|
this._observer.disconnect();
|
|
362
381
|
}
|
|
@@ -415,8 +434,9 @@ class VGSpy extends BaseModule {
|
|
|
415
434
|
// If the target section is currently hidden (tabs/collapses/lazy layout),
|
|
416
435
|
// don't hijack the click; allow UI to reveal it, then retry.
|
|
417
436
|
if (!isVisible(section)) {
|
|
418
|
-
setTimeout(() => {
|
|
419
|
-
|
|
437
|
+
setTimeout(() => {
|
|
438
|
+
if (!this._element) return;
|
|
439
|
+
const revealed = Selectors.findID(id);
|
|
420
440
|
if (!revealed || !isVisible(revealed)) return;
|
|
421
441
|
|
|
422
442
|
this._targetLinks.set(revealed.id, link);
|
|
@@ -505,10 +525,10 @@ class VGSpy extends BaseModule {
|
|
|
505
525
|
const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop;
|
|
506
526
|
this._previousScrollData.parentScrollTop = parentScrollTop;
|
|
507
527
|
|
|
508
|
-
for (const entry of entries) {
|
|
509
|
-
if (!entry.isIntersecting) {
|
|
510
|
-
|
|
511
|
-
continue;
|
|
528
|
+
for (const entry of entries) {
|
|
529
|
+
if (!entry.isIntersecting) {
|
|
530
|
+
if (getTargetLink(entry) === this._activeTarget) this._process(null);
|
|
531
|
+
continue;
|
|
512
532
|
}
|
|
513
533
|
|
|
514
534
|
const entryTop = this._getSectionTop(entry.target);
|
|
@@ -516,7 +536,7 @@ class VGSpy extends BaseModule {
|
|
|
516
536
|
const shouldActivate =
|
|
517
537
|
(userScrollsDown && isEntryBelow) || (!userScrollsDown && !isEntryBelow);
|
|
518
538
|
|
|
519
|
-
if (shouldActivate) {
|
|
539
|
+
if (shouldActivate || !this._activeTarget) {
|
|
520
540
|
this._previousScrollData.visibleEntryTop = entryTop;
|
|
521
541
|
this._process(getTargetLink(entry));
|
|
522
542
|
}
|
|
@@ -595,7 +615,7 @@ class VGSpy extends BaseModule {
|
|
|
595
615
|
parent.classList.remove(CLASS_NAME_ACTIVE);
|
|
596
616
|
|
|
597
617
|
const activeLinks = Selectors.findAll(
|
|
598
|
-
`[href].${CLASS_NAME_ACTIVE}, [data-vg-target].${CLASS_NAME_ACTIVE}`,
|
|
618
|
+
`[href].${CLASS_NAME_ACTIVE}, [data-vg-target].${CLASS_NAME_ACTIVE}, ${SELECTOR_DROPDOWN_TOGGLE}.${CLASS_NAME_ACTIVE}`,
|
|
599
619
|
parent
|
|
600
620
|
);
|
|
601
621
|
for (const link of activeLinks) {
|
|
@@ -603,8 +623,9 @@ class VGSpy extends BaseModule {
|
|
|
603
623
|
}
|
|
604
624
|
}
|
|
605
625
|
|
|
606
|
-
_getTargetIdFromTrigger(trigger) {
|
|
607
|
-
if (!trigger || typeof trigger.getAttribute !== 'function') return null;
|
|
626
|
+
_getTargetIdFromTrigger(trigger) {
|
|
627
|
+
if (!trigger || typeof trigger.getAttribute !== 'function') return null;
|
|
628
|
+
if (isDisabled(trigger) || trigger.matches(SELECTOR_DROPDOWN_TOGGLE)) return null;
|
|
608
629
|
|
|
609
630
|
const dataTarget = (trigger.getAttribute('data-vg-target') || '').trim();
|
|
610
631
|
const href = (trigger.getAttribute('href') || '').trim();
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Описание: вкладки VGTabs с декларативной и ручной инициализацией.
|
|
3
|
+
* Возможности: клавиатура, начальный hash, AJAX, отменяемые события и адаптивный индикатор.
|
|
4
|
+
*/
|
|
5
|
+
import BaseModule from "../../base-module";
|
|
2
6
|
import Selectors from "../../../utils/js/dom/selectors";
|
|
3
7
|
import EventHandler from "../../../utils/js/dom/event";
|
|
4
8
|
import {getNextActiveElement, isDisabled, mergeDeepObject} from "../../../utils/js/functions";
|
|
@@ -132,7 +136,7 @@ class VGTabs extends BaseModule {
|
|
|
132
136
|
once: true,
|
|
133
137
|
output: true,
|
|
134
138
|
},
|
|
135
|
-
},
|
|
139
|
+
}, params || {});
|
|
136
140
|
|
|
137
141
|
this._parent = this._element.closest(SELECTOR.TAB_PANEL);
|
|
138
142
|
this._main_parent = this._parent?.closest(SELECTOR.TAB_CLASS) || null;
|
|
@@ -173,19 +177,19 @@ class VGTabs extends BaseModule {
|
|
|
173
177
|
show() {
|
|
174
178
|
const innerElem = this._element;
|
|
175
179
|
|
|
176
|
-
if (this._elemIsActive(innerElem)) return;
|
|
180
|
+
if (!innerElem || isDisabled(innerElem) || this._elemIsActive(innerElem)) return;
|
|
177
181
|
|
|
178
182
|
const activeElem = this._getActiveElem();
|
|
179
|
-
const relatedTarget = innerElem;
|
|
180
183
|
|
|
181
184
|
// События hide и show
|
|
182
|
-
const hideEvent = activeElem ? EventHandler.trigger(activeElem, EVENT_HIDE, {relatedTarget}) : null;
|
|
183
|
-
const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, {relatedTarget});
|
|
185
|
+
const hideEvent = activeElem ? EventHandler.trigger(activeElem, EVENT_HIDE, {relatedTarget: innerElem}) : null;
|
|
186
|
+
const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, {relatedTarget: activeElem});
|
|
184
187
|
|
|
185
188
|
if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) return;
|
|
186
189
|
|
|
187
190
|
this._deactivate(activeElem, innerElem);
|
|
188
|
-
this._activate(innerElem,
|
|
191
|
+
this._activate(innerElem, activeElem);
|
|
192
|
+
this._updateSlider(innerElem);
|
|
189
193
|
}
|
|
190
194
|
|
|
191
195
|
/**
|
|
@@ -218,21 +222,28 @@ class VGTabs extends BaseModule {
|
|
|
218
222
|
const target = Selectors.getElementFromSelector(element);
|
|
219
223
|
if (target) this._activate(target, relatedTarget);
|
|
220
224
|
|
|
221
|
-
const complete = () => {
|
|
225
|
+
const complete = () => {
|
|
226
|
+
if (!this._element || !element.classList.contains(CLASS_NAME.ACTIVE)) return;
|
|
222
227
|
if (element.getAttribute('role') !== 'tab') {
|
|
223
228
|
element.classList.add(CLASS_NAME.SHOW);
|
|
224
229
|
return;
|
|
225
230
|
}
|
|
226
231
|
|
|
227
|
-
this.
|
|
228
|
-
|
|
229
|
-
|
|
232
|
+
if (this._params.ajax.route && !this._isLoaded && !this._isLoading) {
|
|
233
|
+
this._isLoading = true;
|
|
234
|
+
const loaded = (status, data) => {
|
|
235
|
+
if (!this._element) return;
|
|
236
|
+
this._isLoading = false;
|
|
237
|
+
EventHandler.trigger(this._element, EVENT_LOADED, { stats: status, data });
|
|
238
|
+
};
|
|
239
|
+
this._route(loaded, error => loaded('error', error));
|
|
240
|
+
}
|
|
230
241
|
|
|
231
242
|
element.removeAttribute('tabindex');
|
|
232
243
|
element.setAttribute('aria-selected', 'true');
|
|
233
244
|
this._toggleDropDown(element, true);
|
|
234
245
|
|
|
235
|
-
EventHandler.trigger(element, EVENT_SHOWN, { relatedTarget });
|
|
246
|
+
EventHandler.trigger(element, EVENT_SHOWN, { relatedTarget });
|
|
236
247
|
};
|
|
237
248
|
|
|
238
249
|
this._queueCallback(complete, element, element.classList.contains(CLASS_NAME.FADE));
|
|
@@ -252,7 +263,8 @@ class VGTabs extends BaseModule {
|
|
|
252
263
|
const target = Selectors.getElementFromSelector(element);
|
|
253
264
|
if (target) this._deactivate(target, relatedTarget);
|
|
254
265
|
|
|
255
|
-
const complete = () => {
|
|
266
|
+
const complete = () => {
|
|
267
|
+
if (!this._element || element.classList.contains(CLASS_NAME.ACTIVE)) return;
|
|
256
268
|
if (element.getAttribute('role') !== 'tab') {
|
|
257
269
|
element.classList.remove(CLASS_NAME.SHOW);
|
|
258
270
|
return;
|
|
@@ -300,13 +312,12 @@ class VGTabs extends BaseModule {
|
|
|
300
312
|
_setTabHash() {
|
|
301
313
|
if (!this._params.hash) return;
|
|
302
314
|
|
|
303
|
-
|
|
304
|
-
if (!
|
|
305
|
-
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
null;
|
|
315
|
+
let hash = document.location.hash;
|
|
316
|
+
if (!hash) return;
|
|
317
|
+
try { hash = decodeURIComponent(hash); } catch { return; }
|
|
318
|
+
const element = this._getChildren().find(child =>
|
|
319
|
+
!isDisabled(child) && (child.getAttribute('href') === hash || child.getAttribute('data-vg-target') === hash)
|
|
320
|
+
);
|
|
310
321
|
|
|
311
322
|
if (element) {
|
|
312
323
|
VGTabs.getOrCreateInstance(element).show();
|
|
@@ -316,8 +327,8 @@ class VGTabs extends BaseModule {
|
|
|
316
327
|
/**
|
|
317
328
|
* Инициализация слайдера-индикатора под вкладками
|
|
318
329
|
*/
|
|
319
|
-
_setInitialSlider() {
|
|
320
|
-
if (!this._params.slide) return;
|
|
330
|
+
_setInitialSlider() {
|
|
331
|
+
if (!this._params.slide || !this._main_parent) return;
|
|
321
332
|
|
|
322
333
|
let slider = Selectors.find(`.${CLASS_NAME.SLIDER}`, this._main_parent);
|
|
323
334
|
if (!slider) {
|
|
@@ -328,45 +339,58 @@ class VGTabs extends BaseModule {
|
|
|
328
339
|
|
|
329
340
|
this._main_parent.classList.add(CLASS_NAME.WITH_SLIDER);
|
|
330
341
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
342
|
+
this._updateSlider(this._getActiveElem());
|
|
343
|
+
this._sliderOver = event => {
|
|
344
|
+
const target = event.delegateTarget;
|
|
345
|
+
if (target.closest(SELECTOR.TAB_PANEL) === this._parent && !isDisabled(target)) this._updateSlider(target);
|
|
346
|
+
};
|
|
347
|
+
this._sliderOut = () => this._updateSlider(this._getActiveElem());
|
|
348
|
+
// Только один владелец общих обработчиков на группу вкладок.
|
|
349
|
+
const owner = this._getChildren().some(child => VGTabs.getInstance(child)?._sliderOver && child !== this._element);
|
|
350
|
+
if (owner) {
|
|
351
|
+
this._sliderOver = null;
|
|
352
|
+
this._sliderOut = null;
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
EventHandler.on(this._main_parent, EVENT_MOUSEOVER_DATA_API, SELECTOR.DATA_TOGGLE, this._sliderOver);
|
|
356
|
+
EventHandler.on(this._main_parent, EVENT_MOUSEOUT_DATA_API, SELECTOR.DATA_TOGGLE, this._sliderOut);
|
|
357
|
+
this._sliderResize = () => this._updateSlider(this._getActiveElem());
|
|
358
|
+
window.addEventListener('resize', this._sliderResize);
|
|
359
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
360
|
+
this._sliderObserver = new ResizeObserver(this._sliderResize);
|
|
361
|
+
this._sliderObserver.observe(this._parent);
|
|
362
|
+
this._getChildren().forEach(child => this._sliderObserver.observe(child));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
_updateSlider(target) {
|
|
367
|
+
if (!target || !this._main_parent) return;
|
|
368
|
+
const slider = this._main_parent.querySelector(`.${CLASS_NAME.SLIDER}`);
|
|
369
|
+
if (!slider) return;
|
|
370
|
+
this._getChildren().forEach(child => child.classList.toggle(CLASS_NAME.HOVER, child === target));
|
|
371
|
+
const {width, height} = window.getComputedStyle(target);
|
|
372
|
+
Object.assign(slider.style, {width, height, left: `${target.offsetLeft}px`, top: `${target.offsetTop}px`});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
dispose() {
|
|
376
|
+
if (!this._element) return;
|
|
377
|
+
const parent = this._main_parent;
|
|
378
|
+
const successor = this._sliderOver && this._getChildren()
|
|
379
|
+
.map(child => VGTabs.getInstance(child))
|
|
380
|
+
.find(instance => instance && instance !== this && instance._params.slide);
|
|
381
|
+
if (this._sliderOver) {
|
|
382
|
+
EventHandler.off(parent, EVENT_MOUSEOVER_DATA_API, SELECTOR.DATA_TOGGLE, this._sliderOver);
|
|
383
|
+
EventHandler.off(parent, EVENT_MOUSEOUT_DATA_API, SELECTOR.DATA_TOGGLE, this._sliderOut);
|
|
384
|
+
window.removeEventListener('resize', this._sliderResize);
|
|
385
|
+
this._sliderObserver?.disconnect();
|
|
386
|
+
}
|
|
387
|
+
super.dispose();
|
|
388
|
+
if (successor) successor._setInitialSlider();
|
|
389
|
+
else if (parent && !Selectors.findAll(SELECTOR.DATA_TOGGLE, parent).some(child => VGTabs.getInstance(child)?._params.slide)) {
|
|
390
|
+
parent.querySelector(`.${CLASS_NAME.SLIDER}`)?.remove();
|
|
391
|
+
parent.classList.remove(CLASS_NAME.WITH_SLIDER);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
370
394
|
|
|
371
395
|
/**
|
|
372
396
|
* Устанавливает базовые ARIA-атрибуты родителю
|
|
@@ -391,9 +415,9 @@ class VGTabs extends BaseModule {
|
|
|
391
415
|
if (outerElem !== child) {
|
|
392
416
|
this._setAttributeIfNotExists(outerElem, 'role', 'presentation');
|
|
393
417
|
}
|
|
394
|
-
if (!isActive) {
|
|
395
|
-
child.setAttribute('tabindex', '-1');
|
|
396
|
-
}
|
|
418
|
+
if (!isActive) {
|
|
419
|
+
child.setAttribute('tabindex', '-1');
|
|
420
|
+
} else child.removeAttribute('tabindex');
|
|
397
421
|
this._setAttributeIfNotExists(child, 'role', 'tab');
|
|
398
422
|
this._setInitialAttributesOnTargetPanel(child);
|
|
399
423
|
}
|
|
@@ -429,7 +453,8 @@ class VGTabs extends BaseModule {
|
|
|
429
453
|
* @returns {HTMLElement[]}
|
|
430
454
|
*/
|
|
431
455
|
_getChildren() {
|
|
432
|
-
return Selectors.findAll(SELECTOR.INNER_ELEM, this._parent)
|
|
456
|
+
return Selectors.findAll(SELECTOR.INNER_ELEM, this._parent)
|
|
457
|
+
.filter(child => child.closest(SELECTOR.TAB_PANEL) === this._parent);
|
|
433
458
|
}
|
|
434
459
|
|
|
435
460
|
/**
|
|
@@ -490,4 +515,4 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
|
|
|
490
515
|
});
|
|
491
516
|
});
|
|
492
517
|
|
|
493
|
-
export default VGTabs;
|
|
518
|
+
export default VGTabs;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Описание: уведомления VGToast через Data API и JavaScript.
|
|
3
|
+
* Возможности: стек, AJAX, анимации, автоскрытие, перетаскивание и изменение размера.
|
|
4
|
+
*/
|
|
5
|
+
import BaseModule from "../../base-module";
|
|
2
6
|
import EventHandler from "../../../utils/js/dom/event";
|
|
3
7
|
import {dismissTrigger, getSVG} from "../../module-fn";
|
|
4
8
|
import Sanitize from "../../../utils/js/components/sanitize";
|
|
@@ -331,6 +335,7 @@ class VGToast extends BaseModule {
|
|
|
331
335
|
*/
|
|
332
336
|
show(relatedTarget) {
|
|
333
337
|
if (isDisabled(this._element)) return;
|
|
338
|
+
if (this._isShown() && !this._isHiding) return;
|
|
334
339
|
|
|
335
340
|
const element = this._element;
|
|
336
341
|
this._clearTimeout();
|
|
@@ -466,7 +471,7 @@ class VGToast extends BaseModule {
|
|
|
466
471
|
const elmsShown = Selectors.findAll(`.vg-toast.show.${stackClass}`)
|
|
467
472
|
.filter(el => {
|
|
468
473
|
const instance = VGToast.getInstance(el);
|
|
469
|
-
return instance
|
|
474
|
+
return instance && !instance._isHiding;
|
|
470
475
|
});
|
|
471
476
|
|
|
472
477
|
if (!this._params.stack.enable) {
|
|
@@ -478,8 +483,9 @@ class VGToast extends BaseModule {
|
|
|
478
483
|
}
|
|
479
484
|
|
|
480
485
|
// Ограничиваем по max
|
|
481
|
-
|
|
482
|
-
|
|
486
|
+
const max = Math.max(1, Number(this._params.stack.max) || 5);
|
|
487
|
+
if (elmsShown.length > max) {
|
|
488
|
+
const excess = elmsShown.slice(0, elmsShown.length - max);
|
|
483
489
|
excess.forEach(el => VGToast.getInstance(el).hide());
|
|
484
490
|
}
|
|
485
491
|
|
|
@@ -507,7 +513,7 @@ class VGToast extends BaseModule {
|
|
|
507
513
|
const visibleStack = Selectors.findAll(`.vg-toast.show.${stackClass}`)
|
|
508
514
|
.filter(el => {
|
|
509
515
|
const instance = VGToast.getInstance(el);
|
|
510
|
-
return instance
|
|
516
|
+
return instance && !instance._isHiding;
|
|
511
517
|
});
|
|
512
518
|
const elms = visibleStack.length ? visibleStack : stackItems.map(item => item.el);
|
|
513
519
|
let offset = 0;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Описание: всплывающие подсказки и информационные popover VGApp.
|
|
3
|
+
* Возможности: Data API, позиционирование, события и очистка при удалении триггера.
|
|
4
|
+
*/
|
|
5
|
+
import BaseModule from "../../base-module";
|
|
2
6
|
import {isDisabled, makeRandomString, mergeDeepObject} from "../../../utils/js/functions";
|
|
3
7
|
import EventHandler from "../../../utils/js/dom/event";
|
|
4
8
|
import Selectors from "../../../utils/js/dom/selectors";
|
|
@@ -80,8 +84,13 @@ class VGTooltip extends BaseModule {
|
|
|
80
84
|
constructor(element, params = {}) {
|
|
81
85
|
super(element, params);
|
|
82
86
|
|
|
83
|
-
this._params = this._getParams(element, mergeDeepObject(defaultParams, params));
|
|
84
|
-
|
|
87
|
+
this._params = this._getParams(element, mergeDeepObject(defaultParams, params));
|
|
88
|
+
// Геометрические массивы заменяются целиком, а не дополняют defaults.
|
|
89
|
+
const dataParams = this._getParams(element, {});
|
|
90
|
+
['offset', 'fallbackPlacements'].forEach(key => {
|
|
91
|
+
this._params[key] = [...(dataParams[key] ?? params[key] ?? defaultParams[key])];
|
|
92
|
+
});
|
|
93
|
+
this._tooltip = null;
|
|
85
94
|
this._isHiding = false;
|
|
86
95
|
this._showTimeout = null;
|
|
87
96
|
this._hideTimeout = null;
|
|
@@ -249,10 +258,11 @@ class VGTooltip extends BaseModule {
|
|
|
249
258
|
tooltip.classList.add('vg-tooltip-popover');
|
|
250
259
|
}
|
|
251
260
|
|
|
252
|
-
const inner = document.createElement('div');
|
|
253
|
-
inner.classList.add('vg-tooltip-inner');
|
|
254
|
-
|
|
255
|
-
|
|
261
|
+
const inner = document.createElement('div');
|
|
262
|
+
inner.classList.add('vg-tooltip-inner');
|
|
263
|
+
const content = this._params.content || this._element.dataset.vgContent || '';
|
|
264
|
+
|
|
265
|
+
if (content) {
|
|
256
266
|
const titleBlock = document.createElement('div');
|
|
257
267
|
titleBlock.classList.add('vg-tooltip-inner--title');
|
|
258
268
|
|
|
@@ -261,10 +271,10 @@ class VGTooltip extends BaseModule {
|
|
|
261
271
|
|
|
262
272
|
if (this._params.html) {
|
|
263
273
|
titleBlock.innerHTML = title;
|
|
264
|
-
contentBlock.innerHTML =
|
|
274
|
+
contentBlock.innerHTML = content;
|
|
265
275
|
} else {
|
|
266
276
|
titleBlock.textContent = title;
|
|
267
|
-
contentBlock.textContent =
|
|
277
|
+
contentBlock.textContent = content;
|
|
268
278
|
}
|
|
269
279
|
|
|
270
280
|
inner.append(titleBlock);
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Описание: определение категории файла и соответствующей SVG-иконки.
|
|
3
|
+
* Возможности: распознаёт MIME-тип и расширение, поддерживает явные имена иконок и общий fallback.
|
|
4
|
+
*/
|
|
5
|
+
const FILE_ICON_BY_EXT = {
|
|
2
6
|
pdf: 'file-pdf',
|
|
3
7
|
doc: 'file-word',
|
|
4
8
|
docx: 'file-word',
|
|
@@ -34,7 +38,8 @@ const FILE_ICON_BY_EXT = {
|
|
|
34
38
|
tiff: 'file-image',
|
|
35
39
|
heic: 'file-image',
|
|
36
40
|
heif: 'file-image',
|
|
37
|
-
avif: 'file-image',
|
|
41
|
+
avif: 'file-image',
|
|
42
|
+
ico: 'file-image',
|
|
38
43
|
mp3: 'file-audio',
|
|
39
44
|
wav: 'file-audio',
|
|
40
45
|
ogg: 'file-audio',
|