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

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