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

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