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

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