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.
Files changed (52) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +22 -0
  3. package/app/langs/en/buttons.json +10 -0
  4. package/app/langs/en/messages.json +32 -0
  5. package/app/langs/en/titles.json +6 -0
  6. package/app/langs/ru/buttons.json +10 -0
  7. package/app/langs/ru/messages.json +32 -0
  8. package/app/langs/ru/titles.json +6 -0
  9. package/app/modules/base-module.js +23 -2
  10. package/app/modules/module-fn.js +20 -9
  11. package/app/modules/vgalert/js/vgalert.js +362 -214
  12. package/app/modules/vgalert/readme.md +242 -0
  13. package/app/modules/vgcollapse/js/vgcollapse.js +216 -62
  14. package/app/modules/vgcollapse/readme.md +56 -0
  15. package/app/modules/vgcollapse/scss/_variables.scss +5 -0
  16. package/app/modules/vgcollapse/scss/vgcollapse.scss +41 -0
  17. package/app/modules/vgdropdown/js/vgdropdown.js +140 -38
  18. package/app/modules/vgdropdown/readme.md +225 -0
  19. package/app/modules/vgfiles/js/base.js +499 -0
  20. package/app/modules/vgfiles/js/droppable.js +159 -0
  21. package/app/modules/vgfiles/js/loader.js +389 -0
  22. package/app/modules/vgfiles/js/render.js +83 -0
  23. package/app/modules/vgfiles/js/sortable.js +155 -0
  24. package/app/modules/vgfiles/js/vgfiles.js +796 -280
  25. package/app/modules/vgfiles/readme.md +193 -0
  26. package/app/modules/vgfiles/scss/_animations.scss +18 -0
  27. package/app/modules/vgfiles/scss/_mixins.scss +73 -0
  28. package/app/modules/vgfiles/scss/_variables.scss +103 -26
  29. package/app/modules/vgfiles/scss/vgfiles.scss +573 -60
  30. package/app/modules/vgformsender/js/vgformsender.js +5 -1
  31. package/app/modules/vgformsender/readme.md +30 -1
  32. package/app/modules/vglawcookie/js/vglawcookie.js +96 -62
  33. package/app/modules/vglawcookie/readme.md +102 -0
  34. package/app/modules/vgsidebar/js/vgsidebar.js +6 -4
  35. package/app/utils/js/components/ajax.js +176 -104
  36. package/app/utils/js/components/animation.js +124 -39
  37. package/app/utils/js/components/backdrop.js +54 -31
  38. package/app/utils/js/components/lang.js +71 -64
  39. package/app/utils/js/components/params.js +34 -31
  40. package/app/utils/js/components/scrollbar.js +118 -67
  41. package/app/utils/js/components/templater.js +14 -4
  42. package/app/utils/js/dom/cookie.js +107 -64
  43. package/app/utils/js/dom/data.js +68 -20
  44. package/app/utils/js/dom/event.js +272 -239
  45. package/app/utils/js/dom/manipulator.js +135 -62
  46. package/app/utils/js/dom/selectors.js +134 -59
  47. package/app/utils/js/functions.js +183 -349
  48. package/build/vgapp.css +1 -1
  49. package/build/vgapp.css.map +1 -1
  50. package/index.scss +3 -0
  51. package/package.json +1 -1
  52. package/app/utils/js/components/overflow.js +0 -28
@@ -190,6 +190,35 @@ VGFormSender.buttonClick('#contactForm', (form, instance) => {
190
190
  ```
191
191
  ---
192
192
 
193
+ ## 🔄 Ответ сервера
194
+ Ответ сервера обязательно должен быть в формате JSON.
195
+ ```php
196
+ json_encode([
197
+ 'errors' => false, // флаг ошибки,
198
+ 'title' => 'Успех!', // заголовок уведомления
199
+ 'message' => 'Сообщение отправлено' // текст уведомления
200
+ ])
201
+ ```
202
+ или
203
+
204
+ ```php
205
+ json_encode([
206
+ 'errors' => false, // флаг ошибки,
207
+ 'view' => '<...>' // HTML-контент
208
+ ])
209
+ ```
210
+ Если есть несколько ошибок логики работы сервера, передаем так:
211
+
212
+ ```php
213
+ json_encode([
214
+ 'errors' => [ // массив ошибок
215
+ ['Не заполнено поля имя', 'Не заполнено поля email']
216
+ ],
217
+ ])
218
+ ```
219
+
220
+ ---
221
+
193
222
  ## 🎨 CSS-классы
194
223
 
195
224
  | Класс | Назначение |
@@ -218,4 +247,4 @@ MIT — свободно используйте и модифицируйте.
218
247
  ---
219
248
 
220
249
  > 🚀 Автор: VEGAS STUDIO (vegas-dev.com)
221
- > 📍 Поддерживается в проектах на VEGAS / SberTech
250
+ > 📍 Поддерживается в проектах VEGAS
@@ -1,35 +1,35 @@
1
1
  import BaseModule from "../../base-module";
2
- import {isDisabled, mergeDeepObject} from "../../../utils/js/functions";
2
+ import { isDisabled, mergeDeepObject } from "../../../utils/js/functions";
3
3
  import EventHandler from "../../../utils/js/dom/event";
4
4
  import Selectors from "../../../utils/js/dom/selectors";
5
5
  import Cookies from "../../../utils/js/dom/cookie";
6
- import {dismissTrigger} from "../../module-fn";
6
+ import { dismissTrigger } from "../../module-fn";
7
7
 
8
8
  /**
9
9
  * Constants
10
10
  */
11
- const NAME = 'lawcookie';
11
+ const NAME = 'lawcookie';
12
12
  const NAME_KEY = 'vg.lawcookie';
13
13
 
14
14
  const CLASS_NAME_SHOW = 'show';
15
15
 
16
- const EVENT_KEY_HIDE = `${NAME_KEY}.hide`;
16
+ const EVENT_KEY_HIDE = `${NAME_KEY}.hide`;
17
17
  const EVENT_KEY_HIDDEN = `${NAME_KEY}.hidden`;
18
- const EVENT_KEY_SHOW = `${NAME_KEY}.show`;
19
- const EVENT_KEY_SHOWN = `${NAME_KEY}.shown`;
18
+ const EVENT_KEY_SHOW = `${NAME_KEY}.show`;
19
+ const EVENT_KEY_SHOWN = `${NAME_KEY}.shown`;
20
20
 
21
- const SELECTOR_DATA_TOGGLE = '[data-vg-toggle="lawcookie"]';
21
+ const SELECTOR_DATA_TOGGLE = '[data-vg-toggle="lawcookie"]';
22
22
  const SELECTOR_DATA_TOGGLE_CLEAR = '[data-vg-toggle="lawcookie-clear"]';
23
- const EVENT_KEY_CLICK_DATA_API = `click.${NAME_KEY}.data.api`;
23
+ const EVENT_KEY_CLICK_DATA_API = `click.${NAME_KEY}.data.api`;
24
24
 
25
25
  class VGLawCookie extends BaseModule {
26
- static sParams = {};
26
+ // Убрано статическое sParams избыточно и небезопасно
27
27
 
28
28
  constructor(element, params = {}) {
29
29
  super(element, params);
30
30
 
31
31
  this._params = this._getParams(element, mergeDeepObject({
32
- storage: 'local', // cookie or local
32
+ storage: 'local', // 'cookie' или 'local'
33
33
  delay: 500,
34
34
  cookie: {
35
35
  name: 'lawCookie',
@@ -52,9 +52,11 @@ class VGLawCookie extends BaseModule {
52
52
  }
53
53
  }, params));
54
54
 
55
- VGLawCookie.sParams = this._params;
55
+ // Инициализация хранилища сразу в конструкторе
56
+ this._storage = this._createStorage();
56
57
 
57
- this._params.animation.delay = !this._params.animation.enable ? 0 : this._params.animation.delay;
58
+ // Настройка анимации
59
+ this._params.animation.delay = this._params.animation.enable ? this._params.animation.delay : 0;
58
60
  this._animation(this._element, VGLawCookie.NAME_KEY, this._params.animation);
59
61
  }
60
62
 
@@ -66,82 +68,112 @@ class VGLawCookie extends BaseModule {
66
68
  return NAME_KEY;
67
69
  }
68
70
 
69
- toggle() {
70
- return !this._isShown() ? this.show() : this.hide();
71
+ /**
72
+ * Проверяет, было ли дано согласие
73
+ * @returns {boolean}
74
+ * @private
75
+ */
76
+ _isConsented() {
77
+ return this._storage.get() === this._params.cookie.value;
71
78
  }
72
79
 
73
- _isShown() {
74
- return this.storage().get();
80
+ /**
81
+ * Переключает отображение: показать, если ещё нет согласия
82
+ */
83
+ toggle() {
84
+ return this._isConsented() ? this.hide() : this.show();
75
85
  }
76
86
 
87
+ /**
88
+ * Показать баннер
89
+ */
77
90
  show() {
78
- if (isDisabled(this._element)) return;
91
+ if (isDisabled(this._element) || this._isConsented()) return;
79
92
 
80
- const showEvent = EventHandler.trigger(this._element, EVENT_KEY_SHOW, {})
93
+ const showEvent = EventHandler.trigger(this._element, EVENT_KEY_SHOW);
81
94
  if (showEvent.defaultPrevented) return;
82
95
 
83
96
  this._element.classList.add(CLASS_NAME_SHOW);
84
97
 
85
- const completeCallBack = () => {
86
- EventHandler.trigger(this._element, EVENT_KEY_SHOWN, {});
87
- }
88
- this._queueCallback(completeCallBack, this._element, true, this._params.delay)
98
+ const completeCallback = () => {
99
+ EventHandler.trigger(this._element, EVENT_KEY_SHOWN);
100
+ };
101
+
102
+ this._queueCallback(completeCallback, this._element, true, this._params.delay);
89
103
  }
90
104
 
105
+ /**
106
+ * Скрыть баннер и сохранить согласие
107
+ */
91
108
  hide() {
92
109
  const hideEvent = EventHandler.trigger(this._element, EVENT_KEY_HIDE);
93
110
  if (hideEvent.defaultPrevented) return;
94
111
 
95
- setTimeout(() => {
96
- this._element.classList.remove(CLASS_NAME_SHOW);
112
+ this._element.classList.remove(CLASS_NAME_SHOW);
97
113
 
98
- const completeCallback = () => EventHandler.trigger(this._element, EVENT_KEY_HIDDEN);
99
- this._queueCallback(completeCallback, this._element, true);
100
- }, this._params.animation.delay);
101
- }
102
-
103
- storage() {
104
- this._storage = {
105
- isCookie: this._params.storage === 'cookie',
106
- storage: this._params.storage === 'cookie' ? Cookies : localStorage,
107
- name: this._params.cookie.name,
108
- value: this._params.cookie.value,
109
- attributes: this._params.cookie.attributes,
110
- }
114
+ const completeCallback = () => {
115
+ EventHandler.trigger(this._element, EVENT_KEY_HIDDEN);
116
+ };
111
117
 
112
- return this;
113
- }
114
-
115
- get() {
116
- if (this._storage.isCookie) {
117
- return this._storage.storage.get(this._storage.name);
118
- } else {
119
- return this._storage.storage.getItem(this._storage.name);
120
- }
118
+ this._queueCallback(completeCallback, this._element, true, this._params.animation.delay);
121
119
  }
122
120
 
123
- set() {
124
- if (this._storage.isCookie) {
125
- this._storage.storage.set(this._storage.name, this._storage.value, this._storage.attributes);
121
+ /**
122
+ * Создаёт объект хранилища с унифицированным API
123
+ * @returns {{get: () => string|null, set: () => void}}
124
+ * @private
125
+ */
126
+ _createStorage() {
127
+ const { name, value, attributes } = this._params.cookie;
128
+
129
+ if (this._params.storage === 'cookie') {
130
+ return {
131
+ get: () => Cookies.get(name),
132
+ set: () => Cookies.set(name, value, attributes)
133
+ };
126
134
  } else {
127
- this._storage.storage.setItem(this._storage.name, this._storage.value);
135
+ return {
136
+ get: () => localStorage.getItem(name),
137
+ set: () => localStorage.setItem(name, value)
138
+ };
128
139
  }
129
140
  }
130
141
 
131
- dispose() {
132
- super.dispose();
142
+ /**
143
+ * Сохраняет согласие
144
+ */
145
+ accept() {
146
+ this._storage.set();
133
147
  }
134
148
 
149
+ /**
150
+ * Полный сброс согласия
151
+ */
135
152
  static reset() {
136
- Cookies.remove(VGLawCookie.sParams.cookie.name);
153
+ Cookies.remove(VGLawCookie.getDefaultParams().cookie.name);
137
154
  localStorage.clear();
138
155
  location.reload();
139
156
  }
140
157
 
141
158
  /**
142
- * Инициализация
143
- * @param element
144
- * @param params
159
+ * Возвращает дефолтные параметры (для доступа без инстанса)
160
+ */
161
+ static getDefaultParams() {
162
+ return mergeDeepObject({
163
+ cookie: { name: 'lawCookie' }
164
+ }, {});
165
+ }
166
+
167
+ dispose() {
168
+ Cookies.remove(VGLawCookie.getDefaultParams().cookie.name);
169
+ localStorage.clear();
170
+ super.dispose();
171
+ }
172
+
173
+ /**
174
+ * Инициализация модуля
175
+ * @param {Element} element
176
+ * @param {Object} params
145
177
  */
146
178
  static init(element, params = {}) {
147
179
  const instance = VGLawCookie.getOrCreateInstance(element, params);
@@ -149,11 +181,13 @@ class VGLawCookie extends BaseModule {
149
181
  }
150
182
  }
151
183
 
184
+ // Подключение поведения закрытия через триггер
152
185
  dismissTrigger(VGLawCookie);
153
186
 
187
+ // Обработка кнопки принятия согласия
154
188
  EventHandler.on(document, EVENT_KEY_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
155
189
  if (['A', 'AREA'].includes(this.tagName)) {
156
- event.preventDefault()
190
+ event.preventDefault();
157
191
  }
158
192
 
159
193
  if (isDisabled(this)) return;
@@ -162,13 +196,14 @@ EventHandler.on(document, EVENT_KEY_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, functi
162
196
  if (!element) return;
163
197
 
164
198
  const instance = VGLawCookie.getOrCreateInstance(element);
165
- instance.storage().set();
166
- instance.hide();
199
+ instance.accept(); // Сохраняем согласие
200
+ instance.hide(); // Скрываем баннер
167
201
  });
168
202
 
203
+ // Обработка кнопки сброса
169
204
  EventHandler.on(document, EVENT_KEY_CLICK_DATA_API, SELECTOR_DATA_TOGGLE_CLEAR, function (event) {
170
205
  if (['A', 'AREA'].includes(this.tagName)) {
171
- event.preventDefault()
206
+ event.preventDefault();
172
207
  }
173
208
 
174
209
  if (isDisabled(this)) return;
@@ -178,8 +213,7 @@ EventHandler.on(document, EVENT_KEY_CLICK_DATA_API, SELECTOR_DATA_TOGGLE_CLEAR,
178
213
 
179
214
  const instance = VGLawCookie.getOrCreateInstance(element);
180
215
  instance.dispose();
181
-
182
- location.reload();
216
+ VGLawCookie.reset(); // Полный сброс
183
217
  });
184
218
 
185
219
  export default VGLawCookie;
@@ -0,0 +1,102 @@
1
+ # Модуль `vglawcookie` — Управление согласием на использование cookies
2
+
3
+ Модуль `vglawcookie` предназначен для реализации функциональности **баннера согласия на использование cookies** в соответствии с требованиями законодательства (например, GDPR, российское законодательство о персональных данных и т.д.).
4
+
5
+ Он позволяет отображать всплывающий баннер, который пользователь может подтвердить или отклонить, а также обеспечивает гибкую настройку поведения и хранения согласия.
6
+
7
+ ---
8
+
9
+ ## 🔧 Возможности модуля
10
+
11
+ - Автоматическое отображение баннера при отсутствии согласия.
12
+ - Поддержка двух типов хранения согласия:
13
+ - Через **cookies**
14
+ - Через **localStorage**
15
+ - Анимированное появление и скрытие (на основе [Animate.css](https://animate.style/)).
16
+ - Поддержка задержки перед показом.
17
+ - Гибкая настройка параметров через атрибуты `data-*` или JavaScript.
18
+ - Обработка событий показа/скрытия.
19
+ - Возможность сброса согласия и очистки хранилища.
20
+ - Совместимость с динамически создаваемыми элементами (через делегирование событий).
21
+
22
+ ---
23
+
24
+ ## 📦 Установка
25
+ Инициализация происходит автоматически при наличии разметки или вручную.
26
+
27
+ ## 🏗️ HTML-разметка
28
+
29
+ Пример базового баннера:
30
+ ```html
31
+ <div class="vg-lawcookie left bottom fullwidth" id="vg-lawcookie">
32
+ <div class="vg-lawcookie--content">
33
+ <div class="d-flex align-items-center justify-content-center">
34
+ <p class="mb-0"><b>Мы используем файлы cookie</b>. Продолжая использовать сайт, вы соглашаетесь с <a href="https://museum-arms.ru/terms-of-use">политикой сбора и обработки данных</a>.</p>
35
+ <p class="mb-0 ms-3">
36
+ <a href="#" data-vg-toggle="lawcookie" class="btn btn-primary btn-sm">Хорошо</a>
37
+ </p>
38
+ </div>
39
+ </div>
40
+ </div>
41
+
42
+ ```
43
+
44
+ > ✅ Баннер автоматически будет скрыт после подтверждения и не появится снова, пока не будет сброшен.
45
+
46
+ ---
47
+
48
+ ## ⚙️ Параметры (настройки)
49
+
50
+ Параметры можно задавать:
51
+ - Через `data-*` атрибуты на элементе
52
+ - При инициализации через JavaScript
53
+
54
+ | Параметр | По умолчанию | Описание |
55
+ |-------------------------|----------------------|---------|
56
+ | `storage` | `'local'` | Способ хранения: `'cookie'` или `'local'` (localStorage) |
57
+ | `delay` | `500` | Задержка перед показом баннера (в мс) |
58
+ | `cookie.name` | `'lawCookie'` | Имя cookie или ключа в localStorage |
59
+ | `cookie.value` | `'yes'` | Значение, сохраняемое при согласии |
60
+ | `cookie.attributes` | `{}` | Атрибуты cookie (например, `expires`, `path`, `domain`) |
61
+ | `animation.enable` | `true` | Включить анимацию |
62
+ | `animation.in` | `'animate__fadeInUp'`| Класс анимации входа (из Animate.css) |
63
+ | `animation.out` | `'animate__fadeOutDown'`| Класс анимации исчезновения |
64
+ | `animation.delay` | `800` | Задержка анимации исчезновения |
65
+ | `ajax.route` | `''` | URL для загрузки контента по AJAX |
66
+ | `ajax.target` | `''` | CSS-селектор элемента, куда загружать контент |
67
+ | `ajax.method` | `'get'` | HTTP-метод (`get`, `post`) |
68
+ | `ajax.loader` | `false` | Показывать ли лоадер при AJAX-запросе |
69
+ | `ajax.once` | `false` | Загружать контент только один раз |
70
+ | `ajax.output` | `true` | Вставлять ли ответ в `target` |
71
+
72
+ ---
73
+
74
+ ## 🎯 События
75
+
76
+ Модуль генерирует пользовательские события на элементе баннера:
77
+
78
+ | Событие | Описание |
79
+ |-----------------------|--------|
80
+ | `vg.lawcookie.show` | Перед показом баннера |
81
+ | `vg.lawcookie.shown` | После завершения показа |
82
+ | `vg.lawcookie.hide` | Перед скрытием баннера |
83
+ | `vg.lawcookie.hidden` | После завершения скрытия |
84
+
85
+ ## 🔐 Безопасность и очистка
86
+
87
+ - После вызова `dispose()` или `reset()` удаляется:
88
+ - Cookie с именем из `params.cookie.name`
89
+ - Полностью очищается `localStorage`
90
+ - Это полезно для отладки или реализации кнопки "Отозвать согласие".
91
+
92
+ ---
93
+
94
+ ## 📝 Лицензия
95
+
96
+ MIT. Свободно использовать и модифицировать.
97
+
98
+ ---
99
+
100
+ 📌 *Разработано в рамках фронтенд-системы VG Modules.*
101
+ > 🚀 Автор: VEGAS STUDIO (vegas-dev.com)
102
+ > 📍 Поддерживается в проектах VEGAS
@@ -4,7 +4,8 @@ import EventHandler from "../../../utils/js/dom/event";
4
4
  import {dismissTrigger} from "../../module-fn";
5
5
  import Selectors from "../../../utils/js/dom/selectors";
6
6
  import Backdrop from "../../../utils/js/components/backdrop";
7
- import Overflow from "../../../utils/js/components/overflow";
7
+ import ScrollBarHelper from "../../../utils/js/components/scrollbar";
8
+
8
9
 
9
10
  /**
10
11
  * Constants
@@ -56,6 +57,7 @@ class VGSidebar extends BaseModule {
56
57
  this._addEventListeners();
57
58
  this._dismissElement();
58
59
 
60
+ this._scrollBar = new ScrollBarHelper();
59
61
  this._params.animation.delay = !this._params.animation.enable ? 0 : this._params.animation.delay;
60
62
  this._animation(this._element, VGSidebar.NAME_KEY, this._params.animation);
61
63
  }
@@ -90,7 +92,7 @@ class VGSidebar extends BaseModule {
90
92
  }
91
93
 
92
94
  if (_this._params.overflow) {
93
- Overflow.append();
95
+ this._scrollBar.hide();
94
96
  }
95
97
 
96
98
  if (this._params.hash) {
@@ -131,13 +133,13 @@ class VGSidebar extends BaseModule {
131
133
  if (this._params.backdrop) {
132
134
  Backdrop.hide(() => {
133
135
  if (this._params.overflow) {
134
- Overflow.destroy();
136
+ this._scrollBar.reset();
135
137
  }
136
138
  });
137
139
  }
138
140
 
139
141
  if (this._params.overflow) {
140
- Overflow.destroy();
142
+ this._scrollBar.reset();
141
143
  }
142
144
 
143
145
  if (this._params.hash) {