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

1,541 lines 42.9 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;
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 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 }
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 error: function() {
675 jQuery( object ).find( 'input[type="submit"], input[type="button"]' ).prop( 'disabled', false );
676 object.submit();
677 }
678 });
679 }
680
681 function afterFormSubmitted( object, response ) {
682 var formCompleted = jQuery( response.content ).find( '.frm_message' );
683 if ( formCompleted.length ) {
684 jQuery( document ).trigger( 'frmFormComplete', [ object, response ]);
685 } else {
686 jQuery( document ).trigger( 'frmPageChanged', [ object, response ]);
687 }
688 }
689
690 function removeAddedScripts( formContainer, formID ) {
691 var endReplace = jQuery( '.frm_end_ajax_' + formID );
692 if ( endReplace.length ) {
693 formContainer.nextUntil( '.frm_end_ajax_' + formID ).remove();
694 endReplace.remove();
695 }
696 }
697
698 function maybeSlideOut( oldContent, newContent ) {
699 var c,
700 newClass = 'frm_slideout';
701 if ( newContent.indexOf( ' frm_slide' ) !== -1 ) {
702 c = oldContent.children();
703 if ( newContent.indexOf( ' frm_going_back' ) !== -1 ) {
704 newClass += ' frm_going_back';
705 }
706 c.removeClass( 'frm_going_back' );
707 c.addClass( newClass );
708 return 300;
709 }
710 return 0;
711 }
712
713 function addUrlParam( response ) {
714 var url;
715 if ( history.pushState && typeof response.page !== 'undefined' ) {
716 url = addQueryVar( 'frm_page', response.page );
717 window.history.pushState({ 'html': response.html }, '', '?' + url );
718 }
719 }
720
721 function addQueryVar( key, value ) {
722 var kvp, i, x;
723
724 key = encodeURI( key );
725 value = encodeURI( value );
726
727 kvp = document.location.search.substr( 1 ).split( '&' );
728
729 i = kvp.length;
730 while ( i-- ) {
731 x = kvp[i].split( '=' );
732
733 if ( x[0] == key ) {
734 x[1] = value;
735 kvp[i] = x.join( '=' );
736 break;
737 }
738 }
739
740 if ( i < 0 ) {
741 kvp[ kvp.length ] = [ key, value ].join( '=' );
742 }
743
744 return kvp.join( '&' );
745 }
746
747 function addFieldError( $fieldCont, key, jsErrors ) {
748 var input, id, describedBy;
749 if ( $fieldCont.length && $fieldCont.is( ':visible' ) ) {
750 $fieldCont.addClass( 'frm_blank_field' );
751 input = $fieldCont.find( 'input, select, textarea' );
752 id = 'frm_error_field_' + key;
753 describedBy = input.attr( 'aria-describedby' );
754
755 if ( typeof frmThemeOverride_frmPlaceError === 'function' ) { // eslint-disable-line camelcase
756 frmThemeOverride_frmPlaceError( key, jsErrors );
757 } else {
758 if ( -1 !== jsErrors[key].indexOf( '<div' ) ) {
759 $fieldCont.append(
760 jsErrors[key]
761 );
762 } else {
763 $fieldCont.append( '<div class="frm_error" id="' + id + '">' + jsErrors[key] + '</div>' );
764 }
765
766 if ( typeof describedBy === 'undefined' ) {
767 describedBy = id;
768 } else if ( describedBy.indexOf( id ) === -1 ) {
769 describedBy = describedBy + ' ' + id;
770 }
771 input.attr( 'aria-describedby', describedBy );
772 }
773 input.attr( 'aria-invalid', true );
774
775 jQuery( document ).trigger( 'frmAddFieldError', [ $fieldCont, key, jsErrors ]);
776 }
777 }
778
779 function removeFieldError( $fieldCont ) {
780 var errorMessage = $fieldCont.find( '.frm_error' ),
781 errorId = errorMessage.attr( 'id' ),
782 input = $fieldCont.find( 'input, select, textarea' ),
783 describedBy = input.attr( 'aria-describedby' );
784
785 $fieldCont.removeClass( 'frm_blank_field has-error' );
786 errorMessage.remove();
787 input.attr( 'aria-invalid', false );
788
789 if ( typeof describedBy !== 'undefined' ) {
790 describedBy = describedBy.replace( errorId, '' );
791 input.attr( 'aria-describedby', describedBy );
792 }
793 }
794
795 function removeAllErrors() {
796 jQuery( '.form-field' ).removeClass( 'frm_blank_field has-error' );
797 jQuery( '.form-field .frm_error' ).replaceWith( '' );
798 jQuery( '.frm_error_style' ).remove();
799 }
800
801 function scrollToFirstField( object ) {
802 var field = jQuery( object ).find( '.frm_blank_field' ).first();
803 if ( field.length ) {
804 frmFrontForm.scrollMsg( field, object, true );
805 }
806 }
807
808 function showSubmitLoading( $object ) {
809 showLoadingIndicator( $object );
810 disableSubmitButton( $object );
811 disableSaveDraft( $object );
812 }
813
814 function showLoadingIndicator( $object ) {
815 if ( ! $object.hasClass( 'frm_loading_form' ) && ! $object.hasClass( 'frm_loading_prev' ) ) {
816 addLoadingClass( $object );
817 $object.trigger( 'frmStartFormLoading' );
818 }
819 }
820
821 function addLoadingClass( $object ) {
822 var loadingClass = isGoingToPrevPage( $object ) ? 'frm_loading_prev' : 'frm_loading_form';
823
824 $object.addClass( loadingClass );
825 }
826
827 function isGoingToPrevPage( $object ) {
828 return ( typeof frmProForm !== 'undefined' && frmProForm.goingToPreviousPage( $object ) );
829 }
830
831 function removeSubmitLoading( $object, enable, processesRunning ) {
832 var loadingForm;
833
834 if ( processesRunning > 0 ) {
835 return;
836 }
837
838 loadingForm = jQuery( '.frm_loading_form' );
839 loadingForm.removeClass( 'frm_loading_form' );
840 loadingForm.removeClass( 'frm_loading_prev' );
841
842 loadingForm.trigger( 'frmEndFormLoading' );
843
844 if ( enable === 'enable' ) {
845 enableSubmitButton( loadingForm );
846 enableSaveDraft( loadingForm );
847 }
848 }
849
850 function showFileLoading( object ) {
851 var fileval,
852 loading = document.getElementById( 'frm_loading' );
853 if ( loading !== null ) {
854 fileval = jQuery( object ).find( 'input[type=file]' ).val();
855 if ( typeof fileval !== 'undefined' && fileval !== '' ) {
856 setTimeout( function() {
857 jQuery( loading ).fadeIn( 'slow' );
858 }, 2000 );
859 }
860 }
861 }
862
863 function clearDefault() {
864 /*jshint validthis:true */
865 toggleDefault( jQuery( this ), 'clear' );
866 }
867
868 function replaceDefault() {
869 /*jshint validthis:true */
870 toggleDefault( jQuery( this ), 'replace' );
871 }
872
873 function toggleDefault( $thisField, e ) {
874 // TODO: Fix this for a default value that is a number or array
875 var thisVal,
876 v = $thisField.data( 'frmval' ).replace( /(\n|\r\n)/g, '\r' );
877 if ( v === '' || typeof v === 'undefined' ) {
878 return false;
879 }
880 thisVal = $thisField.val().replace( /(\n|\r\n)/g, '\r' );
881
882 if ( 'replace' === e ) {
883 if ( thisVal === '' ) {
884 $thisField.addClass( 'frm_default' ).val( v );
885 }
886 } else if ( thisVal == v ) {
887 $thisField.removeClass( 'frm_default' ).val( '' );
888 }
889 }
890
891 function resendEmail() {
892 /*jshint validthis:true */
893 var $link = jQuery( this ),
894 entryId = this.getAttribute( 'data-eid' ),
895 formId = this.getAttribute( 'data-fid' ),
896 label = $link.find( '.frm_link_label' );
897 if ( label.length < 1 ) {
898 label = $link;
899 }
900 label.append( '<span class="frm-wait"></span>' );
901
902 jQuery.ajax({
903 type: 'POST',
904 url: frm_js.ajax_url,
905 data: {
906 action: 'frm_entries_send_email',
907 entry_id: entryId,
908 form_id: formId,
909 nonce: frm_js.nonce
910 },
911 success: function( msg ) {
912 var admin = document.getElementById( 'wpbody' );
913 if ( admin === null ) {
914 label.html( msg );
915 } else {
916 label.html( '' );
917 $link.after( msg );
918 }
919 }
920 });
921 return false;
922 }
923
924 /**********************************************
925 * General Helpers
926 *********************************************/
927
928 function confirmClick() {
929 /*jshint validthis:true */
930 var message = jQuery( this ).data( 'frmconfirm' );
931 return confirm( message );
932 }
933
934 function toggleDiv() {
935 /*jshint validthis:true */
936 var div = jQuery( this ).data( 'frmtoggle' );
937 if ( jQuery( div ).is( ':visible' ) ) {
938 jQuery( div ).slideUp( 'fast' );
939 } else {
940 jQuery( div ).slideDown( 'fast' );
941 }
942 return false;
943 }
944
945 /**********************************************
946 * Fallback functions
947 *********************************************/
948
949 function addIndexOfFallbackForIE8() {
950 var len, from;
951
952 if ( ! Array.prototype.indexOf ) {
953 Array.prototype.indexOf = function( elt /*, from*/ ) {
954 len = this.length >>> 0;
955
956 from = Number( arguments[1]) || 0;
957 from = ( from < 0 ) ? Math.ceil( from ) : Math.floor( from );
958 if ( from < 0 ) {
959 from += len;
960 }
961
962 for ( ; from < len; from++ ) {
963 if ( from in this && this[from] === elt ) {
964 return from;
965 }
966 }
967 return -1;
968 };
969 }
970 }
971
972 function addTrimFallbackForIE8() {
973 if ( typeof String.prototype.trim !== 'function' ) {
974 String.prototype.trim = function() {
975 return this.replace( /^\s+|\s+$/g, '' );
976 };
977 }
978 }
979
980 function addFilterFallbackForIE8() {
981 var t, len, res, thisp, i, val;
982
983 if ( ! Array.prototype.filter ) {
984
985 Array.prototype.filter = function( fun /*, thisp */ ) {
986
987 if ( this === void 0 || this === null ) {
988 throw new TypeError();
989 }
990
991 t = Object( this );
992 len = t.length >>> 0;
993 if ( typeof fun !== 'function' ) {
994 throw new TypeError();
995 }
996
997 res = [];
998 thisp = arguments[1];
999 for ( i = 0; i < len; i++ ) {
1000 if ( i in t ) {
1001 val = t[i]; // in case fun mutates this
1002 if ( fun.call( thisp, val, i, t ) ) {
1003 res.push( val );
1004 }
1005 }
1006 }
1007
1008 return res;
1009 };
1010 }
1011 }
1012
1013 function addKeysFallbackForIE8() {
1014 var keys, i;
1015
1016 if ( ! Object.keys ) {
1017 Object.keys = function( obj ) {
1018 keys = [];
1019
1020 for ( i in obj ) {
1021 if ( obj.hasOwnProperty( i ) ) {
1022 keys.push( i );
1023 }
1024 }
1025
1026 return keys;
1027 };
1028 }
1029 }
1030
1031 /**
1032 * Check for -webkit-box-shadow css value for input:-webkit-autofill selector.
1033 * If this is a match, the User is autofilling the input on a Webkit browser.
1034 * We want to delete the Honeypot field, otherwise it will get triggered as spam on autocomplete.
1035 */
1036 function onHoneypotFieldChange() {
1037 var css = jQuery( this ).css( 'box-shadow' );
1038 if ( css.match( /inset/ ) ) {
1039 this.parentNode.removeChild( this );
1040 }
1041 }
1042
1043 /**
1044 * Focus on the first sub field when clicking to the primary label of combo field.
1045 *
1046 * @since 4.10.02
1047 */
1048 function changeFocusWhenClickComboFieldLabel() {
1049 let label;
1050
1051 const comboInputsContainer = document.querySelectorAll( '.frm_combo_inputs_container' );
1052 comboInputsContainer.forEach( function( inputsContainer ) {
1053 if ( ! inputsContainer.closest( '.frm_form_field' ) ) {
1054 return;
1055 }
1056
1057 label = inputsContainer.closest( '.frm_form_field' ).querySelector( '.frm_primary_label' );
1058 if ( ! label ) {
1059 return;
1060 }
1061
1062 label.addEventListener( 'click', function( e ) {
1063 inputsContainer.querySelector( '.frm_form_field:first-child input, .frm_form_field:first-child select, .frm_form_field:first-child textarea' ).focus();
1064 });
1065 });
1066 }
1067
1068 function checkForErrorsAndMaybeSetFocus() {
1069 var errors, element, timeoutCallback;
1070
1071 errors = document.querySelectorAll( '.frm_form_field .frm_error' );
1072 if ( ! errors.length ) {
1073 return;
1074 }
1075
1076 element = errors[0];
1077 do {
1078 element = element.previousSibling;
1079 if ( -1 !== [ 'input', 'select', 'textarea' ].indexOf( element.nodeName.toLowerCase() ) ) {
1080 element.focus();
1081 break;
1082 }
1083
1084 if ( 'undefined' !== typeof element.classList ) {
1085 if ( element.classList.contains( 'html-active' ) ) {
1086 timeoutCallback = function() {
1087 var textarea = element.querySelector( 'textarea' );
1088 if ( null !== textarea ) {
1089 textarea.focus();
1090 }
1091 };
1092 } else if ( element.classList.contains( 'tmce-active' ) ) {
1093 timeoutCallback = function() {
1094 tinyMCE.activeEditor.focus();
1095 };
1096 }
1097
1098 if ( 'function' === typeof timeoutCallback ) {
1099 setTimeout( timeoutCallback, 0 );
1100 break;
1101 }
1102 }
1103 } while ( element.previousSibling );
1104 }
1105
1106 return {
1107 init: function() {
1108 jQuery( document ).off( 'submit.formidable', '.frm-show-form' );
1109 jQuery( document ).on( 'submit.formidable', '.frm-show-form', frmFrontForm.submitForm );
1110
1111 jQuery( '.frm-show-form input[onblur], .frm-show-form textarea[onblur]' ).each( function() {
1112 if ( jQuery( this ).val() === '' ) {
1113 jQuery( this ).trigger( 'blur' );
1114 }
1115 });
1116
1117 jQuery( document ).on( 'focus', '.frm_toggle_default', clearDefault );
1118 jQuery( document ).on( 'blur', '.frm_toggle_default', replaceDefault );
1119 jQuery( '.frm_toggle_default' ).trigger( 'blur' );
1120
1121 jQuery( document.getElementById( 'frm_resend_email' ) ).on( 'click', resendEmail );
1122
1123 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 );
1124 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 );
1125
1126 jQuery( document ).on( 'change', '[id^=frm_email_]', onHoneypotFieldChange );
1127
1128 jQuery( document ).on( 'click', 'a[data-frmconfirm]', confirmClick );
1129 jQuery( 'a[data-frmtoggle]' ).on( 'click', toggleDiv );
1130
1131 checkForErrorsAndMaybeSetFocus();
1132
1133 // Focus on the first sub field when clicking to the primary label of combo field.
1134 changeFocusWhenClickComboFieldLabel();
1135
1136 // Add fallbacks for the beloved IE8
1137 addIndexOfFallbackForIE8();
1138 addTrimFallbackForIE8();
1139 addFilterFallbackForIE8();
1140 addKeysFallbackForIE8();
1141 },
1142
1143 getFieldId: function( field, fullID ) {
1144 return getFieldId( field, fullID );
1145 },
1146
1147 renderRecaptcha: function( captcha ) {
1148 var formID, recaptchaID,
1149 size = captcha.getAttribute( 'data-size' ),
1150 rendered = captcha.getAttribute( 'data-rid' ) !== null,
1151 params = {
1152 'sitekey': captcha.getAttribute( 'data-sitekey' ),
1153 'size': size,
1154 'theme': captcha.getAttribute( 'data-theme' )
1155 };
1156
1157 if ( rendered ) {
1158 return;
1159 }
1160
1161 if ( size === 'invisible' ) {
1162 formID = jQuery( captcha ).closest( 'form' ).find( 'input[name="form_id"]' ).val();
1163 jQuery( captcha ).closest( '.frm_form_field .frm_primary_label' ).hide();
1164 params.callback = function( token ) {
1165 frmFrontForm.afterRecaptcha( token, formID );
1166 };
1167 }
1168
1169 recaptchaID = grecaptcha.render( captcha.id, params );
1170
1171 captcha.setAttribute( 'data-rid', recaptchaID );
1172 },
1173
1174 afterSingleRecaptcha: function() {
1175 var object = jQuery( '.frm-show-form .g-recaptcha' ).closest( 'form' )[0];
1176 frmFrontForm.submitFormNow( object );
1177 },
1178
1179 afterRecaptcha: function( token, formID ) {
1180 var object = jQuery( '#frm_form_' + formID + '_container form' )[0];
1181 frmFrontForm.submitFormNow( object );
1182 },
1183
1184 submitForm: function( e ) {
1185 frmFrontForm.submitFormManual( e, this );
1186 },
1187
1188 submitFormManual: function( e, object ) {
1189 var isPro, errors,
1190 invisibleRecaptcha = hasInvisibleRecaptcha( object ),
1191 classList = object.className.trim().split( /\s+/gi );
1192
1193 if ( classList && invisibleRecaptcha.length < 1 ) {
1194 isPro = classList.indexOf( 'frm_pro_form' ) > -1;
1195 if ( ! isPro ) {
1196 return;
1197 }
1198 }
1199
1200 if ( jQuery( 'body' ).hasClass( 'wp-admin' ) && jQuery( object ).closest( '.frmapi-form' ).length < 1 ) {
1201 return;
1202 }
1203
1204 e.preventDefault();
1205
1206 if ( typeof frmProForm !== 'undefined' && typeof frmProForm.submitAllowed === 'function' ) {
1207 if ( ! frmProForm.submitAllowed( object ) ) {
1208 return;
1209 }
1210 }
1211
1212 if ( invisibleRecaptcha.length ) {
1213 showLoadingIndicator( jQuery( object ) );
1214 executeInvisibleRecaptcha( invisibleRecaptcha );
1215 } else {
1216
1217 errors = frmFrontForm.validateFormSubmit( object );
1218
1219 if ( Object.keys( errors ).length === 0 ) {
1220 showSubmitLoading( jQuery( object ) );
1221
1222 frmFrontForm.submitFormNow( object, classList );
1223 }
1224 }
1225 },
1226
1227 submitFormNow: function( object ) {
1228 var hasFileFields, antispamInput,
1229 classList = object.className.trim().split( /\s+/gi );
1230
1231 if ( object.hasAttribute( 'data-token' ) && null === object.querySelector( '[name="antispam_token"]' ) ) {
1232 // include the antispam token on form submit.
1233 antispamInput = document.createElement( 'input' );
1234 antispamInput.type = 'hidden';
1235 antispamInput.name = 'antispam_token';
1236 antispamInput.value = object.getAttribute( 'data-token' );
1237 object.appendChild( antispamInput );
1238 }
1239
1240 if ( classList.indexOf( 'frm_ajax_submit' ) > -1 ) {
1241 hasFileFields = jQuery( object ).find( 'input[type="file"]' ).filter( function() {
1242 return !! this.value;
1243 }).length;
1244 if ( hasFileFields < 1 ) {
1245 action = jQuery( object ).find( 'input[name="frm_action"]' ).val();
1246 frmFrontForm.checkFormErrors( object, action );
1247 } else {
1248 object.submit();
1249 }
1250 } else {
1251 object.submit();
1252 }
1253 },
1254
1255 validateFormSubmit: function( object ) {
1256 if ( typeof tinyMCE !== 'undefined' && jQuery( object ).find( '.wp-editor-wrap' ).length ) {
1257 tinyMCE.triggerSave();
1258 }
1259
1260 jsErrors = [];
1261
1262 if ( shouldJSValidate( object ) ) {
1263 frmFrontForm.getAjaxFormErrors( object );
1264
1265 if ( Object.keys( jsErrors ).length ) {
1266 frmFrontForm.addAjaxFormErrors( object );
1267 }
1268 }
1269
1270 return jsErrors;
1271 },
1272
1273 getAjaxFormErrors: function( object ) {
1274 var customErrors, key;
1275
1276 jsErrors = validateForm( object );
1277 if ( typeof frmThemeOverride_jsErrors === 'function' ) { // eslint-disable-line camelcase
1278 action = jQuery( object ).find( 'input[name="frm_action"]' ).val();
1279 customErrors = frmThemeOverride_jsErrors( action, object );
1280 if ( Object.keys( customErrors ).length ) {
1281 for ( key in customErrors ) {
1282 jsErrors[ key ] = customErrors[ key ];
1283 }
1284 }
1285 }
1286
1287 return jsErrors;
1288 },
1289
1290 addAjaxFormErrors: function( object ) {
1291 var key, $fieldCont;
1292 removeAllErrors();
1293
1294 for ( key in jsErrors ) {
1295 $fieldCont = jQuery( object ).find( '#frm_field_' + key + '_container' );
1296
1297 if ( $fieldCont.length ) {
1298 addFieldError( $fieldCont, key, jsErrors );
1299 } else {
1300 // we are unable to show the error, so remove it
1301 delete jsErrors[ key ];
1302 }
1303 }
1304
1305 scrollToFirstField( object );
1306 checkForErrorsAndMaybeSetFocus();
1307 },
1308
1309 checkFormErrors: function( object, action ) {
1310 getFormErrors( object, action );
1311 },
1312
1313 checkRequiredField: function( field, errors ) {
1314 return checkRequiredField( field, errors );
1315 },
1316
1317 showSubmitLoading: function( $object ) {
1318 showSubmitLoading( $object );
1319 },
1320
1321 removeSubmitLoading: function( $object, enable, processesRunning ) {
1322 removeSubmitLoading( $object, enable, processesRunning );
1323 },
1324
1325 scrollToID: function( id ) {
1326 var object = jQuery( document.getElementById( id ) );
1327 frmFrontForm.scrollMsg( object, false );
1328 },
1329
1330 scrollMsg: function( id, object, animate ) {
1331 var newPos, m, b, screenTop, screenBottom,
1332 scrollObj = '';
1333 if ( typeof object === 'undefined' ) {
1334 scrollObj = jQuery( document.getElementById( 'frm_form_' + id + '_container' ) );
1335 if ( scrollObj.length < 1 ) {
1336 return;
1337 }
1338 } else if ( typeof id === 'string' ) {
1339 scrollObj = jQuery( object ).find( '#frm_field_' + id + '_container' );
1340 } else {
1341 scrollObj = id;
1342 }
1343
1344 jQuery( scrollObj ).trigger( 'focus' );
1345 newPos = scrollObj.offset().top;
1346 if ( ! newPos || frm_js.offset === '-1' ) {
1347 return;
1348 }
1349 newPos = newPos - frm_js.offset;
1350
1351 m = jQuery( 'html' ).css( 'margin-top' );
1352 b = jQuery( 'body' ).css( 'margin-top' );
1353 if ( m || b ) {
1354 newPos = newPos - parseInt( m ) - parseInt( b );
1355 }
1356
1357 if ( newPos && window.innerHeight ) {
1358 screenTop = document.documentElement.scrollTop || document.body.scrollTop;
1359 screenBottom = screenTop + window.innerHeight;
1360
1361 if ( newPos > screenBottom || newPos < screenTop ) {
1362 // Not in view
1363 if ( typeof animate === 'undefined' ) {
1364 jQuery( window ).scrollTop( newPos );
1365 } else {
1366 jQuery( 'html,body' ).animate({ scrollTop: newPos }, 500 );
1367 }
1368 return false;
1369 }
1370 }
1371 },
1372
1373 fieldValueChanged: function( e ) {
1374 /*jshint validthis:true */
1375
1376 var fieldId = frmFrontForm.getFieldId( this, false );
1377 if ( ! fieldId || typeof fieldId === 'undefined' ) {
1378 return;
1379 }
1380
1381 if ( e.frmTriggered && e.frmTriggered == fieldId ) {
1382 return;
1383 }
1384
1385 jQuery( document ).trigger( 'frmFieldChanged', [ this, fieldId, e ]);
1386
1387 if ( e.selfTriggered !== true ) {
1388 maybeValidateChange( this );
1389 }
1390 },
1391
1392 savingDraft: function( object ) {
1393 console.warn( 'DEPRECATED: function frmFrontForm.savingDraft in v3.0 use frmProForm.savingDraft' );
1394 if ( typeof frmProForm !== 'undefined' ) {
1395 return frmProForm.savingDraft( object );
1396 }
1397 },
1398
1399 goingToPreviousPage: function( object ) {
1400 console.warn( 'DEPRECATED: function frmFrontForm.goingToPreviousPage in v3.0 use frmProForm.goingToPreviousPage' );
1401 if ( typeof frmProForm !== 'undefined' ) {
1402 return frmProForm.goingToPreviousPage( object );
1403 }
1404 },
1405
1406 hideOrShowFields: function() {
1407 console.warn( 'DEPRECATED: function frmFrontForm.hideOrShowFields in v3.0 use frmProForm.hideOrShowFields' );
1408 if ( typeof frmProForm !== 'undefined' ) {
1409 frmProForm.hideOrShowFields();
1410 }
1411 },
1412
1413 hidePreviouslyHiddenFields: function() {
1414 console.warn( 'DEPRECATED: function frmFrontForm.hidePreviouslyHiddenFields in v3.0 use frmProForm.hidePreviouslyHiddenFields' );
1415 if ( typeof frmProForm !== 'undefined' ) {
1416 frmProForm.hidePreviouslyHiddenFields();
1417 }
1418 },
1419
1420 checkDependentDynamicFields: function( ids ) {
1421 console.warn( 'DEPRECATED: function frmFrontForm.checkDependentDynamicFields in v3.0 use frmProForm.checkDependentDynamicFields' );
1422 if ( typeof frmProForm !== 'undefined' ) {
1423 frmProForm.checkDependentDynamicFields( ids );
1424 }
1425 },
1426
1427 checkDependentLookupFields: function( ids ) {
1428 console.warn( 'DEPRECATED: function frmFrontForm.checkDependentLookupFields in v3.0 use frmProForm.checkDependentLookupFields' );
1429 if ( typeof frmProForm !== 'undefined' ) {
1430 frmProForm.checkDependentLookupFields( ids );
1431 }
1432 },
1433
1434 loadGoogle: function() {
1435 console.warn( 'DEPRECATED: function frmFrontForm.loadGoogle in v3.0 use frmProForm.loadGoogle' );
1436 frmProForm.loadGoogle();
1437 },
1438
1439 escapeHtml: function( text ) {
1440 return text
1441 .replace( /&/g, '&amp;' )
1442 .replace( /</g, '&lt;' )
1443 .replace( />/g, '&gt;' )
1444 .replace( /"/g, '&quot;' )
1445 .replace( /'/g, '&#039;' );
1446 },
1447
1448 invisible: function( classes ) {
1449 jQuery( classes ).css( 'visibility', 'hidden' );
1450 },
1451
1452 visible: function( classes ) {
1453 jQuery( classes ).css( 'visibility', 'visible' );
1454 }
1455 };
1456 }
1457 frmFrontForm = frmFrontFormJS();
1458
1459 jQuery( document ).ready( function() {
1460 frmFrontForm.init();
1461 });
1462
1463 function frmRecaptcha() {
1464 var c, cl,
1465 captchas = jQuery( '.frm-g-recaptcha' );
1466 for ( c = 0, cl = captchas.length; c < cl; c++ ) {
1467 frmFrontForm.renderRecaptcha( captchas[c]);
1468 }
1469 }
1470
1471 function frmAfterRecaptcha( token ) {
1472 frmFrontForm.afterSingleRecaptcha( token );
1473 }
1474
1475 function frmUpdateField( entryId, fieldId, value, message, num ) {
1476 jQuery( document.getElementById( 'frm_update_field_' + entryId + '_' + fieldId + '_' + num ) ).html( '<span class="frm-loading-img"></span>' );
1477 jQuery.ajax({
1478 type: 'POST',
1479 url: frm_js.ajax_url,
1480 data: {
1481 action: 'frm_entries_update_field_ajax',
1482 entry_id: entryId,
1483 field_id: fieldId,
1484 value: value,
1485 nonce: frm_js.nonce
1486 },
1487 success: function() {
1488 if ( message.replace( /^\s+|\s+$/g, '' ) === '' ) {
1489 jQuery( document.getElementById( 'frm_update_field_' + entryId + '_' + fieldId + '_' + num ) ).fadeOut( 'slow' );
1490 } else {
1491 jQuery( document.getElementById( 'frm_update_field_' + entryId + '_' + fieldId + '_' + num ) ).replaceWith( message );
1492 }
1493 }
1494 });
1495 }
1496
1497 function frmDeleteEntry( entryId, prefix ) {
1498 console.warn( 'DEPRECATED: function frmDeleteEntry in v2.0.13 use frmFrontForm.deleteEntry' );
1499 jQuery( document.getElementById( 'frm_delete_' + entryId ) ).replaceWith( '<span class="frm-loading-img" id="frm_delete_' + entryId + '"></span>' );
1500 jQuery.ajax({
1501 type: 'POST',
1502 url: frm_js.ajax_url,
1503 data: {
1504 action: 'frm_entries_destroy',
1505 entry: entryId,
1506 nonce: frm_js.nonce
1507 },
1508 success: function( html ) {
1509 if ( html.replace( /^\s+|\s+$/g, '' ) === 'success' ) {
1510 jQuery( document.getElementById( prefix + entryId ) ).fadeOut( 'slow' );
1511 } else {
1512 jQuery( document.getElementById( 'frm_delete_' + entryId ) ).replaceWith( html );
1513 }
1514 }
1515 });
1516 }
1517
1518 function frmOnSubmit( e ) {
1519 console.warn( 'DEPRECATED: function frmOnSubmit in v2.0 use frmFrontForm.submitForm' );
1520 frmFrontForm.submitForm( e, this );
1521 }
1522
1523 function frm_resend_email( entryId, formId ) { // eslint-disable-line camelcase
1524 var $link = jQuery( document.getElementById( 'frm_resend_email' ) );
1525 console.warn( 'DEPRECATED: function frm_resend_email in v2.0' );
1526 $link.append( '<span class="spinner" style="display:inline"></span>' );
1527 jQuery.ajax({
1528 type: 'POST',
1529 url: frm_js.ajax_url,
1530 data: {
1531 action: 'frm_entries_send_email',
1532 entry_id: entryId,
1533 form_id: formId,
1534 nonce: frm_js.nonce
1535 },
1536 success: function( msg ) {
1537 $link.replaceWith( msg );
1538 }
1539 });
1540 }
1541