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

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