vgapp 0.7.7 → 0.7.8
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 +15 -4
- package/app/modules/base-module.js +52 -17
- package/app/modules/module-fn.js +10 -100
- 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 +221 -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 +215 -0
- package/app/utils/js/components/lang.js +82 -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/package.json +1 -1
- package/app/utils/js/components/alert.js +0 -8
|
@@ -1,9 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VGFormSender Module
|
|
3
|
+
*
|
|
4
|
+
* Этот модуль отвечает за отправку форм с поддержкой AJAX, валидации, отображения уведомлений
|
|
5
|
+
* (модальные окна или collapse), обработки ошибок, спиннеров для кнопок и многое другое.
|
|
6
|
+
* Поддерживает кастомизацию через параметры и data-атрибуты.
|
|
7
|
+
*
|
|
8
|
+
* @class VGFormSender
|
|
9
|
+
* @extends BaseModule
|
|
10
|
+
*
|
|
11
|
+
* @param {HTMLElement} element - DOM-элемент формы
|
|
12
|
+
* @param {Object} params - Параметры инициализации
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* VGFormSender.init(document.getElementById('myForm'), {
|
|
16
|
+
* ajax: {
|
|
17
|
+
* route: '/submit',
|
|
18
|
+
* method: 'post'
|
|
19
|
+
* },
|
|
20
|
+
* alert: {
|
|
21
|
+
* type: 'modal',
|
|
22
|
+
* enabled: true
|
|
23
|
+
* },
|
|
24
|
+
* callback: {
|
|
25
|
+
* afterSuccess: (form, instance, event, data) => {
|
|
26
|
+
* console.log('Форма успешно отправлена');
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
|
|
1
32
|
import BaseModule from "../../base-module";
|
|
33
|
+
import VGModal from "../../vgmodal/js/vgmodal";
|
|
34
|
+
import VGCollapse from "../../vgcollapse/js/vgcollapse";
|
|
35
|
+
import VGHideShowPass from "./hideshowpass";
|
|
36
|
+
import {lang_titles, lang_messages} from "../../../utils/js/components/lang";
|
|
37
|
+
import Html from "../../../utils/js/components/templater";
|
|
2
38
|
import {Manipulator} from "../../../utils/js/dom/manipulator";
|
|
3
39
|
import EventHandler from "../../../utils/js/dom/event";
|
|
4
|
-
import
|
|
40
|
+
import Selectors from "../../../utils/js/dom/selectors";
|
|
41
|
+
import {getSVG} from "../../module-fn";
|
|
5
42
|
import {
|
|
6
|
-
execute,
|
|
43
|
+
execute,
|
|
7
44
|
isObject,
|
|
8
45
|
isVisible,
|
|
9
46
|
makeRandomString,
|
|
@@ -11,32 +48,66 @@ import {
|
|
|
11
48
|
noop,
|
|
12
49
|
normalizeData
|
|
13
50
|
} from "../../../utils/js/functions";
|
|
14
|
-
import Selectors from "../../../utils/js/dom/selectors";
|
|
15
|
-
import VGCollapse from "../../vgcollapse/js/vgcollapse";
|
|
16
|
-
import {getSVG} from "../../module-fn";
|
|
17
|
-
import VGHideShowPass from "./hideshowpass";
|
|
18
51
|
|
|
19
52
|
/**
|
|
20
|
-
*
|
|
53
|
+
* Константа: имя модуля
|
|
54
|
+
* @type {string}
|
|
21
55
|
*/
|
|
22
56
|
const NAME = 'form-sender';
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Константа: ключ модуля для использования в data-атрибутах и событиях
|
|
60
|
+
* @type {string}
|
|
61
|
+
*/
|
|
23
62
|
const NAME_KEY = 'vg.fs';
|
|
24
63
|
|
|
25
64
|
/**
|
|
26
|
-
*
|
|
65
|
+
* CSS-класс для алертов
|
|
66
|
+
* @type {string}
|
|
27
67
|
*/
|
|
28
68
|
const CLASS_NAME_ALERT = 'vg-form-sender-alert';
|
|
29
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Событие: успешная отправка формы
|
|
72
|
+
* @type {string}
|
|
73
|
+
*/
|
|
30
74
|
const EVENT_KEY_SUCCESS = 'vg.fs.success';
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Событие: ошибка при отправке формы
|
|
78
|
+
* @type {string}
|
|
79
|
+
*/
|
|
31
80
|
const EVENT_KEY_ERROR = 'vg.fs.error';
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Событие: перед отправкой формы
|
|
84
|
+
* @type {string}
|
|
85
|
+
*/
|
|
32
86
|
const EVENT_KEY_BEFORE = 'vg.fs.before';
|
|
33
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Событие: обработка нативной отправки формы
|
|
90
|
+
* @type {string}
|
|
91
|
+
*/
|
|
34
92
|
const EVENT_SUBMIT_DATA_API = `submit.${NAME_KEY}.data.api`;
|
|
35
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Основной класс модуля формы
|
|
96
|
+
*/
|
|
36
97
|
class VGFormSender extends BaseModule {
|
|
98
|
+
/**
|
|
99
|
+
* Создаёт экземпляр VGFormSender
|
|
100
|
+
* @param {HTMLElement} element - Элемент формы
|
|
101
|
+
* @param {Object} params - Параметры конфигурации
|
|
102
|
+
*/
|
|
37
103
|
constructor(element, params = {}) {
|
|
38
104
|
super(element, params);
|
|
39
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Объединённые параметры с дефолтными значениями
|
|
108
|
+
* @type {Object}
|
|
109
|
+
* @private
|
|
110
|
+
*/
|
|
40
111
|
this._params = this._getParams(element, mergeDeepObject({
|
|
41
112
|
response: {
|
|
42
113
|
enabled: false,
|
|
@@ -69,6 +140,8 @@ class VGFormSender extends BaseModule {
|
|
|
69
140
|
target: '',
|
|
70
141
|
method: 'get',
|
|
71
142
|
timeout: 1000,
|
|
143
|
+
loader: false,
|
|
144
|
+
output: true
|
|
72
145
|
},
|
|
73
146
|
classes: {
|
|
74
147
|
general: 'vg-form-sender',
|
|
@@ -82,6 +155,7 @@ class VGFormSender extends BaseModule {
|
|
|
82
155
|
afterInit: noop,
|
|
83
156
|
afterSuccess: noop,
|
|
84
157
|
afterError: noop,
|
|
158
|
+
afterSend: noop,
|
|
85
159
|
},
|
|
86
160
|
interceptors: {
|
|
87
161
|
beforeSend: () => new Promise((resolve, reject) => resolve()),
|
|
@@ -99,37 +173,84 @@ class VGFormSender extends BaseModule {
|
|
|
99
173
|
},
|
|
100
174
|
click: noop,
|
|
101
175
|
},
|
|
176
|
+
lang: 'ru'
|
|
102
177
|
}, params));
|
|
103
178
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
this.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
179
|
+
/**
|
|
180
|
+
* Кнопка отправки формы
|
|
181
|
+
* @type {HTMLElement|null}
|
|
182
|
+
* @private
|
|
183
|
+
*/
|
|
184
|
+
this._button = null;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Кэш для часто используемых элементов
|
|
188
|
+
* @type {Map<string, any>}
|
|
189
|
+
* @private
|
|
190
|
+
*/
|
|
191
|
+
this._cachedElements = new Map();
|
|
192
|
+
|
|
193
|
+
this._initElements();
|
|
115
194
|
}
|
|
116
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Возвращает имя модуля
|
|
198
|
+
* @returns {string}
|
|
199
|
+
* @static
|
|
200
|
+
*/
|
|
117
201
|
static get NAME() {
|
|
118
202
|
return NAME;
|
|
119
203
|
}
|
|
120
204
|
|
|
205
|
+
/**
|
|
206
|
+
* Возвращает ключ модуля
|
|
207
|
+
* @returns {string}
|
|
208
|
+
* @static
|
|
209
|
+
*/
|
|
121
210
|
static get NAME_KEY() {
|
|
122
211
|
return NAME_KEY;
|
|
123
212
|
}
|
|
124
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Инициализация внутренних элементов: кнопка, поля, параметры
|
|
216
|
+
* @private
|
|
217
|
+
*/
|
|
218
|
+
_initElements() {
|
|
219
|
+
this._button = Selectors.find('[type="submit"]', this._element) ||
|
|
220
|
+
Selectors.find('[form="' + this._element.id + '"]') ||
|
|
221
|
+
null;
|
|
222
|
+
|
|
223
|
+
const fields = Selectors.findAll('input, textarea, select', this._element);
|
|
224
|
+
this._cachedElements.set('fields', fields);
|
|
225
|
+
|
|
226
|
+
this._params.ajax.route = Manipulator.get(this._element, 'action') || this._params.ajax.route;
|
|
227
|
+
this._params.ajax.method = Manipulator.get(this._element, 'method') || this._params.ajax.method;
|
|
228
|
+
|
|
229
|
+
this._params.isBtnText = Manipulator.get(this._element, 'data-btn-text') !== 'false';
|
|
230
|
+
this._params.isJsonParse = Manipulator.get(this._element, 'data-json-parse') !== 'false';
|
|
231
|
+
this._params.isShowPass = Manipulator.get(this._element, 'data-show-pass') === 'true';
|
|
232
|
+
|
|
233
|
+
if (this._button) {
|
|
234
|
+
this._params = this._getParams(this._button, this._params);
|
|
235
|
+
this._params.button.initial = this._button.innerHTML.trim() || this._params.button.initial;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Построение формы: добавление классов, инициализация паролей, валидации
|
|
241
|
+
* @returns {VGFormSender}
|
|
242
|
+
*/
|
|
125
243
|
build() {
|
|
126
244
|
this._element.classList.add(this._params.classes.general);
|
|
127
245
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
246
|
+
const fields = this._cachedElements.get('fields');
|
|
247
|
+
if (fields) {
|
|
248
|
+
fields.forEach((el) => {
|
|
249
|
+
if (isVisible(el) && el.parentElement) {
|
|
250
|
+
el.parentElement.classList.add(this._params.classes.content);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
}
|
|
133
254
|
|
|
134
255
|
if (this._params.validate) {
|
|
135
256
|
Manipulator.set(this._element, 'novalidate', '');
|
|
@@ -147,6 +268,11 @@ class VGFormSender extends BaseModule {
|
|
|
147
268
|
return this
|
|
148
269
|
}
|
|
149
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Отправка формы (AJAX или нативная)
|
|
273
|
+
* @param {Event} event - DOM-событие отправки
|
|
274
|
+
* @param {FormData|null} data - Дополнительные данные для отправки
|
|
275
|
+
*/
|
|
150
276
|
request(event, data = null) {
|
|
151
277
|
const _this = this;
|
|
152
278
|
const mergeFormData = (target, source) => {
|
|
@@ -165,6 +291,8 @@ class VGFormSender extends BaseModule {
|
|
|
165
291
|
else _this._params.ajax.data = formData;
|
|
166
292
|
|
|
167
293
|
_this._route(function (status, data) {
|
|
294
|
+
execute(_this._params.callback.afterSend, [_this._element, _this, status, data]);
|
|
295
|
+
|
|
168
296
|
_this._element.classList.remove('was-validated');
|
|
169
297
|
|
|
170
298
|
if (_this._params.response.enabled) {
|
|
@@ -201,50 +329,81 @@ class VGFormSender extends BaseModule {
|
|
|
201
329
|
|
|
202
330
|
_this._params.interceptors.beforeSend().then(() => {
|
|
203
331
|
submit();
|
|
332
|
+
}).catch(err => {
|
|
333
|
+
console.error(err);
|
|
204
334
|
});
|
|
205
335
|
}
|
|
206
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Действия перед отправкой формы: блокировка кнопки, триггер события
|
|
339
|
+
* @private
|
|
340
|
+
*/
|
|
207
341
|
_alertBefore() {
|
|
208
342
|
const _this = this;
|
|
209
343
|
|
|
210
344
|
if (_this._params.alert.type === 'collapse') {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
345
|
+
const collapseClass = _this._params.classes.alertCollapse;
|
|
346
|
+
if (!_this._cachedElements.has('collapses') || document.querySelector('.' + collapseClass + '.show')) {
|
|
347
|
+
const collapses = document.getElementsByClassName(collapseClass);
|
|
348
|
+
_this._cachedElements.set('collapses', collapses);
|
|
349
|
+
|
|
350
|
+
[...collapses].forEach(function (element) {
|
|
351
|
+
if (element.classList.contains('show')) {
|
|
352
|
+
VGCollapse.getOrCreateInstance(element, { toggle: false }).hide();
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
}
|
|
216
356
|
}
|
|
217
357
|
|
|
218
358
|
_this._statusButton('before');
|
|
219
359
|
EventHandler.trigger(_this._element, EVENT_KEY_BEFORE, _this);
|
|
220
360
|
}
|
|
221
361
|
|
|
362
|
+
/**
|
|
363
|
+
* Обработка ошибки: отображение алерта, вызов колбэка
|
|
364
|
+
* @param {Event} event - DOM-событие
|
|
365
|
+
* @param {Object} data - Данные ответа
|
|
366
|
+
* @private
|
|
367
|
+
*/
|
|
222
368
|
_alertError(event, data) {
|
|
223
369
|
const _this = this;
|
|
224
370
|
|
|
225
371
|
_this._statusButton('after');
|
|
226
372
|
_this._jsonParse(data, 'error');
|
|
227
|
-
EventHandler.trigger(_this._element, EVENT_KEY_ERROR,
|
|
373
|
+
EventHandler.trigger(_this._element, EVENT_KEY_ERROR, {
|
|
374
|
+
vgformsender: {
|
|
375
|
+
event: event,
|
|
376
|
+
self: _this,
|
|
377
|
+
data: data
|
|
378
|
+
}
|
|
379
|
+
});
|
|
228
380
|
}
|
|
229
381
|
|
|
382
|
+
/**
|
|
383
|
+
* Обработка успеха: отображение алерта, вызов колбэка
|
|
384
|
+
* @param {Event} event - DOM-событие
|
|
385
|
+
* @param {Object} data - Данные ответа
|
|
386
|
+
* @private
|
|
387
|
+
*/
|
|
230
388
|
_alertSuccess(event, data) {
|
|
231
389
|
const _this = this;
|
|
232
390
|
|
|
233
391
|
_this._statusButton('after');
|
|
234
392
|
_this._jsonParse(data, 'success');
|
|
235
|
-
EventHandler.trigger(_this._element, EVENT_KEY_SUCCESS,
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
form.addEventListener('vg.fs.' + status, e => {
|
|
243
|
-
execute(callback, [form, instance])
|
|
244
|
-
})
|
|
245
|
-
}
|
|
393
|
+
EventHandler.trigger(_this._element, EVENT_KEY_SUCCESS, {
|
|
394
|
+
vgformsender: {
|
|
395
|
+
event: event,
|
|
396
|
+
self: _this,
|
|
397
|
+
data: data
|
|
398
|
+
}
|
|
399
|
+
});
|
|
246
400
|
}
|
|
247
401
|
|
|
402
|
+
/**
|
|
403
|
+
* Управление состоянием кнопки отправки
|
|
404
|
+
* @param {'before'|'after'} status - Статус: до/после отправки
|
|
405
|
+
* @private
|
|
406
|
+
*/
|
|
248
407
|
_statusButton(status) {
|
|
249
408
|
if (!this._button) return;
|
|
250
409
|
|
|
@@ -286,39 +445,40 @@ class VGFormSender extends BaseModule {
|
|
|
286
445
|
}
|
|
287
446
|
}
|
|
288
447
|
|
|
448
|
+
/**
|
|
449
|
+
* Парсинг JSON-ответа и вызов алерта
|
|
450
|
+
* @param {Object} data - Данные ответа
|
|
451
|
+
* @param {'success'|'error'} status - Статус ответа
|
|
452
|
+
* @private
|
|
453
|
+
*/
|
|
289
454
|
_jsonParse(data, status) {
|
|
290
455
|
const _this = this;
|
|
291
456
|
|
|
292
|
-
if (_this._params.isJsonParse
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
try {
|
|
296
|
-
parserData = JSON.parse(data);
|
|
297
|
-
_this.alert(parserData, status);
|
|
298
|
-
} catch (e) {
|
|
299
|
-
_this.alert(data, status);
|
|
300
|
-
}
|
|
457
|
+
if (_this._params.isJsonParse) {
|
|
458
|
+
_this.alert(normalizeData(data), status);
|
|
301
459
|
} else {
|
|
302
460
|
_this.alert(data, status);
|
|
303
461
|
}
|
|
304
462
|
}
|
|
305
463
|
|
|
464
|
+
/**
|
|
465
|
+
* Отображение алерта в зависимости от типа (modal/collapse)
|
|
466
|
+
* @param {Object|string} data - Данные для отображения
|
|
467
|
+
* @param {string} status - Статус: success, error, danger и т.д.
|
|
468
|
+
*/
|
|
306
469
|
alert(data, status) {
|
|
307
|
-
const _this = this;
|
|
308
|
-
|
|
309
470
|
if (isObject(data)) {
|
|
310
471
|
if (('code' in data) && data.code && data.code === 200) {
|
|
311
472
|
if ('response' in data && data.response) {
|
|
312
473
|
let response = normalizeData(data.response);
|
|
313
474
|
if (typeof response === 'string') {
|
|
314
475
|
if (response.indexOf("Parse error") !== -1 || response.indexOf("syntax error") !== -1) {
|
|
315
|
-
status = '
|
|
476
|
+
status = 'danger';
|
|
316
477
|
data = {
|
|
317
478
|
response: {
|
|
318
|
-
title: '
|
|
319
|
-
message:
|
|
320
|
-
}
|
|
321
|
-
text: 'Something went wrong, please repeat later'
|
|
479
|
+
title: lang_titles(this._params.lang, 'errors').title,
|
|
480
|
+
message: lang_messages(this._params.lang, 'errors').went_wrong
|
|
481
|
+
}
|
|
322
482
|
}
|
|
323
483
|
}
|
|
324
484
|
} else {
|
|
@@ -327,30 +487,40 @@ class VGFormSender extends BaseModule {
|
|
|
327
487
|
}
|
|
328
488
|
}
|
|
329
489
|
}
|
|
490
|
+
} else {
|
|
491
|
+
status = 'danger'
|
|
330
492
|
}
|
|
331
493
|
}
|
|
332
494
|
|
|
333
|
-
if (!
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
495
|
+
if (!this._params.alert.enabled) return;
|
|
336
496
|
|
|
337
|
-
if (
|
|
338
|
-
|
|
497
|
+
if (this._params.alert.type === 'modal') {
|
|
498
|
+
this._alertModal(data, status)
|
|
339
499
|
}
|
|
340
500
|
|
|
341
|
-
if (
|
|
342
|
-
|
|
501
|
+
if (this._params.alert.type === 'collapse') {
|
|
502
|
+
this._alertCollapse(data, status)
|
|
343
503
|
}
|
|
344
504
|
}
|
|
345
505
|
|
|
506
|
+
/**
|
|
507
|
+
* Показ алерта в виде модального окна
|
|
508
|
+
* @param {Object} data - Данные для отображения
|
|
509
|
+
* @param {string} status - Статус (success/error)
|
|
510
|
+
* @private
|
|
511
|
+
*/
|
|
346
512
|
_alertModal(data, status) {
|
|
347
513
|
const _this = this;
|
|
348
514
|
|
|
349
|
-
//
|
|
515
|
+
// Закрытие всех открытых модальных окон
|
|
350
516
|
[...document.getElementsByClassName('modal')].forEach(function (element) {
|
|
351
517
|
if (element && element.classList.contains('show')) {
|
|
352
|
-
|
|
353
|
-
|
|
518
|
+
if (typeof bootstrap !== 'undefined') {
|
|
519
|
+
let mBS = bootstrap.Modal?.getOrCreateInstance(element);
|
|
520
|
+
mBS.hide();
|
|
521
|
+
} else {
|
|
522
|
+
console.warn(lang_messages(_this._params.lang, NAME).bootstrap_not_found)
|
|
523
|
+
}
|
|
354
524
|
}
|
|
355
525
|
});
|
|
356
526
|
|
|
@@ -368,6 +538,7 @@ class VGFormSender extends BaseModule {
|
|
|
368
538
|
|
|
369
539
|
setTimeout(() => {
|
|
370
540
|
VGModal.init(id, {
|
|
541
|
+
dismiss: true,
|
|
371
542
|
classes: {
|
|
372
543
|
alert: _this._params.classes.alertModal
|
|
373
544
|
}
|
|
@@ -375,6 +546,9 @@ class VGFormSender extends BaseModule {
|
|
|
375
546
|
let element = self._element;
|
|
376
547
|
element.classList.add(_this._params.classes.alertModal);
|
|
377
548
|
|
|
549
|
+
let $content = Selectors.find('.vg-modal-content', element);
|
|
550
|
+
if ($content) $content.classList.add(CLASS_NAME_ALERT, CLASS_NAME_ALERT + '-' + status);
|
|
551
|
+
|
|
378
552
|
let $body = Selectors.find('.vg-modal-body', element);
|
|
379
553
|
if ($body) $body.append(_this.setDataRelationStatus(element, status, data, 'modal'));
|
|
380
554
|
|
|
@@ -389,6 +563,12 @@ class VGFormSender extends BaseModule {
|
|
|
389
563
|
}, _this._params.timeout);
|
|
390
564
|
}
|
|
391
565
|
|
|
566
|
+
/**
|
|
567
|
+
* Показ алерта в виде collapse
|
|
568
|
+
* @param {Object} data - Данные для отображения
|
|
569
|
+
* @param {string} status - Статус (success/error)
|
|
570
|
+
* @private
|
|
571
|
+
*/
|
|
392
572
|
_alertCollapse(data, status) {
|
|
393
573
|
const _this = this;
|
|
394
574
|
|
|
@@ -413,129 +593,132 @@ class VGFormSender extends BaseModule {
|
|
|
413
593
|
}
|
|
414
594
|
}
|
|
415
595
|
|
|
596
|
+
/**
|
|
597
|
+
* Формирование содержимого алерта (заголовок, текст, иконка)
|
|
598
|
+
* @param {HTMLElement} $element - Родительский элемент
|
|
599
|
+
* @param {string} status - Статус (success/danger и т.д.)
|
|
600
|
+
* @param {Object} data - Данные ответа
|
|
601
|
+
* @param {'modal'|'collapse'} type - Тип алерта
|
|
602
|
+
* @returns {HTMLElement} - DOM-элемент с контентом
|
|
603
|
+
*/
|
|
416
604
|
setDataRelationStatus($element, status, data, type) {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
let $alert = Selectors.find('.'+ CLASS_NAME_ALERT +'-' + status, $element);
|
|
605
|
+
let response = normalizeData(data.response) || data,
|
|
606
|
+
$alert = Selectors.find('.'+ CLASS_NAME_ALERT +'-content', $element);
|
|
420
607
|
|
|
421
608
|
if (isObject(data)) {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
data.text = 'Unprocessable Entity'
|
|
445
|
-
break;
|
|
446
|
-
case 500:
|
|
447
|
-
data.text = 'Internal Server Error'
|
|
448
|
-
break;
|
|
449
|
-
case 504:
|
|
450
|
-
data.text = 'Gateway Timeout'
|
|
451
|
-
break;
|
|
452
|
-
}
|
|
609
|
+
let view = '';
|
|
610
|
+
|
|
611
|
+
if ('view' in data.response) {
|
|
612
|
+
response = data.response.view
|
|
613
|
+
} else if (typeof response !== 'string') {
|
|
614
|
+
if (status === 'danger') {
|
|
615
|
+
response.title = lang_titles(this._params.lang, 'errors').title;
|
|
616
|
+
|
|
617
|
+
if ('code' in data && data.code !== 200) {
|
|
618
|
+
const messages = {
|
|
619
|
+
400: lang_messages(this._params.lang, 'errors')[400],
|
|
620
|
+
401: lang_messages(this._params.lang, 'errors')[401],
|
|
621
|
+
403: lang_messages(this._params.lang, 'errors')[403],
|
|
622
|
+
404: lang_messages(this._params.lang, 'errors')[404],
|
|
623
|
+
413: lang_messages(this._params.lang, 'errors')[413],
|
|
624
|
+
419: lang_messages(this._params.lang, 'errors')[419],
|
|
625
|
+
422: lang_messages(this._params.lang, 'errors')[422],
|
|
626
|
+
500: lang_messages(this._params.lang, 'errors')[500],
|
|
627
|
+
504: lang_messages(this._params.lang, 'errors')[504],
|
|
628
|
+
};
|
|
629
|
+
response.message = messages[data.code] || lang_messages(this._params.lang, 'errors').went_wrong;
|
|
630
|
+
response.title += ' (' + data.code + ')';
|
|
453
631
|
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
632
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
if (!('view' in response)) {
|
|
461
|
-
if ('title' in response) title = response.title;
|
|
462
|
-
if (status === 'error' && data.code !== 200 && this._params.alert.errors) {
|
|
463
|
-
code = ' ' + data.text + ' (' + data.code + ')';
|
|
464
|
-
}
|
|
633
|
+
if ('errors' in response && this._params.alert.errors) {
|
|
634
|
+
let errors = normalizeData(response.errors) || null;
|
|
635
|
+
response.message = [];
|
|
465
636
|
|
|
466
|
-
if (
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
if ('errors' in response && this._params.alert.errors) {
|
|
474
|
-
let errors = normalizeData(response.errors) || null;
|
|
475
|
-
if (isObject(errors)) {
|
|
476
|
-
for (const error in errors) {
|
|
477
|
-
if (Array.isArray(errors[error])) {
|
|
478
|
-
errors[error].forEach(function (t) {
|
|
479
|
-
txt += '<div>'+ t +'</div>';
|
|
480
|
-
})
|
|
481
|
-
} else {
|
|
482
|
-
txt = '<div>'+ errors[error] +'</div>';
|
|
483
|
-
}
|
|
637
|
+
if (isObject(errors)) {
|
|
638
|
+
for (const error in errors) {
|
|
639
|
+
if (Array.isArray(errors[error])) {
|
|
640
|
+
errors[error].forEach((t) => response.message.push(t))
|
|
641
|
+
} else {
|
|
642
|
+
response.message.push(errors[error]);
|
|
484
643
|
}
|
|
485
644
|
}
|
|
486
645
|
}
|
|
487
|
-
|
|
488
|
-
data = {
|
|
489
|
-
view: txt
|
|
490
|
-
}
|
|
491
646
|
}
|
|
492
|
-
} else {
|
|
493
|
-
data.view = response;
|
|
494
647
|
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
648
|
|
|
498
|
-
|
|
499
|
-
$alert = document.createElement('div');
|
|
500
|
-
$alert.classList.add(CLASS_NAME_ALERT, CLASS_NAME_ALERT + '-' + status, CLASS_NAME_ALERT + '-' + type);
|
|
501
|
-
|
|
502
|
-
let content = document.createElement('div');
|
|
503
|
-
content.classList.add(CLASS_NAME_ALERT + '-content');
|
|
649
|
+
const elm = Html('string');
|
|
504
650
|
|
|
505
|
-
|
|
506
|
-
icon.classList.add(CLASS_NAME_ALERT + '-content--icon');
|
|
651
|
+
view = elm.h4({class: CLASS_NAME_ALERT +'-content--title'}, response.title);
|
|
507
652
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
653
|
+
if (Array.isArray(response.message)) {
|
|
654
|
+
response.message.forEach(message => {
|
|
655
|
+
view += elm.div({
|
|
656
|
+
class: CLASS_NAME_ALERT +'-content--message'
|
|
657
|
+
}, message);
|
|
658
|
+
})
|
|
659
|
+
} else {
|
|
660
|
+
view += elm.div({
|
|
661
|
+
class: CLASS_NAME_ALERT +'-content--message'
|
|
662
|
+
}, response.message);
|
|
663
|
+
}
|
|
513
664
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
665
|
+
response = view;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
517
668
|
|
|
518
|
-
|
|
519
|
-
|
|
669
|
+
if (!$alert) {
|
|
670
|
+
const elm = Html('dom');
|
|
671
|
+
|
|
672
|
+
$alert = elm.div({
|
|
673
|
+
class: CLASS_NAME_ALERT + '-' + type
|
|
674
|
+
}, [
|
|
675
|
+
elm.div({class: CLASS_NAME_ALERT + '-content'}, [
|
|
676
|
+
elm.i({class: CLASS_NAME_ALERT + '-content--icon'}, getSVG(status), {isHTML: true}),
|
|
677
|
+
elm.div({class: CLASS_NAME_ALERT + '-content--text'}, response, {isHTML: true})
|
|
678
|
+
]),
|
|
679
|
+
]);
|
|
520
680
|
} else {
|
|
521
|
-
let text = Selectors.find('.
|
|
522
|
-
text.innerHTML =
|
|
681
|
+
let text = Selectors.find('.vg-modal-body', $element);
|
|
682
|
+
text.innerHTML = response;
|
|
523
683
|
}
|
|
524
684
|
|
|
525
685
|
return $alert;
|
|
526
686
|
}
|
|
527
687
|
|
|
528
688
|
/**
|
|
529
|
-
*
|
|
530
|
-
* @param element
|
|
531
|
-
* @param params
|
|
689
|
+
* Статический метод инициализации формы
|
|
690
|
+
* @param {HTMLElement} element - Форма
|
|
691
|
+
* @param {Object} params - Параметры
|
|
692
|
+
* @example
|
|
693
|
+
* VGFormSender.init(formElement, { validate: true });
|
|
532
694
|
*/
|
|
533
695
|
static init(element, params = {}) {
|
|
534
696
|
const instance = VGFormSender.getOrCreateInstance(element, params);
|
|
535
697
|
instance.build();
|
|
536
698
|
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Подписка на события кнопки формы
|
|
702
|
+
* @param {string} formID - CSS-селектор формы
|
|
703
|
+
* @param {Function} callback - Колбэк-функция
|
|
704
|
+
* @param {'before'|'after'} status - Статус события
|
|
705
|
+
* @example
|
|
706
|
+
* VGFormSender.buttonClick('#myForm', (form, instance) => { ... }, 'before');
|
|
707
|
+
*/
|
|
708
|
+
static buttonClick(formID, callback, status = 'before') {
|
|
709
|
+
const form = Selectors.find(formID);
|
|
710
|
+
if (form) {
|
|
711
|
+
const instance = VGFormSender.getOrCreateInstance(form);
|
|
712
|
+
form.addEventListener('vg.fs.' + status, e => {
|
|
713
|
+
execute(callback, [form, instance])
|
|
714
|
+
})
|
|
715
|
+
}
|
|
716
|
+
}
|
|
537
717
|
}
|
|
538
718
|
|
|
719
|
+
/**
|
|
720
|
+
* Обработчик события отправки формы
|
|
721
|
+
*/
|
|
539
722
|
EventHandler.on(document, EVENT_SUBMIT_DATA_API, function (event) {
|
|
540
723
|
if (!Manipulator.has(event.target, 'data-vgformsender')) {
|
|
541
724
|
return;
|