vgapp 1.3.0 → 1.3.1
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/README.md +133 -133
- package/app/langs/en/buttons.json +17 -17
- package/app/langs/en/messages.json +36 -36
- package/app/langs/ru/buttons.json +17 -17
- package/app/langs/ru/messages.json +36 -36
- package/app/modules/base-module.js +111 -111
- package/app/modules/vgalert/readme.md +105 -105
- package/app/modules/vgdynamictable/index.js +5 -5
- package/app/modules/vgdynamictable/js/editable.js +19 -19
- package/app/modules/vgdynamictable/js/filters.js +21 -21
- package/app/modules/vgdynamictable/js/fixed.js +179 -179
- package/app/modules/vgdynamictable/js/pagination.js +1 -1
- package/app/modules/vgdynamictable/js/search.js +12 -12
- package/app/modules/vgdynamictable/js/sortable.js +71 -71
- package/app/modules/vgdynamictable/js/summary-footer.js +28 -28
- package/app/modules/vgdynamictable/js/table-remote.js +79 -79
- package/app/modules/vgdynamictable/js/table-url-state.js +31 -31
- package/app/modules/vgdynamictable/js/utils/common.js +48 -48
- package/app/modules/vgdynamictable/js/vgdynamictable.js +268 -268
- package/app/modules/vgdynamictable/readme.md +250 -250
- package/app/modules/vgdynamictable/scss/_skeleton.scss +6 -6
- package/app/modules/vgdynamictable/scss/_sortable.scss +24 -24
- package/app/modules/vgdynamictable/scss/_table.scss +4 -4
- package/app/modules/vgdynamictable/scss/_variables.scss +79 -79
- package/app/modules/vgdynamictable/scss/vgdynamictable.scss +27 -27
- package/app/modules/vgfilepreview/js/i18n.js +56 -56
- package/app/modules/vgfilepreview/js/renderers/image-modal.js +145 -145
- package/app/modules/vgfilepreview/js/renderers/image.js +92 -92
- package/app/modules/vgfilepreview/js/renderers/index.js +19 -19
- package/app/modules/vgfilepreview/js/renderers/office-modal.js +168 -168
- package/app/modules/vgfilepreview/js/renderers/office.js +79 -79
- package/app/modules/vgfilepreview/js/renderers/pdf-modal.js +260 -260
- package/app/modules/vgfilepreview/js/renderers/pdf.js +76 -76
- package/app/modules/vgfilepreview/js/renderers/playlist.js +71 -71
- package/app/modules/vgfilepreview/js/renderers/text-modal.js +343 -343
- package/app/modules/vgfilepreview/js/renderers/text.js +83 -83
- package/app/modules/vgfilepreview/js/renderers/video-modal.js +272 -272
- package/app/modules/vgfilepreview/js/renderers/video.js +80 -80
- package/app/modules/vgfilepreview/js/renderers/zip-modal.js +522 -522
- package/app/modules/vgfilepreview/js/renderers/zip.js +89 -89
- package/app/modules/vgfilepreview/js/vgfilepreview.js +7 -7
- package/app/modules/vgfilepreview/readme.md +68 -68
- package/app/modules/vgfilepreview/scss/_variables.scss +113 -113
- package/app/modules/vgfilepreview/scss/vgfilepreview.scss +464 -464
- package/app/modules/vgfiles/js/base.js +26 -26
- package/app/modules/vgfiles/js/droppable.js +260 -260
- package/app/modules/vgfiles/js/render.js +153 -153
- package/app/modules/vgfiles/js/vgfiles.js +104 -104
- package/app/modules/vgfiles/readme.md +123 -123
- package/app/modules/vgfiles/scss/_variables.scss +18 -18
- package/app/modules/vgfiles/scss/vgfiles.scss +148 -148
- package/app/modules/vgformsender/js/hideshowpass.js +16 -16
- package/app/modules/vgformsender/scss/vgformsender.scss +34 -34
- package/app/modules/vgmodal/js/vgmodal.drag.js +332 -332
- package/app/modules/vgmodal/js/vgmodal.js +188 -188
- package/app/modules/vgmodal/js/vgmodal.resize.js +27 -27
- package/app/modules/vgmodal/scss/vgmodal.scss +14 -14
- package/app/modules/vgnav/js/vgnav.js +135 -135
- package/app/modules/vgnav/readme.md +67 -67
- package/app/modules/vgnestable/README.md +307 -307
- package/app/modules/vgnestable/scss/_variables.scss +60 -60
- package/app/modules/vgnestable/scss/vgnestable.scss +163 -163
- package/app/modules/vgrangeslider/js/skins.js +222 -222
- package/app/modules/vgrangeslider/js/vgrangeslider.js +704 -704
- package/app/modules/vgrangeslider/readme.md +523 -523
- package/app/modules/vgrangeslider/scss/_variables.scss +53 -53
- package/app/modules/vgrangeslider/scss/vgrangeslider.scss +240 -240
- package/app/modules/vgselect/js/vgselect.js +39 -39
- package/app/modules/vgselect/scss/vgselect.scss +22 -22
- package/app/modules/vgspy/readme.md +28 -28
- package/app/modules/vgtoast/readme.md +18 -18
- package/app/modules/vgtoast/scss/vgtoast.scss +48 -48
- package/app/modules/vgtooltip/js/vgtooltip.js +89 -89
- package/app/modules/vgtooltip/readme.md +181 -181
- package/app/utils/js/components/ajax.js +117 -117
- package/app/utils/js/components/audio-metadata.js +240 -240
- package/app/utils/js/components/backdrop.js +17 -17
- package/app/utils/js/components/file-icon.js +109 -109
- package/app/utils/js/components/file-preview.js +304 -304
- package/app/utils/js/components/sanitize.js +150 -150
- package/app/utils/js/components/video-metadata.js +140 -140
- package/app/vgapp.js +130 -107
- package/build/vgapp.css +2 -2
- package/build/vgapp.js +2 -2
- package/build/vgapp.js.LICENSE.txt +1 -1
- package/build/vgapp.js.map +1 -1
- package/index.js +14 -14
- package/package.json +1 -1
|
@@ -1,181 +1,181 @@
|
|
|
1
|
-
# VGTooltip — модуль подсказок и popover
|
|
2
|
-
|
|
3
|
-
`VGTooltip` — модуль всплывающих подсказок для Vegas App. Поддерживает tooltip и popover режимы, Data API и JS API, автопозиционирование, анимации и управление через события.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## ✅ Возможности
|
|
8
|
-
|
|
9
|
-
- 📦 **Легковесный и автономный** — работает как модуль без внешнего UI-фреймворка.
|
|
10
|
-
- 🎯 **Два режима работы** — обычный tooltip и `popover` с заголовком и контентом.
|
|
11
|
-
- 🧭 **Умное позиционирование** — поддерживает `top`, `bottom`, `left`, `right` и авто-переворот.
|
|
12
|
-
- 🖱 **Гибкие триггеры** — `hover`, `click` или их комбинация.
|
|
13
|
-
- 🔁 **Автозакрытие других подсказок** — при `closeOther: true`.
|
|
14
|
-
- ⌨ **Поддержка `Esc`** и закрытия по клику вне элемента.
|
|
15
|
-
- 🎬 **Анимации показа и скрытия** через общий animation API.
|
|
16
|
-
- 📱 **Адаптивное поведение** — перерасчёт позиции при `resize` и `scroll`.
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## 📦 Установка
|
|
21
|
-
|
|
22
|
-
Модуль подключается как часть системы модулей. Для работы должны быть доступны:
|
|
23
|
-
- `BaseModule`
|
|
24
|
-
- `EventHandler`
|
|
25
|
-
- `Selectors`
|
|
26
|
-
- `Placement`
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## 🧰 Быстрое использование
|
|
31
|
-
|
|
32
|
-
### Через JavaScript
|
|
33
|
-
```js
|
|
34
|
-
const button = document.querySelector('#tooltip-demo');
|
|
35
|
-
|
|
36
|
-
const tooltip = new VGTooltip(button, {
|
|
37
|
-
title: 'Подсказка',
|
|
38
|
-
placement: 'right'
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
tooltip.show();
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### Через Data API
|
|
45
|
-
```html
|
|
46
|
-
<button
|
|
47
|
-
data-vg-toggle="tooltip"
|
|
48
|
-
data-vg-title="Текст подсказки">
|
|
49
|
-
Наведи на меня
|
|
50
|
-
</button>
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### Popover
|
|
54
|
-
```html
|
|
55
|
-
<button
|
|
56
|
-
data-vg-toggle="popover"
|
|
57
|
-
data-vg-title="Заголовок"
|
|
58
|
-
data-vg-content="Подробный текст">
|
|
59
|
-
Открыть popover
|
|
60
|
-
</button>
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## ⚙️ Параметры
|
|
66
|
-
|
|
67
|
-
| Параметр | Тип | По умолчанию | Описание |
|
|
68
|
-
|--------|------|-------------|--------|
|
|
69
|
-
| `title` | `string` | `''` | Заголовок tooltip/popover |
|
|
70
|
-
| `content` | `string` | `''` | Контент для режима `popover` |
|
|
71
|
-
| `trigger` | `string` | `'hover'` | Триггер показа: `hover`, `click` или комбинация |
|
|
72
|
-
| `placement` | `string` | `'top'` | Позиция: `top`, `bottom`, `left`, `right` и варианты |
|
|
73
|
-
| `container` | `string` | `'body'` | Контейнер, в который рендерится tooltip |
|
|
74
|
-
| `popover` | `boolean` | `false` | Режим popover |
|
|
75
|
-
| `html` | `boolean` | `false` | Разрешить HTML в `title` и `content` |
|
|
76
|
-
| `offset` | `array` | `[8, 8]` | Смещение относительно элемента |
|
|
77
|
-
| `autoFlip` | `boolean` | `true` | Автоматически менять сторону при нехватке места |
|
|
78
|
-
| `overflowProtection` | `boolean` | `true` | Защита от выхода за границы окна |
|
|
79
|
-
| `fallbackPlacements` | `array` | `['bottom', 'right', 'left']` | Порядок запасных позиций |
|
|
80
|
-
| `closeOnOutsideClick` | `boolean` | `true` | Закрывать по клику вне tooltip |
|
|
81
|
-
| `keyboard` | `boolean` | `true` | Закрывать по `Esc` |
|
|
82
|
-
| `closeOther` | `boolean` | `true` | Скрывать другие открытые tooltip |
|
|
83
|
-
| `delay.show` | `number` | `100` | Задержка перед показом, мс |
|
|
84
|
-
| `delay.hide` | `number` | `100` | Задержка перед скрытием, мс |
|
|
85
|
-
| `arrow.padding` | `number` | `8` | Отступ стрелки от краёв |
|
|
86
|
-
| `custom.class` | `string` | `''` | Дополнительный CSS-класс |
|
|
87
|
-
| `animation.enable` | `boolean` | `true` | Включить анимации |
|
|
88
|
-
| `animation.in` | `string` | `'animate__backInUp'` | Анимация появления |
|
|
89
|
-
| `animation.out` | `string` | `'animate__backOutDown'` | Анимация скрытия |
|
|
90
|
-
| `animation.delay` | `number` | `300` | Длительность анимации, мс |
|
|
91
|
-
| `animation.effect` | `string` | `'none'` | Дополнительный CSS-эффект |
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## 💡 Расширенные примеры
|
|
96
|
-
|
|
97
|
-
### 1. Tooltip по клику
|
|
98
|
-
```js
|
|
99
|
-
new VGTooltip(document.querySelector('#help'), {
|
|
100
|
-
title: 'Подсказка по клику',
|
|
101
|
-
trigger: 'click',
|
|
102
|
-
placement: 'bottom'
|
|
103
|
-
});
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### 2. HTML-контент
|
|
107
|
-
```js
|
|
108
|
-
new VGTooltip(document.querySelector('#html-tooltip'), {
|
|
109
|
-
title: '<strong>Важно</strong>',
|
|
110
|
-
content: 'Можно передавать <em>HTML</em>',
|
|
111
|
-
html: true,
|
|
112
|
-
popover: true,
|
|
113
|
-
trigger: 'click'
|
|
114
|
-
});
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### 3. Кастомный контейнер и класс
|
|
118
|
-
```js
|
|
119
|
-
new VGTooltip(document.querySelector('#custom-tooltip'), {
|
|
120
|
-
title: 'Подсказка внутри контейнера',
|
|
121
|
-
container: '.demo-area',
|
|
122
|
-
custom: {
|
|
123
|
-
class: 'tooltip-accent'
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## 🧩 Data API
|
|
131
|
-
|
|
132
|
-
- `data-vg-toggle="tooltip"` — обычная подсказка.
|
|
133
|
-
- `data-vg-toggle="popover"` — popover-режим.
|
|
134
|
-
- `data-vg-title` — текст заголовка.
|
|
135
|
-
- `data-vg-content` — текст контента.
|
|
136
|
-
- Если у элемента есть `title`, модуль переносит его в `data-vg-original-title` и использует как источник текста.
|
|
137
|
-
|
|
138
|
-
---
|
|
139
|
-
|
|
140
|
-
## 🧪 События
|
|
141
|
-
|
|
142
|
-
| Событие | Описание |
|
|
143
|
-
|-------|--------|
|
|
144
|
-
| `vg.tooltip.show` | Перед показом |
|
|
145
|
-
| `vg.tooltip.shown` | После показа |
|
|
146
|
-
| `vg.tooltip.hide` | Перед скрытием |
|
|
147
|
-
| `vg.tooltip.hidden` | После скрытия |
|
|
148
|
-
|
|
149
|
-
---
|
|
150
|
-
|
|
151
|
-
## 🔄 Методы
|
|
152
|
-
|
|
153
|
-
| Метод | Описание |
|
|
154
|
-
|------|--------|
|
|
155
|
-
| `VGTooltip.getInstance(element)` | Получить существующий экземпляр |
|
|
156
|
-
| `VGTooltip.getOrCreateInstance(element, params)` | Получить или создать экземпляр |
|
|
157
|
-
| `tooltip.show(relatedTarget)` | Показать tooltip |
|
|
158
|
-
| `tooltip.hide()` | Скрыть tooltip |
|
|
159
|
-
| `tooltip.toggle(relatedTarget)` | Переключить состояние |
|
|
160
|
-
| `tooltip.dispose()` | Удалить tooltip и очистить обработчики |
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
## 🌐 Глобальные классы
|
|
165
|
-
|
|
166
|
-
- `.vg-tooltip-open` — добавляется к `<body>`, пока открыт хотя бы один tooltip.
|
|
167
|
-
- `.vg-tooltip.show` — tooltip находится в DOM и видим.
|
|
168
|
-
- `.vg-tooltip.shown` — tooltip завершил фазу показа.
|
|
169
|
-
- `.vg-tooltip-popover` — оформление для режима popover.
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
## 📝 Лицензия
|
|
174
|
-
|
|
175
|
-
MIT. Свободно использовать и модифицировать.
|
|
176
|
-
|
|
177
|
-
---
|
|
178
|
-
|
|
179
|
-
📌 *Разработано в рамках фронтенд-системы VG Modules.*
|
|
180
|
-
> 🚀 Автор: VEGAS STUDIO (vegas-dev.com)
|
|
181
|
-
> 📍 Поддерживается в проектах VEGAS
|
|
1
|
+
# VGTooltip — модуль подсказок и popover
|
|
2
|
+
|
|
3
|
+
`VGTooltip` — модуль всплывающих подсказок для Vegas App. Поддерживает tooltip и popover режимы, Data API и JS API, автопозиционирование, анимации и управление через события.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ✅ Возможности
|
|
8
|
+
|
|
9
|
+
- 📦 **Легковесный и автономный** — работает как модуль без внешнего UI-фреймворка.
|
|
10
|
+
- 🎯 **Два режима работы** — обычный tooltip и `popover` с заголовком и контентом.
|
|
11
|
+
- 🧭 **Умное позиционирование** — поддерживает `top`, `bottom`, `left`, `right` и авто-переворот.
|
|
12
|
+
- 🖱 **Гибкие триггеры** — `hover`, `click` или их комбинация.
|
|
13
|
+
- 🔁 **Автозакрытие других подсказок** — при `closeOther: true`.
|
|
14
|
+
- ⌨ **Поддержка `Esc`** и закрытия по клику вне элемента.
|
|
15
|
+
- 🎬 **Анимации показа и скрытия** через общий animation API.
|
|
16
|
+
- 📱 **Адаптивное поведение** — перерасчёт позиции при `resize` и `scroll`.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 📦 Установка
|
|
21
|
+
|
|
22
|
+
Модуль подключается как часть системы модулей. Для работы должны быть доступны:
|
|
23
|
+
- `BaseModule`
|
|
24
|
+
- `EventHandler`
|
|
25
|
+
- `Selectors`
|
|
26
|
+
- `Placement`
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 🧰 Быстрое использование
|
|
31
|
+
|
|
32
|
+
### Через JavaScript
|
|
33
|
+
```js
|
|
34
|
+
const button = document.querySelector('#tooltip-demo');
|
|
35
|
+
|
|
36
|
+
const tooltip = new VGTooltip(button, {
|
|
37
|
+
title: 'Подсказка',
|
|
38
|
+
placement: 'right'
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
tooltip.show();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Через Data API
|
|
45
|
+
```html
|
|
46
|
+
<button
|
|
47
|
+
data-vg-toggle="tooltip"
|
|
48
|
+
data-vg-title="Текст подсказки">
|
|
49
|
+
Наведи на меня
|
|
50
|
+
</button>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Popover
|
|
54
|
+
```html
|
|
55
|
+
<button
|
|
56
|
+
data-vg-toggle="popover"
|
|
57
|
+
data-vg-title="Заголовок"
|
|
58
|
+
data-vg-content="Подробный текст">
|
|
59
|
+
Открыть popover
|
|
60
|
+
</button>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## ⚙️ Параметры
|
|
66
|
+
|
|
67
|
+
| Параметр | Тип | По умолчанию | Описание |
|
|
68
|
+
|--------|------|-------------|--------|
|
|
69
|
+
| `title` | `string` | `''` | Заголовок tooltip/popover |
|
|
70
|
+
| `content` | `string` | `''` | Контент для режима `popover` |
|
|
71
|
+
| `trigger` | `string` | `'hover'` | Триггер показа: `hover`, `click` или комбинация |
|
|
72
|
+
| `placement` | `string` | `'top'` | Позиция: `top`, `bottom`, `left`, `right` и варианты |
|
|
73
|
+
| `container` | `string` | `'body'` | Контейнер, в который рендерится tooltip |
|
|
74
|
+
| `popover` | `boolean` | `false` | Режим popover |
|
|
75
|
+
| `html` | `boolean` | `false` | Разрешить HTML в `title` и `content` |
|
|
76
|
+
| `offset` | `array` | `[8, 8]` | Смещение относительно элемента |
|
|
77
|
+
| `autoFlip` | `boolean` | `true` | Автоматически менять сторону при нехватке места |
|
|
78
|
+
| `overflowProtection` | `boolean` | `true` | Защита от выхода за границы окна |
|
|
79
|
+
| `fallbackPlacements` | `array` | `['bottom', 'right', 'left']` | Порядок запасных позиций |
|
|
80
|
+
| `closeOnOutsideClick` | `boolean` | `true` | Закрывать по клику вне tooltip |
|
|
81
|
+
| `keyboard` | `boolean` | `true` | Закрывать по `Esc` |
|
|
82
|
+
| `closeOther` | `boolean` | `true` | Скрывать другие открытые tooltip |
|
|
83
|
+
| `delay.show` | `number` | `100` | Задержка перед показом, мс |
|
|
84
|
+
| `delay.hide` | `number` | `100` | Задержка перед скрытием, мс |
|
|
85
|
+
| `arrow.padding` | `number` | `8` | Отступ стрелки от краёв |
|
|
86
|
+
| `custom.class` | `string` | `''` | Дополнительный CSS-класс |
|
|
87
|
+
| `animation.enable` | `boolean` | `true` | Включить анимации |
|
|
88
|
+
| `animation.in` | `string` | `'animate__backInUp'` | Анимация появления |
|
|
89
|
+
| `animation.out` | `string` | `'animate__backOutDown'` | Анимация скрытия |
|
|
90
|
+
| `animation.delay` | `number` | `300` | Длительность анимации, мс |
|
|
91
|
+
| `animation.effect` | `string` | `'none'` | Дополнительный CSS-эффект |
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 💡 Расширенные примеры
|
|
96
|
+
|
|
97
|
+
### 1. Tooltip по клику
|
|
98
|
+
```js
|
|
99
|
+
new VGTooltip(document.querySelector('#help'), {
|
|
100
|
+
title: 'Подсказка по клику',
|
|
101
|
+
trigger: 'click',
|
|
102
|
+
placement: 'bottom'
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 2. HTML-контент
|
|
107
|
+
```js
|
|
108
|
+
new VGTooltip(document.querySelector('#html-tooltip'), {
|
|
109
|
+
title: '<strong>Важно</strong>',
|
|
110
|
+
content: 'Можно передавать <em>HTML</em>',
|
|
111
|
+
html: true,
|
|
112
|
+
popover: true,
|
|
113
|
+
trigger: 'click'
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 3. Кастомный контейнер и класс
|
|
118
|
+
```js
|
|
119
|
+
new VGTooltip(document.querySelector('#custom-tooltip'), {
|
|
120
|
+
title: 'Подсказка внутри контейнера',
|
|
121
|
+
container: '.demo-area',
|
|
122
|
+
custom: {
|
|
123
|
+
class: 'tooltip-accent'
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 🧩 Data API
|
|
131
|
+
|
|
132
|
+
- `data-vg-toggle="tooltip"` — обычная подсказка.
|
|
133
|
+
- `data-vg-toggle="popover"` — popover-режим.
|
|
134
|
+
- `data-vg-title` — текст заголовка.
|
|
135
|
+
- `data-vg-content` — текст контента.
|
|
136
|
+
- Если у элемента есть `title`, модуль переносит его в `data-vg-original-title` и использует как источник текста.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 🧪 События
|
|
141
|
+
|
|
142
|
+
| Событие | Описание |
|
|
143
|
+
|-------|--------|
|
|
144
|
+
| `vg.tooltip.show` | Перед показом |
|
|
145
|
+
| `vg.tooltip.shown` | После показа |
|
|
146
|
+
| `vg.tooltip.hide` | Перед скрытием |
|
|
147
|
+
| `vg.tooltip.hidden` | После скрытия |
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 🔄 Методы
|
|
152
|
+
|
|
153
|
+
| Метод | Описание |
|
|
154
|
+
|------|--------|
|
|
155
|
+
| `VGTooltip.getInstance(element)` | Получить существующий экземпляр |
|
|
156
|
+
| `VGTooltip.getOrCreateInstance(element, params)` | Получить или создать экземпляр |
|
|
157
|
+
| `tooltip.show(relatedTarget)` | Показать tooltip |
|
|
158
|
+
| `tooltip.hide()` | Скрыть tooltip |
|
|
159
|
+
| `tooltip.toggle(relatedTarget)` | Переключить состояние |
|
|
160
|
+
| `tooltip.dispose()` | Удалить tooltip и очистить обработчики |
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 🌐 Глобальные классы
|
|
165
|
+
|
|
166
|
+
- `.vg-tooltip-open` — добавляется к `<body>`, пока открыт хотя бы один tooltip.
|
|
167
|
+
- `.vg-tooltip.show` — tooltip находится в DOM и видим.
|
|
168
|
+
- `.vg-tooltip.shown` — tooltip завершил фазу показа.
|
|
169
|
+
- `.vg-tooltip-popover` — оформление для режима popover.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 📝 Лицензия
|
|
174
|
+
|
|
175
|
+
MIT. Свободно использовать и модифицировать.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
📌 *Разработано в рамках фронтенд-системы VG Modules.*
|
|
180
|
+
> 🚀 Автор: VEGAS STUDIO (vegas-dev.com)
|
|
181
|
+
> 📍 Поддерживается в проектах VEGAS
|
|
@@ -1,117 +1,117 @@
|
|
|
1
|
-
import { isObject, noop, normalizeData } from "../functions";
|
|
2
|
-
|
|
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
|
-
/**
|
|
1
|
+
import { isObject, noop, normalizeData } from "../functions";
|
|
2
|
+
|
|
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
|
+
/**
|
|
115
115
|
* Конфигурация запроса
|
|
116
116
|
* @param {Object} options
|
|
117
117
|
* @param {string} options.baseUrl - Базовый URL API (опционально)
|
|
@@ -231,7 +231,7 @@ class Ajax {
|
|
|
231
231
|
method,
|
|
232
232
|
headers,
|
|
233
233
|
signal,
|
|
234
|
-
credentials: withCredentials ? 'include' : 'same-origin',
|
|
234
|
+
credentials: withCredentials ? 'include' : 'same-origin',
|
|
235
235
|
...(body !== undefined && { body }),
|
|
236
236
|
};
|
|
237
237
|
|
|
@@ -267,7 +267,7 @@ class Ajax {
|
|
|
267
267
|
() => {}
|
|
268
268
|
);
|
|
269
269
|
} else {
|
|
270
|
-
onSuccess(data);
|
|
270
|
+
onSuccess(data);
|
|
271
271
|
}
|
|
272
272
|
})
|
|
273
273
|
.catch((error) => {
|
|
@@ -393,4 +393,4 @@ class Ajax {
|
|
|
393
393
|
}
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
-
export default Ajax;
|
|
396
|
+
export default Ajax;
|