PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.4
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.4
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
formidable / js / formidable.js

formidable.js in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 5.4, at js/formidable.js

1,573 lines 43.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* exported frmRecaptcha, frmAfterRecaptcha, frmUpdateField, frmDeleteEntry, frmOnSubmit, frm_resend_email */
2
3 var frmFrontForm;
4
5 function frmFrontFormJS() {
6 'use strict';
7
8 /*global jQuery:false, frm_js, grecaptcha, frmProForm, tinyMCE */
9 /*global frmThemeOverride_jsErrors, frmThemeOverride_frmPlaceError, frmThemeOverride_frmAfterSubmit */
10
11 var action = '';
12 var jsErrors = [];
13
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 }
25 }
26
27 /* Get the ID of the field that changed*/
28 function getFieldId( field, fullID ) {
29 var nameParts, fieldId,
30 isRepeating = false,
31 fieldName = '';
32 if ( field instanceof jQuery ) {
33 fieldName = field.attr( 'name' );
34 } else {
35 fieldName = field.name;
36 }
37
38 if ( typeof fieldName === 'undefined' ) {
39 fieldName = '';
40 }
41
42 if ( fieldName === '' ) {
43 if ( field instanceof jQuery ) {
44 fieldName = field.data( 'name' );
45 } else {
46 fieldName = field.getAttribute( 'data-name' );
47 }
48
49 if ( typeof fieldName === 'undefined' ) {
50 fieldName = '';
51 }
52
53 if ( fieldName !== '' && fieldName ) {
54 return fieldName;
55 }
56 return 0;
57 }
58
59 nameParts = fieldName.replace( 'item_meta[', '' ).replace( '[]', '' ).split( ']' );
60 //TODO: Fix this for checkboxes and address fields
61 if ( nameParts.length < 1 ) {
62 return 0;
63 }
64 nameParts = nameParts.filter( function( n ) {
65 return n !== '';
66 });
67
68 fieldId = nameParts[0];
69
70 if ( nameParts.length === 1 ) {
71 return fieldId;
72 }
73
74 if ( nameParts[1] === '[form' || nameParts[1] === '[row_ids' ) {
75 return 0;
76 }
77
78 // Check if 'this' is in a repeating section
79 if ( jQuery( 'input[name="item_meta[' + fieldId + '][form]"]' ).length ) {
80
81 // this is a repeatable section with name: item_meta[repeating-section-id][row-id][field-id]
82 fieldId = nameParts[2].replace( '[', '' );
83 isRepeating = true;
84 }
85
86 // Check if 'this' is an other text field and get field ID for it
87 if ( 'other' === fieldId ) {
88 if ( isRepeating ) {
89 // name for other fields: item_meta[370][0][other][414]
90 fieldId = nameParts[3].replace( '[', '' );
91 } else {
92 // Other field name: item_meta[other][370]
93 fieldId = nameParts[1].replace( '[', '' );
94 }
95 }
96
97 if ( fullID === true ) {
98 // For use in the container div id
99 if ( fieldId === nameParts[0]) {
100 fieldId = fieldId + '-' + nameParts[1].replace( '[', '' );
101 } else {
102 fieldId = fieldId + '-' + nameParts[0] + '-' + nameParts[1].replace( '[', '' );
103 }
104 }
105
106 return fieldId;
107 }
108
109 /**
110 * Disable the submit button for a given jQuery form object
111 *
112 * @since 2.03.02
113 *
114 * @param {object} $form
115 */
116 function disableSubmitButton( $form ) {
117 $form.find( 'input[type="submit"], input[type="button"], button[type="submit"]' ).attr( 'disabled', 'disabled' );
118 }
119
120 /**
121 * Enable the submit button for a given jQuery form object
122 *
123 * @since 2.03.02
124 *
125 * @param {object} $form
126 */
127 function enableSubmitButton( $form ) {
128 $form.find( 'input[type="submit"], input[type="button"], button[type="submit"]' ).prop( 'disabled', false );
129 }
130
131 /**
132 * Disable the save draft link for a given jQuery form object
133 *
134 * @since 4.04.03
135 *
136 * @param {object} $form
137 */
138 function disableSaveDraft( $form ) {
139 $form.find( 'a.frm_save_draft' ).css( 'pointer-events', 'none' );
140 }
141
142 /**
143 * Enable the save draft link for a given jQuery form object
144 *
145 * @since 4.04.03
146 *
147 * @param {object} $form
148 */
149 function enableSaveDraft( $form ) {
150 $form.find( 'a.frm_save_draft' ).css( 'pointer-events', '' );
151 }
152
153 function validateForm( object ) {
154 var r, rl, n, nl, fields, field, value, requiredFields,
155 errors = [];
156
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;
166 }
167 errors = checkRequiredField( requiredFields[r], errors );
168 }
169 }
170
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 );
189 }
190 }
191 }
192 }
193
194 errors = validateRecaptcha( object, errors );
195
196 return errors;
197 }
198
199 /**
200 * @since 5.0.10
201 *
202 * @param {object} element
203 * @param {string} targetClass
204 * @returns {boolean}
205 */
206 function hasClass( element, targetClass ) {
207 var className = ' ' + element.className + ' ';
208 return -1 !== className.indexOf( ' ' + targetClass + ' ' );
209 }
210
211 function maybeValidateChange( field ) {
212 if ( field.type === 'url' ) {
213 maybeAddHttpToUrl( field );
214 }
215 if ( jQuery( field ).closest( 'form' ).hasClass( 'frm_js_validate' ) ) {
216 validateField( field );
217 }
218 }
219
220 function maybeAddHttpToUrl( field ) {
221 var url = field.value;
222 var matches = url.match( /^(https?|ftps?|mailto|news|feed|telnet):/ );
223 if ( field.value !== '' && matches === null ) {
224 field.value = 'http://' + url;
225 }
226 }
227
228 function validateField( field ) {
229 var key,
230 errors = [],
231 $fieldCont = jQuery( field ).closest( '.frm_form_field' );
232
233 if ( $fieldCont.hasClass( 'frm_required_field' ) && ! jQuery( field ).hasClass( 'frm_optional' ) ) {
234 errors = checkRequiredField( field, errors );
235 }
236
237 if ( errors.length < 1 ) {
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 }
249 }
250
251 removeFieldError( $fieldCont );
252 if ( Object.keys( errors ).length > 0 ) {
253 for ( key in errors ) {
254 addFieldError( $fieldCont, key, errors );
255 }
256 }
257 }
258
259 function checkRequiredField( field, errors ) {
260 var checkGroup, tempVal, i, placeholder,
261 val = '',
262 fieldID = '',
263 fileID = field.getAttribute( 'data-frmfile' );
264
265 if ( field.type === 'hidden' && fileID === null && ! isAppointmentField( field ) && ! isInlineDatepickerField( field ) ) {
266 return errors;
267 }
268
269 if ( field.type === 'checkbox' || field.type === 'radio' ) {
270 checkGroup = jQuery( 'input[name="' + field.name + '"]' ).closest( '.frm_required_field' ).find( 'input:checked' );
271 jQuery( checkGroup ).each( function() {
272 val = this.value;
273 });
274 } else if ( field.type === 'file' || fileID ) {
275 if ( typeof fileID === 'undefined' ) {
276 fileID = getFieldId( field, true );
277 fileID = fileID.replace( 'file', '' );
278 }
279
280 if ( typeof errors[ fileID ] === 'undefined' ) {
281 val = getFileVals( fileID );
282 }
283 fieldID = fileID;
284 } else {
285 if ( hasClass( field, 'frm_pos_none' ) ) {
286 // skip hidden other fields
287 return errors;
288 }
289
290 val = jQuery( field ).val();
291 if ( val === null ) {
292 val = '';
293 } else if ( typeof val !== 'string' ) {
294 tempVal = val;
295 val = '';
296 for ( i = 0; i < tempVal.length; i++ ) {
297 if ( tempVal[i] !== '' ) {
298 val = tempVal[i];
299 }
300 }
301 }
302
303 if ( hasClass( field, 'frm_other_input' ) ) {
304 fieldID = getFieldId( field, false );
305
306 if ( val === '' ) {
307 field = document.getElementById( field.id.replace( '-otext', '' ) );
308 }
309 } else {
310 fieldID = getFieldId( field, true );
311 }
312
313 if ( hasClass( field, 'frm_time_select' ) ) {
314 // set id for time field
315 fieldID = fieldID.replace( '-H', '' ).replace( '-m', '' );
316 } else if ( isSignatureField( field ) ) {
317 if ( val === '' ) {
318 val = jQuery( field ).closest( '.frm_form_field' ).find( '[name="' + field.getAttribute( 'name' ).replace( '[typed]', '[output]' ) + '"]' ).val();
319 }
320 fieldID = fieldID.replace( '-typed', '' );
321 }
322
323 placeholder = field.getAttribute( 'data-frmplaceholder' );
324 if ( placeholder !== null && val === placeholder ) {
325 val = '';
326 }
327 }
328
329 if ( val === '' ) {
330 if ( fieldID === '' ) {
331 fieldID = getFieldId( field, true );
332 }
333 if ( ! ( fieldID in errors ) ) {
334 errors[ fieldID ] = getFieldValidationMessage( field, 'data-reqmsg' );
335 }
336 }
337
338 return errors;
339 }
340
341 function isSignatureField( field ) {
342 var name = field.getAttribute( 'name' );
343 return 'string' === typeof name && '[typed]' === name.substr( -7 );
344 }
345
346 function isAppointmentField( field ) {
347 return hasClass( field, 'ssa_appointment_form_field_appointment_id' );
348 }
349
350 function isInlineDatepickerField( field ) {
351 return 'hidden' === field.type && '_alt' === field.id.substr( -4 ) && hasClass( field.nextElementSibling, 'frm_date_inline' );
352 }
353
354 function getFileVals( fileID ) {
355 var val = '',
356 fileFields = jQuery( 'input[name="file' + fileID + '"], input[name="file' + fileID + '[]"], input[name^="item_meta[' + fileID + ']"]' );
357
358 fileFields.each( function() {
359 if ( val === '' ) {
360 val = this.value;
361 }
362 });
363 return val;
364 }
365
366 function checkUrlField( field, errors ) {
367 var fieldID,
368 url = field.value;
369
370 if ( url !== '' && ! /^http(s)?:\/\/(?:localhost|(?:[\da-z\.-]+\.[\da-z\.-]+))/i.test( url ) ) {
371 fieldID = getFieldId( field, true );
372 if ( ! ( fieldID in errors ) ) {
373 errors[ fieldID ] = getFieldValidationMessage( field, 'data-invmsg' );
374 }
375 }
376 return errors;
377 }
378
379 function checkEmailField( field, errors ) {
380 var fieldID = getFieldId( field, true ),
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;
382
383 // validate the current field we're editing first
384 if ( '' !== field.value && pattern.test( field.value ) === false ) {
385 errors[ fieldID ] = getFieldValidationMessage( field, 'data-invmsg' );
386 }
387
388 confirmField( field, errors );
389 return errors;
390 }
391
392 function checkPasswordField( field, errors ) {
393 confirmField( field, errors );
394 return errors;
395 }
396
397 function confirmField( field, errors ) {
398 var value, confirmValue, firstField,
399 fieldID = getFieldId( field, true ),
400 strippedId = field.id.replace( 'conf_', '' ),
401 strippedFieldID = fieldID.replace( 'conf_', '' ),
402 confirmField = document.getElementById( strippedId.replace( 'field_', 'field_conf_' ) );
403
404 if ( confirmField === null || typeof errors[ 'conf_' + strippedFieldID ] !== 'undefined' ) {
405 return;
406 }
407
408 if ( fieldID !== strippedFieldID ) {
409 firstField = document.getElementById( strippedId );
410 value = firstField.value;
411 confirmValue = confirmField.value;
412 if ( '' !== value && '' !== confirmValue && value !== confirmValue ) {
413 errors[ 'conf_' + strippedFieldID ] = getFieldValidationMessage( confirmField, 'data-confmsg' );
414 }
415 } else {
416 validateField( confirmField );
417 }
418 }
419
420 function checkNumberField( field, errors ) {
421 var fieldID,
422 number = field.value;
423
424 if ( number !== '' && isNaN( number / 1 ) !== false ) {
425 fieldID = getFieldId( field, true );
426 if ( ! ( fieldID in errors ) ) {
427 errors[ fieldID ] = getFieldValidationMessage( field, 'data-invmsg' );
428 }
429 }
430 return errors;
431 }
432
433 function checkPatternField( field, errors ) {
434 var fieldID,
435 text = field.value,
436 format = getFieldValidationMessage( field, 'pattern' );
437
438 if ( format !== '' && text !== '' ) {
439 fieldID = getFieldId( field, true );
440 if ( ! ( fieldID in errors ) ) {
441 format = new RegExp( '^' + format + '$', 'i' );
442 if ( format.test( text ) === false ) {
443 errors[ fieldID ] = getFieldValidationMessage( field, 'data-invmsg' );
444 }
445 }
446 }
447 return errors;
448 }
449
450 function hasInvisibleRecaptcha( object ) {
451 var recaptcha, recaptchaID, alreadyChecked;
452
453 if ( isGoingToPrevPage( object ) ) {
454 return false;
455 }
456
457 recaptcha = jQuery( object ).find( '.frm-g-recaptcha[data-size="invisible"], .g-recaptcha[data-size="invisible"]' );
458 if ( recaptcha.length ) {
459 recaptchaID = recaptcha.data( 'rid' );
460 alreadyChecked = grecaptcha.getResponse( recaptchaID );
461 if ( alreadyChecked.length === 0 ) {
462 return recaptcha;
463 } else {
464 return false;
465 }
466 } else {
467 return false;
468 }
469 }
470
471 function executeInvisibleRecaptcha( invisibleRecaptcha ) {
472 var recaptchaID = invisibleRecaptcha.data( 'rid' );
473 grecaptcha.reset( recaptchaID );
474 grecaptcha.execute( recaptchaID );
475 }
476
477 function validateRecaptcha( form, errors ) {
478 var recaptchaID, response, fieldContainer, fieldID,
479 $recaptcha = jQuery( form ).find( '.frm-g-recaptcha' );
480 if ( $recaptcha.length ) {
481 recaptchaID = $recaptcha.data( 'rid' );
482
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 }
492
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 ] = '';
497 }
498 }
499 return errors;
500 }
501
502 function getFieldValidationMessage( field, messageType ) {
503 var msg, errorHtml;
504
505 msg = field.getAttribute( messageType );
506 if ( null === msg ) {
507 msg = '';
508 }
509
510 if ( '' !== msg && shouldWrapErrorHtmlAroundMessageType( messageType ) ) {
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 }
517 }
518
519 return msg;
520 }
521
522 function shouldWrapErrorHtmlAroundMessageType( type ) {
523 return 'pattern' !== type;
524 }
525
526 function shouldJSValidate( object ) {
527 var validate = jQuery( object ).hasClass( 'frm_js_validate' );
528 if ( validate && typeof frmProForm !== 'undefined' && ( frmProForm.savingDraft( object ) || frmProForm.goingToPreviousPage( object ) ) ) {
529 validate = false;
530 }
531
532 return validate;
533 }
534
535 function getFormErrors( object, action ) {
536 var fieldset, data, success, error;
537
538 if ( typeof action === 'undefined' ) {
539 jQuery( object ).find( 'input[name="frm_action"]' ).val();
540 }
541
542 fieldset = jQuery( object ).find( '.frm_form_field' );
543 fieldset.addClass( 'frm_doing_ajax' );
544
545 data = jQuery( object ).serialize() + '&action=frm_entries_' + action + '&nonce=' + frm_js.nonce;
546
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 }
554
555 response = response.replace( /^\s+|\s+$/g, '' );
556 if ( response.indexOf( '{' ) === 0 ) {
557 response = JSON.parse( response );
558 } else {
559 response = defaultResponse;
560 }
561
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
567
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 );
577
578 setTimeout(
579 function() {
580 var container, input, previousInput;
581
582 replaceContent.replaceWith( response.content );
583
584 addUrlParam( response );
585
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 }
591
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"]' );
596
597 if ( previousInput.length ) {
598 previousInput.replaceWith( input );
599 } else {
600 container.append( input );
601 }
602 }
603
604 afterFormSubmitted( object, response );
605 },
606 delay
607 );
608 } else if ( Object.keys( response.errors ).length ) {
609 // errors were returned
610
611 removeSubmitLoading( jQuery( object ), 'enable' );
612
613 //show errors
614 contSubmit = true;
615 removeAllErrors();
616
617 $fieldCont = null;
618
619 for ( key in response.errors ) {
620 $fieldCont = jQuery( object ).find( '#frm_field_' + key + '_container' );
621
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' );
632 }
633 }
634
635 if ( $fieldCont.is( ':visible' ) ) {
636 addFieldError( $fieldCont, key, response.errors );
637 contSubmit = false;
638 }
639 }
640 }
641
642 jQuery( object ).find( '.frm-g-recaptcha, .g-recaptcha' ).each( function() {
643 var $recaptcha = jQuery( this ),
644 recaptchaID = $recaptcha.data( 'rid' );
645
646 if ( typeof grecaptcha !== 'undefined' && grecaptcha ) {
647 if ( recaptchaID ) {
648 grecaptcha.reset( recaptchaID );
649 } else {
650 grecaptcha.reset();
651 }
652 }
653 });
654
655 jQuery( document ).trigger( 'frmFormErrors', [ object, response ]);
656
657 fieldset.removeClass( 'frm_doing_ajax' );
658 scrollToFirstField( object );
659
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
668
669 showFileLoading( object );
670
671 object.submit();
672 }
673 };
674
675 error = function() {
676 jQuery( object ).find( 'input[type="submit"], input[type="button"]' ).prop( 'disabled', false );
677 object.submit();
678 };
679
680 postToAjaxUrl( object, data, success, error );
681 }
682
683 function postToAjaxUrl( form, data, success, error ) {
684 var ajaxUrl, action, ajaxParams;
685
686 ajaxUrl = frm_js.ajax_url;
687 action = form.getAttribute( 'action' );
688
689 if ( 'string' === typeof action && -1 !== action.indexOf( '?action=frm_forms_preview' ) ) {
690 ajaxUrl = action.split( '?action=frm_forms_preview' )[0];
691 }
692
693 ajaxParams = {
694 type: 'POST',
695 url: ajaxUrl,
696 data: data,
697 success: success
698 };
699
700 if ( 'function' === typeof error ) {
701 ajaxParams.error = error;
702 }
703
704 jQuery.ajax( ajaxParams );
705 }
706
707 function afterFormSubmitted( object, response ) {
708 var formCompleted = jQuery( response.content ).find( '.frm_message' );
709 if ( formCompleted.length ) {
710 jQuery( document ).trigger( 'frmFormComplete', [ object, response ]);
711 } else {
712 jQuery( document ).trigger( 'frmPageChanged', [ object, response ]);
713 }
714 }
715
716 function removeAddedScripts( formContainer, formID ) {
717 var endReplace = jQuery( '.frm_end_ajax_' + formID );
718 if ( endReplace.length ) {
719 formContainer.nextUntil( '.frm_end_ajax_' + formID ).remove();
720 endReplace.remove();
721 }
722 }
723
724 function maybeSlideOut( oldContent, newContent ) {
725 var c,
726 newClass = 'frm_slideout';
727 if ( newContent.indexOf( ' frm_slide' ) !== -1 ) {
728 c = oldContent.children();
729 if ( newContent.indexOf( ' frm_going_back' ) !== -1 ) {
730 newClass += ' frm_going_back';
731 }
732 c.removeClass( 'frm_going_back' );
733 c.addClass( newClass );
734 return 300;
735 }
736 return 0;
737 }
738
739 function addUrlParam( response ) {
740 var url;
741 if ( history.pushState && typeof response.page !== 'undefined' ) {
742 url = addQueryVar( 'frm_page', response.page );
743 window.history.pushState({ 'html': response.html }, '', '?' + url );
744 }
745 }
746
747 function addQueryVar( key, value ) {
748 var kvp, i, x;
749
750 key = encodeURI( key );
751 value = encodeURI( value );
752
753 kvp = document.location.search.substr( 1 ).split( '&' );
754
755 i = kvp.length;
756 while ( i-- ) {
757 x = kvp[i].split( '=' );
758
759 if ( x[0] == key ) {
760 x[1] = value;
761 kvp[i] = x.join( '=' );
762 break;
763 }
764 }
765
766 if ( i < 0 ) {
767 kvp[ kvp.length ] = [ key, value ].join( '=' );
768 }
769
770 return kvp.join( '&' );
771 }
772
773 function addFieldError( $fieldCont, key, jsErrors ) {
774 var input, id, describedBy, roleString;
775 if ( $fieldCont.length && $fieldCont.is( ':visible' ) ) {
776 $fieldCont.addClass( 'frm_blank_field' );
777 input = $fieldCont.find( 'input, select, textarea' );
778 id = 'frm_error_field_' + key;
779 describedBy = input.attr( 'aria-describedby' );
780
781 if ( typeof frmThemeOverride_frmPlaceError === 'function' ) { // eslint-disable-line camelcase
782 frmThemeOverride_frmPlaceError( key, jsErrors );
783 } else {
784 if ( -1 !== jsErrors[key].indexOf( '<div' ) ) {
785 $fieldCont.append(
786 jsErrors[key]
787 );
788 } else {
789 roleString = frm_js.include_alert_role ? 'role="alert"' : '';
790 $fieldCont.append( '<div class="frm_error" ' + roleString + ' id="' + id + '">' + jsErrors[key] + '</div>' );
791 }
792
793 if ( typeof describedBy === 'undefined' ) {
794 describedBy = id;
795 } else if ( describedBy.indexOf( id ) === -1 ) {
796 describedBy = describedBy + ' ' + id;
797 }
798 input.attr( 'aria-describedby', describedBy );
799 }
800 input.attr( 'aria-invalid', true );
801
802 jQuery( document ).trigger( 'frmAddFieldError', [ $fieldCont, key, jsErrors ]);
803 }
804 }
805
806 function removeFieldError( $fieldCont ) {
807 var errorMessage = $fieldCont.find( '.frm_error' ),
808 errorId = errorMessage.attr( 'id' ),
809 input = $fieldCont.find( 'input, select, textarea' ),
810 describedBy = input.attr( 'aria-describedby' );
811
812 $fieldCont.removeClass( 'frm_blank_field has-error' );
813 errorMessage.remove();
814 input.attr( 'aria-invalid', false );
815 input.removeAttr( 'aria-describedby' );
816
817 if ( typeof describedBy !== 'undefined' ) {
818 describedBy = describedBy.replace( errorId, '' );
819 input.attr( 'aria-describedby', describedBy );
820 }
821 }
822
823 function removeAllErrors() {
824 jQuery( '.form-field' ).removeClass( 'frm_blank_field has-error' );
825 jQuery( '.form-field .frm_error' ).replaceWith( '' );
826 jQuery( '.frm_error_style' ).remove();
827 }
828
829 function scrollToFirstField( object ) {
830 var field = jQuery( object ).find( '.frm_blank_field' ).first();
831 if ( field.length ) {
832 frmFrontForm.scrollMsg( field, object, true );
833 }
834 }
835
836 function showSubmitLoading( $object ) {
837 showLoadingIndicator( $object );
838 disableSubmitButton( $object );
839 disableSaveDraft( $object );
840 }
841
842 function showLoadingIndicator( $object ) {
843 if ( ! $object.hasClass( 'frm_loading_form' ) && ! $object.hasClass( 'frm_loading_prev' ) ) {
844 addLoadingClass( $object );
845 $object.trigger( 'frmStartFormLoading' );
846 }
847 }
848
849 function addLoadingClass( $object ) {
850 var loadingClass = isGoingToPrevPage( $object ) ? 'frm_loading_prev' : 'frm_loading_form';
851
852 $object.addClass( loadingClass );
853 }
854
855 function isGoingToPrevPage( $object ) {
856 return ( typeof frmProForm !== 'undefined' && frmProForm.goingToPreviousPage( $object ) );
857 }
858
859 function removeSubmitLoading( $object, enable, processesRunning ) {
860 var loadingForm;
861
862 if ( processesRunning > 0 ) {
863 return;
864 }
865
866 loadingForm = jQuery( '.frm_loading_form' );
867 loadingForm.removeClass( 'frm_loading_form' );
868 loadingForm.removeClass( 'frm_loading_prev' );
869
870 loadingForm.trigger( 'frmEndFormLoading' );
871
872 if ( enable === 'enable' ) {
873 enableSubmitButton( loadingForm );
874 enableSaveDraft( loadingForm );
875 }
876 }
877
878 function showFileLoading( object ) {
879 var fileval,
880 loading = document.getElementById( 'frm_loading' );
881 if ( loading !== null ) {
882 fileval = jQuery( object ).find( 'input[type=file]' ).val();
883 if ( typeof fileval !== 'undefined' && fileval !== '' ) {
884 setTimeout( function() {
885 jQuery( loading ).fadeIn( 'slow' );
886 }, 2000 );
887 }
888 }
889 }
890
891 function clearDefault() {
892 /*jshint validthis:true */
893 toggleDefault( jQuery( this ), 'clear' );
894 }
895
896 function replaceDefault() {
897 /*jshint validthis:true */
898 toggleDefault( jQuery( this ), 'replace' );
899 }
900
901 function toggleDefault( $thisField, e ) {
902 // TODO: Fix this for a default value that is a number or array
903 var thisVal,
904 v = $thisField.data( 'frmval' ).replace( /(\n|\r\n)/g, '\r' );
905 if ( v === '' || typeof v === 'undefined' ) {
906 return false;
907 }
908 thisVal = $thisField.val().replace( /(\n|\r\n)/g, '\r' );
909
910 if ( 'replace' === e ) {
911 if ( thisVal === '' ) {
912 $thisField.addClass( 'frm_default' ).val( v );
913 }
914 } else if ( thisVal == v ) {
915 $thisField.removeClass( 'frm_default' ).val( '' );
916 }
917 }
918
919 function resendEmail() {
920 /*jshint validthis:true */
921 var $link = jQuery( this ),
922 entryId = this.getAttribute( 'data-eid' ),
923 formId = this.getAttribute( 'data-fid' ),
924 label = $link.find( '.frm_link_label' );
925 if ( label.length < 1 ) {
926 label = $link;
927 }
928 label.append( '<span class="frm-wait"></span>' );
929
930 jQuery.ajax({
931 type: 'POST',
932 url: frm_js.ajax_url,
933 data: {
934 action: 'frm_entries_send_email',
935 entry_id: entryId,
936 form_id: formId,
937 nonce: frm_js.nonce
938 },
939 success: function( msg ) {
940 var admin = document.getElementById( 'wpbody' );
941 if ( admin === null ) {
942 label.html( msg );
943 } else {
944 label.html( '' );
945 $link.after( msg );
946 }
947 }
948 });
949 return false;
950 }
951
952 /**********************************************
953 * General Helpers
954 *********************************************/
955
956 function confirmClick() {
957 /*jshint validthis:true */
958 var message = jQuery( this ).data( 'frmconfirm' );
959 return confirm( message );
960 }
961
962 function toggleDiv() {
963 /*jshint validthis:true */
964 var div = jQuery( this ).data( 'frmtoggle' );
965 if ( jQuery( div ).is( ':visible' ) ) {
966 jQuery( div ).slideUp( 'fast' );
967 } else {
968 jQuery( div ).slideDown( 'fast' );
969 }
970 return false;
971 }
972
973 /**********************************************
974 * Fallback functions
975 *********************************************/
976
977 function addIndexOfFallbackForIE8() {
978 var len, from;
979
980 if ( ! Array.prototype.indexOf ) {
981 Array.prototype.indexOf = function( elt /*, from*/ ) {
982 len = this.length >>> 0;
983
984 from = Number( arguments[1]) || 0;
985 from = ( from < 0 ) ? Math.ceil( from ) : Math.floor( from );
986 if ( from < 0 ) {
987 from += len;
988 }
989
990 for ( ; from < len; from++ ) {
991 if ( from in this && this[from] === elt ) {
992 return from;
993 }
994 }
995 return -1;
996 };
997 }
998 }
999
1000 function addTrimFallbackForIE8() {
1001 if ( typeof String.prototype.trim !== 'function' ) {
1002 String.prototype.trim = function() {
1003 return this.replace( /^\s+|\s+$/g, '' );
1004 };
1005 }
1006 }
1007
1008 function addFilterFallbackForIE8() {
1009 var t, len, res, thisp, i, val;
1010
1011 if ( ! Array.prototype.filter ) {
1012
1013 Array.prototype.filter = function( fun /*, thisp */ ) {
1014
1015 if ( this === void 0 || this === null ) {
1016 throw new TypeError();
1017 }
1018
1019 t = Object( this );
1020 len = t.length >>> 0;
1021 if ( typeof fun !== 'function' ) {
1022 throw new TypeError();
1023 }
1024
1025 res = [];
1026 thisp = arguments[1];
1027 for ( i = 0; i < len; i++ ) {
1028 if ( i in t ) {
1029 val = t[i]; // in case fun mutates this
1030 if ( fun.call( thisp, val, i, t ) ) {
1031 res.push( val );
1032 }
1033 }
1034 }
1035
1036 return res;
1037 };
1038 }
1039 }
1040
1041 function addKeysFallbackForIE8() {
1042 var keys, i;
1043
1044 if ( ! Object.keys ) {
1045 Object.keys = function( obj ) {
1046 keys = [];
1047
1048 for ( i in obj ) {
1049 if ( obj.hasOwnProperty( i ) ) {
1050 keys.push( i );
1051 }
1052 }
1053
1054 return keys;
1055 };
1056 }
1057 }
1058
1059 /**
1060 * Check for -webkit-box-shadow css value for input:-webkit-autofill selector.
1061 * If this is a match, the User is autofilling the input on a Webkit browser.
1062 * We want to delete the Honeypot field, otherwise it will get triggered as spam on autocomplete.
1063 */
1064 function onHoneypotFieldChange() {
1065 var css = jQuery( this ).css( 'box-shadow' );
1066 if ( css.match( /inset/ ) ) {
1067 this.parentNode.removeChild( this );
1068 }
1069 }
1070
1071 /**
1072 * Focus on the first sub field when clicking to the primary label of combo field.
1073 *
1074 * @since 4.10.02
1075 */
1076 function changeFocusWhenClickComboFieldLabel() {
1077 let label;
1078
1079 const comboInputsContainer = document.querySelectorAll( '.frm_combo_inputs_container' );
1080 comboInputsContainer.forEach( function( inputsContainer ) {
1081 if ( ! inputsContainer.closest( '.frm_form_field' ) ) {
1082 return;
1083 }
1084
1085 label = inputsContainer.closest( '.frm_form_field' ).querySelector( '.frm_primary_label' );
1086 if ( ! label ) {
1087 return;
1088 }
1089
1090 label.addEventListener( 'click', function( e ) {
1091 inputsContainer.querySelector( '.frm_form_field:first-child input, .frm_form_field:first-child select, .frm_form_field:first-child textarea' ).focus();
1092 });
1093 });
1094 }
1095
1096 function checkForErrorsAndMaybeSetFocus() {
1097 var errors, element, timeoutCallback;
1098
1099 if ( ! frm_js.focus_first_error ) {
1100 return;
1101 }
1102
1103 errors = document.querySelectorAll( '.frm_form_field .frm_error' );
1104 if ( ! errors.length ) {
1105 return;
1106 }
1107
1108 element = errors[0];
1109 do {
1110 element = element.previousSibling;
1111 if ( -1 !== [ 'input', 'select', 'textarea' ].indexOf( element.nodeName.toLowerCase() ) ) {
1112 element.focus();
1113 break;
1114 }
1115
1116 if ( 'undefined' !== typeof element.classList ) {
1117 if ( element.classList.contains( 'html-active' ) ) {
1118 timeoutCallback = function() {
1119 var textarea = element.querySelector( 'textarea' );
1120 if ( null !== textarea ) {
1121 textarea.focus();
1122 }
1123 };
1124 } else if ( element.classList.contains( 'tmce-active' ) ) {
1125 timeoutCallback = function() {
1126 tinyMCE.activeEditor.focus();
1127 };
1128 }
1129
1130 if ( 'function' === typeof timeoutCallback ) {
1131 setTimeout( timeoutCallback, 0 );
1132 break;
1133 }
1134 }
1135 } while ( element.previousSibling );
1136 }
1137
1138 return {
1139 init: function() {
1140 jQuery( document ).off( 'submit.formidable', '.frm-show-form' );
1141 jQuery( document ).on( 'submit.formidable', '.frm-show-form', frmFrontForm.submitForm );
1142
1143 jQuery( '.frm-show-form input[onblur], .frm-show-form textarea[onblur]' ).each( function() {
1144 if ( jQuery( this ).val() === '' ) {
1145 jQuery( this ).trigger( 'blur' );
1146 }
1147 });
1148
1149 jQuery( document ).on( 'focus', '.frm_toggle_default', clearDefault );
1150 jQuery( document ).on( 'blur', '.frm_toggle_default', replaceDefault );
1151 jQuery( '.frm_toggle_default' ).trigger( 'blur' );
1152
1153 jQuery( document.getElementById( 'frm_resend_email' ) ).on( 'click', resendEmail );
1154
1155 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 );
1156 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 );
1157
1158 jQuery( document ).on( 'change', '[id^=frm_email_]', onHoneypotFieldChange );
1159
1160 jQuery( document ).on( 'click', 'a[data-frmconfirm]', confirmClick );
1161 jQuery( 'a[data-frmtoggle]' ).on( 'click', toggleDiv );
1162
1163 checkForErrorsAndMaybeSetFocus();
1164
1165 // Focus on the first sub field when clicking to the primary label of combo field.
1166 changeFocusWhenClickComboFieldLabel();
1167
1168 // Add fallbacks for the beloved IE8
1169 addIndexOfFallbackForIE8();
1170 addTrimFallbackForIE8();
1171 addFilterFallbackForIE8();
1172 addKeysFallbackForIE8();
1173 },
1174
1175 getFieldId: function( field, fullID ) {
1176 return getFieldId( field, fullID );
1177 },
1178
1179 renderRecaptcha: function( captcha ) {
1180 var formID, recaptchaID,
1181 size = captcha.getAttribute( 'data-size' ),
1182 rendered = captcha.getAttribute( 'data-rid' ) !== null,
1183 params = {
1184 'sitekey': captcha.getAttribute( 'data-sitekey' ),
1185 'size': size,
1186 'theme': captcha.getAttribute( 'data-theme' )
1187 };
1188
1189 if ( rendered ) {
1190 return;
1191 }
1192
1193 if ( size === 'invisible' ) {
1194 formID = jQuery( captcha ).closest( 'form' ).find( 'input[name="form_id"]' ).val();
1195 jQuery( captcha ).closest( '.frm_form_field .frm_primary_label' ).hide();
1196 params.callback = function( token ) {
1197 frmFrontForm.afterRecaptcha( token, formID );
1198 };
1199 }
1200
1201 recaptchaID = grecaptcha.render( captcha.id, params );
1202
1203 captcha.setAttribute( 'data-rid', recaptchaID );
1204 },
1205
1206 afterSingleRecaptcha: function() {
1207 var object = jQuery( '.frm-show-form .g-recaptcha' ).closest( 'form' )[0];
1208 frmFrontForm.submitFormNow( object );
1209 },
1210
1211 afterRecaptcha: function( token, formID ) {
1212 var object = jQuery( '#frm_form_' + formID + '_container form' )[0];
1213 frmFrontForm.submitFormNow( object );
1214 },
1215
1216 submitForm: function( e ) {
1217 frmFrontForm.submitFormManual( e, this );
1218 },
1219
1220 submitFormManual: function( e, object ) {
1221 var isPro, errors,
1222 invisibleRecaptcha = hasInvisibleRecaptcha( object ),
1223 classList = object.className.trim().split( /\s+/gi );
1224
1225 if ( classList && invisibleRecaptcha.length < 1 ) {
1226 isPro = classList.indexOf( 'frm_pro_form' ) > -1;
1227 if ( ! isPro ) {
1228 return;
1229 }
1230 }
1231
1232 if ( jQuery( 'body' ).hasClass( 'wp-admin' ) && jQuery( object ).closest( '.frmapi-form' ).length < 1 ) {
1233 return;
1234 }
1235
1236 e.preventDefault();
1237
1238 if ( typeof frmProForm !== 'undefined' && typeof frmProForm.submitAllowed === 'function' ) {
1239 if ( ! frmProForm.submitAllowed( object ) ) {
1240 return;
1241 }
1242 }
1243
1244 if ( invisibleRecaptcha.length ) {
1245 showLoadingIndicator( jQuery( object ) );
1246 executeInvisibleRecaptcha( invisibleRecaptcha );
1247 } else {
1248
1249 errors = frmFrontForm.validateFormSubmit( object );
1250
1251 if ( Object.keys( errors ).length === 0 ) {
1252 showSubmitLoading( jQuery( object ) );
1253
1254 frmFrontForm.submitFormNow( object, classList );
1255 }
1256 }
1257 },
1258
1259 submitFormNow: function( object ) {
1260 var hasFileFields, antispamInput,
1261 classList = object.className.trim().split( /\s+/gi );
1262
1263 if ( object.hasAttribute( 'data-token' ) && null === object.querySelector( '[name="antispam_token"]' ) ) {
1264 // include the antispam token on form submit.
1265 antispamInput = document.createElement( 'input' );
1266 antispamInput.type = 'hidden';
1267 antispamInput.name = 'antispam_token';
1268 antispamInput.value = object.getAttribute( 'data-token' );
1269 object.appendChild( antispamInput );
1270 }
1271
1272 if ( classList.indexOf( 'frm_ajax_submit' ) > -1 ) {
1273 hasFileFields = jQuery( object ).find( 'input[type="file"]' ).filter( function() {
1274 return !! this.value;
1275 }).length;
1276 if ( hasFileFields < 1 ) {
1277 action = jQuery( object ).find( 'input[name="frm_action"]' ).val();
1278 frmFrontForm.checkFormErrors( object, action );
1279 } else {
1280 object.submit();
1281 }
1282 } else {
1283 object.submit();
1284 }
1285 },
1286
1287 validateFormSubmit: function( object ) {
1288 if ( typeof tinyMCE !== 'undefined' && jQuery( object ).find( '.wp-editor-wrap' ).length ) {
1289 tinyMCE.triggerSave();
1290 }
1291
1292 jsErrors = [];
1293
1294 if ( shouldJSValidate( object ) ) {
1295 frmFrontForm.getAjaxFormErrors( object );
1296
1297 if ( Object.keys( jsErrors ).length ) {
1298 frmFrontForm.addAjaxFormErrors( object );
1299 }
1300 }
1301
1302 return jsErrors;
1303 },
1304
1305 getAjaxFormErrors: function( object ) {
1306 var customErrors, key;
1307
1308 jsErrors = validateForm( object );
1309 if ( typeof frmThemeOverride_jsErrors === 'function' ) { // eslint-disable-line camelcase
1310 action = jQuery( object ).find( 'input[name="frm_action"]' ).val();
1311 customErrors = frmThemeOverride_jsErrors( action, object );
1312 if ( Object.keys( customErrors ).length ) {
1313 for ( key in customErrors ) {
1314 jsErrors[ key ] = customErrors[ key ];
1315 }
1316 }
1317 }
1318
1319 return jsErrors;
1320 },
1321
1322 addAjaxFormErrors: function( object ) {
1323 var key, $fieldCont;
1324 removeAllErrors();
1325
1326 for ( key in jsErrors ) {
1327 $fieldCont = jQuery( object ).find( '#frm_field_' + key + '_container' );
1328
1329 if ( $fieldCont.length ) {
1330 addFieldError( $fieldCont, key, jsErrors );
1331 } else {
1332 // we are unable to show the error, so remove it
1333 delete jsErrors[ key ];
1334 }
1335 }
1336
1337 scrollToFirstField( object );
1338 checkForErrorsAndMaybeSetFocus();
1339 },
1340
1341 checkFormErrors: function( object, action ) {
1342 getFormErrors( object, action );
1343 },
1344
1345 checkRequiredField: function( field, errors ) {
1346 return checkRequiredField( field, errors );
1347 },
1348
1349 showSubmitLoading: function( $object ) {
1350 showSubmitLoading( $object );
1351 },
1352
1353 removeSubmitLoading: function( $object, enable, processesRunning ) {
1354 removeSubmitLoading( $object, enable, processesRunning );
1355 },
1356
1357 scrollToID: function( id ) {
1358 var object = jQuery( document.getElementById( id ) );
1359 frmFrontForm.scrollMsg( object, false );
1360 },
1361
1362 scrollMsg: function( id, object, animate ) {
1363 var newPos, m, b, screenTop, screenBottom,
1364 scrollObj = '';
1365 if ( typeof object === 'undefined' ) {
1366 scrollObj = jQuery( document.getElementById( 'frm_form_' + id + '_container' ) );
1367 if ( scrollObj.length < 1 ) {
1368 return;
1369 }
1370 } else if ( typeof id === 'string' ) {
1371 scrollObj = jQuery( object ).find( '#frm_field_' + id + '_container' );
1372 } else {
1373 scrollObj = id;
1374 }
1375
1376 jQuery( scrollObj ).trigger( 'focus' );
1377 newPos = scrollObj.offset().top;
1378 if ( ! newPos || frm_js.offset === '-1' ) {
1379 return;
1380 }
1381 newPos = newPos - frm_js.offset;
1382
1383 m = jQuery( 'html' ).css( 'margin-top' );
1384 b = jQuery( 'body' ).css( 'margin-top' );
1385 if ( m || b ) {
1386 newPos = newPos - parseInt( m ) - parseInt( b );
1387 }
1388
1389 if ( newPos && window.innerHeight ) {
1390 screenTop = document.documentElement.scrollTop || document.body.scrollTop;
1391 screenBottom = screenTop + window.innerHeight;
1392
1393 if ( newPos > screenBottom || newPos < screenTop ) {
1394 // Not in view
1395 if ( typeof animate === 'undefined' ) {
1396 jQuery( window ).scrollTop( newPos );
1397 } else {
1398 jQuery( 'html,body' ).animate({ scrollTop: newPos }, 500 );
1399 }
1400 return false;
1401 }
1402 }
1403 },
1404
1405 fieldValueChanged: function( e ) {
1406 /*jshint validthis:true */
1407
1408 var fieldId = frmFrontForm.getFieldId( this, false );
1409 if ( ! fieldId || typeof fieldId === 'undefined' ) {
1410 return;
1411 }
1412
1413 if ( e.frmTriggered && e.frmTriggered == fieldId ) {
1414 return;
1415 }
1416
1417 jQuery( document ).trigger( 'frmFieldChanged', [ this, fieldId, e ]);
1418
1419 if ( e.selfTriggered !== true ) {
1420 maybeValidateChange( this );
1421 }
1422 },
1423
1424 savingDraft: function( object ) {
1425 console.warn( 'DEPRECATED: function frmFrontForm.savingDraft in v3.0 use frmProForm.savingDraft' );
1426 if ( typeof frmProForm !== 'undefined' ) {
1427 return frmProForm.savingDraft( object );
1428 }
1429 },
1430
1431 goingToPreviousPage: function( object ) {
1432 console.warn( 'DEPRECATED: function frmFrontForm.goingToPreviousPage in v3.0 use frmProForm.goingToPreviousPage' );
1433 if ( typeof frmProForm !== 'undefined' ) {
1434 return frmProForm.goingToPreviousPage( object );
1435 }
1436 },
1437
1438 hideOrShowFields: function() {
1439 console.warn( 'DEPRECATED: function frmFrontForm.hideOrShowFields in v3.0 use frmProForm.hideOrShowFields' );
1440 if ( typeof frmProForm !== 'undefined' ) {
1441 frmProForm.hideOrShowFields();
1442 }
1443 },
1444
1445 hidePreviouslyHiddenFields: function() {
1446 console.warn( 'DEPRECATED: function frmFrontForm.hidePreviouslyHiddenFields in v3.0 use frmProForm.hidePreviouslyHiddenFields' );
1447 if ( typeof frmProForm !== 'undefined' ) {
1448 frmProForm.hidePreviouslyHiddenFields();
1449 }
1450 },
1451
1452 checkDependentDynamicFields: function( ids ) {
1453 console.warn( 'DEPRECATED: function frmFrontForm.checkDependentDynamicFields in v3.0 use frmProForm.checkDependentDynamicFields' );
1454 if ( typeof frmProForm !== 'undefined' ) {
1455 frmProForm.checkDependentDynamicFields( ids );
1456 }
1457 },
1458
1459 checkDependentLookupFields: function( ids ) {
1460 console.warn( 'DEPRECATED: function frmFrontForm.checkDependentLookupFields in v3.0 use frmProForm.checkDependentLookupFields' );
1461 if ( typeof frmProForm !== 'undefined' ) {
1462 frmProForm.checkDependentLookupFields( ids );
1463 }
1464 },
1465
1466 loadGoogle: function() {
1467 console.warn( 'DEPRECATED: function frmFrontForm.loadGoogle in v3.0 use frmProForm.loadGoogle' );
1468 frmProForm.loadGoogle();
1469 },
1470
1471 escapeHtml: function( text ) {
1472 return text
1473 .replace( /&/g, '&amp;' )
1474 .replace( /</g, '&lt;' )
1475 .replace( />/g, '&gt;' )
1476 .replace( /"/g, '&quot;' )
1477 .replace( /'/g, '&#039;' );
1478 },
1479
1480 invisible: function( classes ) {
1481 jQuery( classes ).css( 'visibility', 'hidden' );
1482 },
1483
1484 visible: function( classes ) {
1485 jQuery( classes ).css( 'visibility', 'visible' );
1486 }
1487 };
1488 }
1489 frmFrontForm = frmFrontFormJS();
1490
1491 jQuery( document ).ready( function() {
1492 frmFrontForm.init();
1493 });
1494
1495 function frmRecaptcha() {
1496 var c, cl,
1497 captchas = jQuery( '.frm-g-recaptcha' );
1498 for ( c = 0, cl = captchas.length; c < cl; c++ ) {
1499 frmFrontForm.renderRecaptcha( captchas[c]);
1500 }
1501 }
1502
1503 function frmAfterRecaptcha( token ) {
1504 frmFrontForm.afterSingleRecaptcha( token );
1505 }
1506
1507 function frmUpdateField( entryId, fieldId, value, message, num ) {
1508 jQuery( document.getElementById( 'frm_update_field_' + entryId + '_' + fieldId + '_' + num ) ).html( '<span class="frm-loading-img"></span>' );
1509 jQuery.ajax({
1510 type: 'POST',
1511 url: frm_js.ajax_url,
1512 data: {
1513 action: 'frm_entries_update_field_ajax',
1514 entry_id: entryId,
1515 field_id: fieldId,
1516 value: value,
1517 nonce: frm_js.nonce
1518 },
1519 success: function() {
1520 if ( message.replace( /^\s+|\s+$/g, '' ) === '' ) {
1521 jQuery( document.getElementById( 'frm_update_field_' + entryId + '_' + fieldId + '_' + num ) ).fadeOut( 'slow' );
1522 } else {
1523 jQuery( document.getElementById( 'frm_update_field_' + entryId + '_' + fieldId + '_' + num ) ).replaceWith( message );
1524 }
1525 }
1526 });
1527 }
1528
1529 function frmDeleteEntry( entryId, prefix ) {
1530 console.warn( 'DEPRECATED: function frmDeleteEntry in v2.0.13 use frmFrontForm.deleteEntry' );
1531 jQuery( document.getElementById( 'frm_delete_' + entryId ) ).replaceWith( '<span class="frm-loading-img" id="frm_delete_' + entryId + '"></span>' );
1532 jQuery.ajax({
1533 type: 'POST',
1534 url: frm_js.ajax_url,
1535 data: {
1536 action: 'frm_entries_destroy',
1537 entry: entryId,
1538 nonce: frm_js.nonce
1539 },
1540 success: function( html ) {
1541 if ( html.replace( /^\s+|\s+$/g, '' ) === 'success' ) {
1542 jQuery( document.getElementById( prefix + entryId ) ).fadeOut( 'slow' );
1543 } else {
1544 jQuery( document.getElementById( 'frm_delete_' + entryId ) ).replaceWith( html );
1545 }
1546 }
1547 });
1548 }
1549
1550 function frmOnSubmit( e ) {
1551 console.warn( 'DEPRECATED: function frmOnSubmit in v2.0 use frmFrontForm.submitForm' );
1552 frmFrontForm.submitForm( e, this );
1553 }
1554
1555 function frm_resend_email( entryId, formId ) { // eslint-disable-line camelcase
1556 var $link = jQuery( document.getElementById( 'frm_resend_email' ) );
1557 console.warn( 'DEPRECATED: function frm_resend_email in v2.0' );
1558 $link.append( '<span class="spinner" style="display:inline"></span>' );
1559 jQuery.ajax({
1560 type: 'POST',
1561 url: frm_js.ajax_url,
1562 data: {
1563 action: 'frm_entries_send_email',
1564 entry_id: entryId,
1565 form_id: formId,
1566 nonce: frm_js.nonce
1567 },
1568 success: function( msg ) {
1569 $link.replaceWith( msg );
1570 }
1571 });
1572 }
1573