PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 4.05.02
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v4.05.02
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / js / formidable.js

formidable.js in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 4.05.02, at js/formidable.js

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