vgapp 0.7.7 → 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.
- package/CHANGELOG.md +20 -4
- package/LICENSE +22 -0
- package/app/modules/base-module.js +62 -17
- package/app/modules/module-fn.js +10 -100
- package/app/modules/vgalert/js/vgalert.js +356 -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 +104 -118
- package/app/modules/vgdropdown/scss/vgdropdown.scss +1 -2
- package/app/modules/vgformsender/js/hideshowpass.js +7 -4
- package/app/modules/vgformsender/js/vgformsender.js +343 -160
- package/app/modules/vgformsender/readme.md +250 -0
- package/app/modules/vgformsender/scss/vgformsender.scss +11 -3
- package/app/modules/vgnav/js/vgnav.js +98 -26
- package/app/modules/vgnav/scss/_placement.scss +8 -93
- package/app/modules/vgnav/scss/vgnav.scss +0 -1
- package/app/utils/js/components/ajax.js +237 -0
- package/app/utils/js/components/lang.js +108 -0
- package/app/utils/js/components/params.js +5 -0
- package/app/utils/js/components/placement.js +111 -108
- package/app/utils/js/components/templater.js +365 -33
- package/app/utils/js/functions.js +275 -143
- package/app/utils/scss/default.scss +1 -0
- package/app/utils/scss/placement.scss +72 -0
- package/app/utils/scss/variables.scss +10 -5
- 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/alert.js +0 -8
|
@@ -1,56 +1,116 @@
|
|
|
1
1
|
import BaseModule from "../../base-module";
|
|
2
2
|
import VGModal from "../../vgmodal";
|
|
3
3
|
|
|
4
|
-
import {isElement, isVisible, makeRandomString, mergeDeepObject} from "../../../utils/js/functions";
|
|
5
|
-
import {getSVG} from "../../module-fn";
|
|
6
|
-
import {Classes, Manipulator} from "../../../utils/js/dom/manipulator";
|
|
4
|
+
import { isElement, isVisible, makeRandomString, mergeDeepObject } from "../../../utils/js/functions";
|
|
5
|
+
import { getSVG } from "../../module-fn";
|
|
6
|
+
import { Classes, Manipulator } from "../../../utils/js/dom/manipulator";
|
|
7
7
|
import Selectors from "../../../utils/js/dom/selectors";
|
|
8
8
|
import EventHandler from "../../../utils/js/dom/event";
|
|
9
|
+
import {lang_buttons, lang_messages} from "../../../utils/js/components/lang";
|
|
10
|
+
import Html from "../../../utils/js/components/templater";
|
|
9
11
|
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {Object} AjaxParams
|
|
14
|
+
* @property {string} route - URL-адрес для AJAX-запроса.
|
|
15
|
+
* @property {string} target - Селектор элемента, куда будет вставлен ответ.
|
|
16
|
+
* @property {string} method - HTTP-метод ('get', 'post' и т.д.).
|
|
17
|
+
* @property {boolean} loader - Показывать ли индикатор загрузки.
|
|
18
|
+
* @property {boolean} once - Выполнить запрос только один раз.
|
|
19
|
+
* @property {boolean} output - Выводить ли результат в целевой элемент.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {Object} ModalParams
|
|
24
|
+
* @property {boolean} centered - Центрировать ли модальное окно по вертикали.
|
|
25
|
+
* @property {boolean|string} backdrop - Фоновая подложка ('static', true, false).
|
|
26
|
+
* @property {boolean} overflow - Разрешить прокрутку фона при открытом окне.
|
|
27
|
+
* @property {boolean} keyboard - Закрывать по нажатию Escape.
|
|
28
|
+
* @property {boolean} dismiss - Закрывать при клике по подложке.
|
|
29
|
+
* @property {Object} animation - Параметры анимации.
|
|
30
|
+
* @property {boolean} animation.enable - Включить анимацию.
|
|
31
|
+
* @property {string} animation.in - Класс анимации входа.
|
|
32
|
+
* @property {string} animation.out - Класс анимации выхода.
|
|
33
|
+
* @property {number} animation.delay - Задержка перед показом (мс).
|
|
34
|
+
* @property {number} animation.duration - Длительность анимации (мс).
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @typedef {Object} ButtonConfig
|
|
39
|
+
* @property {string} [element] - Готовый HTML-элемент кнопки.
|
|
40
|
+
* @property {'button'|'a'} [tag='button'] - Тип элемента.
|
|
41
|
+
* @property {string} [type='button'] - Атрибут type (для <button>).
|
|
42
|
+
* @property {Object.<string, string>} [attr] - Дополнительные атрибуты.
|
|
43
|
+
* @property {string} toggle - Атрибут данных для управления.
|
|
44
|
+
* @property {string[]} class - CSS-классы кнопки.
|
|
45
|
+
* @property {string} text - Текст кнопки.
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @typedef {Object} MessageConfig
|
|
50
|
+
* @property {string} title - Заголовок сообщения.
|
|
51
|
+
* @property {string} description - Описание/текст сообщения.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @typedef {Object} AlertParams
|
|
56
|
+
* @property {AjaxParams} ajax - Параметры AJAX-запроса.
|
|
57
|
+
* @property {ModalParams} modal - Параметры модального окна.
|
|
58
|
+
* @property {'confirm'|'info'} mode - Режим алерта: подтверждение или информационное.
|
|
59
|
+
* @property {'danger'|'warning'|'success'|'info'} theme - Тема оформления.
|
|
60
|
+
* @property {{agree: ButtonConfig, cancel: ButtonConfig}} buttons - Конфигурация кнопок.
|
|
61
|
+
* @property {MessageConfig} message - Сообщение и заголовок.
|
|
62
|
+
* @property {string} [icon] - SVG-иконка, соответствующая теме.
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Константы
|
|
67
|
+
*/
|
|
10
68
|
const CLASS_NAME_ALERT = "vg-alert";
|
|
69
|
+
const DATA_AGREE = "data-vg-alert-agree";
|
|
70
|
+
const DATA_CANCEL = "data-vg-alert-cancel";
|
|
11
71
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
element: '',
|
|
18
|
-
tag: 'button',
|
|
19
|
-
attr: {
|
|
20
|
-
type: 'button',
|
|
21
|
-
},
|
|
22
|
-
toggle: 'data-vg-alert-agree',
|
|
23
|
-
class: ['btn'],
|
|
24
|
-
text: 'Да, согласен'
|
|
25
|
-
},
|
|
26
|
-
cancel: {
|
|
27
|
-
element: '',
|
|
28
|
-
tag: 'button',
|
|
29
|
-
attr: {
|
|
30
|
-
type: 'button',
|
|
31
|
-
},
|
|
32
|
-
toggle: 'data-vg-alert-cancel',
|
|
33
|
-
class: ['btn'],
|
|
34
|
-
text: 'Отмена'
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
message: {
|
|
38
|
-
title: 'Заголовок по умолчанию',
|
|
39
|
-
description: 'Описание текущего действия',
|
|
40
|
-
},
|
|
41
|
-
icons: {
|
|
42
|
-
danger: getSVG('danger'),
|
|
43
|
-
warning: getSVG('warning'),
|
|
44
|
-
success: getSVG('success'),
|
|
45
|
-
info: getSVG('info'),
|
|
46
|
-
}
|
|
47
|
-
}
|
|
72
|
+
const NAME = "alert";
|
|
73
|
+
const NAME_KEY = "vg.alert";
|
|
74
|
+
|
|
75
|
+
// Глобальная блокировка: предотвращаем открытие нескольких алертов
|
|
76
|
+
let isAlertOpen = false;
|
|
48
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Класс VGAlert — модальное окно подтверждения или информационное уведомление.
|
|
80
|
+
*
|
|
81
|
+
* @class
|
|
82
|
+
* @example
|
|
83
|
+
* VGAlert.call({
|
|
84
|
+
* mode: 'confirm',
|
|
85
|
+
* theme: 'danger',
|
|
86
|
+
* message: {
|
|
87
|
+
* title: 'Вы уверены?',
|
|
88
|
+
* description: 'Это действие нельзя отменить.'
|
|
89
|
+
* },
|
|
90
|
+
* buttons: {
|
|
91
|
+
* agree: { text: 'Удалить', class: ['btn-danger'] },
|
|
92
|
+
* cancel: { text: 'Отмена' }
|
|
93
|
+
* }
|
|
94
|
+
* }).then(() => {
|
|
95
|
+
* console.log('Подтверждено');
|
|
96
|
+
* }).catch(() => {
|
|
97
|
+
* console.log('Отменено');
|
|
98
|
+
* });
|
|
99
|
+
*/
|
|
100
|
+
class VGAlert {
|
|
101
|
+
/**
|
|
102
|
+
* Создаёт экземпляр VGAlert.
|
|
103
|
+
*
|
|
104
|
+
* @param {AlertParams} params - Пользовательские параметры.
|
|
105
|
+
* @param {'ru'|'en'} [lang='ru'] - Язык интерфейса.
|
|
106
|
+
*/
|
|
107
|
+
constructor(params = {}, lang = 'ru') {
|
|
108
|
+
this.lang = lang;
|
|
49
109
|
this._defaultParams = {
|
|
50
110
|
ajax: {
|
|
51
|
-
route:
|
|
52
|
-
target:
|
|
53
|
-
method:
|
|
111
|
+
route: "",
|
|
112
|
+
target: "",
|
|
113
|
+
method: "get",
|
|
54
114
|
loader: false,
|
|
55
115
|
once: false,
|
|
56
116
|
output: true,
|
|
@@ -63,32 +123,77 @@ class VGAlert {
|
|
|
63
123
|
dismiss: true,
|
|
64
124
|
animation: {
|
|
65
125
|
enable: false,
|
|
66
|
-
in:
|
|
67
|
-
out:
|
|
126
|
+
in: "animate__rollIn",
|
|
127
|
+
out: "animate__rollOut",
|
|
68
128
|
delay: 300,
|
|
69
|
-
duration: 700
|
|
129
|
+
duration: 700,
|
|
70
130
|
},
|
|
71
131
|
},
|
|
72
|
-
mode:
|
|
73
|
-
theme:
|
|
132
|
+
mode: "confirm",
|
|
133
|
+
theme: "danger",
|
|
74
134
|
buttons: {},
|
|
75
135
|
message: {},
|
|
76
136
|
};
|
|
77
|
-
|
|
137
|
+
this._elementsDefault = {
|
|
138
|
+
buttons: {
|
|
139
|
+
agree: {
|
|
140
|
+
element: "",
|
|
141
|
+
tag: "button",
|
|
142
|
+
type: "button",
|
|
143
|
+
attr: {},
|
|
144
|
+
toggle: DATA_AGREE,
|
|
145
|
+
class: ["btn"],
|
|
146
|
+
text: lang_buttons(this.lang, NAME).agree,
|
|
147
|
+
},
|
|
148
|
+
cancel: {
|
|
149
|
+
element: "",
|
|
150
|
+
tag: "button",
|
|
151
|
+
type: "button",
|
|
152
|
+
attr: {},
|
|
153
|
+
toggle: DATA_CANCEL,
|
|
154
|
+
class: ["btn"],
|
|
155
|
+
text: lang_buttons(this.lang, NAME).cancel,
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
message: {
|
|
159
|
+
title: lang_messages(this.lang, NAME).title,
|
|
160
|
+
description: lang_messages(this.lang, NAME).description
|
|
161
|
+
},
|
|
162
|
+
icons: {
|
|
163
|
+
danger: getSVG("danger"),
|
|
164
|
+
warning: getSVG("warning"),
|
|
165
|
+
success: getSVG("success"),
|
|
166
|
+
info: getSVG("info"),
|
|
167
|
+
},
|
|
168
|
+
};
|
|
78
169
|
this._params = this._setParams(params);
|
|
79
170
|
}
|
|
80
171
|
|
|
81
|
-
|
|
82
|
-
|
|
172
|
+
/**
|
|
173
|
+
* Открывает алерт и возвращает Promise.
|
|
174
|
+
*
|
|
175
|
+
* @static
|
|
176
|
+
* @param {AlertParams} options - Параметры алерта.
|
|
177
|
+
* @param {'ru'|'en'} [lang='ru'] - Язык.
|
|
178
|
+
* @returns {Promise<{accepted: boolean, timestamp: Date}>} Результат взаимодействия.
|
|
179
|
+
* @throws {Error} Если алерт уже открыт.
|
|
180
|
+
*/
|
|
181
|
+
static call(options = {}, lang = 'ru') {
|
|
182
|
+
const context = new VGAlert(options, lang);
|
|
183
|
+
|
|
184
|
+
if (isAlertOpen) return Promise.reject({ accepted: false, reason: lang_messages(context.lang, NAME_KEY).reason });
|
|
185
|
+
isAlertOpen = true;
|
|
186
|
+
|
|
83
187
|
let modal = context._buildModal();
|
|
84
188
|
modal.show();
|
|
85
189
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
190
|
+
const container = modal._element;
|
|
191
|
+
const agreeBtn = Selectors.find(`[${DATA_AGREE}]`, container);
|
|
192
|
+
const cancelBtn = Selectors.find(`[${DATA_CANCEL}]`, container);
|
|
89
193
|
|
|
90
194
|
return new Promise((resolve, reject) => {
|
|
91
|
-
const handleAgree = () => {
|
|
195
|
+
const handleAgree = (e) => {
|
|
196
|
+
e.preventDefault();
|
|
92
197
|
cleanup();
|
|
93
198
|
resolve({
|
|
94
199
|
accepted: true,
|
|
@@ -97,241 +202,278 @@ class VGAlert {
|
|
|
97
202
|
modal.hide();
|
|
98
203
|
};
|
|
99
204
|
|
|
100
|
-
const handleCancel = () => {
|
|
205
|
+
const handleCancel = (e) => {
|
|
206
|
+
e.preventDefault();
|
|
101
207
|
modal.hide();
|
|
102
208
|
};
|
|
103
209
|
|
|
104
|
-
const
|
|
105
|
-
if (agreeBtn)
|
|
106
|
-
|
|
210
|
+
const handleKeydown = (e) => {
|
|
211
|
+
if (e.key === "Enter" && agreeBtn) {
|
|
212
|
+
e.preventDefault();
|
|
213
|
+
handleAgree(e);
|
|
214
|
+
}
|
|
215
|
+
if (e.key === "Escape") {
|
|
216
|
+
e.preventDefault();
|
|
217
|
+
handleCancel(e);
|
|
218
|
+
}
|
|
107
219
|
};
|
|
108
220
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
221
|
+
const cleanup = () => {
|
|
222
|
+
isAlertOpen = false;
|
|
223
|
+
document.removeEventListener("keydown", handleKeydown);
|
|
224
|
+
if (agreeBtn) agreeBtn.removeEventListener("click", handleAgree);
|
|
225
|
+
if (cancelBtn) cancelBtn.removeEventListener("click", handleCancel);
|
|
226
|
+
};
|
|
115
227
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
});
|
|
120
|
-
})
|
|
228
|
+
if (context._params.mode === "confirm") {
|
|
229
|
+
if (agreeBtn) agreeBtn.addEventListener("click", handleAgree);
|
|
230
|
+
if (cancelBtn) cancelBtn.addEventListener("click", handleCancel);
|
|
121
231
|
}
|
|
122
232
|
|
|
123
|
-
if (context._params.mode ===
|
|
124
|
-
if (cancelBtn) cancelBtn.addEventListener(
|
|
233
|
+
if (context._params.mode === "info") {
|
|
234
|
+
if (cancelBtn) cancelBtn.addEventListener("click", handleCancel);
|
|
235
|
+
}
|
|
125
236
|
|
|
126
|
-
|
|
127
|
-
|
|
237
|
+
document.addEventListener("keydown", handleKeydown);
|
|
238
|
+
container.addEventListener("vg.modal.hide", () => {
|
|
239
|
+
cleanup();
|
|
240
|
+
reject({
|
|
241
|
+
accepted: false,
|
|
242
|
+
timestamp: new Date(),
|
|
243
|
+
});
|
|
244
|
+
});
|
|
128
245
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
timestamp: new Date(),
|
|
132
|
-
});
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
})
|
|
246
|
+
container.focus();
|
|
247
|
+
});
|
|
136
248
|
}
|
|
137
249
|
|
|
250
|
+
/**
|
|
251
|
+
* Инициирует алерт подтверждения на основе DOM-элемента.
|
|
252
|
+
*
|
|
253
|
+
* @static
|
|
254
|
+
* @param {HTMLElement} elem - Элемент, вызвавший алерт.
|
|
255
|
+
* @param {AlertParams} options - Параметры алерта.
|
|
256
|
+
* @returns {void}
|
|
257
|
+
*/
|
|
138
258
|
static confirm(elem, options = {}) {
|
|
139
|
-
|
|
140
|
-
if (context._params.mode !==
|
|
259
|
+
const context = new VGAlert(options);
|
|
260
|
+
if (context._params.mode !== "confirm") return;
|
|
141
261
|
|
|
142
262
|
const instance = VGAlertConfirm.getOrCreateInstance(elem, context._params);
|
|
143
263
|
instance.run(VGAlert);
|
|
144
264
|
}
|
|
145
265
|
|
|
266
|
+
/**
|
|
267
|
+
* Слияние пользовательских параметров с дефолтными.
|
|
268
|
+
*
|
|
269
|
+
* @private
|
|
270
|
+
* @param {AlertParams} params - Пользовательские параметры.
|
|
271
|
+
* @returns {AlertParams} Полный объект параметров.
|
|
272
|
+
*/
|
|
146
273
|
_setParams(params) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
274
|
+
const merged = mergeDeepObject(this._defaultParams, params);
|
|
275
|
+
merged.buttons = mergeDeepObject(this._elementsDefault.buttons, merged.buttons);
|
|
276
|
+
merged.message = mergeDeepObject(this._elementsDefault.message, merged.message);
|
|
277
|
+
merged.icon = this._elementsDefault.icons[merged.theme];
|
|
151
278
|
|
|
152
|
-
return
|
|
279
|
+
return merged;
|
|
153
280
|
}
|
|
154
281
|
|
|
282
|
+
/**
|
|
283
|
+
* Создаёт и возвращает экземпляр модального окна с контентом алерта.
|
|
284
|
+
*
|
|
285
|
+
* @private
|
|
286
|
+
* @returns {VGModal} Экземпляр модального окна.
|
|
287
|
+
*/
|
|
155
288
|
_buildModal() {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
289
|
+
const id = `${CLASS_NAME_ALERT}-${crypto.randomUUID ? crypto.randomUUID().slice(0, 8) : makeRandomString()}`;
|
|
290
|
+
const $modal = Selectors.find(`.${CLASS_NAME_ALERT}-modal`);
|
|
159
291
|
if ($modal) $modal.remove();
|
|
160
292
|
|
|
161
|
-
|
|
162
|
-
let element = self._element;
|
|
163
|
-
element.classList.add(CLASS_NAME_ALERT + '-modal');
|
|
164
|
-
|
|
165
|
-
let $body = Selectors.find('.vg-modal-body', element);
|
|
166
|
-
if ($body) {
|
|
167
|
-
let wrapper = document.createElement('div');
|
|
168
|
-
Classes.add(wrapper, CLASS_NAME_ALERT + '-wrapper');
|
|
169
|
-
Classes.add(wrapper, CLASS_NAME_ALERT + '-' + this._params.theme);
|
|
170
|
-
|
|
171
|
-
let content = document.createElement('div');
|
|
172
|
-
Classes.add(content, CLASS_NAME_ALERT + '-content');
|
|
173
|
-
|
|
174
|
-
let icon = document.createElement('div');
|
|
175
|
-
Classes.add(icon, CLASS_NAME_ALERT + '-content--icon');
|
|
176
|
-
this._create(icon, 'icons', this._params.theme);
|
|
177
|
-
|
|
178
|
-
let message = document.createElement('div');
|
|
179
|
-
Classes.add(message, CLASS_NAME_ALERT + '-content--message');
|
|
180
|
-
|
|
181
|
-
let title = document.createElement('div');
|
|
182
|
-
Classes.add(title, CLASS_NAME_ALERT + '-content--title');
|
|
183
|
-
this._create(title, 'messages', 'title');
|
|
293
|
+
const html = Html('dom');
|
|
184
294
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
295
|
+
return VGModal.build(id, this._params.modal, (modalInstance) => {
|
|
296
|
+
const element = modalInstance._element;
|
|
297
|
+
element.classList.add(`${CLASS_NAME_ALERT}-modal`);
|
|
298
|
+
element.setAttribute("role", "alertdialog");
|
|
299
|
+
element.setAttribute("aria-modal", "true");
|
|
188
300
|
|
|
189
|
-
|
|
190
|
-
|
|
301
|
+
const $body = Selectors.find(".vg-modal-body", element);
|
|
302
|
+
if (!$body) return;
|
|
191
303
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
Classes.add(buttons, 'vg-alert-buttons');
|
|
304
|
+
let icon = null;
|
|
305
|
+
if (this._params.icon) {
|
|
306
|
+
icon = html.div({class: `${CLASS_NAME_ALERT}-content--icon`}, this._params.icon, {isHTML: true});
|
|
307
|
+
}
|
|
197
308
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
this._create(buttons, 'button', 'agree');
|
|
201
|
-
}
|
|
309
|
+
const buttons = document.createElement("div");
|
|
310
|
+
Classes.add(buttons, "vg-alert-buttons");
|
|
202
311
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
312
|
+
if (this._params.mode === "confirm") {
|
|
313
|
+
this._createButton(buttons, "cancel");
|
|
314
|
+
this._createButton(buttons, "agree");
|
|
315
|
+
}
|
|
206
316
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
$body.append(wrapper);
|
|
317
|
+
if (this._params.mode === "info") {
|
|
318
|
+
this._createButton(buttons, "cancel");
|
|
210
319
|
}
|
|
320
|
+
|
|
321
|
+
let wrapper = html.div({class: `${CLASS_NAME_ALERT}-wrapper ${CLASS_NAME_ALERT}-${this._params.theme}`}, [
|
|
322
|
+
html.div({class: `${CLASS_NAME_ALERT}-content`}, [
|
|
323
|
+
icon,
|
|
324
|
+
html.div({class: `${CLASS_NAME_ALERT}-content--message`}, [
|
|
325
|
+
html.div({class: `${CLASS_NAME_ALERT}-content--title`}, this._params.message.title),
|
|
326
|
+
html.div({class: `${CLASS_NAME_ALERT}-content--description`}, this._params.message.description),
|
|
327
|
+
])
|
|
328
|
+
]),
|
|
329
|
+
buttons
|
|
330
|
+
]);
|
|
331
|
+
|
|
332
|
+
$body.appendChild(wrapper);
|
|
211
333
|
});
|
|
212
334
|
}
|
|
213
335
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
Manipulator.set(btn, key, attr[key]);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
336
|
+
/**
|
|
337
|
+
* Создаёт кнопку и добавляет её в контейнер.
|
|
338
|
+
*
|
|
339
|
+
* @private
|
|
340
|
+
* @param {HTMLElement} container - Родительский элемент.
|
|
341
|
+
* @param {'agree'|'cancel'} key - Ключ кнопки.
|
|
342
|
+
* @returns {void}
|
|
343
|
+
*/
|
|
344
|
+
_createButton(container, key) {
|
|
345
|
+
const button = this._params.buttons[key];
|
|
346
|
+
if (!button || button.element) {
|
|
347
|
+
container.insertAdjacentHTML("beforeend", button?.element || "");
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
231
350
|
|
|
232
|
-
|
|
233
|
-
btn.innerHTML = button.text;
|
|
351
|
+
if (!button.tag) return;
|
|
234
352
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
353
|
+
let btn = null,
|
|
354
|
+
classes = [...new Set(button.class)].join(" "),
|
|
355
|
+
attrs = mergeDeepObject({
|
|
356
|
+
class: classes
|
|
357
|
+
}, button.attr);
|
|
238
358
|
|
|
239
|
-
if (
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
359
|
+
if (button.tag === "button") {
|
|
360
|
+
btn = Html('dom').button(button.text, button.type, attrs);
|
|
361
|
+
} else if (button.tag === "a") {
|
|
362
|
+
btn = Html('dom').a('#', button.text, attrs);
|
|
243
363
|
}
|
|
244
364
|
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
365
|
+
if (!btn) return;
|
|
366
|
+
|
|
367
|
+
btn.setAttribute(button.toggle, "true");
|
|
368
|
+
container.appendChild(btn);
|
|
250
369
|
}
|
|
251
370
|
}
|
|
252
371
|
|
|
253
|
-
|
|
254
372
|
/**
|
|
255
|
-
*
|
|
373
|
+
* Константы для событий и селекторов
|
|
256
374
|
*/
|
|
257
|
-
const
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
const EVENT_KEY_LOADED = 'vg.alert.loaded';
|
|
264
|
-
const EVENT_KEY_ACCEPT = 'vg.alert.accept';
|
|
265
|
-
const EVENT_KEY_REJECT = 'vg.alert.reject';
|
|
375
|
+
const SELECTOR_DATA_TOGGLE = `[data-vg-toggle="${NAME}"]`;
|
|
376
|
+
const EVENT_KEY_CLICK_DATA_API = `click.${NAME_KEY}.data.api`;
|
|
377
|
+
const EVENT_KEY_LOADED = `${NAME_KEY}.loaded`;
|
|
378
|
+
const EVENT_KEY_ACCEPT = `${NAME_KEY}.accept`;
|
|
379
|
+
const EVENT_KEY_REJECT = `${NAME_KEY}.reject`;
|
|
380
|
+
const EVENT_KEY_FINALLY = `${NAME_KEY}.finally`;
|
|
266
381
|
|
|
382
|
+
/**
|
|
383
|
+
* Класс для работы с алертами по data-атрибутам.
|
|
384
|
+
*
|
|
385
|
+
* @class
|
|
386
|
+
* @extends BaseModule
|
|
387
|
+
* @example
|
|
388
|
+
* <button data-vg-toggle="alert" data-ajax-route="/delete/1">Удалить</button>
|
|
389
|
+
*/
|
|
267
390
|
class VGAlertConfirm extends BaseModule {
|
|
391
|
+
/**
|
|
392
|
+
* Создаёт экземпляр VGAlertConfirm.
|
|
393
|
+
*
|
|
394
|
+
* @param {HTMLElement} element - DOM-элемент.
|
|
395
|
+
* @param {AlertParams} options - Параметры.
|
|
396
|
+
*/
|
|
268
397
|
constructor(element, options = {}) {
|
|
269
398
|
super(element);
|
|
270
|
-
|
|
271
|
-
this._params = this._getParams(this._element, mergeDeepObject({
|
|
272
|
-
|
|
273
|
-
}, options));
|
|
399
|
+
this._params = this._getParams(element, mergeDeepObject({}, options));
|
|
274
400
|
}
|
|
275
401
|
|
|
402
|
+
/**
|
|
403
|
+
* Возвращает имя модуля.
|
|
404
|
+
* @returns {string}
|
|
405
|
+
*/
|
|
276
406
|
static get NAME() {
|
|
277
407
|
return NAME;
|
|
278
408
|
}
|
|
279
409
|
|
|
410
|
+
/**
|
|
411
|
+
* Возвращает ключевое имя с префиксом.
|
|
412
|
+
* @returns {string}
|
|
413
|
+
*/
|
|
280
414
|
static get NAME_KEY() {
|
|
281
|
-
return NAME_KEY
|
|
415
|
+
return NAME_KEY;
|
|
282
416
|
}
|
|
283
417
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
418
|
+
/**
|
|
419
|
+
* Запускает логику алерта: вызывает модальное окно и обрабатывает результат.
|
|
420
|
+
*
|
|
421
|
+
* @param {typeof VGAlert} AlertClass - Класс алерта.
|
|
422
|
+
* @returns {void}
|
|
423
|
+
*/
|
|
424
|
+
run(AlertClass) {
|
|
425
|
+
if (this._params.mode !== "confirm") return;
|
|
426
|
+
|
|
427
|
+
AlertClass.call(this._params)
|
|
428
|
+
.then((resolve) => {
|
|
429
|
+
if (!resolve.accepted) return Promise.reject(resolve);
|
|
430
|
+
if (!this._params.ajax.route) return resolve;
|
|
431
|
+
return this._ajax();
|
|
432
|
+
})
|
|
433
|
+
.then((response) => {
|
|
434
|
+
EventHandler.trigger(this._element, EVENT_KEY_ACCEPT, { vgalert: response });
|
|
435
|
+
})
|
|
436
|
+
.catch((error) => {
|
|
437
|
+
EventHandler.trigger(this._element, EVENT_KEY_REJECT, { vgalert: error });
|
|
438
|
+
})
|
|
439
|
+
.finally(() => {
|
|
440
|
+
EventHandler.trigger(this._element, EVENT_KEY_FINALLY, { vgalert: 'finally' });
|
|
441
|
+
});
|
|
300
442
|
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Выполняет AJAX-запрос после подтверждения.
|
|
446
|
+
*
|
|
447
|
+
* @private
|
|
448
|
+
* @returns {Promise<Object>} Ответ от сервера.
|
|
449
|
+
*/
|
|
301
450
|
_ajax() {
|
|
302
451
|
return new Promise((resolve) => {
|
|
303
452
|
this._route((status, data) => {
|
|
304
|
-
EventHandler.trigger(this._element, EVENT_KEY_LOADED, {stats: status, data
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
status: status,
|
|
308
|
-
data: data
|
|
309
|
-
});
|
|
310
|
-
})
|
|
453
|
+
EventHandler.trigger(this._element, EVENT_KEY_LOADED, { stats: status, data });
|
|
454
|
+
resolve({ status, data });
|
|
455
|
+
});
|
|
311
456
|
});
|
|
312
457
|
}
|
|
313
458
|
}
|
|
314
459
|
|
|
315
|
-
|
|
460
|
+
// Делегирование кликов по data-атрибутам
|
|
461
|
+
EventHandler.on(document, EVENT_KEY_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
|
|
316
462
|
event.preventDefault();
|
|
463
|
+
const target = event.target;
|
|
317
464
|
|
|
318
|
-
let target = event.target;
|
|
319
465
|
if (!isVisible(target) || !isElement(target)) return;
|
|
320
466
|
|
|
321
467
|
VGAlert.confirm(target, {
|
|
322
|
-
message: {
|
|
323
|
-
title: 'Удалить этот товар',
|
|
324
|
-
description: 'Внимание этот товар будет удален'
|
|
325
|
-
},
|
|
326
468
|
buttons: {
|
|
327
469
|
agree: {
|
|
328
|
-
class: [
|
|
470
|
+
class: ["btn-primary"],
|
|
329
471
|
},
|
|
330
472
|
cancel: {
|
|
331
|
-
class: [
|
|
332
|
-
}
|
|
333
|
-
}
|
|
473
|
+
class: ["btn-outline-primary"],
|
|
474
|
+
},
|
|
475
|
+
},
|
|
334
476
|
});
|
|
335
|
-
})
|
|
477
|
+
});
|
|
336
478
|
|
|
337
479
|
export default VGAlert;
|