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,242 @@
|
|
|
1
|
+
# VGAlert — Модуль модальных окон подтверждения и уведомлений
|
|
2
|
+
|
|
3
|
+
`VGAlert` — это мощный и гибкий JavaScript-модуль, предназначенный для отображения модальных окон подтверждения действий или информационных сообщений. Он интегрирован с системой `VGModal` и поддерживает AJAX-запросы, локализацию, кастомизацию кнопок, тем оформления и работу через `data`-атрибуты.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ✅ Возможности
|
|
8
|
+
|
|
9
|
+
- Отображение **подтверждающих алертов** (`confirm`) и **информационных сообщений** (`info`)
|
|
10
|
+
- Поддержка **AJAX-запросов** после подтверждения
|
|
11
|
+
- Полная **локализация** (настройка языка)
|
|
12
|
+
- Гибкая **настройка кнопок** и сообщений
|
|
13
|
+
- Поддержка **SVG-иконок** и тем стилей (`danger`, `warning`, `success`, `info`)
|
|
14
|
+
- Работа как через **API**, так и через **`data`-атрибуты**
|
|
15
|
+
- Интеграция с промисами (`Promise`)
|
|
16
|
+
- Защита от **множественных одновременных вызовов**
|
|
17
|
+
- Поддержка **клавиатурных сокращений** (Enter, Escape)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 📦 Установка
|
|
22
|
+
|
|
23
|
+
Модуль автоматически подключается при инициализации системы. Убедитесь, что подключены зависимости:
|
|
24
|
+
```js
|
|
25
|
+
import VGAlert from "./app/modules/vgalert/js/vgalert.js";
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 🧩 Режимы работы
|
|
31
|
+
|
|
32
|
+
### 1. `confirm` — Подтверждение действия
|
|
33
|
+
Показывает два действия: **Подтвердить** и **Отмена**.
|
|
34
|
+
|
|
35
|
+
### 2. `info` — Информационное сообщение
|
|
36
|
+
Показывает только кнопку **ОК** (или "Продолжить").
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 🎨 Темы (`theme`)
|
|
41
|
+
| Значение | Иконка | Назначение |
|
|
42
|
+
|--------|--------|----------|
|
|
43
|
+
| `danger` | ⚠️ | Опасные действия (удаление, сброс) |
|
|
44
|
+
| `warning` | ⚠️ | Предупреждения |
|
|
45
|
+
| `success` | ✅ | Успешные операции |
|
|
46
|
+
| `info` | ℹ️ | Общая информация |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 🧱 Вызов через JS (API)
|
|
51
|
+
|
|
52
|
+
### Пример 1: Подтверждение удаления
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
VGAlert.call({
|
|
56
|
+
mode: "confirm",
|
|
57
|
+
theme: "danger",
|
|
58
|
+
message: {
|
|
59
|
+
title: "Вы уверены?",
|
|
60
|
+
description: "Это действие нельзя отменить."
|
|
61
|
+
},
|
|
62
|
+
buttons: {
|
|
63
|
+
agree: {
|
|
64
|
+
text: "Удалить",
|
|
65
|
+
class: ["btn-danger"]
|
|
66
|
+
},
|
|
67
|
+
cancel: {
|
|
68
|
+
text: "Отмена",
|
|
69
|
+
class: ["btn-outline-secondary"]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}).then(() => { // Выполнить AJAX-удаление
|
|
73
|
+
console.log("Пользователь подтвердил удаление");
|
|
74
|
+
}).catch(() => {
|
|
75
|
+
console.log("Пользователь отменил действие");
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Пример 2: Информационное сообщение
|
|
80
|
+
```js
|
|
81
|
+
VGAlert.call({
|
|
82
|
+
mode: "info",
|
|
83
|
+
theme: "success",
|
|
84
|
+
message: {
|
|
85
|
+
title: "Успешно!",
|
|
86
|
+
description: "Данные были сохранены."
|
|
87
|
+
},
|
|
88
|
+
buttons: {
|
|
89
|
+
cancel: {
|
|
90
|
+
text: "ОК",
|
|
91
|
+
class: ["btn-success"]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 🔌 Работа с AJAX
|
|
100
|
+
|
|
101
|
+
Модуль можно связать с AJAX-запросом, который выполнится после подтверждения:
|
|
102
|
+
```js
|
|
103
|
+
// Удалить запись
|
|
104
|
+
// Автоматически вызывается при клике
|
|
105
|
+
VGAlert.confirm(element, {
|
|
106
|
+
mode: "confirm",
|
|
107
|
+
theme: "danger",
|
|
108
|
+
message: {
|
|
109
|
+
title: "Удалить?",
|
|
110
|
+
description: "Вы действительно хотите удалить эту запись?"
|
|
111
|
+
},
|
|
112
|
+
ajax: {
|
|
113
|
+
route: "/api/delete/123",
|
|
114
|
+
method: "post",
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
После подтверждения:
|
|
119
|
+
- Выполняется `POST /api/delete/123`
|
|
120
|
+
- Результат можно отследить через события
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 🔔 События
|
|
125
|
+
|
|
126
|
+
Модуль генерирует события:
|
|
127
|
+
|
|
128
|
+
| Событие | Описание |
|
|
129
|
+
|--------|--------|
|
|
130
|
+
| `vg.alert.accept` | Пользователь подтвердил действие |
|
|
131
|
+
| `vg.alert.reject` | Пользователь отменил действие |
|
|
132
|
+
| `vg.alert.finally` | Действие завершено (в любом случае) |
|
|
133
|
+
| `vg.alert.loaded` | Получен ответ от сервера (если был AJAX) |
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
document.addEventListener('vg.alert.accept', function(e) {
|
|
137
|
+
console.log('Подтверждено:', e.vgalert);
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## ⌨️ Клавиатурные комбинации
|
|
144
|
+
|
|
145
|
+
- `Enter` — подтверждение (если фокус на кнопке "Подтвердить")
|
|
146
|
+
- `Escape` — отмена (если `keyboard: true`)
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 🛠️ Конфигурация по умолчанию
|
|
151
|
+
```js
|
|
152
|
+
{
|
|
153
|
+
mode: "confirm",
|
|
154
|
+
theme: "danger",
|
|
155
|
+
modal: {
|
|
156
|
+
centered: false,
|
|
157
|
+
backdrop: true,
|
|
158
|
+
keyboard: true,
|
|
159
|
+
dismiss: true
|
|
160
|
+
},
|
|
161
|
+
buttons: {
|
|
162
|
+
agree: {
|
|
163
|
+
text: "Да",
|
|
164
|
+
class: ["btn-primary"] },
|
|
165
|
+
cancel: {
|
|
166
|
+
text: "Отмена",
|
|
167
|
+
class: ["btn-secondary"]
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
message: {
|
|
171
|
+
title: "Подтвердите действие",
|
|
172
|
+
description: "Вы уверены, что хотите продолжить?"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## 🌐 Локализация
|
|
180
|
+
|
|
181
|
+
Поддерживаются языки: `ru` (по умолчанию), `en`.
|
|
182
|
+
|
|
183
|
+
Настройка языка:
|
|
184
|
+
|
|
185
|
+
```js
|
|
186
|
+
VGAlert.call(params, 'en');
|
|
187
|
+
```
|
|
188
|
+
Переводы хранятся в `lang_buttons` и `lang_messages`.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 🧩 Кастомизация кнопок
|
|
193
|
+
|
|
194
|
+
Поддерживает:
|
|
195
|
+
- `tag: 'button' | 'a'`
|
|
196
|
+
- `type` (для `<button>`)
|
|
197
|
+
- `class` — массив CSS-классов
|
|
198
|
+
- `attr` — любые дополнительные атрибуты
|
|
199
|
+
- `element` — готовый HTML-код кнопки
|
|
200
|
+
|
|
201
|
+
### Пример: кнопка-ссылка
|
|
202
|
+
```js
|
|
203
|
+
buttons: {
|
|
204
|
+
agree: {
|
|
205
|
+
tag: "a",
|
|
206
|
+
attr: {},
|
|
207
|
+
class: ["btn", "btn-info"],
|
|
208
|
+
text: "Перейти в профиль" },
|
|
209
|
+
cancel: {
|
|
210
|
+
text: "Закрыть"
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## 🚫 Ограничения
|
|
218
|
+
|
|
219
|
+
- Нельзя открыть более одного `VGAlert` одновременно (защита от дублирования)
|
|
220
|
+
- Если `isAlertOpen = true`, последующие вызовы будут отклонены с ошибкой
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## 📎 Смотрите также
|
|
225
|
+
|
|
226
|
+
- [`VGModal`](../vgmodal/readme.md) — основа модального окна
|
|
227
|
+
- [`BaseModule`](../../base-module.js) — базовый класс модулей
|
|
228
|
+
- [`lang`](../../../utils/js/components/lang.js) — система локализации
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
💡 **Совет**: Используйте `VGAlert` для критичных действий, где важно получить подтверждение от пользователя.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
## 📄 Лицензия
|
|
236
|
+
|
|
237
|
+
MIT — свободно используйте и модифицируйте.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
> 🚀 Автор: VEGAS STUDIO (vegas-dev.com)
|
|
242
|
+
> 📍 Поддерживается в проектах VEGAS
|
|
@@ -1,11 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @class VGCollapse
|
|
3
|
+
* @extends BaseModule
|
|
4
|
+
* @classdesc Класс для реализации поведения "collapse" (раскрытие/свертывание элементов) с поддержкой анимации, AJAX-загрузки и иерархической структуры.
|
|
5
|
+
*
|
|
6
|
+
* Поддерживает переключение видимости контента по клику на элементы с атрибутом `data-vg-toggle="collapse"`.
|
|
7
|
+
* Может работать в вертикальном и горизонтальном режимах, управлять aria-атрибутами и состоянием кнопок.
|
|
8
|
+
*
|
|
9
|
+
* @param {HTMLElement} element - Основной элемент, к которому применяется collapse.
|
|
10
|
+
* @param {Object} params - Параметры конфигурации.
|
|
11
|
+
* @param {boolean} [params.toggle=true] - Автоматически переключать состояние при инициализации.
|
|
12
|
+
* @param {string|HTMLElement|null} [params.parent=null] - Родительский контейнер, ограничивающий поиск дочерних collapse-элементов.
|
|
13
|
+
* @param {Object} params.ajax - Настройки AJAX-загрузки контента.
|
|
14
|
+
* @param {string} params.ajax.route - URL-адрес для запроса.
|
|
15
|
+
* @param {string} params.ajax.target - CSS-селектор, куда вставлять ответ.
|
|
16
|
+
* @param {string} params.ajax.method='get' - HTTP-метод запроса.
|
|
17
|
+
* @param {boolean} params.ajax.loader=false - Показывать ли лоадер при загрузке.
|
|
18
|
+
* @param {boolean} params.ajax.once=true - Загружать контент только один раз.
|
|
19
|
+
* @param {boolean} params.ajax.output=true - Вставлять ли ответ в DOM.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const collapse = new VGCollapse(document.getElementById('myCollapse'), {
|
|
23
|
+
* toggle: true,
|
|
24
|
+
* parent: '#accordion'
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* <div id="accordion">
|
|
29
|
+
* <div class="vg-collapse" id="collapseOne">
|
|
30
|
+
* <button data-vg-toggle="collapse" data-target="#collapseOne">Toggle</button>
|
|
31
|
+
* </div>
|
|
32
|
+
* </div>
|
|
33
|
+
*/
|
|
1
34
|
import BaseModule from "../../base-module";
|
|
2
|
-
import {mergeDeepObject, reflow} from "../../../utils/js/functions";
|
|
35
|
+
import {getElement, mergeDeepObject, reflow} from "../../../utils/js/functions";
|
|
3
36
|
import EventHandler from "../../../utils/js/dom/event";
|
|
4
37
|
import Selectors from "../../../utils/js/dom/selectors";
|
|
5
38
|
import {Manipulator} from "../../../utils/js/dom/manipulator";
|
|
6
39
|
|
|
7
40
|
/**
|
|
8
|
-
*
|
|
41
|
+
* Константы, используемые в классе VGCollapse.
|
|
42
|
+
* @private
|
|
43
|
+
* @type {Object}
|
|
9
44
|
*/
|
|
10
45
|
const NAME = 'collapse';
|
|
11
46
|
const NAME_KEY = 'vg.collapse';
|
|
@@ -14,21 +49,36 @@ const CLASS_NAME_COLLAPSE = 'vg-collapse';
|
|
|
14
49
|
const CLASS_NAME_COLLAPSING = 'vg-collapsing';
|
|
15
50
|
const CLASS_NAME_COLLAPSED = 'vg-collapsed';
|
|
16
51
|
const CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`;
|
|
52
|
+
const CLASS_NAME_HORIZONTAL = 'vg-collapse-horizontal';
|
|
17
53
|
|
|
18
|
-
const SELECTOR_DATA_TOGGLE= '[data-vg-toggle="collapse"]';
|
|
19
|
-
const SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing';
|
|
54
|
+
const SELECTOR_DATA_TOGGLE = '[data-vg-toggle="collapse"]';
|
|
55
|
+
const SELECTOR_ACTIVES = '.vg-collapse.show, .vg-collapse.vg-collapsing';
|
|
20
56
|
|
|
21
|
-
const EVENT_KEY_HIDE
|
|
57
|
+
const EVENT_KEY_HIDE = `${NAME_KEY}.hide`;
|
|
22
58
|
const EVENT_KEY_HIDDEN = `${NAME_KEY}.hidden`;
|
|
23
|
-
const EVENT_KEY_SHOW
|
|
24
|
-
const EVENT_KEY_SHOWN
|
|
59
|
+
const EVENT_KEY_SHOW = `${NAME_KEY}.show`;
|
|
60
|
+
const EVENT_KEY_SHOWN = `${NAME_KEY}.shown`;
|
|
61
|
+
const EVENT_KEY_LOADED = `${NAME_KEY}.loaded`;
|
|
25
62
|
|
|
26
63
|
const EVENT_KEY_CLICK_DATA_API = `click.${NAME_KEY}.data.api`;
|
|
27
64
|
|
|
65
|
+
const WIDTH = 'width';
|
|
66
|
+
const HEIGHT = 'height';
|
|
67
|
+
|
|
28
68
|
class VGCollapse extends BaseModule {
|
|
69
|
+
/**
|
|
70
|
+
* Создает экземпляр VGCollapse.
|
|
71
|
+
* @param {HTMLElement} element - DOM-элемент, к которому применяется collapse.
|
|
72
|
+
* @param {Object} params - Параметры инициализации.
|
|
73
|
+
*/
|
|
29
74
|
constructor(element, params = {}) {
|
|
30
75
|
super(element, params);
|
|
31
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Объединённые параметры с учётом значений по умолчанию и переданных пользователем.
|
|
79
|
+
* @type {Object}
|
|
80
|
+
* @private
|
|
81
|
+
*/
|
|
32
82
|
this._params = this._getParams(element, mergeDeepObject({
|
|
33
83
|
toggle: true,
|
|
34
84
|
parent: null,
|
|
@@ -37,13 +87,31 @@ class VGCollapse extends BaseModule {
|
|
|
37
87
|
target: '',
|
|
38
88
|
method: 'get',
|
|
39
89
|
loader: false,
|
|
40
|
-
once:
|
|
90
|
+
once: true,
|
|
41
91
|
output: true,
|
|
42
92
|
}
|
|
43
93
|
}, params));
|
|
44
94
|
|
|
45
|
-
|
|
46
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Родительский элемент (если задан).
|
|
97
|
+
* @type {HTMLElement|null}
|
|
98
|
+
* @private
|
|
99
|
+
*/
|
|
100
|
+
this._params.parent = getElement(this._params.parent) || null;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Флаг, указывающий на переход (анимацию).
|
|
104
|
+
* @type {boolean}
|
|
105
|
+
* @private
|
|
106
|
+
*/
|
|
107
|
+
this._isTransitioning = false;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Массив элементов, которые управляют этим collapse (например, кнопки).
|
|
111
|
+
* @type {HTMLElement[]}
|
|
112
|
+
* @private
|
|
113
|
+
*/
|
|
114
|
+
this._triggerArray = [];
|
|
47
115
|
|
|
48
116
|
const toggleList = Selectors.findAll(SELECTOR_DATA_TOGGLE);
|
|
49
117
|
|
|
@@ -52,7 +120,7 @@ class VGCollapse extends BaseModule {
|
|
|
52
120
|
const filterElement = Selectors.findAll(selector).filter(foundElement => foundElement === this._element);
|
|
53
121
|
|
|
54
122
|
if (selector !== null && filterElement.length) {
|
|
55
|
-
this._triggerArray.push(elem)
|
|
123
|
+
this._triggerArray.push(elem);
|
|
56
124
|
}
|
|
57
125
|
}
|
|
58
126
|
|
|
@@ -67,112 +135,172 @@ class VGCollapse extends BaseModule {
|
|
|
67
135
|
}
|
|
68
136
|
}
|
|
69
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Возвращает статическое имя модуля.
|
|
140
|
+
* @returns {string} Имя модуля.
|
|
141
|
+
* @static
|
|
142
|
+
*/
|
|
70
143
|
static get NAME() {
|
|
71
144
|
return NAME;
|
|
72
145
|
}
|
|
73
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Возвращает статический ключ модуля (используется для событий и хранения экземпляров).
|
|
149
|
+
* @returns {string} Ключ модуля.
|
|
150
|
+
* @static
|
|
151
|
+
*/
|
|
74
152
|
static get NAME_KEY() {
|
|
75
|
-
return NAME_KEY
|
|
153
|
+
return NAME_KEY;
|
|
76
154
|
}
|
|
77
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Переключает состояние collapse: если скрыт — показывает, если показан — скрывает.
|
|
158
|
+
* @param {EventTarget} [relatedTarget] - Связанный элемент (опционально).
|
|
159
|
+
* @returns {void}
|
|
160
|
+
*/
|
|
78
161
|
toggle(relatedTarget) {
|
|
79
162
|
return !this._isShown() ? this.show(relatedTarget) : this.hide();
|
|
80
163
|
}
|
|
81
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Открывает collapse с анимацией и, при необходимости, AJAX-загрузкой.
|
|
167
|
+
* @emits VGCollapse#show - Перед началом открытия.
|
|
168
|
+
* @emits VGCollapse#shown - После завершения открытия.
|
|
169
|
+
* @emits VGCollapse#loaded - После загрузки AJAX-контента (если используется).
|
|
170
|
+
* @returns {void}
|
|
171
|
+
*/
|
|
82
172
|
show() {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
173
|
+
if (this._isTransitioning || this._isShown()) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
86
176
|
|
|
87
177
|
let activeChildren = [];
|
|
88
178
|
|
|
89
|
-
if (
|
|
179
|
+
if (this._params.parent) {
|
|
90
180
|
activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)
|
|
91
181
|
.filter(element => element !== this._element)
|
|
92
182
|
.map(element => VGCollapse.getOrCreateInstance(element, { toggle: false }));
|
|
93
183
|
}
|
|
94
184
|
|
|
95
|
-
if (activeChildren.length && activeChildren[0]._isTransitioning)
|
|
185
|
+
if (activeChildren.length && activeChildren[0]._isTransitioning) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
96
188
|
|
|
97
|
-
const startEvent = EventHandler.trigger(
|
|
98
|
-
if (startEvent.defaultPrevented)
|
|
189
|
+
const startEvent = EventHandler.trigger(this._element, EVENT_KEY_SHOW);
|
|
190
|
+
if (startEvent.defaultPrevented) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
99
193
|
|
|
100
194
|
for (const activeInstance of activeChildren) {
|
|
101
195
|
activeInstance.hide();
|
|
102
196
|
}
|
|
103
197
|
|
|
104
|
-
|
|
105
|
-
_this._element.classList.add(CLASS_NAME_COLLAPSING)
|
|
198
|
+
const dimension = this._getDimension();
|
|
106
199
|
|
|
107
|
-
|
|
200
|
+
this._element.classList.remove(CLASS_NAME_COLLAPSE);
|
|
201
|
+
this._element.classList.add(CLASS_NAME_COLLAPSING);
|
|
108
202
|
|
|
109
|
-
|
|
110
|
-
_this._isTransitioning = true;
|
|
203
|
+
this._element.style[dimension] = '0';
|
|
111
204
|
|
|
112
|
-
|
|
205
|
+
this._addAriaAndCollapsedClass(this._triggerArray, true);
|
|
206
|
+
this._isTransitioning = true;
|
|
113
207
|
|
|
114
208
|
const complete = () => {
|
|
115
|
-
|
|
209
|
+
this._isTransitioning = false;
|
|
116
210
|
|
|
117
|
-
|
|
118
|
-
|
|
211
|
+
this._element.classList.remove(CLASS_NAME_COLLAPSING);
|
|
212
|
+
this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW);
|
|
119
213
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
214
|
+
this._element.style[dimension] = '';
|
|
215
|
+
|
|
216
|
+
this._route((status, data) => {
|
|
217
|
+
EventHandler.trigger(this._element, EVENT_KEY_LOADED, { stats: status, data });
|
|
218
|
+
});
|
|
123
219
|
|
|
124
|
-
|
|
220
|
+
EventHandler.trigger(this._element, EVENT_KEY_SHOWN);
|
|
221
|
+
};
|
|
125
222
|
|
|
126
|
-
const
|
|
127
|
-
|
|
223
|
+
const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
|
|
224
|
+
const scrollSize = `scroll${capitalizedDimension}`;
|
|
225
|
+
|
|
226
|
+
this._queueCallback(complete, this._element, true);
|
|
227
|
+
this._element.style[dimension] = `${this._element[scrollSize]}px`;
|
|
128
228
|
}
|
|
129
229
|
|
|
230
|
+
/**
|
|
231
|
+
* Скрывает collapse с анимацией.
|
|
232
|
+
* @emits VGCollapse#hide - Перед началом скрытия.
|
|
233
|
+
* @emits VGCollapse#hidden - После завершения скрытия.
|
|
234
|
+
* @returns {void}
|
|
235
|
+
*/
|
|
130
236
|
hide() {
|
|
131
|
-
|
|
237
|
+
if (this._isTransitioning || !this._isShown()) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const startEvent = EventHandler.trigger(this._element, EVENT_KEY_HIDE);
|
|
242
|
+
if (startEvent.defaultPrevented) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
132
245
|
|
|
133
|
-
|
|
246
|
+
const dimension = this._getDimension();
|
|
134
247
|
|
|
135
|
-
|
|
136
|
-
if (startEvent.defaultPrevented) return;
|
|
248
|
+
this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`;
|
|
137
249
|
|
|
138
|
-
|
|
139
|
-
reflow(_this._element);
|
|
250
|
+
reflow(this._element);
|
|
140
251
|
|
|
141
|
-
|
|
142
|
-
|
|
252
|
+
this._element.classList.add(CLASS_NAME_COLLAPSING);
|
|
253
|
+
this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW);
|
|
143
254
|
|
|
144
|
-
for (const trigger of
|
|
255
|
+
for (const trigger of this._triggerArray) {
|
|
145
256
|
const element = Selectors.getElementFromSelector(trigger);
|
|
146
257
|
|
|
147
|
-
if (element && !
|
|
148
|
-
|
|
258
|
+
if (element && !this._isShown(element)) {
|
|
259
|
+
this._addAriaAndCollapsedClass([trigger], false);
|
|
149
260
|
}
|
|
150
261
|
}
|
|
151
262
|
|
|
152
|
-
|
|
263
|
+
this._isTransitioning = true;
|
|
153
264
|
|
|
154
265
|
const complete = () => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
EventHandler.trigger(
|
|
159
|
-
}
|
|
266
|
+
this._isTransitioning = false;
|
|
267
|
+
this._element.classList.remove(CLASS_NAME_COLLAPSING);
|
|
268
|
+
this._element.classList.add(CLASS_NAME_COLLAPSE);
|
|
269
|
+
EventHandler.trigger(this._element, EVENT_KEY_HIDDEN);
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
this._element.style[dimension] = '';
|
|
160
273
|
|
|
161
|
-
|
|
162
|
-
_this._queueCallback(complete, _this._element, true);
|
|
274
|
+
this._queueCallback(complete, this._element, true);
|
|
163
275
|
}
|
|
164
276
|
|
|
277
|
+
/**
|
|
278
|
+
* Удаляет экземпляр collapse и очищает память.
|
|
279
|
+
* @returns {void}
|
|
280
|
+
*/
|
|
165
281
|
dispose() {
|
|
166
282
|
super.dispose();
|
|
167
283
|
}
|
|
168
284
|
|
|
285
|
+
/**
|
|
286
|
+
* Проверяет, является ли элемент открытым.
|
|
287
|
+
* @param {HTMLElement} [element=this._element] - Элемент для проверки.
|
|
288
|
+
* @returns {boolean} `true`, если элемент имеет класс `.show`.
|
|
289
|
+
* @private
|
|
290
|
+
*/
|
|
169
291
|
_isShown(element = this._element) {
|
|
170
292
|
return element.classList.contains(CLASS_NAME_SHOW);
|
|
171
293
|
}
|
|
172
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Добавляет или удаляет aria-атрибуты и классы у управляющих элементов.
|
|
297
|
+
* @param {HTMLElement[]} triggerArray - Массив элементов управления.
|
|
298
|
+
* @param {boolean} isOpen - Состояние: открыто или закрыто.
|
|
299
|
+
* @private
|
|
300
|
+
*/
|
|
173
301
|
_addAriaAndCollapsedClass(triggerArray, isOpen) {
|
|
174
302
|
if (!triggerArray.length) {
|
|
175
|
-
return
|
|
303
|
+
return;
|
|
176
304
|
}
|
|
177
305
|
|
|
178
306
|
for (const element of triggerArray) {
|
|
@@ -180,43 +308,69 @@ class VGCollapse extends BaseModule {
|
|
|
180
308
|
}
|
|
181
309
|
}
|
|
182
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Инициализирует дочерние collapse-элементы, если указан родитель.
|
|
313
|
+
* @private
|
|
314
|
+
*/
|
|
183
315
|
_initializeChildren() {
|
|
184
316
|
if (!this._params.parent) return;
|
|
185
317
|
|
|
186
318
|
const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE);
|
|
187
319
|
|
|
188
320
|
for (const element of children) {
|
|
189
|
-
const selected = Selectors.getElementFromSelector(element)
|
|
321
|
+
const selected = Selectors.getElementFromSelector(element);
|
|
190
322
|
|
|
191
323
|
if (selected) {
|
|
192
|
-
this._addAriaAndCollapsedClass([element], this._isShown(selected))
|
|
324
|
+
this._addAriaAndCollapsedClass([element], this._isShown(selected));
|
|
193
325
|
}
|
|
194
326
|
}
|
|
195
327
|
}
|
|
196
328
|
|
|
329
|
+
/**
|
|
330
|
+
* Возвращает дочерние элементы первого уровня (без вложенных).
|
|
331
|
+
* @param {string} selector - CSS-селектор для поиска.
|
|
332
|
+
* @returns {HTMLElement[]} Массив найденных элементов.
|
|
333
|
+
* @private
|
|
334
|
+
*/
|
|
197
335
|
_getFirstLevelChildren(selector) {
|
|
198
|
-
const children = Selectors.
|
|
199
|
-
return Selectors.
|
|
336
|
+
const children = Selectors.findAll(CLASS_NAME_DEEPER_CHILDREN, this._params.parent);
|
|
337
|
+
return Selectors.findAll(selector, this._params.parent).filter(element => !children.includes(element));
|
|
200
338
|
}
|
|
201
339
|
|
|
340
|
+
/**
|
|
341
|
+
* Обновляет состояние кнопки: классы, текст, aria-expanded.
|
|
342
|
+
* @param {HTMLElement} element - Кнопка, управляющая collapse.
|
|
343
|
+
* @param {boolean} isOpen - Текущее состояние (открыто/закрыто).
|
|
344
|
+
* @private
|
|
345
|
+
*/
|
|
202
346
|
_changeStateButton(element, isOpen) {
|
|
203
347
|
element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen);
|
|
204
348
|
element.setAttribute('aria-expanded', isOpen);
|
|
205
349
|
element.innerHTML = Manipulator.get(element, `data-${isOpen ? 'hide' : 'show'}-text`) || element.innerHTML;
|
|
206
350
|
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Определяет, по какой оси происходит анимация (высота или ширина).
|
|
354
|
+
* @returns {string} `'height'` или `'width'`.
|
|
355
|
+
* @private
|
|
356
|
+
*/
|
|
357
|
+
_getDimension() {
|
|
358
|
+
return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT;
|
|
359
|
+
}
|
|
207
360
|
}
|
|
208
361
|
|
|
209
362
|
/**
|
|
210
|
-
* Data API
|
|
363
|
+
* Реализация Data API: автоматическая инициализация по атрибуту `data-vg-toggle="collapse"`.
|
|
364
|
+
* @listens document#click
|
|
211
365
|
*/
|
|
212
366
|
EventHandler.on(document, EVENT_KEY_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
|
|
213
367
|
if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {
|
|
214
|
-
event.preventDefault()
|
|
368
|
+
event.preventDefault();
|
|
215
369
|
}
|
|
216
370
|
|
|
217
371
|
Selectors.getMultipleElementsFromSelector(this).forEach(function (element) {
|
|
218
|
-
VGCollapse.getOrCreateInstance(element, {toggle: false}).toggle();
|
|
372
|
+
VGCollapse.getOrCreateInstance(element, { toggle: false }).toggle();
|
|
219
373
|
});
|
|
220
|
-
})
|
|
374
|
+
});
|
|
221
375
|
|
|
222
376
|
export default VGCollapse;
|