PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.1
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | js/formidable.js +657 -1205 6.255.1 View file →
@@ -1,44 +1,33 @@
1 -/* exported frmRecaptcha, frmAfterRecaptcha */
2 -/* eslint-disable prefer-const */
1 +/* exported frmRecaptcha, frmAfterRecaptcha, frmUpdateField, frmDeleteEntry, frmOnSubmit, frm_resend_email */
3 2
3 +var frmFrontForm;
4 +
4 5 function frmFrontFormJS() {
5 6 'use strict';
6 7
7 - /*global jQuery:false, frm_js, grecaptcha, hcaptcha, turnstile, frmProForm, tinyMCE */
8 + /*global jQuery:false, frm_js, grecaptcha, frmProForm, tinyMCE */
8 9 /*global frmThemeOverride_jsErrors, frmThemeOverride_frmPlaceError, frmThemeOverride_frmAfterSubmit */
9 10
10 - let jsErrors = [];
11 + var action = '';
12 + var jsErrors = [];
11 13
12 - /**
13 - * Triggers custom JS event.
14 - *
15 - * @since 5.5.3
16 - *
17 - * @param {HTMLElement} el The HTML element.
18 - * @param {string} eventName Event name.
19 - * @param {*} data The passed data.
20 - */
21 - function triggerCustomEvent( el, eventName, data ) {
22 - if ( typeof window.CustomEvent !== 'function' ) {
23 - return;
14 + function maybeShowLabel() {
15 + /*jshint validthis:true */
16 + var $field = jQuery( this ),
17 + $label = $field.closest( '.frm_inside_container' ).find( '.frm_primary_label' ),
18 + val = $field.val();
19 +
20 + if ( val !== null && val.length > 0 ) {
21 + $label.addClass( 'frm_visible' );
22 + } else {
23 + $label.removeClass( 'frm_visible' );
24 24 }
25 -
26 - const event = new CustomEvent( eventName );
27 - event.frmData = data;
28 -
29 - el.dispatchEvent( event );
30 25 }
31 26
32 - /**
33 - * Get the ID of the field that changed.
34 - *
35 - * @param {HTMLElement|jQuery} field
36 - * @param {boolean} fullID
37 - * @return {string|number} Field ID.
38 - */
27 + /* Get the ID of the field that changed*/
39 28 function getFieldId( field, fullID ) {
40 - let nameParts, fieldId,
29 + var nameParts, fieldId,
41 30 isRepeating = false,
42 31 fieldName = '';
43 32 if ( field instanceof jQuery ) {
44 33 fieldName = field.attr( 'name' );
@@ -73,24 +62,25 @@
73 62 return 0;
74 63 }
75 64 nameParts = nameParts.filter( function( n ) {
76 65 return n !== '';
77 - } );
66 + });
78 67
79 - fieldId = nameParts[ 0 ];
68 + fieldId = nameParts[0];
80 69
81 70 if ( nameParts.length === 1 ) {
82 71 return fieldId;
83 72 }
84 73
85 - if ( nameParts[ 1 ] === '[form' || nameParts[ 1 ] === '[row_ids' ) {
74 + if ( nameParts[1] === '[form' || nameParts[1] === '[row_ids' ) {
86 75 return 0;
87 76 }
88 77
89 78 // Check if 'this' is in a repeating section
90 - if ( document.querySelector( 'input[name="item_meta[' + fieldId + '][form]"]' ) ) {
79 + if ( jQuery( 'input[name="item_meta[' + fieldId + '][form]"]' ).length ) {
80 +
91 81 // this is a repeatable section with name: item_meta[repeating-section-id][row-id][field-id]
92 - fieldId = nameParts[ 2 ].replace( '[', '' );
82 + fieldId = nameParts[2].replace( '[', '' );
93 83 isRepeating = true;
94 84 }
95 85
96 86 // Check if 'this' is an other text field and get field ID for it
@@ -96,21 +86,21 @@
96 86 // Check if 'this' is an other text field and get field ID for it
97 87 if ( 'other' === fieldId ) {
98 88 if ( isRepeating ) {
99 89 // name for other fields: item_meta[370][0][other][414]
100 - fieldId = nameParts[ 3 ].replace( '[', '' );
90 + fieldId = nameParts[3].replace( '[', '' );
101 91 } else {
102 92 // Other field name: item_meta[other][370]
103 - fieldId = nameParts[ 1 ].replace( '[', '' );
93 + fieldId = nameParts[1].replace( '[', '' );
104 94 }
105 95 }
106 96
107 97 if ( fullID === true ) {
108 98 // For use in the container div id
109 - if ( fieldId === nameParts[ 0 ] ) {
110 - fieldId = fieldId + '-' + nameParts[ 1 ].replace( '[', '' );
99 + if ( fieldId === nameParts[0]) {
100 + fieldId = fieldId + '-' + nameParts[1].replace( '[', '' );
111 101 } else {
112 - fieldId = fieldId + '-' + nameParts[ 0 ] + '-' + nameParts[ 1 ].replace( '[', '' );
102 + fieldId = fieldId + '-' + nameParts[0] + '-' + nameParts[1].replace( '[', '' );
113 103 }
114 104 }
115 105
116 106 return fieldId;
@@ -120,12 +110,12 @@
120 110 * Disable the submit button for a given jQuery form object
121 111 *
122 112 * @since 2.03.02
123 113 *
124 - * @param {Object} $form
125 - */
114 + * @param {object} $form
115 + */
126 116 function disableSubmitButton( $form ) {
127 - $form.find( 'input[type="submit"], input[type="button"], button[type="submit"], button.frm_save_draft' ).attr( 'disabled', 'disabled' );
117 + $form.find( 'input[type="submit"], input[type="button"], button[type="submit"]' ).attr( 'disabled', 'disabled' );
128 118 }
129 119
130 120 /**
131 121 * Enable the submit button for a given jQuery form object
@@ -131,10 +121,10 @@
131 121 * Enable the submit button for a given jQuery form object
132 122 *
133 123 * @since 2.03.02
134 124 *
135 - * @param {Object} $form
136 - */
125 + * @param {object} $form
126 + */
137 127 function enableSubmitButton( $form ) {
138 128 $form.find( 'input[type="submit"], input[type="button"], button[type="submit"]' ).prop( 'disabled', false );
139 129 }
140 130
@@ -142,9 +132,9 @@
142 132 * Disable the save draft link for a given jQuery form object
143 133 *
144 134 * @since 4.04.03
145 135 *
146 - * @param {Object} $form
136 + * @param {object} $form
147 137 */
148 138 function disableSaveDraft( $form ) {
149 139 $form.find( 'a.frm_save_draft' ).css( 'pointer-events', 'none' );
150 140 }
@@ -153,171 +143,114 @@
153 143 * Enable the save draft link for a given jQuery form object
154 144 *
155 145 * @since 4.04.03
156 146 *
157 - * @param {jQuery} $form
147 + * @param {object} $form
158 148 */
159 149 function enableSaveDraft( $form ) {
160 - if ( ! $form.length ) {
161 - return;
162 - }
163 - $form[ 0 ].querySelectorAll( '.frm_save_draft' ).forEach( saveDraftButton => {
164 - saveDraftButton.disabled = false;
165 - saveDraftButton.style.pointerEvents = '';
166 - } );
150 + $form.find( 'a.frm_save_draft' ).css( 'pointer-events', '' );
167 151 }
168 152
169 - /**
170 - * Validate form with JS.
171 - *
172 - * @param {HTMLElement|jQuery} object
173 - * @return {Array} Errors.
174 - */
175 153 function validateForm( object ) {
176 - let errors = [];
154 + var r, rl, n, nl, fields, field, value, requiredFields,
155 + errors = [];
177 156
178 - const vanillaJsObject = 'function' === typeof object.get ? object.get( 0 ) : object;
179 -
180 - // Required field validation.
181 - vanillaJsObject?.querySelectorAll( '.frm_required_field' ).forEach(
182 - requiredField => {
183 - const isVisible = requiredField.offsetParent !== null;
184 - if ( ! isVisible ) {
185 - return;
157 + // Make sure required text field is filled in
158 + requiredFields = jQuery( object ).find(
159 + '.frm_required_field:visible input, .frm_required_field:visible select, .frm_required_field:visible textarea'
160 + ).filter( ':not(.frm_optional)' );
161 + if ( requiredFields.length ) {
162 + for ( r = 0, rl = requiredFields.length; r < rl; r++ ) {
163 + if ( hasClass( requiredFields[r], 'ed_button' ) ) {
164 + // skip rich text field buttons.
165 + continue;
186 166 }
187 -
188 - requiredField.querySelectorAll( 'input, select, textarea' ).forEach(
189 - requiredInput => {
190 - if ( hasClass( requiredInput, 'frm_optional' ) || hasClass( requiredInput, 'ed_button' ) ) {
191 - // skip rich text field buttons.
192 - return;
193 - }
194 -
195 - errors = checkRequiredField( requiredInput, errors );
196 - }
197 - );
167 + errors = checkRequiredField( requiredFields[r], errors );
198 168 }
199 - );
169 + }
200 170
201 - vanillaJsObject?.querySelectorAll( 'input,select,textarea' ).forEach(
202 - field => {
203 - if ( '' === field.value ) {
204 - if ( 'number' === field.type ) {
205 - // A number field will return an empty string when it is invalid.
206 - checkValidity( field, errors );
171 + fields = jQuery( object ).find( 'input,select,textarea' );
172 + if ( fields.length ) {
173 + for ( n = 0, nl = fields.length; n < nl; n++ ) {
174 + field = fields[n];
175 + value = field.value;
176 + if ( value !== '' ) {
177 + if ( field.type === 'hidden' ) {
178 + // don't validate
179 + } else if ( field.type === 'number' ) {
180 + errors = checkNumberField( field, errors );
181 + } else if ( field.type === 'email' ) {
182 + errors = checkEmailField( field, errors );
183 + } else if ( field.type === 'password' ) {
184 + errors = checkPasswordField( field, errors );
185 + } else if ( field.type === 'url' ) {
186 + errors = checkUrlField( field, errors );
187 + } else if ( field.pattern !== null ) {
188 + errors = checkPatternField( field, errors );
207 189 }
208 -
209 - const isConfirmationField = field.name && 0 === field.name.indexOf( 'item_meta[conf_' );
210 - if ( ! isConfirmationField ) {
211 - // Allow a blank confirmation field to still call validateFieldValue.
212 - // If we continue for a confirmation field there are issues with forms submitting with a blank confirmation field.
213 - return;
214 - }
215 190 }
216 -
217 - validateFieldValue( field, errors, true );
218 - checkValidity( field, errors );
219 191 }
220 - );
192 + }
221 193
222 - // Invisible captchas are processed after validation.
223 - // We only want to validate a visible captcha on submit.
224 - if ( ! hasInvisibleRecaptcha( object ) ) {
225 - errors = validateRecaptcha( object, errors );
226 - }
194 + errors = validateRecaptcha( object, errors );
227 195
228 196 return errors;
229 197 }
230 198
231 199 /**
232 - * Check the ValidityState interface for the field.
233 - * If it is invalid, show an error for it.
234 - *
235 - * @param {HTMLElement} field
236 - * @param {Array} errors
237 - * @return {void}
238 - */
239 - function checkValidity( field, errors ) {
240 - let fieldID;
241 - if ( 'object' !== typeof field.validity || false !== field.validity.valid ) {
242 - return;
243 - }
244 -
245 - fieldID = getFieldId( field, true );
246 - if ( 'undefined' === typeof errors[ fieldID ] ) {
247 - errors[ fieldID ] = getFieldValidationMessage( field, 'data-invmsg' );
248 - }
249 -
250 - if ( 'function' === typeof field.reportValidity ) {
251 - // This triggers an error pop up.
252 - field.reportValidity();
253 - }
254 - }
255 -
256 - /**
257 200 * @since 5.0.10
258 201 *
259 - * @param {Object} element
202 + * @param {object} element
260 203 * @param {string} targetClass
261 - * @return {boolean} True if the element has the target class.
204 + * @returns {boolean}
262 205 */
263 206 function hasClass( element, targetClass ) {
264 - return element.classList && element.classList.contains( targetClass );
207 + var className = ' ' + element.className + ' ';
208 + return -1 !== className.indexOf( ' ' + targetClass + ' ' );
265 209 }
266 210
267 - /**
268 - * @param {HTMLElement} field
269 - */
270 211 function maybeValidateChange( field ) {
271 212 if ( field.type === 'url' ) {
272 - maybeAddHttpsToUrl( field );
213 + maybeAddHttpToUrl( field );
273 214 }
274 - const form = field.closest( 'form' );
275 - if ( form && hasClass( form, 'frm_js_validate' ) ) {
215 + if ( jQuery( field ).closest( 'form' ).hasClass( 'frm_js_validate' ) ) {
276 216 validateField( field );
277 217 }
278 218 }
279 219
280 - /**
281 - * @param {HTMLElement} field
282 - */
283 - function maybeAddHttpsToUrl( field ) {
284 - const url = field.value;
285 - const matches = url.match( /^(https?|ftps?|mailto|news|feed|telnet):/ );
220 + function maybeAddHttpToUrl( field ) {
221 + var url = field.value;
222 + var matches = url.match( /^(https?|ftps?|mailto|news|feed|telnet):/ );
286 223 if ( field.value !== '' && matches === null ) {
287 - field.value = 'https://' + url;
224 + field.value = 'http://' + url;
288 225 }
289 226 }
290 227
291 - /**
292 - * Validate a field with JS.
293 - *
294 - * @param {HTMLElement} field
295 - *
296 - * @return {void}
297 - */
298 228 function validateField( field ) {
299 - let errors, key;
229 + var key,
230 + errors = [],
231 + $fieldCont = jQuery( field ).closest( '.frm_form_field' );
300 232
301 - errors = [];
302 - const fieldContainer = field.closest( '.frm_form_field' );
303 -
304 - if ( ! fieldContainer ) {
305 - // Hidden fields do not have a field container and do not require JS validation.
306 - return;
307 - }
308 -
309 - if ( hasClass( fieldContainer, 'frm_required_field' ) && ! hasClass( field, 'frm_optional' ) ) {
233 + if ( $fieldCont.hasClass( 'frm_required_field' ) && ! jQuery( field ).hasClass( 'frm_optional' ) ) {
310 234 errors = checkRequiredField( field, errors );
311 235 }
312 236
313 237 if ( errors.length < 1 ) {
314 - validateFieldValue( field, errors, false );
238 + if ( field.type === 'email' ) {
239 + errors = checkEmailField( field, errors );
240 + } else if ( field.type === 'password' ) {
241 + errors = checkPasswordField( field, errors );
242 + } else if ( field.type === 'number' ) {
243 + errors = checkNumberField( field, errors );
244 + } else if ( field.type === 'url' ) {
245 + errors = checkUrlField( field, errors );
246 + } else if ( field.pattern !== null ) {
247 + errors = checkPatternField( field, errors );
248 + }
315 249 }
316 250
317 - const $fieldCont = jQuery( fieldContainer );
318 251 removeFieldError( $fieldCont );
319 - if ( Object.keys( errors ).length > 0 ) {
252 + if ( Object.keys( errors ).length > 0 ) {
320 253 for ( key in errors ) {
321 254 addFieldError( $fieldCont, key, errors );
322 255 }
323 256 }
@@ -322,49 +255,10 @@
322 255 }
323 256 }
324 257 }
325 258
326 - /**
327 - * Validates a field value.
328 - *
329 - * @since 6.15 Added `onSubmit` parameter.
330 - *
331 - * @param {HTMLElement} field Field input.
332 - * @param {Object} errors Errors data.
333 - * @param {boolean} onSubmit Is `true` if the form is being submitted.
334 - */
335 - function validateFieldValue( field, errors, onSubmit ) {
336 - if ( field.type === 'hidden' ) {
337 - // don't validate
338 - } else if ( field.type === 'number' ) {
339 - checkNumberField( field, errors );
340 - } else if ( field.type === 'email' ) {
341 - checkEmailField( field, errors, onSubmit );
342 - } else if ( field.type === 'password' ) {
343 - checkPasswordField( field, errors, onSubmit );
344 - } else if ( field.type === 'url' ) {
345 - checkUrlField( field, errors );
346 - } else if ( field.pattern !== null ) {
347 - checkPatternField( field, errors );
348 - }
349 -
350 - /**
351 - * @since 6.15 Added `onSubmit` to the data.
352 - */
353 - triggerCustomEvent( document, 'frm_validate_field_value', {
354 - field: field,
355 - errors: errors,
356 - onSubmit: onSubmit
357 - } );
358 - }
359 -
360 - /**
361 - * @param {HTMLElement} field
362 - * @param {Array} errors
363 - * @return {Array} Errors
364 - */
365 259 function checkRequiredField( field, errors ) {
366 - let tempVal, i, placeholder,
260 + var checkGroup, tempVal, i, placeholder,
367 261 val = '',
368 262 fieldID = '',
369 263 fileID = field.getAttribute( 'data-frmfile' );
370 264
@@ -372,19 +266,12 @@
372 266 return errors;
373 267 }
374 268
375 269 if ( field.type === 'checkbox' || field.type === 'radio' ) {
376 - document.querySelectorAll( 'input[name="' + field.name + '"]' ).forEach( function( input ) {
377 - const requiredField = input.closest( '.frm_required_field' );
378 - if ( ! requiredField ) {
379 - return;
380 - }
381 -
382 - const checkedInputs = requiredField.querySelectorAll( 'input:checked' );
383 - checkedInputs.forEach( function( checkedInput ) {
384 - val = checkedInput.value;
385 - } );
386 - } );
270 + checkGroup = jQuery( 'input[name="' + field.name + '"]' ).closest( '.frm_required_field' ).find( 'input:checked' );
271 + jQuery( checkGroup ).each( function() {
272 + val = this.value;
273 + });
387 274 } else if ( field.type === 'file' || fileID ) {
388 275 if ( typeof fileID === 'undefined' ) {
389 276 fileID = getFieldId( field, true );
390 277 fileID = fileID.replace( 'file', '' );
@@ -406,10 +293,10 @@
406 293 } else if ( typeof val !== 'string' ) {
407 294 tempVal = val;
408 295 val = '';
409 296 for ( i = 0; i < tempVal.length; i++ ) {
410 - if ( tempVal[ i ] !== '' ) {
411 - val = tempVal[ i ];
297 + if ( tempVal[i] !== '' ) {
298 + val = tempVal[i];
412 299 }
413 300 }
414 301 }
415 302
@@ -422,14 +309,8 @@
422 309 } else {
423 310 fieldID = getFieldId( field, true );
424 311 }
425 312
426 - // Make sure fieldID is a string.
427 - // fieldID may be a number which doesn't include a .replace function.
428 - if ( 'function' !== typeof fieldID.replace ) {
429 - fieldID = fieldID.toString();
430 - }
431 -
432 313 if ( hasClass( field, 'frm_time_select' ) ) {
433 314 // set id for time field
434 315 fieldID = fieldID.replace( '-H', '' ).replace( '-m', '' );
435 316 } else if ( isSignatureField( field ) ) {
@@ -456,39 +337,23 @@
456 337
457 338 return errors;
458 339 }
459 340
460 - /**
461 - * @param {HTMLElement} field
462 - * @return {boolean} True if the input is a typed signature input.
463 - */
464 341 function isSignatureField( field ) {
465 - const name = field.getAttribute( 'name' );
342 + var name = field.getAttribute( 'name' );
466 343 return 'string' === typeof name && '[typed]' === name.substr( -7 );
467 344 }
468 345
469 - /**
470 - * @param {HTMLElement} field
471 - * @return {boolean} True if the field is a SSA appointment field.
472 - */
473 346 function isAppointmentField( field ) {
474 347 return hasClass( field, 'ssa_appointment_form_field_appointment_id' );
475 348 }
476 349
477 - /**
478 - * @param {HTMLElement} field
479 - * @return {boolean} True if the field is inline datepicker field.
480 - */
481 350 function isInlineDatepickerField( field ) {
482 351 return 'hidden' === field.type && '_alt' === field.id.substr( -4 ) && hasClass( field.nextElementSibling, 'frm_date_inline' );
483 352 }
484 353
485 - /**
486 - * @param {string|number} fileID
487 - * @return {string} File input value.
488 - */
489 354 function getFileVals( fileID ) {
490 - let val = '',
355 + var val = '',
491 356 fileFields = jQuery( 'input[name="file' + fileID + '"], input[name="file' + fileID + '[]"], input[name^="item_meta[' + fileID + ']"]' );
492 357
493 358 fileFields.each( function() {
494 359 if ( val === '' ) {
@@ -493,19 +358,14 @@
493 358 fileFields.each( function() {
494 359 if ( val === '' ) {
495 360 val = this.value;
496 361 }
497 - } );
362 + });
498 363 return val;
499 364 }
500 365
501 - /**
502 - * @param {HTMLElement} field
503 - * @param {Array} errors
504 - * @return {void}
505 - */
506 366 function checkUrlField( field, errors ) {
507 - let fieldID,
367 + var fieldID,
508 368 url = field.value;
509 369
510 370 if ( url !== '' && ! /^http(s)?:\/\/(?:localhost|(?:[\da-z\.-]+\.[\da-z\.-]+))/i.test( url ) ) {
511 371 fieldID = getFieldId( field, true );
@@ -512,44 +372,13 @@
512 372 if ( ! ( fieldID in errors ) ) {
513 373 errors[ fieldID ] = getFieldValidationMessage( field, 'data-invmsg' );
514 374 }
515 375 }
376 + return errors;
516 377 }
517 378
518 - /**
519 - * Checks if the confirm field should be checked.
520 - *
521 - * @since 6.15
522 - *
523 - * @param {HTMLElement} field Field input.
524 - * @param {boolean} onSubmit Is `true` if the form is being submitted.
525 - * @return {boolean} True if we should confirm the field.
526 - */
527 - function shouldCheckConfirmField( field, onSubmit ) {
528 - if ( onSubmit ) {
529 - // Always check on submitting.
530 - return true;
531 - }
532 -
533 - if ( 0 === field.id.indexOf( 'field_conf_' ) ) {
534 - // Always check if it's the confirm field.
535 - return true;
536 - }
537 -
538 - return false;
539 - }
540 -
541 - /**
542 - * Check the email field for errors.
543 - *
544 - * @since 6.15 Added `onSubmit` parameter.
545 - *
546 - * @param {HTMLElement} field Field input.
547 - * @param {Object} errors Errors data.
548 - * @param {boolean} onSubmit Is `true` if the form is being submitted.
549 - */
550 - function checkEmailField( field, errors, onSubmit ) {
551 - const fieldID = getFieldId( field, true ),
379 + function checkEmailField( field, errors ) {
380 + var fieldID = getFieldId( field, true ),
552 381 pattern = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i;
553 382
554 383 // validate the current field we're editing first
555 384 if ( '' !== field.value && pattern.test( field.value ) === false ) {
@@ -555,35 +384,19 @@
555 384 if ( '' !== field.value && pattern.test( field.value ) === false ) {
556 385 errors[ fieldID ] = getFieldValidationMessage( field, 'data-invmsg' );
557 386 }
558 387
559 - if ( shouldCheckConfirmField( field, onSubmit ) ) {
560 - confirmField( field, errors );
561 - }
388 + confirmField( field, errors );
389 + return errors;
562 390 }
563 391
564 - /**
565 - * Check the password field for errors.
566 - *
567 - * @since 6.15 Added `onSubmit` parameter.
568 - *
569 - * @param {HTMLElement} field Field input.
570 - * @param {Object} errors Errors data.
571 - * @param {boolean} onSubmit Is `true` if the form is being submitted.
572 - */
573 - function checkPasswordField( field, errors, onSubmit ) {
574 - if ( shouldCheckConfirmField( field, onSubmit ) ) {
575 - confirmField( field, errors );
576 - }
392 + function checkPasswordField( field, errors ) {
393 + confirmField( field, errors );
394 + return errors;
577 395 }
578 396
579 - /**
580 - * @param {HTMLElement} field
581 - * @param {Array} errors
582 - * @return {void}
583 - */
584 397 function confirmField( field, errors ) {
585 - let value, confirmValue, firstField,
398 + var value, confirmValue, firstField,
586 399 fieldID = getFieldId( field, true ),
587 400 strippedId = field.id.replace( 'conf_', '' ),
588 401 strippedFieldID = fieldID.replace( 'conf_', '' ),
589 402 confirmField = document.getElementById( strippedId.replace( 'field_', 'field_conf_' ) );
@@ -595,9 +408,9 @@
595 408 if ( fieldID !== strippedFieldID ) {
596 409 firstField = document.getElementById( strippedId );
597 410 value = firstField.value;
598 411 confirmValue = confirmField.value;
599 - if ( value !== confirmValue ) {
412 + if ( '' !== value && '' !== confirmValue && value !== confirmValue ) {
600 413 errors[ 'conf_' + strippedFieldID ] = getFieldValidationMessage( confirmField, 'data-confmsg' );
601 414 }
602 415 } else {
603 416 validateField( confirmField );
@@ -603,15 +416,10 @@
603 416 validateField( confirmField );
604 417 }
605 418 }
606 419
607 - /**
608 - * @param {HTMLElement} field
609 - * @param {Array} errors
610 - * @return {void}
611 - */
612 420 function checkNumberField( field, errors ) {
613 - let fieldID,
421 + var fieldID,
614 422 number = field.value;
615 423
616 424 if ( number !== '' && isNaN( number / 1 ) !== false ) {
617 425 fieldID = getFieldId( field, true );
@@ -618,17 +426,13 @@
618 426 if ( ! ( fieldID in errors ) ) {
619 427 errors[ fieldID ] = getFieldValidationMessage( field, 'data-invmsg' );
620 428 }
621 429 }
430 + return errors;
622 431 }
623 432
624 - /**
625 - * @param {HTMLElement} field
626 - * @param {Array} errors
627 - * @return {void}
628 - */
629 433 function checkPatternField( field, errors ) {
630 - let fieldID,
434 + var fieldID,
631 435 text = field.value,
632 436 format = getFieldValidationMessage( field, 'pattern' );
633 437
634 438 if ( format !== '' && text !== '' ) {
@@ -633,65 +437,19 @@
633 437
634 438 if ( format !== '' && text !== '' ) {
635 439 fieldID = getFieldId( field, true );
636 440 if ( ! ( fieldID in errors ) ) {
637 - if ( 'object' === typeof window.frmProForm && 'function' === typeof window.frmProForm.isIntlPhoneInput && window.frmProForm.isIntlPhoneInput( field ) ) {
638 - if ( ! window.frmProForm.validateIntlPhoneInput( field ) ) {
639 - errors[ fieldID ] = getFieldValidationMessage( field, 'data-invmsg' );
640 - }
641 - } else {
642 - format = new RegExp( '^' + format + '$', 'i' );
643 - if ( format.test( text ) === false ) {
644 - errors[ fieldID ] = getFieldValidationMessage( field, 'data-invmsg' );
645 - }
441 + format = new RegExp( '^' + format + '$', 'i' );
442 + if ( format.test( text ) === false ) {
443 + errors[ fieldID ] = getFieldValidationMessage( field, 'data-invmsg' );
646 444 }
647 445 }
648 446 }
447 + return errors;
649 448 }
650 449
651 - /**
652 - * Set color for select placeholders.
653 - *
654 - * @since 6.5.1
655 - */
656 - function setSelectPlaceholderColor() {
657 - let selects = document.querySelectorAll( '.form-field select' ),
658 - styleElement = document.querySelector( '.with_frm_style' ),
659 - textColorDisabled = styleElement ? getComputedStyle( styleElement ).getPropertyValue( '--text-color-disabled' ).trim() : '',
660 - changeSelectColor;
661 -
662 - // Exit if there are no select elements or the textColorDisabled property is missing
663 - if ( ! selects.length || ! textColorDisabled ) {
664 - return;
665 - }
666 -
667 - // Function to change the color of a select element
668 - changeSelectColor = function( select ) {
669 - if ( select.options[ select.selectedIndex ] && hasClass( select.options[ select.selectedIndex ], 'frm-select-placeholder' ) ) {
670 - select.style.setProperty( 'color', textColorDisabled, 'important' );
671 - } else {
672 - select.style.color = '';
673 - }
674 - };
675 -
676 - // Use a loop to iterate through each select element
677 - Array.prototype.forEach.call( selects, function( select ) {
678 - // Apply the color change to each select element
679 - changeSelectColor( select );
680 -
681 - // Add an event listener for future changes
682 - select.addEventListener( 'change', function() {
683 - changeSelectColor( select );
684 - } );
685 - } );
686 - }
687 -
688 - /**
689 - * @param {HTMLElement|jQuery} object
690 - * @return {boolean} True if there is an invisible recaptcha.
691 - */
692 450 function hasInvisibleRecaptcha( object ) {
693 - let recaptcha, recaptchaID, alreadyChecked;
451 + var recaptcha, recaptchaID, alreadyChecked;
694 452
695 453 if ( isGoingToPrevPage( object ) ) {
696 454 return false;
697 455 }
@@ -701,106 +459,73 @@
701 459 recaptchaID = recaptcha.data( 'rid' );
702 460 alreadyChecked = grecaptcha.getResponse( recaptchaID );
703 461 if ( alreadyChecked.length === 0 ) {
704 462 return recaptcha;
463 + } else {
464 + return false;
705 465 }
466 + } else {
467 + return false;
706 468 }
707 - return false;
708 469 }
709 470
710 - /**
711 - * @param {jQuery} invisibleRecaptcha
712 - */
713 471 function executeInvisibleRecaptcha( invisibleRecaptcha ) {
714 - const recaptchaID = invisibleRecaptcha.data( 'rid' );
472 + var recaptchaID = invisibleRecaptcha.data( 'rid' );
715 473 grecaptcha.reset( recaptchaID );
716 474 grecaptcha.execute( recaptchaID );
717 475 }
718 476
719 477 function validateRecaptcha( form, errors ) {
720 - let response;
478 + var recaptchaID, response, fieldContainer, fieldID,
479 + $recaptcha = jQuery( form ).find( '.frm-g-recaptcha' );
480 + if ( $recaptcha.length ) {
481 + recaptchaID = $recaptcha.data( 'rid' );
721 482
722 - const $recaptcha = jQuery( form ).find( '.frm-g-recaptcha' );
723 - if ( ! $recaptcha.length ) {
724 - return errors;
725 - }
483 + try {
484 + response = grecaptcha.getResponse( recaptchaID );
485 + } catch ( e ) {
486 + if ( jQuery( form ).find( 'input[name="recaptcha_checked"]' ).length ) {
487 + return errors;
488 + } else {
489 + response = '';
490 + }
491 + }
726 492
727 - const recaptchaID = $recaptcha.data( 'rid' );
728 -
729 - try {
730 - response = grecaptcha.getResponse( recaptchaID );
731 - } catch ( e ) {
732 - if ( jQuery( form ).find( 'input[name="recaptcha_checked"]' ).length ) {
733 - return errors;
493 + if ( response.length === 0 ) {
494 + fieldContainer = $recaptcha.closest( '.frm_form_field' );
495 + fieldID = fieldContainer.attr( 'id' ).replace( 'frm_field_', '' ).replace( '_container', '' );
496 + errors[ fieldID ] = '';
734 497 }
735 - response = '';
736 498 }
737 -
738 - if ( response.length === 0 ) {
739 - const fieldContainer = $recaptcha.closest( '.frm_form_field' );
740 - const fieldID = fieldContainer.attr( 'id' ).replace( 'frm_field_', '' ).replace( '_container', '' );
741 - errors[ fieldID ] = '';
742 - }
743 -
744 499 return errors;
745 500 }
746 501
747 - /**
748 - * @param {HTMLElement} field
749 - * @param {string} messageType
750 - * @return {string} The error message to display.
751 - */
752 502 function getFieldValidationMessage( field, messageType ) {
753 - let msg = field.getAttribute( messageType );
503 + var msg, errorHtml;
504 +
505 + msg = field.getAttribute( messageType );
754 506 if ( null === msg ) {
755 507 msg = '';
756 508 }
757 509
758 510 if ( '' !== msg && shouldWrapErrorHtmlAroundMessageType( messageType ) ) {
759 - msg = wrapErrorHtml( msg, field );
511 + errorHtml = field.getAttribute( 'data-error-html' );
512 + if ( null !== errorHtml ) {
513 + errorHtml = errorHtml.replace( /\+/g, '%20' );
514 + msg = decodeURIComponent( errorHtml ).replace( '[error]', msg );
515 + msg = msg.replace( '[key]', getFieldId( field, false ) );
516 + }
760 517 }
761 518
762 519 return msg;
763 520 }
764 521
765 - /**
766 - * @param {string} msg
767 - * @param {HTMLElement} field
768 - * @return {string} The error HTML to use.
769 - */
770 - function wrapErrorHtml( msg, field ) {
771 - let errorHtml = field.getAttribute( 'data-error-html' );
772 - if ( null === errorHtml ) {
773 - return msg;
774 - }
775 -
776 - errorHtml = errorHtml.replace( /\+/g, '%20' );
777 - msg = decodeURIComponent( errorHtml ).replace( '[error]', msg );
778 - const fieldId = getFieldId( field, false );
779 - const split = fieldId.split( '-' );
780 - const fieldIdParts = field.id.split( '_' );
781 - fieldIdParts.shift(); // Drop the "field" value from the front.
782 - split[ 0 ] = fieldIdParts.join( '_' );
783 - const errorKey = split.join( '-' );
784 - return msg.replace( '[key]', errorKey );
785 - }
786 -
787 522 function shouldWrapErrorHtmlAroundMessageType( type ) {
788 523 return 'pattern' !== type;
789 524 }
790 525
791 - /**
792 - * Check if JS validation should happen.
793 - *
794 - * @param {HTMLElement|Object} object Form object.
795 - * @return {boolean} True if validation is enabled and we are not saving a draft or going to a previous page.
796 - */
797 526 function shouldJSValidate( object ) {
798 - if ( 'function' === typeof object.get ) {
799 - // Get the HTMLElement from a jQuery object.
800 - object = object.get( 0 );
801 - }
802 - let validate = hasClass( object, 'frm_js_validate' );
527 + var validate = jQuery( object ).hasClass( 'frm_js_validate' );
803 528 if ( validate && typeof frmProForm !== 'undefined' && ( frmProForm.savingDraft( object ) || frmProForm.goingToPreviousPage( object ) ) ) {
804 529 validate = false;
805 530 }
806 531
@@ -806,52 +531,28 @@
806 531
807 532 return validate;
808 533 }
809 534
810 - /**
811 - * @param {HTMLElement} object
812 - * @param {string} action
813 - * @return {void}
814 - */
815 535 function getFormErrors( object, action ) {
816 - let fieldset, data, success, error, shouldTriggerEvent;
536 + var fieldset;
817 537
538 + if ( typeof action === 'undefined' ) {
539 + jQuery( object ).find( 'input[name="frm_action"]' ).val();
540 + }
541 +
818 542 fieldset = jQuery( object ).find( '.frm_form_field' );
819 543 fieldset.addClass( 'frm_doing_ajax' );
544 + jQuery.ajax({
545 + type: 'POST', url: frm_js.ajax_url,
546 + data: jQuery( object ).serialize() + '&action=frm_entries_' + action + '&nonce=' + frm_js.nonce,
547 + success: function( response ) {
548 + var formID, replaceContent, pageOrder, formReturned, contSubmit, delay,
549 + $fieldCont, key, inCollapsedSection, frmTrigger,
550 + defaultResponse = { 'content': '', 'errors': {}, 'pass': false };
551 + if ( response === null ) {
552 + response = defaultResponse;
553 + }
820 554
821 - data = jQuery( object ).serialize() + '&action=frm_entries_' + action + '&nonce=' + frm_js.nonce; // eslint-disable-line camelcase
822 - shouldTriggerEvent = object.classList.contains( 'frm_trigger_event_on_submit' );
823 -
824 - const doRedirect = response => {
825 - jQuery( document ).trigger( 'frmBeforeFormRedirect', [ object, response ] );
826 -
827 - if ( ! response.openInNewTab ) {
828 - // We return here because we're redirecting there is no need to update content.
829 - window.location = response.redirect;
830 - return;
831 - }
832 -
833 - // We don't return here because we're opening in a new tab, the old tab will still update.
834 - const newTab = window.open( response.redirect, '_blank' );
835 - if ( ! newTab && response.fallbackMsg && response.content ) {
836 - response.content = response.content.trim().replace( /(<\/div><\/div>)$/, ' ' + response.fallbackMsg + '</div></div>' );
837 - }
838 - };
839 -
840 - success = function( response ) {
841 - let defaultResponse, formID, replaceContent, pageOrder, formReturned, contSubmit, delay,
842 - $fieldCont, key, inCollapsedSection, frmTrigger;
843 -
844 - defaultResponse = {
845 - content: '',
846 - errors: {},
847 - pass: false
848 - };
849 -
850 - if ( response === null ) {
851 - response = defaultResponse;
852 - } else {
853 - // Response is a string. Convert it to an object.
854 555 response = response.replace( /^\s+|\s+$/g, '' );
855 556 if ( response.indexOf( '{' ) === 0 ) {
856 557 response = JSON.parse( response );
857 558 } else {
@@ -856,210 +557,139 @@
856 557 response = JSON.parse( response );
857 558 } else {
858 559 response = defaultResponse;
859 560 }
860 - }
861 561
862 - if ( typeof response.redirect !== 'undefined' ) {
863 - if ( shouldTriggerEvent ) {
864 - triggerCustomEvent( object, 'frmSubmitEvent' );
865 - return;
866 - }
562 + if ( typeof response.redirect !== 'undefined' ) {
563 + jQuery( document ).trigger( 'frmBeforeFormRedirect', [ object, response ]);
564 + window.location = response.redirect;
565 + } else if ( response.content !== '' ) {
566 + // the form or success message was returned
867 567
868 - if ( response.delay ) {
869 - setTimeout( function() {
870 - doRedirect( response );
871 - }, 1000 * response.delay );
872 - } else {
873 - doRedirect( response );
874 - }
875 - }
568 + removeSubmitLoading( jQuery( object ) );
569 + if ( frm_js.offset != -1 ) {
570 + frmFrontForm.scrollMsg( jQuery( object ), false );
571 + }
572 + formID = jQuery( object ).find( 'input[name="form_id"]' ).val();
573 + response.content = response.content.replace( / frm_pro_form /g, ' frm_pro_form frm_no_hide ' );
574 + replaceContent = jQuery( object ).closest( '.frm_forms' );
575 + removeAddedScripts( replaceContent, formID );
576 + delay = maybeSlideOut( replaceContent, response.content );
876 577
877 - if ( 'string' === typeof response.content && response.content !== '' ) {
878 - // the form or success message was returned
578 + setTimeout(
579 + function() {
580 + var container, input, previousInput;
879 581
880 - if ( shouldTriggerEvent ) {
881 - triggerCustomEvent( object, 'frmSubmitEvent', { content: response.content } );
882 - return;
883 - }
582 + replaceContent.replaceWith( response.content );
884 583
885 - removeSubmitLoading( jQuery( object ) );
886 - if ( frm_js.offset != -1 ) { // eslint-disable-line camelcase
887 - frmFrontForm.scrollMsg( jQuery( object ), false );
888 - }
584 + addUrlParam( response );
889 585
890 - formID = jQuery( object ).find( 'input[name="form_id"]' ).val();
891 - response.content = response.content.replace( / frm_pro_form /g, ' frm_pro_form frm_no_hide ' );
892 - replaceContent = jQuery( object ).closest( '.frm_forms' );
893 - removeAddedScripts( replaceContent, formID );
894 - delay = maybeSlideOut( replaceContent, response.content );
586 + if ( typeof frmThemeOverride_frmAfterSubmit === 'function' ) { // eslint-disable-line camelcase
587 + pageOrder = jQuery( 'input[name="frm_page_order_' + formID + '"]' ).val();
588 + formReturned = jQuery( response.content ).find( 'input[name="form_id"]' ).val();
589 + frmThemeOverride_frmAfterSubmit( formReturned, pageOrder, response.content, object );
590 + }
895 591
896 - setTimeout(
897 - function() {
898 - let container, input, previousInput;
592 + if ( typeof response.recaptcha !== 'undefined' ) {
593 + container = jQuery( '#frm_form_' + formID + '_container' ).find( '.frm_fields_container' );
594 + input = '<input type="hidden" name="recaptcha_checked" value="' + response.recaptcha + '">';
595 + previousInput = container.find( 'input[name="recaptcha_checked"]' );
899 596
900 - afterFormSubmittedBeforeReplace( object, response );
597 + if ( previousInput.length ) {
598 + previousInput.replaceWith( input );
599 + } else {
600 + container.append( input );
601 + }
602 + }
901 603
902 - replaceContent.replaceWith( response.content );
604 + afterFormSubmitted( object, response );
605 + },
606 + delay
607 + );
608 + } else if ( Object.keys( response.errors ).length ) {
609 + // errors were returned
903 610
904 - addUrlParam( response );
611 + removeSubmitLoading( jQuery( object ), 'enable' );
905 612
906 - if ( typeof frmThemeOverride_frmAfterSubmit === 'function' ) { // eslint-disable-line camelcase
907 - pageOrder = jQuery( 'input[name="frm_page_order_' + formID + '"]' ).val();
908 - formReturned = jQuery( response.content ).find( 'input[name="form_id"]' ).val();
909 - frmThemeOverride_frmAfterSubmit( formReturned, pageOrder, response.content, object );
910 - }
613 + //show errors
614 + contSubmit = true;
615 + removeAllErrors();
911 616
912 - if ( typeof response.recaptcha !== 'undefined' ) {
913 - container = jQuery( '#frm_form_' + formID + '_container' ).find( '.frm_fields_container' );
914 - input = '<input type="hidden" name="recaptcha_checked" value="' + response.recaptcha + '">';
915 - previousInput = container.find( 'input[name="recaptcha_checked"]' );
617 + $fieldCont = null;
916 618
917 - if ( previousInput.length ) {
918 - previousInput.replaceWith( input );
919 - } else {
920 - container.append( input );
921 - }
922 - }
619 + for ( key in response.errors ) {
620 + $fieldCont = jQuery( object ).find( '#frm_field_' + key + '_container' );
923 621
924 - afterFormSubmitted( object, response );
925 - },
926 - delay
927 - );
928 - } else if ( Object.keys( response.errors ).length ) {
929 - // errors were returned
930 - removeSubmitLoading( jQuery( object ), 'enable' );
931 -
932 - //show errors
933 - contSubmit = true;
934 - removeAllErrors();
935 -
936 - $fieldCont = null;
937 -
938 - for ( key in response.errors ) {
939 - $fieldCont = jQuery( object ).find( '#frm_field_' + key + '_container' );
940 -
941 - if ( $fieldCont.length ) {
942 - if ( ! $fieldCont.is( ':visible' ) ) {
943 - inCollapsedSection = $fieldCont.closest( '.frm_toggle_container' );
944 - if ( inCollapsedSection.length ) {
945 - frmTrigger = inCollapsedSection.prev();
946 - if ( ! frmTrigger.hasClass( 'frm_trigger' ) ) {
947 - // If the frmTrigger object is the section description, check to see if the previous element is the trigger
948 - frmTrigger = frmTrigger.prev( '.frm_trigger' );
622 + if ( $fieldCont.length ) {
623 + if ( ! $fieldCont.is( ':visible' ) ) {
624 + inCollapsedSection = $fieldCont.closest( '.frm_toggle_container' );
625 + if ( inCollapsedSection.length ) {
626 + frmTrigger = inCollapsedSection.prev();
627 + if ( ! frmTrigger.hasClass( 'frm_trigger' ) ) {
628 + // If the frmTrigger object is the section description, check to see if the previous element is the trigger
629 + frmTrigger = frmTrigger.prev( '.frm_trigger' );
630 + }
631 + frmTrigger.trigger( 'click' );
949 632 }
950 - frmTrigger.trigger( 'click' );
951 633 }
952 - }
953 634
954 - if ( $fieldCont.is( ':visible' ) ) {
955 - addFieldError( $fieldCont, key, response.errors );
956 - contSubmit = false;
635 + if ( $fieldCont.is( ':visible' ) ) {
636 + addFieldError( $fieldCont, key, response.errors );
637 + contSubmit = false;
638 + }
957 639 }
958 640 }
959 - }
960 641
961 - jQuery( object ).find( '.frm-g-recaptcha, .g-recaptcha, .h-captcha' ).each( function() {
962 - const $recaptcha = jQuery( this ),
963 - recaptchaID = $recaptcha.data( 'rid' );
642 + jQuery( object ).find( '.frm-g-recaptcha, .g-recaptcha' ).each( function() {
643 + var $recaptcha = jQuery( this ),
644 + recaptchaID = $recaptcha.data( 'rid' );
964 645
965 - if ( typeof grecaptcha !== 'undefined' && grecaptcha ) {
966 - if ( recaptchaID ) {
967 - grecaptcha.reset( recaptchaID );
968 - } else {
969 - grecaptcha.reset();
646 + if ( typeof grecaptcha !== 'undefined' && grecaptcha ) {
647 + if ( recaptchaID ) {
648 + grecaptcha.reset( recaptchaID );
649 + } else {
650 + grecaptcha.reset();
651 + }
970 652 }
971 - }
972 - if ( typeof hcaptcha !== 'undefined' && hcaptcha ) {
973 - hcaptcha.reset();
974 - }
975 - } );
653 + });
976 654
977 - if ( window.turnstile ) {
978 - object.querySelectorAll( '.cf-turnstile' ).forEach(
979 - turnstileField => turnstileField.dataset.rid && turnstile.reset( turnstileField.dataset.rid )
980 - );
981 - }
655 + jQuery( document ).trigger( 'frmFormErrors', [ object, response ]);
982 656
983 - jQuery( document ).trigger( 'frmFormErrors', [ object, response ] );
657 + fieldset.removeClass( 'frm_doing_ajax' );
658 + scrollToFirstField( object );
984 659
985 - fieldset.removeClass( 'frm_doing_ajax' );
986 - scrollToFirstField( object );
660 + if ( contSubmit ) {
661 + object.submit();
662 + } else {
663 + jQuery( object ).prepend( response.error_message );
664 + checkForErrorsAndMaybeSetFocus();
665 + }
666 + } else {
667 + // there may have been a plugin conflict, or the form is not set to submit with ajax
987 668
988 - if ( contSubmit ) {
669 + showFileLoading( object );
670 +
989 671 object.submit();
990 - } else {
991 - object.insertAdjacentHTML( 'afterbegin', response.error_message );
992 - checkForErrorsAndMaybeSetFocus();
993 672 }
994 - } else {
995 - // there may have been a plugin conflict, or the form is not set to submit with ajax
996 -
997 - showFileLoading( object );
998 -
673 + },
674 + error: function() {
675 + jQuery( object ).find( 'input[type="submit"], input[type="button"]' ).prop( 'disabled', false );
999 676 object.submit();
1000 677 }
1001 - };
1002 -
1003 - error = function() {
1004 - jQuery( object ).find( 'input[type="submit"], input[type="button"]' ).prop( 'disabled', false );
1005 - object.submit();
1006 - };
1007 -
1008 - postToAjaxUrl( object, data, success, error );
678 + });
1009 679 }
1010 680
1011 - function postToAjaxUrl( form, data, success, error ) {
1012 - let ajaxUrl, action, ajaxParams;
1013 -
1014 - ajaxUrl = frm_js.ajax_url; // eslint-disable-line camelcase
1015 - action = form.getAttribute( 'action' );
1016 -
1017 - if ( 'string' === typeof action && -1 !== action.indexOf( '?action=frm_forms_preview' ) ) {
1018 - ajaxUrl = action.split( '?action=frm_forms_preview' )[ 0 ];
1019 - }
1020 -
1021 - ajaxParams = {
1022 - type: 'POST',
1023 - url: ajaxUrl,
1024 - data: data,
1025 - success: success
1026 - };
1027 -
1028 - if ( 'function' === typeof error ) {
1029 - ajaxParams.error = error;
1030 - }
1031 -
1032 - jQuery.ajax( ajaxParams );
1033 - }
1034 -
1035 681 function afterFormSubmitted( object, response ) {
1036 - const formCompleted = jQuery( response.content ).find( '.frm_message' );
682 + var formCompleted = jQuery( response.content ).find( '.frm_message' );
1037 683 if ( formCompleted.length ) {
1038 - jQuery( document ).trigger( 'frmFormComplete', [ object, response ] );
684 + jQuery( document ).trigger( 'frmFormComplete', [ object, response ]);
1039 685 } else {
1040 - jQuery( document ).trigger( 'frmPageChanged', [ object, response ] );
686 + jQuery( document ).trigger( 'frmPageChanged', [ object, response ]);
1041 687 }
1042 688 }
1043 689
1044 - /**
1045 - * Trigger an event before the form is replaced with a success message.
1046 - *
1047 - * @since 6.9
1048 - *
1049 - * @param {HTMLElement} object The form.
1050 - * @param {Object} response The response from submitting the form with AJAX.
1051 - * @return {void}
1052 - */
1053 - function afterFormSubmittedBeforeReplace( object, response ) {
1054 - const formCompleted = jQuery( response.content ).find( '.frm_message' );
1055 - if ( formCompleted.length ) {
1056 - triggerCustomEvent( document, 'frmFormCompleteBeforeReplace', { object, response } );
1057 - }
1058 - }
1059 -
1060 690 function removeAddedScripts( formContainer, formID ) {
1061 - const endReplace = jQuery( '.frm_end_ajax_' + formID );
691 + var endReplace = jQuery( '.frm_end_ajax_' + formID );
1062 692 if ( endReplace.length ) {
1063 693 formContainer.nextUntil( '.frm_end_ajax_' + formID ).remove();
1064 694 endReplace.remove();
1065 695 }
@@ -1065,9 +695,9 @@
1065 695 }
1066 696 }
1067 697
1068 698 function maybeSlideOut( oldContent, newContent ) {
1069 - let c,
699 + var c,
1070 700 newClass = 'frm_slideout';
1071 701 if ( newContent.indexOf( ' frm_slide' ) !== -1 ) {
1072 702 c = oldContent.children();
1073 703 if ( newContent.indexOf( ' frm_going_back' ) !== -1 ) {
@@ -1080,17 +710,17 @@
1080 710 return 0;
1081 711 }
1082 712
1083 713 function addUrlParam( response ) {
1084 - let url;
714 + var url;
1085 715 if ( history.pushState && typeof response.page !== 'undefined' ) {
1086 716 url = addQueryVar( 'frm_page', response.page );
1087 - window.history.pushState( { html: response.html }, '', '?' + url );
717 + window.history.pushState({ 'html': response.html }, '', '?' + url );
1088 718 }
1089 719 }
1090 720
1091 721 function addQueryVar( key, value ) {
1092 - let kvp, i, x;
722 + var kvp, i, x;
1093 723
1094 724 key = encodeURI( key );
1095 725 value = encodeURI( value );
1096 726
@@ -1097,13 +727,13 @@
1097 727 kvp = document.location.search.substr( 1 ).split( '&' );
1098 728
1099 729 i = kvp.length;
1100 730 while ( i-- ) {
1101 - x = kvp[ i ].split( '=' );
731 + x = kvp[i].split( '=' );
1102 732
1103 - if ( x[ 0 ] == key ) {
1104 - x[ 1 ] = value;
1105 - kvp[ i ] = x.join( '=' );
733 + if ( x[0] == key ) {
734 + x[1] = value;
735 + kvp[i] = x.join( '=' );
1106 736 break;
1107 737 }
1108 738 }
1109 739
@@ -1114,91 +744,49 @@
1114 744 return kvp.join( '&' );
1115 745 }
1116 746
1117 747 function addFieldError( $fieldCont, key, jsErrors ) {
1118 - let input, id, describedBy, roleString;
748 + var input, id, describedBy;
1119 749 if ( $fieldCont.length && $fieldCont.is( ':visible' ) ) {
1120 750 $fieldCont.addClass( 'frm_blank_field' );
1121 751 input = $fieldCont.find( 'input, select, textarea' );
1122 - id = getErrorElementId( key, input.get( 0 ) );
1123 -
752 + id = 'frm_error_field_' + key;
1124 753 describedBy = input.attr( 'aria-describedby' );
1125 754
1126 755 if ( typeof frmThemeOverride_frmPlaceError === 'function' ) { // eslint-disable-line camelcase
1127 756 frmThemeOverride_frmPlaceError( key, jsErrors );
1128 757 } else {
1129 - if ( -1 !== jsErrors[ key ].indexOf( '<div' ) ) {
758 + if ( -1 !== jsErrors[key].indexOf( '<div' ) ) {
1130 759 $fieldCont.append(
1131 - jsErrors[ key ]
760 + jsErrors[key]
1132 761 );
1133 762 } else {
1134 - roleString = frm_js.include_alert_role ? 'role="alert"' : ''; // eslint-disable-line camelcase
1135 - $fieldCont.append( '<div class="frm_error" ' + roleString + ' id="' + id + '">' + jsErrors[ key ] + '</div>' );
763 + $fieldCont.append( '<div class="frm_error" role="alert" id="' + id + '">' + jsErrors[key] + '</div>' );
1136 764 }
1137 765
1138 766 if ( typeof describedBy === 'undefined' ) {
1139 767 describedBy = id;
1140 - } else if ( describedBy.indexOf( id ) === -1 && describedBy.indexOf( 'frm_error_field_' ) === -1 ) {
1141 - if ( input.data( 'error-first' ) === 0 ) {
1142 - describedBy = describedBy + ' ' + id;
1143 - } else {
1144 - describedBy = id + ' ' + describedBy;
1145 - }
768 + } else if ( describedBy.indexOf( id ) === -1 ) {
769 + describedBy = describedBy + ' ' + id;
1146 770 }
1147 -
1148 771 input.attr( 'aria-describedby', describedBy );
1149 772 }
773 + input.attr( 'aria-invalid', true );
774 + input.attr( 'aria-describedby', id );
1150 775
1151 - if ( [ 'radio', 'checkbox' ].includes( input.attr( 'type' ) ) ) {
1152 - input.closest( '[role="radiogroup"], [role="group"]' ).attr( 'aria-invalid', true );
1153 - } else {
1154 - input.attr( 'aria-invalid', true );
1155 - }
1156 -
1157 - jQuery( document ).trigger( 'frmAddFieldError', [ $fieldCont, key, jsErrors ] );
776 + jQuery( document ).trigger( 'frmAddFieldError', [ $fieldCont, key, jsErrors ]);
1158 777 }
1159 778 }
1160 779
1161 - /**
1162 - * Get the ID to use for an error element added when submitting with AJAX.
1163 - *
1164 - * @param {string} key
1165 - * @param {HTMLElement} input
1166 - * @return {string} The ID to use for the error element.
1167 - */
1168 - function getErrorElementId( key, input ) {
1169 - if ( isNaN( key ) || ! input || ! input.id ) {
1170 - // If key isn't a number, assume it's already in the right format.
1171 - return 'frm_error_field_' + key;
1172 - }
1173 - return 'frm_error_' + input.id;
1174 - }
1175 -
1176 - /**
1177 - * Removes errors before validating with JS.
1178 - * This prevents issues with stale errors that has since been fixed.
1179 - *
1180 - * @param {Object} $fieldCont jQuery object.
1181 - * @return {void}
1182 - */
1183 780 function removeFieldError( $fieldCont ) {
1184 - const errorMessage = $fieldCont.find( '.frm_error' );
1185 - const errorId = errorMessage.attr( 'id' );
1186 - const input = $fieldCont.find( 'input, select, textarea' );
1187 - let describedBy = input.attr( 'aria-describedby' );
781 + var errorMessage = $fieldCont.find( '.frm_error' ),
782 + errorId = errorMessage.attr( 'id' ),
783 + input = $fieldCont.find( 'input, select, textarea' ),
784 + describedBy = input.attr( 'aria-describedby' );
1188 785
1189 - const fieldContainer = $fieldCont.get( 0 );
1190 - if ( fieldContainer && fieldContainer.classList ) {
1191 - fieldContainer.classList.remove( 'frm_blank_field', 'has-error' );
1192 - }
1193 -
1194 - if ( 'true' === input.attr( 'aria-invalid' ) ) {
1195 - input.attr( 'aria-invalid', false );
1196 - } else if ( [ 'radio', 'checkbox' ].includes( input.attr( 'type' ) ) ) {
1197 - input.closest( '[role="radiogroup"], [role="group"]' ).attr( 'aria-invalid', false );
1198 - }
1199 -
786 + $fieldCont.removeClass( 'frm_blank_field has-error' );
1200 787 errorMessage.remove();
788 + input.attr( 'aria-invalid', false );
1201 789 input.removeAttr( 'aria-describedby' );
1202 790
1203 791 if ( typeof describedBy !== 'undefined' ) {
1204 792 describedBy = describedBy.replace( errorId, '' );
@@ -1211,21 +799,13 @@
1211 799 jQuery( '.form-field .frm_error' ).replaceWith( '' );
1212 800 jQuery( '.frm_error_style' ).remove();
1213 801 }
1214 802
1215 - /**
1216 - * @param {HTMLElement|Object} object Form object.
1217 - * @return {void}
1218 - */
1219 803 function scrollToFirstField( object ) {
1220 - if ( 'function' === typeof object.get ) {
1221 - // Get the HTMLElement from a jQuery object.
1222 - object = object.get( 0 );
804 + var field = jQuery( object ).find( '.frm_blank_field' ).first();
805 + if ( field.length ) {
806 + frmFrontForm.scrollMsg( field, object, true );
1223 807 }
1224 - const field = object.querySelector( '.frm_blank_field' );
1225 - if ( field ) {
1226 - frmFrontForm.scrollMsg( jQuery( field ), object, true );
1227 - }
1228 808 }
1229 809
1230 810 function showSubmitLoading( $object ) {
1231 811 showLoadingIndicator( $object );
@@ -1240,9 +820,9 @@
1240 820 }
1241 821 }
1242 822
1243 823 function addLoadingClass( $object ) {
1244 - const loadingClass = isGoingToPrevPage( $object ) ? 'frm_loading_prev' : 'frm_loading_form';
824 + var loadingClass = isGoingToPrevPage( $object ) ? 'frm_loading_prev' : 'frm_loading_form';
1245 825
1246 826 $object.addClass( loadingClass );
1247 827 }
1248 828
@@ -1249,10 +829,10 @@
1249 829 function isGoingToPrevPage( $object ) {
1250 830 return ( typeof frmProForm !== 'undefined' && frmProForm.goingToPreviousPage( $object ) );
1251 831 }
1252 832
1253 - function removeSubmitLoading( _, enable, processesRunning ) {
1254 - let loadingForm;
833 + function removeSubmitLoading( $object, enable, processesRunning ) {
834 + var loadingForm;
1255 835
1256 836 if ( processesRunning > 0 ) {
1257 837 return;
1258 838 }
@@ -1269,9 +849,9 @@
1269 849 }
1270 850 }
1271 851
1272 852 function showFileLoading( object ) {
1273 - let fileval,
853 + var fileval,
1274 854 loading = document.getElementById( 'frm_loading' );
1275 855 if ( loading !== null ) {
1276 856 fileval = jQuery( object ).find( 'input[type=file]' ).val();
1277 857 if ( typeof fileval !== 'undefined' && fileval !== '' ) {
@@ -1281,8 +861,69 @@
1281 861 }
1282 862 }
1283 863 }
1284 864
865 + function clearDefault() {
866 + /*jshint validthis:true */
867 + toggleDefault( jQuery( this ), 'clear' );
868 + }
869 +
870 + function replaceDefault() {
871 + /*jshint validthis:true */
872 + toggleDefault( jQuery( this ), 'replace' );
873 + }
874 +
875 + function toggleDefault( $thisField, e ) {
876 + // TODO: Fix this for a default value that is a number or array
877 + var thisVal,
878 + v = $thisField.data( 'frmval' ).replace( /(\n|\r\n)/g, '\r' );
879 + if ( v === '' || typeof v === 'undefined' ) {
880 + return false;
881 + }
882 + thisVal = $thisField.val().replace( /(\n|\r\n)/g, '\r' );
883 +
884 + if ( 'replace' === e ) {
885 + if ( thisVal === '' ) {
886 + $thisField.addClass( 'frm_default' ).val( v );
887 + }
888 + } else if ( thisVal == v ) {
889 + $thisField.removeClass( 'frm_default' ).val( '' );
890 + }
891 + }
892 +
893 + function resendEmail() {
894 + /*jshint validthis:true */
895 + var $link = jQuery( this ),
896 + entryId = this.getAttribute( 'data-eid' ),
897 + formId = this.getAttribute( 'data-fid' ),
898 + label = $link.find( '.frm_link_label' );
899 + if ( label.length < 1 ) {
900 + label = $link;
901 + }
902 + label.append( '<span class="frm-wait"></span>' );
903 +
904 + jQuery.ajax({
905 + type: 'POST',
906 + url: frm_js.ajax_url,
907 + data: {
908 + action: 'frm_entries_send_email',
909 + entry_id: entryId,
910 + form_id: formId,
911 + nonce: frm_js.nonce
912 + },
913 + success: function( msg ) {
914 + var admin = document.getElementById( 'wpbody' );
915 + if ( admin === null ) {
916 + label.html( msg );
917 + } else {
918 + label.html( '' );
919 + $link.after( msg );
920 + }
921 + }
922 + });
923 + return false;
924 + }
925 +
1285 926 /**********************************************
1286 927 * General Helpers
1287 928 *********************************************/
1288 929
@@ -1287,12 +928,109 @@
1287 928 *********************************************/
1288 929
1289 930 function confirmClick() {
1290 931 /*jshint validthis:true */
1291 - const message = jQuery( this ).data( 'frmconfirm' );
932 + var message = jQuery( this ).data( 'frmconfirm' );
1292 933 return confirm( message );
1293 934 }
1294 935
936 + function toggleDiv() {
937 + /*jshint validthis:true */
938 + var div = jQuery( this ).data( 'frmtoggle' );
939 + if ( jQuery( div ).is( ':visible' ) ) {
940 + jQuery( div ).slideUp( 'fast' );
941 + } else {
942 + jQuery( div ).slideDown( 'fast' );
943 + }
944 + return false;
945 + }
946 +
947 + /**********************************************
948 + * Fallback functions
949 + *********************************************/
950 +
951 + function addIndexOfFallbackForIE8() {
952 + var len, from;
953 +
954 + if ( ! Array.prototype.indexOf ) {
955 + Array.prototype.indexOf = function( elt /*, from*/ ) {
956 + len = this.length >>> 0;
957 +
958 + from = Number( arguments[1]) || 0;
959 + from = ( from < 0 ) ? Math.ceil( from ) : Math.floor( from );
960 + if ( from < 0 ) {
961 + from += len;
962 + }
963 +
964 + for ( ; from < len; from++ ) {
965 + if ( from in this && this[from] === elt ) {
966 + return from;
967 + }
968 + }
969 + return -1;
970 + };
971 + }
972 + }
973 +
974 + function addTrimFallbackForIE8() {
975 + if ( typeof String.prototype.trim !== 'function' ) {
976 + String.prototype.trim = function() {
977 + return this.replace( /^\s+|\s+$/g, '' );
978 + };
979 + }
980 + }
981 +
982 + function addFilterFallbackForIE8() {
983 + var t, len, res, thisp, i, val;
984 +
985 + if ( ! Array.prototype.filter ) {
986 +
987 + Array.prototype.filter = function( fun /*, thisp */ ) {
988 +
989 + if ( this === void 0 || this === null ) {
990 + throw new TypeError();
991 + }
992 +
993 + t = Object( this );
994 + len = t.length >>> 0;
995 + if ( typeof fun !== 'function' ) {
996 + throw new TypeError();
997 + }
998 +
999 + res = [];
1000 + thisp = arguments[1];
1001 + for ( i = 0; i < len; i++ ) {
1002 + if ( i in t ) {
1003 + val = t[i]; // in case fun mutates this
1004 + if ( fun.call( thisp, val, i, t ) ) {
1005 + res.push( val );
1006 + }
1007 + }
1008 + }
1009 +
1010 + return res;
1011 + };
1012 + }
1013 + }
1014 +
1015 + function addKeysFallbackForIE8() {
1016 + var keys, i;
1017 +
1018 + if ( ! Object.keys ) {
1019 + Object.keys = function( obj ) {
1020 + keys = [];
1021 +
1022 + for ( i in obj ) {
1023 + if ( obj.hasOwnProperty( i ) ) {
1024 + keys.push( i );
1025 + }
1026 + }
1027 +
1028 + return keys;
1029 + };
1030 + }
1031 + }
1032 +
1295 1033 /**
1296 1034 * Check for -webkit-box-shadow css value for input:-webkit-autofill selector.
1297 1035 * If this is a match, the User is autofilling the input on a Webkit browser.
1298 1036 * We want to delete the Honeypot field, otherwise it will get triggered as spam on autocomplete.
@@ -1297,9 +1035,9 @@
1297 1035 * If this is a match, the User is autofilling the input on a Webkit browser.
1298 1036 * We want to delete the Honeypot field, otherwise it will get triggered as spam on autocomplete.
1299 1037 */
1300 1038 function onHoneypotFieldChange() {
1301 - const css = jQuery( this ).css( 'box-shadow' );
1039 + var css = jQuery( this ).css( 'box-shadow' );
1302 1040 if ( css.match( /inset/ ) ) {
1303 1041 this.parentNode.removeChild( this );
1304 1042 }
1305 1043 }
@@ -1322,65 +1060,34 @@
1322 1060 if ( ! label ) {
1323 1061 return;
1324 1062 }
1325 1063
1326 - label.addEventListener( 'click', function() {
1064 + label.addEventListener( 'click', function( e ) {
1327 1065 inputsContainer.querySelector( '.frm_form_field:first-child input, .frm_form_field:first-child select, .frm_form_field:first-child textarea' ).focus();
1328 - } );
1329 - } );
1066 + });
1067 + });
1330 1068 }
1331 1069
1332 - /**
1333 - * Sets focus on a the first subfield of a combo field that has an error.
1334 - *
1335 - * @since 6.16.3
1336 - *
1337 - * @param {HTMLElement} element
1338 - * @return {boolean} True if the focus was set on a combo field.
1339 - */
1340 - function maybeFocusOnComboSubField( element ) {
1341 - if ( 'FIELDSET' !== element.nodeName ) {
1342 - return false;
1343 - }
1344 - if ( ! element.querySelector( '.frm_combo_inputs_container' ) ) {
1345 - return false;
1346 - }
1347 - const comboSubfield = element.querySelector( '[aria-invalid="true"]' );
1348 - if ( comboSubfield ) {
1349 - focusInput( comboSubfield );
1350 - return true;
1351 - }
1352 - return false;
1353 - }
1354 -
1355 1070 function checkForErrorsAndMaybeSetFocus() {
1356 - let errors, element, timeoutCallback;
1071 + var errors, element, timeoutCallback;
1357 1072
1358 - if ( ! frm_js.focus_first_error ) { // eslint-disable-line camelcase
1359 - return;
1360 - }
1361 -
1362 1073 errors = document.querySelectorAll( '.frm_form_field .frm_error' );
1363 1074 if ( ! errors.length ) {
1364 1075 return;
1365 1076 }
1366 1077
1367 - element = errors[ 0 ];
1078 + element = errors[0];
1368 1079 do {
1369 1080 element = element.previousSibling;
1370 1081 if ( -1 !== [ 'input', 'select', 'textarea' ].indexOf( element.nodeName.toLowerCase() ) ) {
1371 - focusInput( element );
1082 + element.focus();
1372 1083 break;
1373 1084 }
1374 1085
1375 - if ( maybeFocusOnComboSubField( element ) ) {
1376 - break;
1377 - }
1378 -
1379 1086 if ( 'undefined' !== typeof element.classList ) {
1380 1087 if ( element.classList.contains( 'html-active' ) ) {
1381 1088 timeoutCallback = function() {
1382 - const textarea = element.querySelector( 'textarea' );
1089 + var textarea = element.querySelector( 'textarea' );
1383 1090 if ( null !== textarea ) {
1384 1091 textarea.focus();
1385 1092 }
1386 1093 };
@@ -1387,14 +1094,8 @@
1387 1094 } else if ( element.classList.contains( 'tmce-active' ) ) {
1388 1095 timeoutCallback = function() {
1389 1096 tinyMCE.activeEditor.focus();
1390 1097 };
1391 - } else if ( element.classList.contains( 'frm_opt_container' ) ) {
1392 - const firstInput = element.querySelector( 'input' );
1393 - if ( firstInput ) {
1394 - focusInput( firstInput );
1395 - break;
1396 - }
1397 1098 }
1398 1099
1399 1100 if ( 'function' === typeof timeoutCallback ) {
1400 1101 setTimeout( timeoutCallback, 0 );
@@ -1403,283 +1104,8 @@
1403 1104 }
1404 1105 } while ( element.previousSibling );
1405 1106 }
1406 1107
1407 - /**
1408 - * Focus a visible input, or possibly delay the focus event until the form has faded in.
1409 - *
1410 - * @since 6.16.3
1411 - *
1412 - * @param {HTMLElement} input
1413 - * @return {void}
1414 - */
1415 - function focusInput( input ) {
1416 - if ( input.offsetParent !== null ) {
1417 - input.focus();
1418 - } else {
1419 - triggerCustomEvent( document, 'frmMaybeDelayFocus', { input } );
1420 - }
1421 - }
1422 -
1423 - /**
1424 - * Does the same as jQuery( document ).on( 'event', 'selector', handler ).
1425 - *
1426 - * @since 5.4
1427 - *
1428 - * @param {string} event Event name.
1429 - * @param {string} selector Selector.
1430 - * @param {Function} handler Handler.
1431 - * @param {boolean | Object} options Options to be added to `addEventListener()` method. Default is `false`.
1432 - */
1433 - function documentOn( event, selector, handler, options ) {
1434 - if ( 'undefined' === typeof options ) {
1435 - options = false;
1436 - }
1437 -
1438 - document.addEventListener( event, function( e ) {
1439 - let target;
1440 -
1441 - // loop parent nodes from the target to the delegation node.
1442 - for ( target = e.target; target && target != this; target = target.parentNode ) {
1443 - if ( target && target.matches && target.matches( selector ) ) {
1444 - handler.call( target, e );
1445 - break;
1446 - }
1447 - }
1448 - }, options );
1449 - }
1450 -
1451 - function initFloatingLabels() {
1452 - let checkFloatLabel, checkDropdownLabel, runOnLoad, selector, floatClass;
1453 -
1454 - selector = '.frm-show-form .frm_inside_container input, .frm-show-form .frm_inside_container select, .frm-show-form .frm_inside_container textarea';
1455 - floatClass = 'frm_label_float_top';
1456 -
1457 - checkFloatLabel = function( input ) {
1458 - let container, shouldFloatTop, firstOpt;
1459 -
1460 - container = input.closest( '.frm_inside_container' );
1461 - if ( ! container ) {
1462 - return;
1463 - }
1464 -
1465 - shouldFloatTop = input.value || document.activeElement === input;
1466 -
1467 - container.classList.toggle( floatClass, shouldFloatTop );
1468 -
1469 - if ( 'SELECT' === input.tagName ) {
1470 - firstOpt = input.querySelector( 'option:first-child' );
1471 -
1472 - if ( shouldFloatTop ) {
1473 - if ( firstOpt.hasAttribute( 'data-label' ) ) {
1474 - firstOpt.textContent = firstOpt.getAttribute( 'data-label' );
1475 - firstOpt.removeAttribute( 'data-label' );
1476 - }
1477 - } else if ( firstOpt.textContent ) {
1478 - firstOpt.setAttribute( 'data-label', firstOpt.textContent );
1479 - firstOpt.textContent = '';
1480 - }
1481 - }
1482 - };
1483 -
1484 - checkDropdownLabel = function() {
1485 - document.querySelectorAll( '.frm-show-form .frm_inside_container:not(.' + floatClass + ') select' ).forEach( function( input ) {
1486 - const firstOpt = input.querySelector( 'option:first-child' );
1487 -
1488 - if ( firstOpt.textContent ) {
1489 - firstOpt.setAttribute( 'data-label', firstOpt.textContent );
1490 - firstOpt.textContent = '';
1491 - }
1492 - } );
1493 - };
1494 -
1495 - [ 'focus', 'blur', 'change' ].forEach( function( eventName ) {
1496 - documentOn(
1497 - eventName,
1498 - selector,
1499 - function( event ) {
1500 - checkFloatLabel( event.target );
1501 - },
1502 - true
1503 - );
1504 - } );
1505 -
1506 - jQuery( document ).on( 'change', selector, function( event ) {
1507 - checkFloatLabel( event.target );
1508 - } );
1509 -
1510 - runOnLoad = function( firstLoad ) {
1511 - if ( firstLoad && document.activeElement && -1 !== [ 'INPUT', 'SELECT', 'TEXTAREA' ].indexOf( document.activeElement.tagName ) ) {
1512 - checkFloatLabel( document.activeElement );
1513 - } else if ( firstLoad ) {
1514 - document.querySelectorAll( '.frm_inside_container' ).forEach(
1515 - function( container ) {
1516 - const input = container.querySelector( 'input, select, textarea' );
1517 - if ( input && '' !== input.value ) {
1518 - checkFloatLabel( input );
1519 - }
1520 - }
1521 - );
1522 - }
1523 -
1524 - checkDropdownLabel();
1525 - };
1526 -
1527 - runOnLoad( true );
1528 -
1529 - jQuery( document ).on( 'frmPageChanged', function( event ) {
1530 - runOnLoad();
1531 - } );
1532 -
1533 - document.addEventListener( 'frm_after_start_over', function( event ) {
1534 - runOnLoad();
1535 - } );
1536 - }
1537 -
1538 - function shouldUpdateValidityMessage( target ) {
1539 - if ( 'INPUT' !== target.nodeName ) {
1540 - return false;
1541 - }
1542 -
1543 - if ( ! target.dataset.invmsg ) {
1544 - return false;
1545 - }
1546 -
1547 - if ( 'text' !== target.getAttribute( 'type' ) ) {
1548 - return false;
1549 - }
1550 -
1551 - if ( target.classList.contains( 'frm_verify' ) ) {
1552 - return false;
1553 - }
1554 -
1555 - return true;
1556 - }
1557 -
1558 - function maybeClearCustomValidityMessage( event, field ) {
1559 - let key,
1560 - isInvalid = false;
1561 -
1562 - if ( ! shouldUpdateValidityMessage( field ) ) {
1563 - return;
1564 - }
1565 -
1566 - for ( key in field.validity ) {
1567 - if ( 'customError' === key ) {
1568 - continue;
1569 - }
1570 - if ( 'valid' !== key && field.validity[ key ] === true ) {
1571 - isInvalid = true;
1572 - break;
1573 - }
1574 - }
1575 -
1576 - if ( ! isInvalid ) {
1577 - field.setCustomValidity( '' );
1578 - }
1579 - }
1580 -
1581 - function maybeShowNewTabFallbackMessage() {
1582 - let messageEl;
1583 -
1584 - if ( ! window.frmShowNewTabFallback ) {
1585 - return;
1586 - }
1587 -
1588 - messageEl = document.querySelector( '#frm_form_' + frmShowNewTabFallback.formId + '_container .frm_message' );
1589 - if ( ! messageEl ) {
1590 - return;
1591 - }
1592 -
1593 - messageEl.insertAdjacentHTML( 'beforeend', ' ' + frmShowNewTabFallback.message );
1594 - }
1595 -
1596 - function setCustomValidityMessage() {
1597 - let forms, length, index;
1598 -
1599 - forms = document.getElementsByClassName( 'frm-show-form' );
1600 - length = forms.length;
1601 -
1602 - for ( index = 0; index < length; ++index ) {
1603 - forms[ index ].addEventListener(
1604 - 'invalid',
1605 - function( event ) {
1606 - const target = event.target;
1607 -
1608 - if ( shouldUpdateValidityMessage( target ) ) {
1609 - target.setCustomValidity( target.dataset.invmsg );
1610 - }
1611 - },
1612 - true
1613 - );
1614 - }
1615 - }
1616 -
1617 - function enableSubmitButtonOnBackButtonPress() {
1618 - window.addEventListener( 'pageshow', function( event ) {
1619 - if ( event.persisted ) {
1620 - document.querySelectorAll( '.frm_loading_form' ).forEach(
1621 - function( form ) {
1622 - enableSubmitButton( jQuery( form ) );
1623 - }
1624 - );
1625 - removeSubmitLoading();
1626 - }
1627 - } );
1628 - }
1629 -
1630 - /**
1631 - * Destroys the formidable generated global hcaptcha object since it wouldn't otherwise render.
1632 - */
1633 - function destroyhCaptcha() {
1634 - if ( ! window.hasOwnProperty( 'hcaptcha' ) || ! document.querySelector( '.frm-show-form .h-captcha' ) ) {
1635 - return;
1636 - }
1637 - window.hcaptcha = null;
1638 - }
1639 -
1640 - /**
1641 - * @since 6.16.3
1642 - *
1643 - * @return {string} Unique key, used for duplicate checks.
1644 - */
1645 - function getUniqueKey() {
1646 - const uniqueKey = Array.from( window.crypto.getRandomValues( new Uint8Array( 8 ) ) )
1647 - .map( b => b.toString( 16 ).padStart( 2, '0' ) )
1648 - .join( '' );
1649 - const timestamp = Date.now().toString( 16 );
1650 - return uniqueKey + '-' + timestamp;
1651 - }
1652 -
1653 - /**
1654 - * Animates the scroll position of the document.
1655 - *
1656 - * @since 6.20
1657 - *
1658 - * @param {number} start
1659 - * @param {number} end
1660 - * @param {number} duration
1661 - * @return {void}
1662 - */
1663 - function animateScroll( start, end, duration ) {
1664 - if ( ! window.hasOwnProperty( 'performance' ) || ! window.hasOwnProperty( 'requestAnimationFrame' ) ) {
1665 - document.documentElement.scrollTop = end;
1666 - return;
1667 - }
1668 -
1669 - /* eslint-disable compat/compat */
1670 - const startTime = performance.now();
1671 - const step = currentTime => {
1672 - const progress = Math.min( ( currentTime - startTime ) / duration, 1 );
1673 - document.documentElement.scrollTop = start + ( ( end - start ) * progress );
1674 - if ( progress < 1 ) {
1675 - requestAnimationFrame( step );
1676 - }
1677 - };
1678 - requestAnimationFrame( step );
1679 - /* eslint-enable compat/compat */
1680 - }
1681 -
1682 1108 return {
1683 1109 init: function() {
1684 1110 jQuery( document ).off( 'submit.formidable', '.frm-show-form' );
1685 1111 jQuery( document ).on( 'submit.formidable', '.frm-show-form', frmFrontForm.submitForm );
@@ -1687,15 +1113,23 @@
1687 1113 jQuery( '.frm-show-form input[onblur], .frm-show-form textarea[onblur]' ).each( function() {
1688 1114 if ( jQuery( this ).val() === '' ) {
1689 1115 jQuery( this ).trigger( 'blur' );
1690 1116 }
1691 - } );
1117 + });
1692 1118
1119 + jQuery( document ).on( 'focus', '.frm_toggle_default', clearDefault );
1120 + jQuery( document ).on( 'blur', '.frm_toggle_default', replaceDefault );
1121 + jQuery( '.frm_toggle_default' ).trigger( 'blur' );
1122 +
1123 + jQuery( document.getElementById( 'frm_resend_email' ) ).on( 'click', resendEmail );
1124 +
1693 1125 jQuery( document ).on( 'change', '.frm-show-form input[name^="item_meta"], .frm-show-form select[name^="item_meta"], .frm-show-form textarea[name^="item_meta"]', frmFrontForm.fieldValueChanged );
1126 + jQuery( document ).on( 'change keyup', '.frm-show-form .frm_inside_container input, .frm-show-form .frm_inside_container select, .frm-show-form .frm_inside_container textarea', maybeShowLabel );
1694 1127
1695 - jQuery( document ).on( 'change', '.frm_verify[id^=field_]', onHoneypotFieldChange );
1128 + jQuery( document ).on( 'change', '[id^=frm_email_]', onHoneypotFieldChange );
1696 1129
1697 1130 jQuery( document ).on( 'click', 'a[data-frmconfirm]', confirmClick );
1131 + jQuery( 'a[data-frmtoggle]' ).on( 'click', toggleDiv );
1698 1132
1699 1133 checkForErrorsAndMaybeSetFocus();
1700 1134
1701 1135 // Focus on the first sub field when clicking to the primary label of combo field.
@@ -1700,76 +1134,53 @@
1700 1134
1701 1135 // Focus on the first sub field when clicking to the primary label of combo field.
1702 1136 changeFocusWhenClickComboFieldLabel();
1703 1137
1704 - initFloatingLabels();
1705 - maybeShowNewTabFallbackMessage();
1138 + // Add fallbacks for the beloved IE8
1139 + addIndexOfFallbackForIE8();
1140 + addTrimFallbackForIE8();
1141 + addFilterFallbackForIE8();
1142 + addKeysFallbackForIE8();
1143 + },
1706 1144
1707 - jQuery( document ).on( 'frmAfterAddRow', setCustomValidityMessage );
1708 - setCustomValidityMessage();
1709 - jQuery( document ).on( 'frmFieldChanged', maybeClearCustomValidityMessage );
1710 -
1711 - setSelectPlaceholderColor();
1712 -
1713 - // Elementor popup show event. Fix Elementor Popup && FF Captcha field conflicts
1714 - jQuery( document ).on( 'elementor/popup/show', frmRecaptcha );
1715 -
1716 - enableSubmitButtonOnBackButtonPress();
1717 - jQuery( document ).on(
1718 - 'frmPageChanged',
1719 - destroyhCaptcha
1720 - );
1145 + getFieldId: function( field, fullID ) {
1146 + return getFieldId( field, fullID );
1721 1147 },
1722 1148
1723 - getFieldId,
1149 + renderRecaptcha: function( captcha ) {
1150 + var formID, recaptchaID,
1151 + size = captcha.getAttribute( 'data-size' ),
1152 + rendered = captcha.getAttribute( 'data-rid' ) !== null,
1153 + params = {
1154 + 'sitekey': captcha.getAttribute( 'data-sitekey' ),
1155 + 'size': size,
1156 + 'theme': captcha.getAttribute( 'data-theme' )
1157 + };
1724 1158
1725 - /**
1726 - * Render a captcha field.
1727 - *
1728 - * @param {HTMLElement} captcha
1729 - * @param {string} captchaSelector
1730 - * @return {void}
1731 - */
1732 - renderCaptcha: function( captcha, captchaSelector ) {
1733 - const rendered = captcha.getAttribute( 'data-rid' ) !== null;
1734 1159 if ( rendered ) {
1735 1160 return;
1736 1161 }
1737 1162
1738 - const size = captcha.getAttribute( 'data-size' );
1739 - const params = {
1740 - sitekey: captcha.getAttribute( 'data-sitekey' ),
1741 - size: size,
1742 - theme: captcha.getAttribute( 'data-theme' )
1743 - };
1744 -
1745 1163 if ( size === 'invisible' ) {
1746 - const formID = captcha.closest( 'form' )?.querySelector( 'input[name="form_id"]' )?.value;
1747 -
1748 - const captchaLabel = captcha.closest( '.frm_form_field' )?.querySelector( '.frm_primary_label' );
1749 - if ( captchaLabel ) {
1750 - captchaLabel.style.display = 'none';
1751 - }
1752 -
1164 + formID = jQuery( captcha ).closest( 'form' ).find( 'input[name="form_id"]' ).val();
1165 + jQuery( captcha ).closest( '.frm_form_field .frm_primary_label' ).hide();
1753 1166 params.callback = function( token ) {
1754 1167 frmFrontForm.afterRecaptcha( token, formID );
1755 1168 };
1756 1169 }
1757 1170
1758 - const activeCaptcha = getSelectedCaptcha( captchaSelector );
1759 - const captchaContainer = typeof turnstile !== 'undefined' && turnstile === activeCaptcha ? '#' + captcha.id : captcha.id;
1760 - const captchaID = activeCaptcha.render( captchaContainer, params );
1171 + recaptchaID = grecaptcha.render( captcha.id, params );
1761 1172
1762 - captcha.setAttribute( 'data-rid', captchaID );
1173 + captcha.setAttribute( 'data-rid', recaptchaID );
1763 1174 },
1764 1175
1765 1176 afterSingleRecaptcha: function() {
1766 - const object = jQuery( '.frm-show-form .g-recaptcha' ).closest( 'form' )[ 0 ];
1177 + var object = jQuery( '.frm-show-form .g-recaptcha' ).closest( 'form' )[0];
1767 1178 frmFrontForm.submitFormNow( object );
1768 1179 },
1769 1180
1770 - afterRecaptcha: function( _, formID ) {
1771 - const object = jQuery( '#frm_form_' + formID + '_container form' )[ 0 ];
1181 + afterRecaptcha: function( token, formID ) {
1182 + var object = jQuery( '#frm_form_' + formID + '_container form' )[0];
1772 1183 frmFrontForm.submitFormNow( object );
1773 1184 },
1774 1185
1775 1186 submitForm: function( e ) {
@@ -1775,15 +1186,10 @@
1775 1186 submitForm: function( e ) {
1776 1187 frmFrontForm.submitFormManual( e, this );
1777 1188 },
1778 1189
1779 - /**
1780 - * @param {Event} e
1781 - * @param {HTMLElement} object The form object that is being submitted.
1782 - * @return {void}
1783 - */
1784 1190 submitFormManual: function( e, object ) {
1785 - let isPro, errors,
1191 + var isPro, errors,
1786 1192 invisibleRecaptcha = hasInvisibleRecaptcha( object ),
1787 1193 classList = object.className.trim().split( /\s+/gi );
1788 1194
1789 1195 if ( classList && invisibleRecaptcha.length < 1 ) {
@@ -1798,29 +1204,31 @@
1798 1204 }
1799 1205
1800 1206 e.preventDefault();
1801 1207
1802 - if ( typeof frmProForm !== 'undefined' && typeof frmProForm.submitAllowed === 'function' && ! frmProForm.submitAllowed( object ) ) {
1803 - return;
1208 + if ( typeof frmProForm !== 'undefined' && typeof frmProForm.submitAllowed === 'function' ) {
1209 + if ( ! frmProForm.submitAllowed( object ) ) {
1210 + return;
1211 + }
1804 1212 }
1805 1213
1806 - errors = frmFrontForm.validateFormSubmit( object );
1807 - if ( Object.keys( errors ).length !== 0 ) {
1808 - return;
1809 - }
1810 -
1811 1214 if ( invisibleRecaptcha.length ) {
1812 1215 showLoadingIndicator( jQuery( object ) );
1813 1216 executeInvisibleRecaptcha( invisibleRecaptcha );
1814 1217 } else {
1815 - showSubmitLoading( jQuery( object ) );
1816 1218
1817 - frmFrontForm.submitFormNow( object );
1219 + errors = frmFrontForm.validateFormSubmit( object );
1220 +
1221 + if ( Object.keys( errors ).length === 0 ) {
1222 + showSubmitLoading( jQuery( object ) );
1223 +
1224 + frmFrontForm.submitFormNow( object, classList );
1225 + }
1818 1226 }
1819 1227 },
1820 1228
1821 1229 submitFormNow: function( object ) {
1822 - let hasFileFields, antispamInput,
1230 + var hasFileFields, antispamInput,
1823 1231 classList = object.className.trim().split( /\s+/gi );
1824 1232
1825 1233 if ( object.hasAttribute( 'data-token' ) && null === object.querySelector( '[name="antispam_token"]' ) ) {
1826 1234 // include the antispam token on form submit.
@@ -1830,21 +1238,14 @@
1830 1238 antispamInput.value = object.getAttribute( 'data-token' );
1831 1239 object.appendChild( antispamInput );
1832 1240 }
1833 1241
1834 - // Add a unique ID, used for duplicate checks.
1835 - const uniqueIDInput = document.createElement( 'input' );
1836 - uniqueIDInput.type = 'hidden';
1837 - uniqueIDInput.name = 'unique_id';
1838 - uniqueIDInput.value = getUniqueKey();
1839 - object.appendChild( uniqueIDInput );
1840 -
1841 1242 if ( classList.indexOf( 'frm_ajax_submit' ) > -1 ) {
1842 1243 hasFileFields = jQuery( object ).find( 'input[type="file"]' ).filter( function() {
1843 1244 return !! this.value;
1844 - } ).length;
1245 + }).length;
1845 1246 if ( hasFileFields < 1 ) {
1846 - const action = jQuery( object ).find( 'input[name="frm_action"]' ).val();
1247 + action = jQuery( object ).find( 'input[name="frm_action"]' ).val();
1847 1248 frmFrontForm.checkFormErrors( object, action );
1848 1249 } else {
1849 1250 object.submit();
1850 1251 }
@@ -1852,13 +1253,8 @@
1852 1253 object.submit();
1853 1254 }
1854 1255 },
1855 1256
1856 - /**
1857 - * @param {HTMLElement|Object} object Form object. This might be a jQuery object.
1858 - *
1859 - * @return {Array} List of errors.
1860 - */
1861 1257 validateFormSubmit: function( object ) {
1862 1258 if ( typeof tinyMCE !== 'undefined' && jQuery( object ).find( '.wp-editor-wrap' ).length ) {
1863 1259 tinyMCE.triggerSave();
1864 1260 }
@@ -1875,20 +1271,16 @@
1875 1271
1876 1272 return jsErrors;
1877 1273 },
1878 1274
1879 - /**
1880 - * @param {HTMLElement|Object} object Form object. This might be a jQuery object.
1881 - * @return {Array} List of errors.
1882 - */
1883 1275 getAjaxFormErrors: function( object ) {
1884 - let customErrors, key;
1276 + var customErrors, key;
1885 1277
1886 1278 jsErrors = validateForm( object );
1887 1279 if ( typeof frmThemeOverride_jsErrors === 'function' ) { // eslint-disable-line camelcase
1888 - const action = jQuery( object ).find( 'input[name="frm_action"]' ).val();
1280 + action = jQuery( object ).find( 'input[name="frm_action"]' ).val();
1889 1281 customErrors = frmThemeOverride_jsErrors( action, object );
1890 - if ( Object.keys( customErrors ).length ) {
1282 + if ( Object.keys( customErrors ).length ) {
1891 1283 for ( key in customErrors ) {
1892 1284 jsErrors[ key ] = customErrors[ key ];
1893 1285 }
1894 1286 }
@@ -1893,22 +1285,13 @@
1893 1285 }
1894 1286 }
1895 1287 }
1896 1288
1897 - triggerCustomEvent( document, 'frm_get_ajax_form_errors', {
1898 - formEl: object,
1899 - errors: jsErrors
1900 - } );
1901 -
1902 1289 return jsErrors;
1903 1290 },
1904 1291
1905 - /**
1906 - * @param {HTMLElement|Object} object Form object. This might be a jQuery object.
1907 - * @return {void}
1908 - */
1909 1292 addAjaxFormErrors: function( object ) {
1910 - let key, $fieldCont;
1293 + var key, $fieldCont;
1911 1294 removeAllErrors();
1912 1295
1913 1296 for ( key in jsErrors ) {
1914 1297 $fieldCont = jQuery( object ).find( '#frm_field_' + key + '_container' );
@@ -1924,20 +1307,31 @@
1924 1307 scrollToFirstField( object );
1925 1308 checkForErrorsAndMaybeSetFocus();
1926 1309 },
1927 1310
1928 - checkFormErrors: getFormErrors,
1929 - checkRequiredField,
1930 - showSubmitLoading,
1931 - removeSubmitLoading,
1311 + checkFormErrors: function( object, action ) {
1312 + getFormErrors( object, action );
1313 + },
1932 1314
1933 - scrollToID: function( id ) {
1934 - const object = jQuery( document.getElementById( id ) );
1935 - frmFrontForm.scrollMsg( object, false );
1315 + checkRequiredField: function( field, errors ) {
1316 + return checkRequiredField( field, errors );
1936 1317 },
1937 1318
1319 + showSubmitLoading: function( $object ) {
1320 + showSubmitLoading( $object );
1321 + },
1322 +
1323 + removeSubmitLoading: function( $object, enable, processesRunning ) {
1324 + removeSubmitLoading( $object, enable, processesRunning );
1325 + },
1326 +
1327 + scrollToID: function( id ) {
1328 + var object = jQuery( document.getElementById( id ) );
1329 + frmFrontForm.scrollMsg( object, false );
1330 + },
1331 +
1938 1332 scrollMsg: function( id, object, animate ) {
1939 - let newPos, m, b, screenTop, screenBottom,
1333 + var newPos, m, b, screenTop, screenBottom,
1940 1334 scrollObj = '';
1941 1335 if ( typeof object === 'undefined' ) {
1942 1336 scrollObj = jQuery( document.getElementById( 'frm_form_' + id + '_container' ) );
1943 1337 if ( scrollObj.length < 1 ) {
@@ -1950,12 +1344,12 @@
1950 1344 }
1951 1345
1952 1346 jQuery( scrollObj ).trigger( 'focus' );
1953 1347 newPos = scrollObj.offset().top;
1954 - if ( ! newPos || frm_js.offset === '-1' ) { // eslint-disable-line camelcase
1348 + if ( ! newPos || frm_js.offset === '-1' ) {
1955 1349 return;
1956 1350 }
1957 - newPos = newPos - frm_js.offset; // eslint-disable-line camelcase
1351 + newPos = newPos - frm_js.offset;
1958 1352
1959 1353 m = jQuery( 'html' ).css( 'margin-top' );
1960 1354 b = jQuery( 'body' ).css( 'margin-top' );
1961 1355 if ( m || b ) {
@@ -1968,11 +1362,11 @@
1968 1362
1969 1363 if ( newPos > screenBottom || newPos < screenTop ) {
1970 1364 // Not in view
1971 1365 if ( typeof animate === 'undefined' ) {
1972 - document.documentElement.scrollTop = newPos;
1366 + jQuery( window ).scrollTop( newPos );
1973 1367 } else {
1974 - animateScroll( screenTop, newPos, 500 );
1368 + jQuery( 'html,body' ).animate({ scrollTop: newPos }, 500 );
1975 1369 }
1976 1370 return false;
1977 1371 }
1978 1372 }
@@ -1980,9 +1374,9 @@
1980 1374
1981 1375 fieldValueChanged: function( e ) {
1982 1376 /*jshint validthis:true */
1983 1377
1984 - const fieldId = frmFrontForm.getFieldId( this, false );
1378 + var fieldId = frmFrontForm.getFieldId( this, false );
1985 1379 if ( ! fieldId || typeof fieldId === 'undefined' ) {
1986 1380 return;
1987 1381 }
1988 1382
@@ -1989,9 +1383,9 @@
1989 1383 if ( e.frmTriggered && e.frmTriggered == fieldId ) {
1990 1384 return;
1991 1385 }
1992 1386
1993 - jQuery( document ).trigger( 'frmFieldChanged', [ this, fieldId, e ] );
1387 + jQuery( document ).trigger( 'frmFieldChanged', [ this, fieldId, e ]);
1994 1388
1995 1389 if ( e.selfTriggered !== true ) {
1996 1390 maybeValidateChange( this );
1997 1391 }
@@ -1996,10 +1390,56 @@
1996 1390 maybeValidateChange( this );
1997 1391 }
1998 1392 },
1999 1393
1394 + savingDraft: function( object ) {
1395 + console.warn( 'DEPRECATED: function frmFrontForm.savingDraft in v3.0 use frmProForm.savingDraft' );
1396 + if ( typeof frmProForm !== 'undefined' ) {
1397 + return frmProForm.savingDraft( object );
1398 + }
1399 + },
1400 +
1401 + goingToPreviousPage: function( object ) {
1402 + console.warn( 'DEPRECATED: function frmFrontForm.goingToPreviousPage in v3.0 use frmProForm.goingToPreviousPage' );
1403 + if ( typeof frmProForm !== 'undefined' ) {
1404 + return frmProForm.goingToPreviousPage( object );
1405 + }
1406 + },
1407 +
1408 + hideOrShowFields: function() {
1409 + console.warn( 'DEPRECATED: function frmFrontForm.hideOrShowFields in v3.0 use frmProForm.hideOrShowFields' );
1410 + if ( typeof frmProForm !== 'undefined' ) {
1411 + frmProForm.hideOrShowFields();
1412 + }
1413 + },
1414 +
1415 + hidePreviouslyHiddenFields: function() {
1416 + console.warn( 'DEPRECATED: function frmFrontForm.hidePreviouslyHiddenFields in v3.0 use frmProForm.hidePreviouslyHiddenFields' );
1417 + if ( typeof frmProForm !== 'undefined' ) {
1418 + frmProForm.hidePreviouslyHiddenFields();
1419 + }
1420 + },
1421 +
1422 + checkDependentDynamicFields: function( ids ) {
1423 + console.warn( 'DEPRECATED: function frmFrontForm.checkDependentDynamicFields in v3.0 use frmProForm.checkDependentDynamicFields' );
1424 + if ( typeof frmProForm !== 'undefined' ) {
1425 + frmProForm.checkDependentDynamicFields( ids );
1426 + }
1427 + },
1428 +
1429 + checkDependentLookupFields: function( ids ) {
1430 + console.warn( 'DEPRECATED: function frmFrontForm.checkDependentLookupFields in v3.0 use frmProForm.checkDependentLookupFields' );
1431 + if ( typeof frmProForm !== 'undefined' ) {
1432 + frmProForm.checkDependentLookupFields( ids );
1433 + }
1434 + },
1435 +
1436 + loadGoogle: function() {
1437 + console.warn( 'DEPRECATED: function frmFrontForm.loadGoogle in v3.0 use frmProForm.loadGoogle' );
1438 + frmProForm.loadGoogle();
1439 + },
1440 +
2000 1441 escapeHtml: function( text ) {
2001 - console.warn( 'DEPRECATED: function frmFrontForm.escapeHtml in v6.17' );
2002 1442 return text
2003 1443 .replace( /&/g, '&amp;' )
2004 1444 .replace( /</g, '&lt;' )
2005 1445 .replace( />/g, '&gt;' )
@@ -2006,85 +1446,97 @@
2006 1446 .replace( /"/g, '&quot;' )
2007 1447 .replace( /'/g, '&#039;' );
2008 1448 },
2009 1449
2010 - /**
2011 - * This function was used in old back end code in v2.0.
2012 - *
2013 - * @param {string} classes
2014 - * @return {void}
2015 - */
2016 1450 invisible: function( classes ) {
2017 - console.warn( 'DEPRECATED: function frmFrontForm.invisible in v6.16.3' );
2018 1451 jQuery( classes ).css( 'visibility', 'hidden' );
2019 1452 },
2020 1453
2021 - /**
2022 - * This function was used in old back end code in v2.0.
2023 - *
2024 - * @param {string} classes
2025 - * @return {void}
2026 - */
2027 1454 visible: function( classes ) {
2028 - console.warn( 'DEPRECATED: function frmFrontForm.visible in v6.16.3' );
2029 1455 jQuery( classes ).css( 'visibility', 'visible' );
2030 - },
2031 -
2032 - triggerCustomEvent: triggerCustomEvent,
2033 - documentOn
1456 + }
2034 1457 };
2035 1458 }
1459 +frmFrontForm = frmFrontFormJS();
2036 1460
2037 -window.frmFrontForm = frmFrontFormJS();
2038 -
2039 1461 jQuery( document ).ready( function() {
2040 1462 frmFrontForm.init();
2041 -} );
1463 +});
2042 1464
2043 1465 function frmRecaptcha() {
2044 - frmCaptcha( '.frm-g-recaptcha' );
1466 + var c, cl,
1467 + captchas = jQuery( '.frm-g-recaptcha' );
1468 + for ( c = 0, cl = captchas.length; c < cl; c++ ) {
1469 + frmFrontForm.renderRecaptcha( captchas[c]);
1470 + }
2045 1471 }
2046 1472
2047 -function frmTurnstile() {
2048 - frmCaptcha( '.cf-turnstile' );
1473 +function frmAfterRecaptcha( token ) {
1474 + frmFrontForm.afterSingleRecaptcha( token );
2049 1475 }
2050 1476
2051 -function frmCaptcha( captchaSelector ) {
2052 - let c;
2053 - const captchas = document.querySelectorAll( captchaSelector );
2054 - const cl = captchas.length;
2055 - for ( c = 0; c < cl; c++ ) {
2056 - const closestForm = captchas[ c ].closest( 'form' );
2057 - const formIsVisible = closestForm && closestForm.offsetParent !== null;
2058 - const captcha = captchas[ c ];
2059 - if ( ! formIsVisible ) {
2060 - // If the form is not visible, try again later in 400ms.
2061 - // This fixes issues where the form fades visible on page load.
2062 - // Or whne the form is inside of a modal.
2063 - const interval = setInterval(
2064 - function() {
2065 - if ( closestForm && closestForm.offsetParent !== null ) {
2066 - frmFrontForm.renderCaptcha( captcha, captchaSelector );
2067 - clearInterval( interval );
2068 - }
2069 - },
2070 - 400
2071 - );
2072 - continue;
1477 +function frmUpdateField( entryId, fieldId, value, message, num ) {
1478 + jQuery( document.getElementById( 'frm_update_field_' + entryId + '_' + fieldId + '_' + num ) ).html( '<span class="frm-loading-img"></span>' );
1479 + jQuery.ajax({
1480 + type: 'POST',
1481 + url: frm_js.ajax_url,
1482 + data: {
1483 + action: 'frm_entries_update_field_ajax',
1484 + entry_id: entryId,
1485 + field_id: fieldId,
1486 + value: value,
1487 + nonce: frm_js.nonce
1488 + },
1489 + success: function() {
1490 + if ( message.replace( /^\s+|\s+$/g, '' ) === '' ) {
1491 + jQuery( document.getElementById( 'frm_update_field_' + entryId + '_' + fieldId + '_' + num ) ).fadeOut( 'slow' );
1492 + } else {
1493 + jQuery( document.getElementById( 'frm_update_field_' + entryId + '_' + fieldId + '_' + num ) ).replaceWith( message );
1494 + }
2073 1495 }
2074 - frmFrontForm.renderCaptcha( captcha, captchaSelector );
2075 - }
1496 + });
2076 1497 }
2077 1498
2078 -function getSelectedCaptcha( captchaSelector ) {
2079 - if ( captchaSelector === '.frm-g-recaptcha' ) {
2080 - return grecaptcha;
2081 - }
2082 - if ( document.querySelector( '.cf-turnstile' ) ) {
2083 - return turnstile;
2084 - }
2085 - return hcaptcha;
1499 +function frmDeleteEntry( entryId, prefix ) {
1500 + console.warn( 'DEPRECATED: function frmDeleteEntry in v2.0.13 use frmFrontForm.deleteEntry' );
1501 + jQuery( document.getElementById( 'frm_delete_' + entryId ) ).replaceWith( '<span class="frm-loading-img" id="frm_delete_' + entryId + '"></span>' );
1502 + jQuery.ajax({
1503 + type: 'POST',
1504 + url: frm_js.ajax_url,
1505 + data: {
1506 + action: 'frm_entries_destroy',
1507 + entry: entryId,
1508 + nonce: frm_js.nonce
1509 + },
1510 + success: function( html ) {
1511 + if ( html.replace( /^\s+|\s+$/g, '' ) === 'success' ) {
1512 + jQuery( document.getElementById( prefix + entryId ) ).fadeOut( 'slow' );
1513 + } else {
1514 + jQuery( document.getElementById( 'frm_delete_' + entryId ) ).replaceWith( html );
1515 + }
1516 + }
1517 + });
2086 1518 }
2087 1519
2088 -function frmAfterRecaptcha( token ) {
2089 - frmFrontForm.afterSingleRecaptcha( token );
1520 +function frmOnSubmit( e ) {
1521 + console.warn( 'DEPRECATED: function frmOnSubmit in v2.0 use frmFrontForm.submitForm' );
1522 + frmFrontForm.submitForm( e, this );
1523 +}
1524 +
1525 +function frm_resend_email( entryId, formId ) { // eslint-disable-line camelcase
1526 + var $link = jQuery( document.getElementById( 'frm_resend_email' ) );
1527 + console.warn( 'DEPRECATED: function frm_resend_email in v2.0' );
1528 + $link.append( '<span class="spinner" style="display:inline"></span>' );
1529 + jQuery.ajax({
1530 + type: 'POST',
1531 + url: frm_js.ajax_url,
1532 + data: {
1533 + action: 'frm_entries_send_email',
1534 + entry_id: entryId,
1535 + form_id: formId,
1536 + nonce: frm_js.nonce
1537 + },
1538 + success: function( msg ) {
1539 + $link.replaceWith( msg );
1540 + }
1541 + });
2090 1542 }