@alexsab-ru/scripts 0.15.1 → 0.15.3
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/lib/form.js +108 -28
- package/package.json +1 -1
package/lib/form.js
CHANGED
|
@@ -6,34 +6,51 @@ export const noValidPhone = (phoneValue) => {
|
|
|
6
6
|
return ([...new Set(phoneValue.replace(/^(\+7)/g, "").replace(/\D/g, ""))].length === 1);
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
export const maskphone = (e) => {
|
|
10
|
+
const input = e.currentTarget;
|
|
11
|
+
let num = input.value.replace(/^(\+7|8|7)/g, "").replace(/\D/g, "").split(/(?=.)/);
|
|
12
|
+
const i = num.length;
|
|
12
13
|
|
|
13
|
-
if(
|
|
14
|
+
if (input.value !== "" && input.value !== "+") {
|
|
14
15
|
if (0 <= i) num.unshift("+7");
|
|
15
16
|
if (1 <= i) num.splice(1, 0, " ");
|
|
16
17
|
if (4 <= i) num.splice(5, 0, " ");
|
|
17
18
|
if (7 <= i) num.splice(9, 0, "-");
|
|
18
19
|
if (9 <= i) num.splice(12, 0, "-");
|
|
19
|
-
|
|
20
|
+
input.value = num.join("");
|
|
20
21
|
}
|
|
21
|
-
}
|
|
22
|
+
};
|
|
23
|
+
|
|
22
24
|
|
|
25
|
+
export const phoneChecker = (phone, options = {}) => {
|
|
26
|
+
// Опция silent:
|
|
27
|
+
// - true => функция работает в "тихом" режиме (НЕ показывает сообщения), возвращает только true|false
|
|
28
|
+
// - false => ведёт себя как раньше: показывает разные сообщения об ошибках
|
|
29
|
+
const { silent = false } = options;
|
|
23
30
|
|
|
24
|
-
export const phoneChecker = (phone) => {
|
|
25
31
|
let form = phone.closest("form");
|
|
32
|
+
|
|
33
|
+
// Пустое значение
|
|
26
34
|
if (!phone.value.length) {
|
|
27
|
-
|
|
35
|
+
if (!silent && form) {
|
|
36
|
+
showErrorMes(form, ".phone", "Телефон является обязательным полем");
|
|
37
|
+
}
|
|
28
38
|
return false;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Формат и анти-флуд (одинаковые цифры)
|
|
42
|
+
const phoneRe = new RegExp(/^\+7 [0-9]{3} [0-9]{3}-[0-9]{2}-[0-9]{2}$/);
|
|
43
|
+
if (!phoneRe.test(phone.value) || noValidPhone(phone.value)) {
|
|
44
|
+
if (!silent && form) {
|
|
32
45
|
showErrorMes(form, ".phone", "Введен некорректный номер телефона");
|
|
33
|
-
return false;
|
|
34
46
|
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Валидно — в шумном режиме прячем текст ошибки
|
|
51
|
+
if (!silent && form) {
|
|
52
|
+
showErrorMes(form, ".phone", "");
|
|
35
53
|
}
|
|
36
|
-
showErrorMes(form, ".phone", "");
|
|
37
54
|
return true;
|
|
38
55
|
};
|
|
39
56
|
|
|
@@ -62,12 +79,18 @@ const stateBtn = (btn, value, disable = false) => {
|
|
|
62
79
|
}
|
|
63
80
|
};
|
|
64
81
|
|
|
82
|
+
// Показ сообщения об ошибке
|
|
65
83
|
export const showErrorMes = (form, el, text) => {
|
|
66
84
|
let field = form.querySelector(el);
|
|
85
|
+
if (!field) {
|
|
86
|
+
console.warn('showErrorMes: element not found', { selector: el, form });
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
67
89
|
field.innerText = text;
|
|
68
90
|
field.classList.remove("hidden");
|
|
69
91
|
};
|
|
70
92
|
|
|
93
|
+
// Показ модального окна с сообщением об успехе/ошибке
|
|
71
94
|
export const showMessageModal = (messageModal, icon, message) => {
|
|
72
95
|
document.querySelectorAll(".modal-overlay").forEach((el) => {
|
|
73
96
|
el.classList.add("hidden");
|
|
@@ -99,6 +122,7 @@ export const messageModal = document.getElementById("message-modal");
|
|
|
99
122
|
export const connectForms = (url, props = propsParams) => {
|
|
100
123
|
props = {...propsParams, ...props};
|
|
101
124
|
|
|
125
|
+
|
|
102
126
|
document.querySelectorAll("input[name=phone]").forEach(function (element) {
|
|
103
127
|
// element.addEventListener("focus", maskphone);
|
|
104
128
|
element.addEventListener("input", maskphone);
|
|
@@ -137,7 +161,8 @@ export const connectForms = (url, props = propsParams) => {
|
|
|
137
161
|
}
|
|
138
162
|
});
|
|
139
163
|
|
|
140
|
-
|
|
164
|
+
|
|
165
|
+
const submitForm = async (form) => {
|
|
141
166
|
const btn = form.querySelector('[type="submit"]');
|
|
142
167
|
const btnText = btn.value || btn.innerText;
|
|
143
168
|
const agree = form.querySelector('[name="' + props.agreeSelector + '"]');
|
|
@@ -145,26 +170,81 @@ async function submitForm(form){
|
|
|
145
170
|
const name = form.querySelector('[name="name"]');
|
|
146
171
|
const dealer = form.querySelector('[name="dealer"]');
|
|
147
172
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
173
|
+
let validate;
|
|
174
|
+
|
|
175
|
+
// Валидируем форму. Поддерживаем 2 кейса:
|
|
176
|
+
// 1) Пользователь передал класс (конструктор), который имеет метод validate() или run() или поле isValid
|
|
177
|
+
// 2) Пользователь передал функцию, возвращающую boolean или объект с isValid
|
|
178
|
+
if (props.validation && typeof props.validation === 'function') {
|
|
179
|
+
try {
|
|
180
|
+
let instance;
|
|
181
|
+
let result;
|
|
182
|
+
|
|
183
|
+
// Пытаемся создать экземпляр (если передан класс). Если не конструктор — вызовем как функцию ниже
|
|
184
|
+
try {
|
|
185
|
+
instance = new props.validation(form);
|
|
186
|
+
} catch (e) {
|
|
187
|
+
// Если это не конструктор (например, стрелочная функция), пробуем вызвать как обычную функцию
|
|
188
|
+
result = props.validation(form);
|
|
189
|
+
}
|
|
151
190
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
191
|
+
// Если есть экземпляр, пробуем стандартные методы
|
|
192
|
+
if (instance) {
|
|
193
|
+
if (typeof instance.validate === 'function') {
|
|
194
|
+
result = await instance.validate();
|
|
195
|
+
} else if (typeof instance.run === 'function') {
|
|
196
|
+
result = await instance.run();
|
|
197
|
+
} else if (typeof instance.isValid !== 'undefined') {
|
|
198
|
+
result = { isValid: instance.isValid };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Нормализуем результат к виду { isValid: boolean }
|
|
203
|
+
if (typeof result === 'boolean') {
|
|
204
|
+
validate = { isValid: result };
|
|
205
|
+
} else if (result && typeof result === 'object' && 'isValid' in result) {
|
|
206
|
+
validate = { isValid: Boolean(result.isValid) };
|
|
207
|
+
} else if (instance && typeof instance.isValid !== 'undefined') {
|
|
208
|
+
validate = { isValid: Boolean(instance.isValid) };
|
|
209
|
+
} else {
|
|
210
|
+
// Если валидатор ничего не вернул, считаем, что он сам показал ошибки и блокируем отправку
|
|
211
|
+
validate = { isValid: false };
|
|
212
|
+
}
|
|
213
|
+
} catch (err) {
|
|
214
|
+
// Если кастомный валидатор упал — показываем в консоли и блокируем отправку, чтобы не уйти с невалидной формой
|
|
215
|
+
console.error('Validation error:', err);
|
|
216
|
+
validate = { isValid: false };
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
// Базовые проверки, если кастомный валидатор не передан
|
|
220
|
+
if (!phoneChecker(phone)) {
|
|
155
221
|
return;
|
|
156
222
|
}
|
|
157
|
-
|
|
223
|
+
|
|
224
|
+
if(dealer && dealer.hasAttribute('required')){
|
|
225
|
+
if(!dealer.value){
|
|
226
|
+
showErrorMes(form, '.dealer', 'Выберите дилерский центр');
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
158
230
|
|
|
159
|
-
|
|
160
|
-
|
|
231
|
+
// agree обязателен: если не найден или не отмечен — показываем ошибку
|
|
232
|
+
if (!agree || !agree.checked) {
|
|
233
|
+
showErrorMes(form, "." + props.agreeSelector, "Чтобы продолжить, установите флажок");
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Иначе считаем форму валидной
|
|
238
|
+
validate = { isValid: true };
|
|
161
239
|
}
|
|
162
240
|
|
|
163
|
-
//
|
|
164
|
-
if (!
|
|
165
|
-
showErrorMes(form, "." + props.agreeSelector, "Чтобы продолжить, установите флажок");
|
|
241
|
+
// Если форма невалидна (isValid === false), прекращаем отправку
|
|
242
|
+
if (!validate.isValid) {
|
|
166
243
|
return;
|
|
167
|
-
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// если флажок установлен - устанавливаем куки (проверяем на наличие agree)
|
|
247
|
+
if (agree && agree.checked) {
|
|
168
248
|
setAgreeCookie(90);
|
|
169
249
|
}
|
|
170
250
|
|
|
@@ -277,7 +357,7 @@ async function submitForm(form){
|
|
|
277
357
|
deleteCookie(sendMailCookie);
|
|
278
358
|
// Вызов callback_error при ошибке
|
|
279
359
|
if (props.callback_error && typeof props.callback_error === 'function') {
|
|
280
|
-
props.callback_error(
|
|
360
|
+
props.callback_error(error);
|
|
281
361
|
} else if (messageModal) {
|
|
282
362
|
showMessageModal(messageModal, errorIcon, errorText + "<br>" + error);
|
|
283
363
|
}
|