vgapp 0.7.8 → 0.7.9

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.
@@ -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
- * Constants
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 = `${NAME_KEY}.hide`;
57
+ const EVENT_KEY_HIDE = `${NAME_KEY}.hide`;
22
58
  const EVENT_KEY_HIDDEN = `${NAME_KEY}.hidden`;
23
- const EVENT_KEY_SHOW = `${NAME_KEY}.show`;
24
- const EVENT_KEY_SHOWN = `${NAME_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: false,
90
+ once: true,
41
91
  output: true,
42
92
  }
43
93
  }, params));
44
94
 
45
- this._isTransitioning = false
46
- this._triggerArray = []
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
- const _this = this;
84
-
85
- if (_this._isTransitioning || _this._isShown()) return;
173
+ if (this._isTransitioning || this._isShown()) {
174
+ return;
175
+ }
86
176
 
87
177
  let activeChildren = [];
88
178
 
89
- if (_this._params.parent) {
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) return;
185
+ if (activeChildren.length && activeChildren[0]._isTransitioning) {
186
+ return;
187
+ }
96
188
 
97
- const startEvent = EventHandler.trigger(_this._element, EVENT_KEY_SHOW);
98
- if (startEvent.defaultPrevented) return;
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
- _this._element.classList.remove(CLASS_NAME_COLLAPSE)
105
- _this._element.classList.add(CLASS_NAME_COLLAPSING)
198
+ const dimension = this._getDimension();
106
199
 
107
- _this._element.style.height = 0;
200
+ this._element.classList.remove(CLASS_NAME_COLLAPSE);
201
+ this._element.classList.add(CLASS_NAME_COLLAPSING);
108
202
 
109
- _this._addAriaAndCollapsedClass(_this._triggerArray, true);
110
- _this._isTransitioning = true;
203
+ this._element.style[dimension] = '0';
111
204
 
112
- _this._route();
205
+ this._addAriaAndCollapsedClass(this._triggerArray, true);
206
+ this._isTransitioning = true;
113
207
 
114
208
  const complete = () => {
115
- _this._isTransitioning = false;
209
+ this._isTransitioning = false;
116
210
 
117
- _this._element.classList.remove(CLASS_NAME_COLLAPSING);
118
- _this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW);
211
+ this._element.classList.remove(CLASS_NAME_COLLAPSING);
212
+ this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW);
119
213
 
120
- _this._element.style.height = '';
121
- EventHandler.trigger(_this._element, EVENT_KEY_SHOWN);
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
- _this._queueCallback(complete, _this._element, true);
220
+ EventHandler.trigger(this._element, EVENT_KEY_SHOWN);
221
+ };
125
222
 
126
- const scrollSize = `scrollHeight`;
127
- _this._element.style.height = `${_this._element[scrollSize]}px`;
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
- const _this = this;
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
- if (_this._isTransitioning || !_this._isShown()) return;
246
+ const dimension = this._getDimension();
134
247
 
135
- const startEvent = EventHandler.trigger(_this._element, EVENT_KEY_HIDE)
136
- if (startEvent.defaultPrevented) return;
248
+ this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`;
137
249
 
138
- _this._element.style.height = `${this._element.getBoundingClientRect().height}px`;
139
- reflow(_this._element);
250
+ reflow(this._element);
140
251
 
141
- _this._element.classList.add(CLASS_NAME_COLLAPSING);
142
- _this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW);
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 _this._triggerArray) {
255
+ for (const trigger of this._triggerArray) {
145
256
  const element = Selectors.getElementFromSelector(trigger);
146
257
 
147
- if (element && !_this._isShown(element)) {
148
- _this._addAriaAndCollapsedClass([trigger], false);
258
+ if (element && !this._isShown(element)) {
259
+ this._addAriaAndCollapsedClass([trigger], false);
149
260
  }
150
261
  }
151
262
 
152
- _this._isTransitioning = true
263
+ this._isTransitioning = true;
153
264
 
154
265
  const complete = () => {
155
- _this._isTransitioning = false;
156
- _this._element.classList.remove(CLASS_NAME_COLLAPSING);
157
- _this._element.classList.add(CLASS_NAME_COLLAPSE);
158
- EventHandler.trigger(_this._element, EVENT_KEY_HIDDEN);
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
- _this._element.style.height = '';
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.find(CLASS_NAME_DEEPER_CHILDREN, this._params.parent);
199
- return Selectors.find(selector, this._params.parent).filter(element => !children.includes(element));
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 implementation
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;