PageSourceSearch

https://revistapantalla.com/wp-content/plugins/extensions-for-elem…/js/shared/mask-validators.js?ver=2.7.7

js revistapantalla.com collected 2026-10-02 10:22:19 UTC 18,102 bytes, 623 lines download raw bytes

1/**
2 * Shared input-mask validation helpers (Elementor Pro, Cool Form, Hello Plus, Atomic Form).
3 */
4window.CFKEF = window.CFKEF || {};
5
6window.CFKEF.MaskValidators = (function () {
7	'use strict';
8
9	function isValidPhoneUSA(phoneStr) {
10		return /^\(\d{3}\) \d{3}-\d{4}$/.test(phoneStr);
11	}
12
13	function isValidPhone8(phoneStr) {
14		return /^\d{4}-\d{4}$/.test(phoneStr);
15	}
16
17	function isValidPhoneDDD8(phoneStr) {
18		return /^\(\d{2}\) \d{4}-\d{4}$/.test(phoneStr);
19	}
20
21	function isValidPhoneDDD9(phoneStr) {
22		return /^\(\d{2}\) 9\d{4}-\d{4}$/.test(phoneStr);
23	}
24
25	function isValidDateTime(value, format) {
26		var regexPattern;
27		var expectedParts;
28
29		switch (format) {
30			case 'DMY':
31				regexPattern = /^(\d{2})\/(\d{2})\/(\d{4})$/;
32				expectedParts = ['day', 'month', 'year'];
33				break;
34			case 'MDY':
35				regexPattern = /^(\d{2})\/(\d{2})\/(\d{4})$/;
36				expectedParts = ['month', 'day', 'year'];
37				break;
38			case 'HMS':
39				regexPattern = /^(\d{2}):(\d{2}):(\d{2})$/;
40				expectedParts = ['hour', 'minute', 'second'];
41				break;
42			case 'HM':
43				regexPattern = /^(\d{2}):(\d{2})$/;
44				expectedParts = ['hour', 'minute'];
45				break;
46			case 'DMY-HM':
47				regexPattern = /^(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2})$/;
48				expectedParts = ['day', 'month', 'year', 'hour', 'minute'];
49				break;
50			case 'MDY-HM':
51				regexPattern = /^(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2})$/;
52				expectedParts = ['month', 'day', 'year', 'hour', 'minute'];
53				break;
54			case 'MY':
55				regexPattern = /^(\d{2})\/(\d{4})$/;
56				expectedParts = ['month', 'year'];
57				break;
58			default:
59				return false;
60		}
61
62		var match = value.match(regexPattern);
63		if (!match) {
64			return false;
65		}
66
67		var parts = {};
68		expectedParts.forEach(function (part, index) {
69			parts[part] = parseInt(match[index + 1], 10);
70		});
71
72		if (parts.year && (parts.year < 1500 || parts.year > 3000)) {
73			return false;
74		}
75		if (parts.month && (parts.month < 1 || parts.month > 12)) {
76			return false;
77		}
78		if (parts.day) {
79			var daysInMonth = new Date(parts.year, parts.month, 0).getDate();
80			if (parts.day < 1 || parts.day > daysInMonth) {
81				return false;
82			}
83		}
84		if (parts.hour && (parts.hour < 0 || parts.hour >= 24)) {
85			return false;
86		}
87		if (parts.minute && (parts.minute < 0 || parts.minute >= 60)) {
88			return false;
89		}
90		if (parts.second && (parts.second < 0 || parts.second >= 60)) {
91			return false;
92		}
93
94		return true;
95	}
96
97	function isValidExpiryDate(value, format) {
98		var regexPattern = format === 'MM/YY' ? /^(\d{2})\/(\d{2})$/ : /^(\d{2})\/(\d{4})$/;
99		var match = value.match(regexPattern);
100		if (!match) {
101			return false;
102		}
103
104		var month = parseInt(match[1], 10);
105		var year = parseInt(match[2], 10);
106		var currentYear = new Date().getFullYear();
107		var currentMonth = new Date().getMonth() + 1;
108
109		if (format === 'MM/YY') {
110			year += 2000;
111		}
112		if (month < 1 || month > 12) {
113			return false;
114		}
115		if (year < currentYear || (year === currentYear && month < currentMonth)) {
116			return false;
117		}
118		return true;
119	}
120
121	function isValidCreditCard(cardNumber) {
122		var cleaned = String(cardNumber).replace(/\D/g, '');
123		if (cleaned.length < 15 || cleaned.length > 16) {
124			return false;
125		}
126		var sum = 0;
127		var shouldDouble = false;
128		for (var i = cleaned.length - 1; i >= 0; i--) {
129			var digit = parseInt(cleaned.charAt(i), 10);
130			if (shouldDouble) {
131				digit *= 2;
132				if (digit > 9) {
133					digit -= 9;
134				}
135			}
136			sum += digit;
137			shouldDouble = !shouldDouble;
138		}
139		return sum % 10 === 0;
140	}
141
142	function isValidCNPJ(cnpj) {
143		cnpj = String(cnpj).toUpperCase().replace(/[.\-\/]/g, '');
144		if (!/^[A-Z0-9]{12}\d{2}$/.test(cnpj)) {
145			return false;
146		}
147		if (/^(.)\1{13}$/.test(cnpj)) {
148			return false;
149		}
150		var calcCheckDigit = function (str, length) {
151			var weights = length === 12
152				? [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
153				: [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
154			var s = 0;
155			for (var i = 0; i < weights.length; i++) {
156				s += (str.charCodeAt(i) - 48) * weights[i];
157			}
158			var remainder = s % 11;
159			return remainder < 2 ? 0 : 11 - remainder;
160		};
161		var firstCheck = calcCheckDigit(cnpj, 12);
162		var secondCheck = calcCheckDigit(cnpj.slice(0, 12) + firstCheck, 13);
163		return firstCheck === parseInt(cnpj.charAt(12), 10) && secondCheck === parseInt(cnpj.charAt(13), 10);
164	}
165
166	function isValidCPF(cpf) {
167		cpf = String(cpf).replace(/\D/g, '');
168		if (cpf.length !== 11) {
169			return false;
170		}
171		if (/^(\d)\1+$/.test(cpf)) {
172			return false;
173		}
174		var validateCPFDigit = function (str, length) {
175			var s = 0;
176			for (var i = 0; i < length; i++) {
177				s += parseInt(str.charAt(i), 10) * (length + 1 - i);
178			}
179			var result = (s * 10) % 11;
180			if (result === 10) {
181				result = 0;
182			}
183			return result === parseInt(str.charAt(length), 10);
184		};
185		return validateCPFDigit(cpf, 9) && validateCPFDigit(cpf, 10);
186	}
187
188	function isValidCEP(cep) {
189		return /^\d{5}-\d{3}$/.test(cep);
190	}
191
192	function isValidIPv4(ip) {
193		var ipv4Pattern = /^(?:\d{1,3}\.){3}\d{1,3}$/;
194		if (!ipv4Pattern.test(ip)) {
195			return false;
196		}
197		return ip.split('.').every(function (octet) {
198			var num = parseInt(octet, 10);
199			return num >= 0 && num <= 255;
200		});
201	}
202
203		return {
204		isValidPhoneUSA: isValidPhoneUSA,
205		isValidPhone8: isValidPhone8,
206		isValidPhoneDDD8: isValidPhoneDDD8,
207		isValidPhoneDDD9: isValidPhoneDDD9,
208		isValidDateTime: isValidDateTime,
209		isValidExpiryDate: isValidExpiryDate,
210		isValidDateDMY: function (v) { return isValidDateTime(v, 'DMY'); },
211		isValidDateMDY: function (v) { return isValidDateTime(v, 'MDY'); },
212		isValidTimeHMS: function (v) { return isValidDateTime(v, 'HMS'); },
213		isValidTimeHM: function (v) { return isValidDateTime(v, 'HM'); },
214		isValidDateDMYHM: function (v) { return isValidDateTime(v, 'DMY-HM'); },
215		isValidDateMDYHM: function (v) { return isValidDateTime(v, 'MDY-HM'); },
216		isValidDateMY: function (v) { return isValidDateTime(v, 'MY'); },
217		isValidExpiryMMYY: function (v) { return isValidExpiryDate(v, 'MM/YY'); },
218		isValidExpiryMMYYYY: function (v) { return isValidExpiryDate(v, 'MM/YYYY'); },
219		isValidCreditCard: isValidCreditCard,
220		isValidCNPJ: isValidCNPJ,
221		isValidCPF: isValidCPF,
222		isValidCEP: isValidCEP,
223		isValidIPv4: isValidIPv4,
224	};
225})();
226
227CFKEF.getMaskValidationDefs = function () {
228	var MV = CFKEF.MaskValidators || {};
229	return [
230		{ sel: '.mask-cnpj', errorClass: 'error-cnpj', validate: MV.isValidCNPJ, key: 'mask-cnpj' },
231		{ sel: '.mask-cpf', errorClass: 'error-cpf', validate: MV.isValidCPF, key: 'mask-cpf' },
232		{ sel: '.mask-cep', errorClass: 'error-cep', validate: MV.isValidCEP, key: 'mask-cep' },
233		{ sel: '.mask-phus', errorClass: 'error-phus', validate: MV.isValidPhoneUSA, key: 'mask-phus' },
234		{ sel: '.mask-ph8', errorClass: 'error-ph8', validate: MV.isValidPhone8, key: 'mask-ph8' },
235		{ sel: '.mask-ddd8', errorClass: 'error-ddd8', validate: MV.isValidPhoneDDD8, key: 'mask-ddd8' },
236		{ sel: '.mask-ddd9', errorClass: 'error-ddd9', validate: MV.isValidPhoneDDD9, key: 'mask-ddd9' },
237		{ sel: '.mask-dmy', errorClass: 'error-dmy', validate: MV.isValidDateDMY, key: 'mask-dmy' },
238		{ sel: '.mask-mdy', errorClass: 'error-mdy', validate: MV.isValidDateMDY, key: 'mask-mdy' },
239		{ sel: '.mask-hms', errorClass: 'error-hms', validate: MV.isValidTimeHMS, key: 'mask-hms' },
240		{ sel: '.mask-hm', errorClass: 'error-hm', validate: MV.isValidTimeHM, key: 'mask-hm' },
241		{ sel: '.mask-dmyhm', errorClass: 'error-dmyhm', validate: MV.isValidDateDMYHM, key: 'mask-dmyhm' },
242		{ sel: '.mask-mdyhm', errorClass: 'error-mdyhm', validate: MV.isValidDateMDYHM, key: 'mask-mdyhm' },
243		{ sel: '.mask-my', errorClass: 'error-my', validate: MV.isValidDateMY, key: 'mask-my' },
244		{ sel: '.mask-ccs', errorClass: 'error-ccs', validate: MV.isValidCreditCard, key: 'mask-ccs' },
245		{ sel: '.mask-cch', errorClass: 'error-cch', validate: MV.isValidCreditCard, key: 'mask-cch' },
246		{ sel: '.mask-ccmy', errorClass: 'error-ccmy', validate: MV.isValidExpiryMMYY, key: 'mask-ccmy' },
247		{ sel: '.mask-ccmyy', errorClass: 'error-ccmyy', validate: MV.isValidExpiryMMYYYY, key: 'mask-ccmyy' },
248		{ sel: '.mask-ipv4', errorClass: 'error-ipv4', validate: MV.isValidIPv4, key: 'mask-ipv4' },
249	];
250};
251
252/**
253 * Resolve the .mask-error node for an input.
254 *
255 * @param {jQuery} $
256 * @param {jQuery} $input
257 * @param {string} errorClass
258 * @param {Object} [opts]
259 * @param {Function} [opts.resolveErrorElement]
260 * @return {jQuery}
261 */
262CFKEF.resolveMaskErrorElement = function ($, $input, errorClass, opts) {
263	opts = opts || {};
264	if ($input.hasClass('hide-fme-mask-input')) {
265		return $();
266	}
267	if (typeof opts.resolveErrorElement === 'function') {
268		return opts.resolveErrorElement($input, errorClass);
269	}
270	if ($input.hasClass('cool-form__field')) {
271		return $input.closest('.cool-form__field-group').find('.' + errorClass);
272	}
273	if ($input.hasClass('ehp-form__field')) {
274		return $input.closest('.ehp-form__field-group').find('.' + errorClass);
275	}
276	return $input.closest('.elementor-field-group').find('.' + errorClass);
277};
278
279/**
280 * Find mask validation def matching an input's classes.
281 *
282 * @param {jQuery} $input
283 * @return {Object|null}
284 */
285CFKEF.findMaskDefForInput = function ($input) {
286	var defs = CFKEF.getMaskValidationDefs();
287	for (var i = 0; i < defs.length; i++) {
288		var cls = defs[i].sel.replace(/^\./, '');
289		if ($input.hasClass(cls)) {
290			return defs[i];
291		}
292	}
293	return null;
294};
295
296/**
297 * Bind blur/input validation for one mask selector.
298 *
299 * @param {jQuery} $
300 * @param {string} selector
301 * @param {string} errorClass
302 * @param {Function} validationFunction
303 * @param {string} errorMessage
304 * @param {Object} [opts]
305 */
306CFKEF.bindMaskFieldValidation = function ($, selector, errorClass, validationFunction, errorMessage, opts) {
307	opts = opts || {};
308
309	$(document).on('blur', selector, function () {
310		var $input = $(this);
311		if (typeof opts.shouldHandle === 'function' && !opts.shouldHandle($input)) {
312			return;
313		}
314		if ($input.hasClass('hide-fme-mask-input')) {
315			return;
316		}
317
318		var val = $input.val();
319		var $errorEl = CFKEF.resolveMaskErrorElement($, $input, errorClass, opts);
320
321		if (String(val).length === 1 && !/\d/.test(val)) {
322			$input.val('');
323			$errorEl.hide().text('');
324			return;
325		}
326
327		if (val !== '' && !validationFunction(val)) {
328			$errorEl.text(errorMessage).css('display', 'flex').hide().fadeIn(200);
329		} else {
330			$errorEl.fadeOut(100, function () {
331				$(this).css('display', 'none');
332			});
333		}
334	});
335
336	$(document).on('input', selector, function () {
337		var $input = $(this);
338		if (typeof opts.shouldHandle === 'function' && !opts.shouldHandle($input)) {
339			return;
340		}
341		if (typeof opts.onInput === 'function') {
342			opts.onInput($input, errorClass, validationFunction);
343		}
344
345		var $errorEl = CFKEF.resolveMaskErrorElement($, $input, errorClass, opts);
346		if ($errorEl.is(':visible')) {
347			var val = $input.val();
348			if (validationFunction(val)) {
349				$errorEl.fadeOut(100, function () {
350					$(this).css('display', 'none');
351				});
352			}
353		}
354	});
355};
356
357/**
358 * Bind blur/input validation for all shared mask defs.
359 *
360 * @param {jQuery} $
361 * @param {Object} [opts]
362 */
363CFKEF.bindAllMaskValidations = function ($, opts) {
364	opts = opts || {};
365	var msgs = opts.errorMessages || (window.fmeData && window.fmeData.errorMessages) || {};
366	var defs = CFKEF.getMaskValidationDefs();
367
368	defs.forEach(function (def) {
369		if (typeof def.validate !== 'function') {
370			return;
371		}
372		CFKEF.bindMaskFieldValidation(
373			$,
374			def.sel,
375			def.errorClass,
376			def.validate,
377			msgs[def.key] || def.key,
378			opts
379		);
380	});
381};
382
383/**
384 * Actively validate mask inputs in a form; show errors and optionally scroll.
385 *
386 * @param {jQuery} $
387 * @param {jQuery} $form
388 * @param {Object} [opts]
389 * @return {boolean} true if submit must be blocked
390 */
391CFKEF.maskValidationBlocksSubmit = function ($, $form, opts) {
392	opts = opts || {};
393	var msgs = opts.errorMessages || (window.fmeData && window.fmeData.errorMessages) || {};
394	var blocked = false;
395	var $scrollTarget = null;
396	var inputSelector = opts.inputSelector || 'input.fme-mask-input';
397
398	$form.find(inputSelector).not('.hide-fme-mask-input').each(function () {
399		var $inp = $(this);
400		if (typeof opts.shouldValidate === 'function' && !opts.shouldValidate($inp)) {
401			return;
402		}
403
404		var val = String($inp.val() || '').trim();
405		if (val.length === 1 && !/\d/.test(val)) {
406			$inp.val('');
407			val = '';
408		}
409
410		var def = CFKEF.findMaskDefForInput($inp);
411		if (!def || typeof def.validate !== 'function') {
412			return;
413		}
414
415		var $err = CFKEF.resolveMaskErrorElement($, $inp, def.errorClass, opts);
416		if (val !== '' && !def.validate(val)) {
417			$err.text(msgs[def.key] || def.key).css('display', 'flex').show();
418			blocked = true;
419			if (!$scrollTarget || !$scrollTarget.length) {
420				$scrollTarget = $err;
421			}
422		} else {
423			$err.text('').hide().css('display', 'none');
424		}
425	});
426
427	if (blocked && $scrollTarget && $scrollTarget.length && opts.scroll !== false) {
428		var off = $scrollTarget.offset();
429		if (off) {
430			$('html, body').animate({ scrollTop: off.top - (opts.scrollOffset || 200) }, opts.scrollDuration || 300);
431		}
432	}
433
434	return blocked;
435};
436
437/**
438 * Shared Cool Form / Hello Plus (and similar) mask submit click guard.
439 *
440 * @param {jQuery} $
441 * @param {string} selector
442 * @param {Object} [opts]
443 */
444CFKEF.bindMaskSubmitGuard = function ($, selector, opts) {
445	opts = opts || {};
446	var delay = opts.delay != null ? opts.delay : 400;
447	var preventDefaultAlways = !!opts.preventDefaultAlways;
448	var checkRequiredEmpty = !!opts.checkRequiredEmpty;
449	var addWaitingClass = !!opts.addWaitingClass;
450	var checkHtml5Validity = !!opts.checkHtml5Validity;
451	var scrollOffset = opts.scrollOffset || 200;
452	var scrollDuration = opts.scrollDuration || 400;
453	var errorDisplayFlex = !!opts.errorDisplayFlex;
454	var onBefore = typeof opts.onBefore === 'function' ? opts.onBefore : null;
455	var onAfterValid = typeof opts.onAfterValid === 'function' ? opts.onAfterValid : null;
456	var onBlocked = typeof opts.onBlocked === 'function' ? opts.onBlocked : null;
457	var shouldHandle = typeof opts.shouldHandle === 'function' ? opts.shouldHandle : null;
458
459	$(document).on('click', selector, function (e) {
460		var $submitBtn = $(this);
461
462		if (shouldHandle && !shouldHandle($submitBtn, e)) {
463			return;
464		}
465
466		if (preventDefaultAlways) {
467			e.preventDefault();
468		}
469
470		var $form = $submitBtn.closest('form');
471
472		if ($submitBtn.data('clicked')) {
473			e.preventDefault();
474			return;
475		}
476		$submitBtn.data('clicked', true);
477
478		if (onBefore) {
479			onBefore($submitBtn, $form, e);
480		}
481
482		$form.find('input').trigger('blur');
483		if (addWaitingClass && $form[0]) {
484			$form[0].classList.add('elementor-form-waiting');
485		}
486
487		setTimeout(function () {
488			var hasError = false;
489			var $errors = $form.find('.mask-error').filter(function () {
490				var visible = errorDisplayFlex
491					? $(this).css('display') === 'flex'
492					: $(this).is(':visible');
493				return $(this).text().trim() !== '' && visible;
494			});
495
496			if ($errors.length > 0) {
497				hasError = true;
498				$('html, body').animate(
499					{ scrollTop: $errors.first().offset().top - scrollOffset },
500					scrollDuration
501				);
502			}
503
504			if (checkRequiredEmpty) {
505				var $emptyRequiredMasked = $form.find('input[required]').filter(function () {
506					if ($(this).hasClass('hide-fme-mask-input')) {
507						return false;
508					}
509					var val = String($(this).val() || '').trim();
510					var isVisible = errorDisplayFlex
511						? $(this).css('display') === 'flex'
512						: $(this).is(':visible');
513					return isVisible && (val === '' || /^[\s_\-\(\)\.:/]+$/.test(val));
514				});
515
516				if ($emptyRequiredMasked.length > 0) {
517					hasError = true;
518					$('html, body').animate(
519						{ scrollTop: $emptyRequiredMasked.first().offset().top - scrollOffset },
520						scrollDuration
521					);
522					$emptyRequiredMasked.first().focus();
523				}
524			}
525
526			if (hasError || (checkHtml5Validity && $form[0] && !$form[0].checkValidity())) {
527				if (addWaitingClass && $form[0]) {
528					$form[0].classList.remove('elementor-form-waiting');
529				}
530				$submitBtn.data('clicked', false);
531				e.preventDefault();
532				if (onBlocked) {
533					onBlocked($submitBtn, $form, e);
534				}
535				return;
536			}
537
538			if (addWaitingClass && $form[0]) {
539				$form[0].classList.remove('elementor-form-waiting');
540			}
541
542			if (onAfterValid) {
543				onAfterValid($submitBtn, $form, e);
544				$submitBtn.data('clicked', false);
545				return;
546			}
547
548			if ($form[0] && typeof $form[0].requestSubmit === 'function') {
549				$form[0].requestSubmit();
550			}
551			$submitBtn.data('clicked', false);
552		}, delay);
553	});
554};
555
556/**
557 * Atomic-style form submit guard: validate masks then allow one re-entrant submit.
558 *
559 * @param {jQuery} $
560 * @param {Object} [opts]
561 */
562CFKEF.bindMaskAllowOnceSubmitGuard = function ($, opts) {
563	opts = opts || {};
564	if (CFKEF._maskAllowOnceSubmitGuardBound) {
565		return;
566	}
567	CFKEF._maskAllowOnceSubmitGuardBound = true;
568
569	var formMatch = typeof opts.formMatch === 'function' ? opts.formMatch : function () { return true; };
570	var hasMaskInputs = typeof opts.hasMaskInputs === 'function'
571		? opts.hasMaskInputs
572		: function ($form) {
573			return $form.find('input.fme-mask-input').not('.hide-fme-mask-input').length > 0;
574		};
575	var validate = typeof opts.validate === 'function' ? opts.validate : function ($form) {
576		return CFKEF.maskValidationBlocksSubmit($, $form, opts);
577	};
578	var clickSelector = opts.clickSelector || 'button[type="submit"]';
579	var allowOnce = false;
580
581	$(document).on('submit', 'form', function (e) {
582		var formEl = this;
583		var $form = $(formEl);
584		if (!formMatch($form)) {
585			return;
586		}
587		if (!hasMaskInputs($form)) {
588			return;
589		}
590
591		if (allowOnce) {
592			allowOnce = false;
593			return;
594		}
595
596		if (validate($form)) {
597			e.preventDefault();
598			e.stopImmediatePropagation();
599			return;
600		}
601
602		e.preventDefault();
603		e.stopImmediatePropagation();
604		if (typeof formEl.requestSubmit === 'function') {
605			allowOnce = true;
606			formEl.requestSubmit();
607		} else {
608			formEl.submit();
609		}
610	});
611
612	$(document).on('click', clickSelector, function (e) {
613		var $btn = $(this);
614		var $form = $btn.closest('form');
615		if (!$form.length || !formMatch($form) || !hasMaskInputs($form)) {
616			return;
617		}
618		if (validate($form)) {
619			e.preventDefault();
620			e.stopPropagation();
621		}
622	});
623};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.