vgapp 0.7.8 → 0.8.0
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 +9 -0
- package/LICENSE +22 -0
- package/app/langs/en/buttons.json +10 -0
- package/app/langs/en/messages.json +32 -0
- package/app/langs/en/titles.json +6 -0
- package/app/langs/ru/buttons.json +10 -0
- package/app/langs/ru/messages.json +32 -0
- package/app/langs/ru/titles.json +6 -0
- package/app/modules/base-module.js +23 -2
- package/app/modules/module-fn.js +20 -9
- package/app/modules/vgalert/js/vgalert.js +362 -214
- package/app/modules/vgalert/readme.md +242 -0
- package/app/modules/vgcollapse/js/vgcollapse.js +216 -62
- package/app/modules/vgcollapse/readme.md +56 -0
- package/app/modules/vgcollapse/scss/_variables.scss +5 -0
- package/app/modules/vgcollapse/scss/vgcollapse.scss +41 -0
- package/app/modules/vgdropdown/js/vgdropdown.js +140 -38
- package/app/modules/vgdropdown/readme.md +225 -0
- package/app/modules/vgfiles/js/base.js +499 -0
- package/app/modules/vgfiles/js/droppable.js +159 -0
- package/app/modules/vgfiles/js/loader.js +389 -0
- package/app/modules/vgfiles/js/render.js +83 -0
- package/app/modules/vgfiles/js/sortable.js +155 -0
- package/app/modules/vgfiles/js/vgfiles.js +796 -280
- package/app/modules/vgfiles/readme.md +193 -0
- package/app/modules/vgfiles/scss/_animations.scss +18 -0
- package/app/modules/vgfiles/scss/_mixins.scss +73 -0
- package/app/modules/vgfiles/scss/_variables.scss +103 -26
- package/app/modules/vgfiles/scss/vgfiles.scss +573 -60
- package/app/modules/vgformsender/js/vgformsender.js +5 -1
- package/app/modules/vgformsender/readme.md +30 -1
- package/app/modules/vglawcookie/js/vglawcookie.js +96 -62
- package/app/modules/vglawcookie/readme.md +102 -0
- package/app/modules/vgsidebar/js/vgsidebar.js +6 -4
- package/app/utils/js/components/ajax.js +176 -104
- package/app/utils/js/components/animation.js +124 -39
- package/app/utils/js/components/backdrop.js +54 -31
- package/app/utils/js/components/lang.js +71 -64
- package/app/utils/js/components/params.js +34 -31
- package/app/utils/js/components/scrollbar.js +118 -67
- package/app/utils/js/components/templater.js +14 -4
- package/app/utils/js/dom/cookie.js +107 -64
- package/app/utils/js/dom/data.js +68 -20
- package/app/utils/js/dom/event.js +272 -239
- package/app/utils/js/dom/manipulator.js +135 -62
- package/app/utils/js/dom/selectors.js +134 -59
- package/app/utils/js/functions.js +183 -349
- package/build/vgapp.css +1 -1
- package/build/vgapp.css.map +1 -1
- package/index.scss +3 -0
- package/package.json +1 -1
- package/app/utils/js/components/overflow.js +0 -28
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# VGCollapse
|
|
2
|
+
|
|
3
|
+
**VGCollapse** — это легковесный и гибкий JavaScript-модуль для создания анимированных блоков с возможностью сворачивания/разворачивания содержимого. Подходит для аккордеонов, скрытых форм, FAQ-секций и других интерактивных элементов, где нужно управлять видимостью контента.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ✅ Возможности
|
|
8
|
+
|
|
9
|
+
- Плавная анимация открытия/закрытия (через `height` и `overflow`)
|
|
10
|
+
- Поддержка нескольких экземпляров на одной странице
|
|
11
|
+
- Работа без jQuery — чистый ES6+
|
|
12
|
+
- Возможность инициализации вручную или через data-атрибуты
|
|
13
|
+
- Совместимость с динамически добавленным контентом
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 📦 Установка
|
|
18
|
+
|
|
19
|
+
Подключите JS-файл в проект:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import VGCollapse from './path/to/vgcollapse.js';
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🧱 HTML Структура
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<a href="#example-simple" data-vg-toggle="collapse" aria-expanded="true" class="btn btn-primary" data-hide-text="Скрыть контент" data-show-text="Показать контент">Скрыть контент</a>
|
|
31
|
+
<div class="vg-collapse show" id="example-simple">
|
|
32
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci eligendi magnam
|
|
33
|
+
minus nihil quaerat.
|
|
34
|
+
</div>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## ⚙️ Инициализация
|
|
40
|
+
|
|
41
|
+
### 1. Через data-атрибуты (авто-инициализация)
|
|
42
|
+
|
|
43
|
+
Добавьте `data-vg-collapse` — модуль автоматически найдёт и инициализирует все блоки.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 📝 Заметки
|
|
48
|
+
|
|
49
|
+
- Контент должен быть видим при инициализации, чтобы корректно рассчитать высоту.
|
|
50
|
+
- Не используйте `display: none` на контейнере при инициализации.
|
|
51
|
+
- Поддерживает современные браузеры (включая Edge, не поддерживает IE11).
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
> 🚀 Автор: VEGAS STUDIO (vegas-dev.com)
|
|
56
|
+
> 📍 Поддерживается в проектах VEGAS
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*--------------------------------------------------------------------------
|
|
3
|
+
* Модуль: VGCollapse, реализация vg-accordion
|
|
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
|
+
|
|
15
|
+
.vg-accordion {
|
|
16
|
+
@include mix-vars('accordion', $collapse-accordion-map);
|
|
17
|
+
position: relative;
|
|
18
|
+
border: var(--vg-accordion-border);
|
|
19
|
+
border-radius: var(--vg-accordion-border-radius);
|
|
20
|
+
|
|
21
|
+
&-item {
|
|
22
|
+
border-top: 0;
|
|
23
|
+
border-left: 0;
|
|
24
|
+
border-right: 0;
|
|
25
|
+
border-bottom: var(--vg-accordion-border);
|
|
26
|
+
|
|
27
|
+
&:last-child {
|
|
28
|
+
border: none;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&-button {
|
|
33
|
+
display: block;
|
|
34
|
+
padding: var(--vg-accordion-padding);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&-content {
|
|
38
|
+
display: block;
|
|
39
|
+
padding: var(--vg-accordion-padding);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -3,10 +3,19 @@ import EventHandler from "../../../utils/js/dom/event";
|
|
|
3
3
|
import Selectors from "../../../utils/js/dom/selectors";
|
|
4
4
|
import {isDisabled, mergeDeepObject, noop} from "../../../utils/js/functions";
|
|
5
5
|
import Placement from "../../../utils/js/components/placement";
|
|
6
|
-
import Overflow from "../../../utils/js/components/overflow";
|
|
7
|
-
import Backdrop from "../../../utils/js/components/backdrop";
|
|
8
|
-
import {dismissTrigger} from "../../module-fn";
|
|
9
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Константы, используемые в модуле выпадающего списка.
|
|
9
|
+
* @type {Object}
|
|
10
|
+
* @property {string} NAME - Имя модуля.
|
|
11
|
+
* @property {string} NAME_KEY - Уникальный ключ модуля с префиксом.
|
|
12
|
+
* @property {string} CLASS_NAME_SHOW - CSS-класс для отображения элемента.
|
|
13
|
+
* @property {string} CLASS_NAME_FADE - CSS-класс для эффекта затухания.
|
|
14
|
+
* @property {string} CLASS_NAME_OPEN - CSS-класс для немигающего открытия.
|
|
15
|
+
* @property {string} TARGET_CONTAINER - Класс контейнера выпадающего меню.
|
|
16
|
+
* @property {string} PARENT_CONTAINER - Класс родительского контейнера.
|
|
17
|
+
* @property {string} SELECTOR_DATA_TOGGLE - Селектор элемента-переключателя.
|
|
18
|
+
*/
|
|
10
19
|
const NAME = 'dropdown';
|
|
11
20
|
const NAME_KEY = 'vg.dropdown';
|
|
12
21
|
const CLASS_NAME_SHOW = 'show';
|
|
@@ -16,26 +25,75 @@ const TARGET_CONTAINER = 'vg-dropdown-content';
|
|
|
16
25
|
const PARENT_CONTAINER = 'vg-dropdown';
|
|
17
26
|
const SELECTOR_DATA_TOGGLE = '[data-vg-toggle="dropdown"]';
|
|
18
27
|
|
|
28
|
+
/**
|
|
29
|
+
* События, генерируемые модулем.
|
|
30
|
+
* @type {Object}
|
|
31
|
+
*/
|
|
19
32
|
const EVENT_KEY_HIDE = `${NAME_KEY}.hide`;
|
|
20
33
|
const EVENT_KEY_HIDDEN = `${NAME_KEY}.hidden`;
|
|
21
34
|
const EVENT_KEY_SHOW = `${NAME_KEY}.show`;
|
|
22
35
|
const EVENT_KEY_SHOWN = `${NAME_KEY}.shown`;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
36
|
+
const EVENT_KEY_LOADED = `${NAME_KEY}.loaded`;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Делегированные события на уровне документа.
|
|
40
|
+
* @type {Object}
|
|
41
|
+
*/
|
|
42
|
+
const EVENT_KEYUP_DATA_API = `keyup.${NAME_KEY}.data.api`;
|
|
43
|
+
const EVENT_KEYDOWN_DATA_API = `keydown.${NAME_KEY}.data.api`;
|
|
44
|
+
const EVENT_CLICK_DATA_API = `click.${NAME_KEY}.data.api`;
|
|
27
45
|
const EVENT_MOUSEOVER_DATA_API = `mouseover.${NAME_KEY}.data.api`;
|
|
28
|
-
const EVENT_MOUSEOUT_DATA_API
|
|
29
|
-
|
|
46
|
+
const EVENT_MOUSEOUT_DATA_API = `mouseout.${NAME_KEY}.data.api`;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Компонент выпадающего списка (Dropdown).
|
|
50
|
+
*
|
|
51
|
+
* @extends BaseModule
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const dropdown = new VGDropdown(document.querySelector('[data-vg-toggle="dropdown"]'), {
|
|
55
|
+
* placement: 'bottom-start',
|
|
56
|
+
* hover: true,
|
|
57
|
+
* animation: {
|
|
58
|
+
* enable: true,
|
|
59
|
+
* in: 'animate__fadeIn',
|
|
60
|
+
* out: 'animate__fadeOut',
|
|
61
|
+
* delay: 150
|
|
62
|
+
* }
|
|
63
|
+
* });
|
|
64
|
+
*
|
|
65
|
+
* @example <caption>Инициализация через data-атрибуты</caption>
|
|
66
|
+
* <div class="vg-dropdown">
|
|
67
|
+
* <button data-vg-toggle="dropdown" aria-expanded="false">Меню</button>
|
|
68
|
+
* <div class="vg-dropdown-content">Содержимое меню</div>
|
|
69
|
+
* </div>
|
|
70
|
+
*/
|
|
30
71
|
class VGDropdown extends BaseModule {
|
|
72
|
+
/**
|
|
73
|
+
* Создаёт экземпляр VGDropdown.
|
|
74
|
+
*
|
|
75
|
+
* @param {HTMLElement} element - Элемент-переключатель (кнопка).
|
|
76
|
+
* @param {Object} [params] - Пользовательские параметры.
|
|
77
|
+
* @param {string} [params.placement='auto'] - Позиция выпадающего окна: 'top', 'bottom', 'left', 'right', 'auto' и т.д.
|
|
78
|
+
* @param {boolean} [params.hover=false] - Открывать по наведению мыши.
|
|
79
|
+
* @param {Object} [params.ajax] - Параметры AJAX-загрузки.
|
|
80
|
+
* @param {string} [params.ajax.route=''] - URL для загрузки контента.
|
|
81
|
+
* @param {string} [params.ajax.target=''] - Селектор внутри drop для вставки данных.
|
|
82
|
+
* @param {string} [params.ajax.method='get'] - HTTP-метод.
|
|
83
|
+
* @param {boolean} [params.ajax.loader=false] - Показывать ли лоадер.
|
|
84
|
+
* @param {boolean} [params.ajax.once=false] - Загружать один раз.
|
|
85
|
+
* @param {boolean} [params.ajax.output=true] - Вставлять ли ответ в DOM.
|
|
86
|
+
* @param {Object} [params.animation] - Настройки анимации.
|
|
87
|
+
* @param {boolean} [params.animation.fade=false] - Использовать fade-анимацию.
|
|
88
|
+
* @param {boolean} [params.animation.enable=false] - Включить CSS-анимации.
|
|
89
|
+
* @param {string} [params.animation.in='animate__flipInY'] - Класс для анимации входа.
|
|
90
|
+
* @param {string} [params.animation.out='animate__flipOutY'] - Класс для анимации выхода.
|
|
91
|
+
* @param {number} [params.animation.delay=300] - Задержка перед завершением скрытия (в мс).
|
|
92
|
+
*/
|
|
31
93
|
constructor(element, params) {
|
|
32
94
|
super(element, params);
|
|
33
95
|
|
|
34
96
|
let defaultParams = {
|
|
35
|
-
backdrop: false,
|
|
36
|
-
overflow: false,
|
|
37
|
-
keyboard: false,
|
|
38
|
-
timeoutAnimation: 10,
|
|
39
97
|
placement: 'auto',
|
|
40
98
|
hover: false,
|
|
41
99
|
ajax: {
|
|
@@ -71,18 +129,36 @@ class VGDropdown extends BaseModule {
|
|
|
71
129
|
this._animation(this._drop, VGDropdown.NAME_KEY, this._params.animation);
|
|
72
130
|
}
|
|
73
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Возвращает имя компонента.
|
|
134
|
+
* @return {string}
|
|
135
|
+
*/
|
|
74
136
|
static get NAME() {
|
|
75
137
|
return NAME;
|
|
76
138
|
}
|
|
77
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Возвращает уникальный ключ компонента.
|
|
142
|
+
* @return {string}
|
|
143
|
+
*/
|
|
78
144
|
static get NAME_KEY() {
|
|
79
145
|
return NAME_KEY;
|
|
80
146
|
}
|
|
81
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Переключает состояние выпадающего списка (открыто/закрыто).
|
|
150
|
+
* @return {void}
|
|
151
|
+
*/
|
|
82
152
|
toggle() {
|
|
83
153
|
return this._isShown() ? this.hide() : this.show();
|
|
84
154
|
}
|
|
85
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Открывает выпадающий список.
|
|
158
|
+
* @fires VGDropdown#show - Перед открытием.
|
|
159
|
+
* @fires VGDropdown#shown - После открытия.
|
|
160
|
+
* @return {void}
|
|
161
|
+
*/
|
|
86
162
|
show() {
|
|
87
163
|
if (isDisabled(this._element) || this._isShown()) return;
|
|
88
164
|
|
|
@@ -101,18 +177,12 @@ class VGDropdown extends BaseModule {
|
|
|
101
177
|
this._element.classList.add(CLASS_NAME_SHOW);
|
|
102
178
|
this._drop.classList.add(CLASS_NAME_SHOW);
|
|
103
179
|
this._setPlacement();
|
|
104
|
-
this._route();
|
|
105
|
-
|
|
106
|
-
if (this._params.backdrop && !this._params.hover) {
|
|
107
|
-
Backdrop.show();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (this._params.overflow) {
|
|
111
|
-
Overflow.append();
|
|
112
|
-
document.body.classList.add('dropdown-open');
|
|
113
|
-
}
|
|
114
180
|
|
|
115
181
|
const completeCallback = () => {
|
|
182
|
+
this._route((status, data) => {
|
|
183
|
+
EventHandler.trigger(this._element, EVENT_KEY_LOADED, { stats: status, data });
|
|
184
|
+
});
|
|
185
|
+
|
|
116
186
|
if (this.isFade) {
|
|
117
187
|
this._drop.classList.add(CLASS_NAME_FADE);
|
|
118
188
|
} else if (!this.isAnimation) {
|
|
@@ -124,19 +194,39 @@ class VGDropdown extends BaseModule {
|
|
|
124
194
|
this._queueCallback(completeCallback, this._drop, this.isAnimation || this.isFade, 50);
|
|
125
195
|
}
|
|
126
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Закрывает выпадающий список.
|
|
199
|
+
* @fires VGDropdown#hide - Перед закрытием.
|
|
200
|
+
* @fires VGDropdown#hidden - После закрытия.
|
|
201
|
+
* @return {void}
|
|
202
|
+
*/
|
|
127
203
|
hide() {
|
|
128
204
|
if (isDisabled(this._element) || !this._isShown()) return;
|
|
129
205
|
this._completeHide({ relatedTarget: this._element });
|
|
130
206
|
}
|
|
131
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Удаляет инстанс компонента и очищает обработчики событий.
|
|
210
|
+
* @return {void}
|
|
211
|
+
*/
|
|
132
212
|
dispose() {
|
|
133
213
|
super.dispose();
|
|
134
214
|
}
|
|
135
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Проверяет, открыто ли выпадающее меню.
|
|
218
|
+
* @return {boolean} - `true`, если открыто.
|
|
219
|
+
* @private
|
|
220
|
+
*/
|
|
136
221
|
_isShown() {
|
|
137
222
|
return this._element.classList.contains(CLASS_NAME_SHOW);
|
|
138
223
|
}
|
|
139
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Полностью закрывает меню с анимацией и callback.
|
|
227
|
+
* @param {Object} relatedTarget - Событие-инициатор.
|
|
228
|
+
* @private
|
|
229
|
+
*/
|
|
140
230
|
_completeHide(relatedTarget) {
|
|
141
231
|
const hideEvent = EventHandler.trigger(this._drop, EVENT_KEY_HIDE, relatedTarget);
|
|
142
232
|
if (hideEvent.defaultPrevented) return;
|
|
@@ -156,19 +246,6 @@ class VGDropdown extends BaseModule {
|
|
|
156
246
|
this._drop.classList.remove(CLASS_NAME_OPEN);
|
|
157
247
|
}
|
|
158
248
|
|
|
159
|
-
if (this._params.backdrop && !this._params.hover) {
|
|
160
|
-
Backdrop.hide(() => {
|
|
161
|
-
if (this._params.overflow) {
|
|
162
|
-
Overflow.destroy();
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (this._params.overflow) {
|
|
168
|
-
Overflow.destroy();
|
|
169
|
-
document.body.classList.remove('dropdown-open');
|
|
170
|
-
}
|
|
171
|
-
|
|
172
249
|
setTimeout(() => {
|
|
173
250
|
const completeCallback = () => {
|
|
174
251
|
this._drop.classList.remove(CLASS_NAME_SHOW);
|
|
@@ -178,6 +255,10 @@ class VGDropdown extends BaseModule {
|
|
|
178
255
|
}, this._params.animation.delay);
|
|
179
256
|
}
|
|
180
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Устанавливает позицию выпадающего окна с помощью вспомогательного класса Placement.
|
|
260
|
+
* @private
|
|
261
|
+
*/
|
|
181
262
|
_setPlacement() {
|
|
182
263
|
if (!this._drop) return;
|
|
183
264
|
|
|
@@ -209,6 +290,12 @@ class VGDropdown extends BaseModule {
|
|
|
209
290
|
this._isPlacement = true;
|
|
210
291
|
}
|
|
211
292
|
|
|
293
|
+
/**
|
|
294
|
+
* Инициализирует компонент на указанном элементе и устанавливает обработчики событий.
|
|
295
|
+
* @param {HTMLElement} element - Элемент-переключатель.
|
|
296
|
+
* @param {Object} [params] - Параметры инициализации.
|
|
297
|
+
* @return {VGDropdown} - Экземпляр компонента.
|
|
298
|
+
*/
|
|
212
299
|
static init(element, params = {}) {
|
|
213
300
|
const instance = VGDropdown.getOrCreateInstance(element, params);
|
|
214
301
|
|
|
@@ -253,8 +340,15 @@ class VGDropdown extends BaseModule {
|
|
|
253
340
|
event.preventDefault();
|
|
254
341
|
instance.toggle();
|
|
255
342
|
});
|
|
343
|
+
|
|
344
|
+
return instance;
|
|
256
345
|
}
|
|
257
346
|
|
|
347
|
+
/**
|
|
348
|
+
* Скрывает все открытые выпадающие списки.
|
|
349
|
+
* @param {Event} event - Событие, инициировавшее скрытие.
|
|
350
|
+
* @static
|
|
351
|
+
*/
|
|
258
352
|
static hideOpenToggles(event) {
|
|
259
353
|
const openToggles = Selectors.findAll(`${SELECTOR_DATA_TOGGLE}:not(.disabled):not(:disabled).${CLASS_NAME_SHOW}`);
|
|
260
354
|
for (const toggle of openToggles) {
|
|
@@ -279,6 +373,11 @@ class VGDropdown extends BaseModule {
|
|
|
279
373
|
}
|
|
280
374
|
}
|
|
281
375
|
|
|
376
|
+
/**
|
|
377
|
+
* Обработчик клавиатурных событий (стрелки, Esc).
|
|
378
|
+
* @param {KeyboardEvent} event - Клавиатурное событие.
|
|
379
|
+
* @static
|
|
380
|
+
*/
|
|
282
381
|
static keydownHandler(event) {
|
|
283
382
|
const isInput = /input|textarea/i.test(event.target.tagName);
|
|
284
383
|
const isEscapeEvent = event.key === 'Escape';
|
|
@@ -307,6 +406,11 @@ class VGDropdown extends BaseModule {
|
|
|
307
406
|
}
|
|
308
407
|
}
|
|
309
408
|
|
|
409
|
+
/**
|
|
410
|
+
* Обработчик кликов и Tab для закрытия выпадающих списков.
|
|
411
|
+
* @param {Event} event - Событие (click или keyup).
|
|
412
|
+
* @static
|
|
413
|
+
*/
|
|
310
414
|
static clearDrops(event) {
|
|
311
415
|
if (event.button === 2 || (event.type === 'keyup' && event.key !== 'Tab')) {
|
|
312
416
|
return;
|
|
@@ -315,6 +419,4 @@ class VGDropdown extends BaseModule {
|
|
|
315
419
|
}
|
|
316
420
|
}
|
|
317
421
|
|
|
318
|
-
dismissTrigger(VGDropdown);
|
|
319
|
-
|
|
320
422
|
export default VGDropdown;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# VGDropdown — Модуль выпадающего списка
|
|
2
|
+
|
|
3
|
+
**VGDropdown** — это универсальный и гибко настраиваемый JavaScript-компонент для создания интерактивных
|
|
4
|
+
выпадающих меню (dropdown) в веб-интерфейсах. Поддерживает позиционирование, анимации, AJAX-загрузку контента,
|
|
5
|
+
работу с hover/кликами, клавиатурную навигацию и доступность.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 📌 Основные возможности
|
|
10
|
+
|
|
11
|
+
- Открытие/закрытие по клику или наведению (`hover`)
|
|
12
|
+
- Поддержка **автоматического позиционирования** (с учётом границ экрана и overflow)
|
|
13
|
+
- Полная **клавиатурная навигация** (стрелки, Esc, Tab)
|
|
14
|
+
- **AJAX-загрузка контента** динамически
|
|
15
|
+
- **CSS-анимации** (вход/выход) с использованием Animate.css
|
|
16
|
+
- Поддержка **fade-эффектов** и кастомных задержек
|
|
17
|
+
- Автоматическое закрытие других открытых dropdown'ов
|
|
18
|
+
- Полная **доступность (a11y)**: `aria-expanded`
|
|
19
|
+
- Совместимость с **мобильными устройствами**
|
|
20
|
+
- Гибкая инициализация: через JS или `data-*` атрибуты
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🧩 Структура HTML
|
|
25
|
+
|
|
26
|
+
```bladehtml
|
|
27
|
+
<div class="vg-dropdown">
|
|
28
|
+
<a href="#" data-vg-toggle="dropdown" data-params='{"hover": "true"}' ( или data-hover="true") class="btn btn-primary" aria-expanded="false">Open</a>
|
|
29
|
+
<div class="vg-dropdown-content">
|
|
30
|
+
<div class="vg-dropdown-container">
|
|
31
|
+
<ul class="list-group">
|
|
32
|
+
<li class="list-group-item"><a href="#">Home</a></li>
|
|
33
|
+
<li class="list-group-item"><a href="#">Services</a></li>
|
|
34
|
+
<li class="list-group-item"><a href="#">About</a></li>
|
|
35
|
+
<li class="list-group-item"><a href="#">Contacts</a></li>
|
|
36
|
+
</ul>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
> 💡 Убедитесь, что `.vg-dropdown-content` находится внутри `.vg-dropdown`, либо укажите селектор явно через `data-vg-target`.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## ⚙️ Параметры инициализации
|
|
47
|
+
|
|
48
|
+
| Параметр | Тип | По умолчанию | Описание |
|
|
49
|
+
|--------|------|-------------|-------------------------------------------------------------------------------|
|
|
50
|
+
| `placement` | `string` | `'auto'` | Позиция меню: `'top-start'`, `'bottom-start'`, `'left-start'`, `'right-start'`, `'auto'` и т.д. |
|
|
51
|
+
| `hover` | `boolean` | `false` | Открывать при наведении мыши (на десктопе) |
|
|
52
|
+
| `animation.fade` | `boolean` | `true` | Добавить класс `fade` при показе |
|
|
53
|
+
| `animation.enable` | `boolean` | `false` | Включить CSS-анимации |
|
|
54
|
+
| `animation.in` | `string` | `'animate__flipInY'` | Класс анимации входа (например, Animate.css) |
|
|
55
|
+
| `animation.out` | `string` | `'animate__flipOutY'` | Класс анимации выхода |
|
|
56
|
+
| `animation.delay` | `number` | `300` | Задержка перед удалением `.show` (в мс) |
|
|
57
|
+
| `ajax.route` | `string` | `''` | URL для загрузки контента |
|
|
58
|
+
| `ajax.target` | `string` | `''` | Селектор внутри `.vg-dropdown-content` для вставки данных |
|
|
59
|
+
| `ajax.method` | `string` | `'get'` | HTTP-метод запроса |
|
|
60
|
+
| `ajax.loader` | `boolean` | `false` | Показывать лоадер при загрузке |
|
|
61
|
+
| `ajax.once` | `boolean` | `false` | Загружать контент только один раз |
|
|
62
|
+
| `ajax.output` | `boolean` | `true` | Вставлять ответ в DOM |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 🚀 Инициализация
|
|
67
|
+
|
|
68
|
+
### Через JavaScript
|
|
69
|
+
```js
|
|
70
|
+
import VGDropdown from 'app/modules/vgdropdown/js/vgdropdown';
|
|
71
|
+
|
|
72
|
+
const dropdown = new VGDropdown(document.querySelector('[data-vg-toggle="dropdown"]'), {
|
|
73
|
+
placement: 'bottom-start',
|
|
74
|
+
hover: true,
|
|
75
|
+
animation: {
|
|
76
|
+
enable: true,
|
|
77
|
+
in: 'animate__fadeInDown',
|
|
78
|
+
out: 'animate__fadeOutUp',
|
|
79
|
+
delay: 200
|
|
80
|
+
},
|
|
81
|
+
ajax: {
|
|
82
|
+
route: '',
|
|
83
|
+
target: '',
|
|
84
|
+
method: 'get',
|
|
85
|
+
once: true
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
> Атрибуты автоматически преобразуются в параметры:
|
|
91
|
+
> `data-placement` → `placement`
|
|
92
|
+
> `data-ajax-route` → `ajax.route`
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 🔁 Методы
|
|
97
|
+
|
|
98
|
+
| Метод | Описание |
|
|
99
|
+
|------|--------|
|
|
100
|
+
| `.toggle()` | Переключает состояние (открыть/закрыть) |
|
|
101
|
+
| `.show()` | Открывает меню |
|
|
102
|
+
| `.hide()` | Закрывает меню |
|
|
103
|
+
| `.dispose()` | Удаляет экземпляр и обработчики событий |
|
|
104
|
+
| `.getInstance(element)` | Получить существующий экземпляр |
|
|
105
|
+
| `.getOrCreateInstance(element, params)` | Получить или создать экземпляр |
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
VGDropdown.getOrCreateInstance().hide(); // Закрыть drop
|
|
109
|
+
```
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 📣 События
|
|
113
|
+
|
|
114
|
+
VGDropdown генерирует пользовательские события.
|
|
115
|
+
|
|
116
|
+
| Событие | Срабатывает | Детали (`event.detail`) |
|
|
117
|
+
|--------|-------------|-------------------------|
|
|
118
|
+
| `vg.dropdown.show` | Перед открытием | `relatedTarget` — кнопка |
|
|
119
|
+
| `vg.dropdown.shown` | После открытия | `relatedTarget` |
|
|
120
|
+
| `vg.dropdown.hide` | Перед закрытием | `relatedTarget` |
|
|
121
|
+
| `vg.dropdown.hidden` | После закрытия | `relatedTarget` |
|
|
122
|
+
| `vg.dropdown.loaded` | После AJAX-загрузки | `stats`, `data` |
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
dropdown._drop.addEventListener('vg.dropdown.shown', (e) => {
|
|
126
|
+
console.log('Дроп открыт', e.detail.relatedTarget);
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 🖱️ Поведение при наведении (`hover`)
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
hover: true
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- Работает только на десктопах (`!isMobileDevice()`)
|
|
139
|
+
- Автоматически закрывается при уходе курсора
|
|
140
|
+
- Не конфликтует с другими открытыми меню
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 🔁 AJAX-загрузка контента
|
|
145
|
+
|
|
146
|
+
```js
|
|
147
|
+
ajax: {
|
|
148
|
+
route: '/menu',
|
|
149
|
+
target: '#drop-content', // Целевой селектор внутри .vg-dropdown-container
|
|
150
|
+
method: 'get',
|
|
151
|
+
once: true,
|
|
152
|
+
loader: false,
|
|
153
|
+
output: true
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
- Контент загружается при первом открытии (если `once: true`)
|
|
157
|
+
- Ответ вставляется в указанный селектор
|
|
158
|
+
- Генерируется событие `vg.dropdown.loaded`
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 🎨 Анимации
|
|
163
|
+
|
|
164
|
+
Поддерживается два режима:
|
|
165
|
+
|
|
166
|
+
### 1. Fade (CSS)
|
|
167
|
+
### 2. CSS-анимации (через Animate.css)
|
|
168
|
+
```js
|
|
169
|
+
animation: { enable: true, in: 'animate__fadeInUp', out: 'animate__fadeOutDown' }
|
|
170
|
+
```
|
|
171
|
+
> Убедитесь, что подключили animate.css или свои классы анимаций.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 📱 Адаптивность и мобильные устройства
|
|
176
|
+
|
|
177
|
+
- На мобильных устройствах `hover` отключается
|
|
178
|
+
- При открытии временно блокируются `mouseover` события на других элементах (для стабильности)
|
|
179
|
+
- Поддерживает тач-события корректно
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 🔐 Доступность (a11y)
|
|
184
|
+
|
|
185
|
+
- `aria-expanded` автоматически обновляется
|
|
186
|
+
- Поддержка клавиатуры: **Enter**, **Space**, **Esc**, **↑↓**
|
|
187
|
+
- Закрытие при клике вне или нажатии `Tab`
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
## 🧰 Статические методы
|
|
191
|
+
|
|
192
|
+
| Метод | Описание |
|
|
193
|
+
|------|--------|
|
|
194
|
+
| `VGDropdown.hideOpenToggles(event)` | Закрывает все открытые меню |
|
|
195
|
+
| `VGDropdown.keydownHandler(event)` | Обработчик клавиш |
|
|
196
|
+
| `VGDropdown.clearDrops(event)` | Обработчик кликов вне и Tab |
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 📦 CSS-классы
|
|
201
|
+
|
|
202
|
+
| Класс | Назначение |
|
|
203
|
+
|------|----------|
|
|
204
|
+
| `.vg-dropdown` | Родительский контейнер |
|
|
205
|
+
| `.vg-dropdown-content` | Выпадающее меню |
|
|
206
|
+
| `.show` | Показывает элемент |
|
|
207
|
+
| `.fade` | Эффект затухания |
|
|
208
|
+
| `.open` | Альтернатива fade (без анимации) |
|
|
209
|
+
| `[data-vg-toggle="dropdown"]` | Кнопка-переключатель |
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 📄 Лицензия
|
|
214
|
+
|
|
215
|
+
MIT — свободное использование и модификация.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
🛠 Разработано с использованием современных паттернов и лучших практик.
|
|
220
|
+
Создано для масштабируемых, доступных и красивых интерфейсов.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
> 🚀 Автор: VEGAS STUDIO (vegas-dev.com)
|
|
225
|
+
> 📍 Поддерживается в проектах VEGAS
|