diff --git a/classes/factories/FrmFieldFactory.php b/classes/factories/FrmFieldFactory.php index c3850e7e1a..765469754c 100644 --- a/classes/factories/FrmFieldFactory.php +++ b/classes/factories/FrmFieldFactory.php @@ -91,24 +91,25 @@ public static function get_field_type( $field_type, $field = 0 ) { */ private static function get_field_type_class( $field_type ) { $type_classes = array( - 'text' => 'FrmFieldText', - 'textarea' => 'FrmFieldTextarea', - 'select' => 'FrmFieldSelect', - 'radio' => 'FrmFieldRadio', - 'checkbox' => 'FrmFieldCheckbox', - 'number' => 'FrmFieldNumber', - 'phone' => 'FrmFieldPhone', - 'url' => 'FrmFieldUrl', - 'website' => 'FrmFieldUrl', - 'email' => 'FrmFieldEmail', - 'user_id' => 'FrmFieldUserID', - 'html' => 'FrmFieldHTML', - 'hidden' => 'FrmFieldHidden', - 'captcha' => 'FrmFieldCaptcha', - 'name' => 'FrmFieldName', - 'credit_card' => 'FrmFieldCreditCard', + 'text' => 'FrmFieldText', + 'textarea' => 'FrmFieldTextarea', + 'select' => 'FrmFieldSelect', + 'radio' => 'FrmFieldRadio', + 'checkbox' => 'FrmFieldCheckbox', + 'number' => 'FrmFieldNumber', + 'phone' => 'FrmFieldPhone', + 'url' => 'FrmFieldUrl', + 'website' => 'FrmFieldUrl', + 'email' => 'FrmFieldEmail', + 'user_id' => 'FrmFieldUserID', + 'html' => 'FrmFieldHTML', + 'hidden' => 'FrmFieldHidden', + 'captcha' => 'FrmFieldCaptcha', + 'name' => 'FrmFieldName', + 'credit_card' => 'FrmFieldCreditCard', // Submit button field. - FrmSubmitHelper::FIELD_TYPE => 'FrmFieldSubmit', + FrmSubmitHelper::FIELD_TYPE => 'FrmFieldSubmit', + FrmFieldGdprHelper::FIELD_TYPE => FrmFieldGdprHelper::get_gdpr_field_class( $field_type ), ); $class = isset( $type_classes[ $field_type ] ) ? $type_classes[ $field_type ] : ''; diff --git a/classes/helpers/FrmAppHelper.php b/classes/helpers/FrmAppHelper.php index ef7d3a4e01..172e8de692 100644 --- a/classes/helpers/FrmAppHelper.php +++ b/classes/helpers/FrmAppHelper.php @@ -4444,4 +4444,28 @@ public static function print_setting_error( $args ) { enable_gdpr || $frm_settings->no_ips || $frm_settings->custom_header_ip || $frm_settings->no_gdpr_cookies; + } + + /** + * Check if GDPR cookies are disabled. + * + * @since x.x + * + * @return bool + */ + public static function no_gdpr_cookies() { + $frm_settings = self::get_settings(); + return $frm_settings->enable_gdpr && $frm_settings->no_gdpr_cookies; + } } diff --git a/classes/helpers/FrmFieldGdprHelper.php b/classes/helpers/FrmFieldGdprHelper.php new file mode 100644 index 0000000000..2ee09d8c73 --- /dev/null +++ b/classes/helpers/FrmFieldGdprHelper.php @@ -0,0 +1,73 @@ +enable_gdpr; + } + + /** + * Add GDPR field to form builder + * + * @since x.x + * @param array $fields + * @return array + */ + public static function add_gdpr_field( $fields ) { + $fields[ self::FIELD_TYPE ] = array( + 'name' => __( 'GDPR', 'formidable' ), + 'icon' => 'frm_icon_font frm-gdpr-icon', + ); + return $fields; + } + + /** + * Initialize GDPR field Class name + * + * @since x.x + * @param string $field_type + * @return string + */ + public static function get_gdpr_field_class( $field_type = '' ) { + if ( self::FIELD_TYPE === $field_type ) { + return self::FIELD_CLASS; + } + return ''; + } +} diff --git a/classes/helpers/FrmFieldsHelper.php b/classes/helpers/FrmFieldsHelper.php index 92da9689c1..2f5fa1f3e8 100644 --- a/classes/helpers/FrmFieldsHelper.php +++ b/classes/helpers/FrmFieldsHelper.php @@ -1291,6 +1291,7 @@ public static function single_input_fields() { 'time', 'tag', 'password', + 'gdpr', ); return apply_filters( 'frm_single_input_fields', $fields ); } diff --git a/classes/models/FrmField.php b/classes/models/FrmField.php index e7e62fbf1e..a6d12154fe 100644 --- a/classes/models/FrmField.php +++ b/classes/models/FrmField.php @@ -10,70 +10,75 @@ class FrmField { public static function field_selection() { $fields = array( - 'text' => array( + 'text' => array( 'name' => __( 'Text', 'formidable' ), 'icon' => 'frm_icon_font frm_text2_icon', ), - 'textarea' => array( + 'textarea' => array( 'name' => __( 'Paragraph', 'formidable' ), 'icon' => 'frm_icon_font frm_paragraph_icon', ), - 'checkbox' => array( + 'checkbox' => array( 'name' => __( 'Checkboxes', 'formidable' ), 'icon' => 'frm_icon_font frm_check_square_icon', ), - 'radio' => array( + 'radio' => array( 'name' => __( 'Radio Buttons', 'formidable' ), 'icon' => 'frm_icon_font frm_radio_checked_icon', ), - 'select' => array( + 'select' => array( 'name' => __( 'Dropdown', 'formidable' ), 'icon' => 'frm_icon_font frm_caret_square_down_icon', ), - 'email' => array( + 'email' => array( 'name' => __( 'Email', 'formidable' ), 'icon' => 'frm_icon_font frm_email_icon', ), - 'url' => array( + 'url' => array( 'name' => __( 'Website/URL', 'formidable' ), 'icon' => 'frm_icon_font frm_link_icon', ), - 'number' => array( + 'number' => array( 'name' => __( 'Number', 'formidable' ), 'icon' => 'frm_icon_font frm_hashtag_icon', ), - 'name' => array( + 'name' => array( 'name' => __( 'Name', 'formidable' ), 'icon' => 'frm_icon_font frm_user_name_icon', ), - 'phone' => array( + 'phone' => array( 'name' => __( 'Phone', 'formidable' ), 'icon' => 'frm_icon_font frm_phone_icon', ), - 'html' => array( + 'html' => array( 'name' => __( 'HTML', 'formidable' ), 'icon' => 'frm_icon_font frm_code_icon', ), - 'hidden' => array( + 'hidden' => array( 'name' => __( 'Hidden', 'formidable' ), 'icon' => 'frm_icon_font frm_eye_slash_icon', ), - 'user_id' => array( + 'user_id' => array( 'name' => __( 'User ID', 'formidable' ), 'icon' => 'frm_icon_font frm_user_icon', ), - 'captcha' => array( + 'captcha' => array( 'name' => self::get_captcha_field_name(), 'icon' => 'frm_icon_font frm_shield_check_icon', ), - 'credit_card' => array( + 'credit_card' => array( 'name' => __( 'Payment', 'formidable' ), 'icon' => 'frm_icon_font frm_credit_card_icon', ), - FrmSubmitHelper::FIELD_TYPE => array( + FrmSubmitHelper::FIELD_TYPE => array( 'name' => __( 'Submit', 'formidable' ), 'hide' => true, ), + FrmFieldGdprHelper::FIELD_TYPE => array( + 'name' => __( 'GDPR', 'formidable' ), + 'icon' => 'frm_icon_font frm-gdpr-icon', + 'hide' => FrmFieldGdprHelper::hide_gdpr_field(), + ), ); /** @@ -378,7 +383,9 @@ public static function create( $values, $return = true ) { $values = FrmAppHelper::maybe_filter_array( $values, array( 'name', 'description' ) ); foreach ( array( 'name', 'description', 'type', 'default_value' ) as $col ) { - $new_values[ $col ] = $values[ $col ]; + if ( isset( $values[ $col ] ) ) { + $new_values[ $col ] = $values[ $col ]; + } } $new_values['options'] = self::maybe_filter_options( $values['options'] ); diff --git a/classes/models/FrmSettings.php b/classes/models/FrmSettings.php index 76f1f27283..2c7970d0ab 100644 --- a/classes/models/FrmSettings.php +++ b/classes/models/FrmSettings.php @@ -151,6 +151,8 @@ public function default_options() { 'new_tab_msg' => __( 'The page has been opened in a new tab.', 'formidable' ), 'email_to' => '[admin_email]', + 'enable_gdpr' => 0, + 'no_gdpr_cookies' => 0, 'no_ips' => 0, 'custom_header_ip' => 0, 'tracking' => FrmAppHelper::pro_is_installed(), @@ -399,7 +401,7 @@ private function update_settings( $params ) { $this->from_email = $params['frm_from_email']; $this->currency = $params['frm_currency']; - $checkboxes = array( 'mu_menu', 're_multi', 'fade_form', 'no_ips', 'custom_header_ip', 'tracking', 'admin_bar', 'summary_emails' ); + $checkboxes = array( 'mu_menu', 're_multi', 'fade_form', 'no_ips', 'no_gdpr_cookies', 'enable_gdpr', 'custom_header_ip', 'tracking', 'admin_bar', 'summary_emails' ); foreach ( $checkboxes as $set ) { $this->$set = isset( $params[ 'frm_' . $set ] ) ? absint( $params[ 'frm_' . $set ] ) : 0; } diff --git a/classes/models/fields/FrmFieldGdpr.php b/classes/models/fields/FrmFieldGdpr.php new file mode 100644 index 0000000000..101023661d --- /dev/null +++ b/classes/models/fields/FrmFieldGdpr.php @@ -0,0 +1,158 @@ + false, + 'description' => false, + 'type' => $this->type, + 'options' => false, + 'required' => false, + 'field_options' => false, + ); + } + + return array( + 'name' => $this->get_new_field_name() . __( ' Consent', 'formidable' ), + 'description' => '', + 'type' => $this->type, + 'options' => '', + 'required' => true, + 'field_options' => $this->get_default_field_options(), + ); + } + + /** + * Get the field settings for the field type. + * + * @since x.x + * @return bool[] + */ + protected function field_settings_for_type() { + if ( FrmFieldGdprHelper::hide_gdpr_field() ) { + return array( + 'size' => false, + 'clear_on_focus' => false, + 'default' => false, + 'invalid' => false, + 'max' => false, + 'required' => false, + 'label' => false, + 'css' => false, + 'label_position' => false, + 'description' => false, + ); + } + + return array( + 'size' => true, + 'clear_on_focus' => false, + 'default' => false, + 'invalid' => false, + 'max' => false, + 'readonly_required' => true, + 'required' => true, + ); + } + + /** + * Show the primary options for the field. + * + * @since x.x + * @param array $args The arguments. + */ + public function show_primary_options( $args ) { + if ( FrmFieldGdprHelper::hide_gdpr_field() ) { + return; + } + $field = $args['field']; + include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/gdpr/primary-options.php'; + } + + public function show_label_on_form_builder() { + if ( FrmFieldGdprHelper::hide_gdpr_field() ) { + return; + } + parent::show_label_on_form_builder(); + } + + /** + * Gets extra field options. + * + * @since x.x + * @return string[] + */ + protected function extra_field_opts() { + return array( + 'gdpr_agreement_text' => __( 'I consent to having this website store my submitted information so they can respond to my inquiry.', 'formidable' ), + ); + } + + /** + * Include the form builder file. + * + * @since x.x + * @return string + */ + protected function include_form_builder_file() { + return FrmAppHelper::plugin_path() . self::VIEW_PATH; + } + + /** + * Include the front form file. + * + * @since x.x + * @return string + */ + protected function include_front_form_file() { + return FrmAppHelper::plugin_path() . self::VIEW_PATH; + } + + /** + * Hide the field name/label if the GDPR field is disabled. + * + * @since x.x + * + * @param array $args The arguments. + * @param string $html The HTML. + * @return string + */ + protected function before_replace_html_shortcodes( $args, $html ) { + if ( FrmFieldGdprHelper::hide_gdpr_field() && ! current_user_can( 'frm_edit_forms' ) ) { + return ''; + } + return $html; + } +} diff --git a/classes/models/fields/FrmFieldType.php b/classes/models/fields/FrmFieldType.php index 001a27a5b1..0a213a8100 100644 --- a/classes/models/fields/FrmFieldType.php +++ b/classes/models/fields/FrmFieldType.php @@ -338,27 +338,28 @@ public function display_field_settings() { */ protected function default_field_settings() { return array( - 'type' => $this->type, - 'label' => true, - 'required' => true, - 'unique' => false, - 'read_only' => false, - 'description' => true, - 'options' => true, - 'label_position' => true, - 'invalid' => false, - 'size' => false, + 'type' => $this->type, + 'label' => true, + 'required' => true, + 'readonly_required' => false, + 'unique' => false, + 'read_only' => false, + 'description' => true, + 'options' => true, + 'label_position' => true, + 'invalid' => false, + 'size' => false, // Shows the placeholder option. - 'clear_on_focus' => false, - 'css' => true, - 'conf_field' => false, - 'max' => true, - 'range' => false, - 'captcha_size' => false, - 'captcha_theme' => false, - 'format' => false, - 'show_image' => false, - 'default' => true, + 'clear_on_focus' => false, + 'css' => true, + 'conf_field' => false, + 'max' => true, + 'range' => false, + 'captcha_size' => false, + 'captcha_theme' => false, + 'format' => false, + 'show_image' => false, + 'default' => true, ); } diff --git a/classes/views/frm-fields/back-end/gdpr/primary-options.php b/classes/views/frm-fields/back-end/gdpr/primary-options.php new file mode 100644 index 0000000000..dd62cc7299 --- /dev/null +++ b/classes/views/frm-fields/back-end/gdpr/primary-options.php @@ -0,0 +1,25 @@ + +

+ + +

diff --git a/classes/views/frm-fields/back-end/settings.php b/classes/views/frm-fields/back-end/settings.php index ac540e1a5f..73c3479b08 100644 --- a/classes/views/frm-fields/back-end/settings.php +++ b/classes/views/frm-fields/back-end/settings.php @@ -53,6 +53,23 @@ } } ?> + + +
+ 'width:24px' ) ); ?> + + ', '' ); + ?> + +
+ +

diff --git a/classes/views/frm-fields/front-end/gdpr/gdpr-field.php b/classes/views/frm-fields/front-end/gdpr/gdpr-field.php new file mode 100644 index 0000000000..e028c2fb40 --- /dev/null +++ b/classes/views/frm-fields/front-end/gdpr/gdpr-field.php @@ -0,0 +1,36 @@ + + + +
+ +
+ +
+ +
+ diff --git a/classes/views/frm-settings/general.php b/classes/views/frm-settings/general.php index f0be3c0805..a5c9efe529 100644 --- a/classes/views/frm-settings/general.php +++ b/classes/views/frm-settings/general.php @@ -2,6 +2,8 @@ if ( ! defined( 'ABSPATH' ) ) { die( 'You are not allowed to call this page directly.' ); } +$is_gdpr_enabled = FrmAppHelper::is_gdpr_enabled(); + ?>

@@ -49,26 +51,42 @@
-

- +

+ 'frm_gdpr_options' ); +if ( ! $is_gdpr_enabled ) { + $gdpr_options_wrapper_params['class'] .= ' frm_hidden'; +} +$custom_header_ip_wrapper_params = array( 'class' => 'frm_custom_header_ip_cont frm_gdpr_options' ); +if ( $frm_settings->no_ips || ! $is_gdpr_enabled ) { + $custom_header_ip_wrapper_params['class'] .= ' frm_hidden'; +} +?>

- 'frm_custom_header_ip_cont' ); -if ( $frm_settings->no_ips ) { - $custom_header_ip_wrapper_params['class'] .= ' frm_hidden'; -} -?> +

> + +

+ +

> + +

>

+

+ %s', 'https://formidableforms.com/knowledgebase/gdpr-settings/', esc_html__( 'here', 'formidable' ) ); + ?> +

+

+ diff --git a/js/formidable.min.js b/js/formidable.min.js index 341c5d7732..64603471d5 100644 --- a/js/formidable.min.js +++ b/js/formidable.min.js @@ -1,14 +1,14 @@ function frmFrontFormJS(){let jsErrors=[];function triggerCustomEvent(el,eventName,data){if(typeof window.CustomEvent!=="function")return;const event=new CustomEvent(eventName);event.frmData=data;el.dispatchEvent(event)}function getFieldId(field,fullID){let nameParts,fieldId,isRepeating=false,fieldName="";if(field instanceof jQuery)fieldName=field.attr("name");else fieldName=field.name;if(typeof fieldName==="undefined")fieldName="";if(fieldName===""){if(field instanceof jQuery)fieldName=field.data("name"); else fieldName=field.getAttribute("data-name");if(typeof fieldName==="undefined")fieldName="";if(fieldName!==""&&fieldName)return fieldName;return 0}nameParts=fieldName.replace("item_meta[","").replace("[]","").split("]");if(nameParts.length<1)return 0;nameParts=nameParts.filter(function(n){return n!==""});fieldId=nameParts[0];if(nameParts.length===1)return fieldId;if(nameParts[1]==="[form"||nameParts[1]==="[row_ids")return 0;if(document.querySelector('input[name="item_meta['+fieldId+'][form]"]')){fieldId= nameParts[2].replace("[","");isRepeating=true}if("other"===fieldId)if(isRepeating)fieldId=nameParts[3].replace("[","");else fieldId=nameParts[1].replace("[","");if(fullID===true)if(fieldId===nameParts[0])fieldId=fieldId+"-"+nameParts[1].replace("[","");else fieldId=fieldId+"-"+nameParts[0]+"-"+nameParts[1].replace("[","");return fieldId}function disableSubmitButton($form){$form.find('input[type="submit"], input[type="button"], button[type="submit"], button.frm_save_draft').attr("disabled","disabled")} -function enableSubmitButton($form){$form.find('input[type="submit"], input[type="button"], button[type="submit"]').prop("disabled",false)}function disableSaveDraft($form){$form.find("a.frm_save_draft").css("pointer-events","none")}function enableSaveDraft($form){if(!$form.length)return;$form[0].querySelectorAll(".frm_save_draft").forEach(saveDraftButton=>{saveDraftButton.disabled=false;saveDraftButton.style.pointerEvents=""})}function validateForm(object){let errors,n,nl,fields,field;errors=[];const vanillaJsObject= -"function"===typeof object.get?object.get(0):object;vanillaJsObject?.querySelectorAll(".frm_required_field").forEach(requiredField=>{const isVisible=requiredField.offsetParent!==null;if(!isVisible)return;requiredField.querySelectorAll("input, select, textarea").forEach(requiredInput=>{if(hasClass(requiredInput,"frm_optional")||hasClass(requiredInput,"ed_button"))return;errors=checkRequiredField(requiredInput,errors)})});fields=jQuery(object).find("input,select,textarea");if(fields.length)for(n=0, -nl=fields.length;n -0)for(key in errors)addFieldError($fieldCont,key,errors)}function validateFieldValue(field,errors,onSubmit){if(field.type==="hidden");else if(field.type==="number")checkNumberField(field,errors);else if(field.type==="email")checkEmailField(field,errors,onSubmit);else if(field.type==="password")checkPasswordField(field,errors,onSubmit);else if(field.type==="url")checkUrlField(field,errors);else if(field.pattern!==null)checkPatternField(field,errors);triggerCustomEvent(document,"frm_validate_field_value", -{field:field,errors:errors,onSubmit:onSubmit})}function checkRequiredField(field,errors){let checkGroup,tempVal,i,placeholder,val="",fieldID="",fileID=field.getAttribute("data-frmfile");if(field.type==="hidden"&&fileID===null&&!isAppointmentField(field)&&!isInlineDatepickerField(field))return errors;if(field.type==="checkbox"||field.type==="radio"){checkGroup=jQuery('input[name="'+field.name+'"]').closest(".frm_required_field").find("input:checked");jQuery(checkGroup).each(function(){val=this.value})}else if(field.type=== -"file"||fileID){if(typeof fileID==="undefined"){fileID=getFieldId(field,true);fileID=fileID.replace("file","")}if(typeof errors[fileID]==="undefined")val=getFileVals(fileID);fieldID=fileID}else{if(hasClass(field,"frm_pos_none"))return errors;val=jQuery(field).val();if(val===null)val="";else if(typeof val!=="string"){tempVal=val;val="";for(i=0;i{saveDraftButton.disabled=false;saveDraftButton.style.pointerEvents=""})}function validateForm(object){let errors=[];const vanillaJsObject="function"=== +typeof object.get?object.get(0):object;vanillaJsObject?.querySelectorAll(".frm_required_field").forEach(requiredField=>{const isVisible=requiredField.offsetParent!==null;if(!isVisible)return;requiredField.querySelectorAll("input, select, textarea").forEach(requiredInput=>{if(hasClass(requiredInput,"frm_optional")||hasClass(requiredInput,"ed_button"))return;errors=checkRequiredField(requiredInput,errors)})});vanillaJsObject?.querySelectorAll("input,select,textarea").forEach(field=>{if(""===field.value){if("number"=== +field.type)checkValidity(field,errors);const isConfirmationField=field.name&&0===field.name.indexOf("item_meta[conf_");if(!isConfirmationField)return}validateFieldValue(field,errors,true);checkValidity(field,errors)});if(!hasInvisibleRecaptcha(object))errors=validateRecaptcha(object,errors);return errors}function checkValidity(field,errors){let fieldID;if("object"!==typeof field.validity||false!==field.validity.valid)return;fieldID=getFieldId(field,true);if("undefined"===typeof errors[fieldID])errors[fieldID]= +getFieldValidationMessage(field,"data-invmsg");if("function"===typeof field.reportValidity)field.reportValidity()}function hasClass(element,targetClass){return element.classList&&element.classList.contains(targetClass)}function maybeValidateChange(field){if(field.type==="url")maybeAddHttpToUrl(field);const form=field.closest("form");if(form&&hasClass(form,"frm_js_validate"))validateField(field)}function maybeAddHttpToUrl(field){const url=field.value;const matches=url.match(/^(https?|ftps?|mailto|news|feed|telnet):/); +if(field.value!==""&&matches===null)field.value="http://"+url}function validateField(field){let errors,key;errors=[];const fieldContainer=field.closest(".frm_form_field");if(!fieldContainer)return;if(hasClass(fieldContainer,"frm_required_field")&&!hasClass(field,"frm_optional"))errors=checkRequiredField(field,errors);if(errors.length<1)validateFieldValue(field,errors,false);const $fieldCont=jQuery(fieldContainer);removeFieldError($fieldCont);if(Object.keys(errors).length>0)for(key in errors)addFieldError($fieldCont, +key,errors)}function validateFieldValue(field,errors,onSubmit){if(field.type==="hidden");else if(field.type==="number")checkNumberField(field,errors);else if(field.type==="email")checkEmailField(field,errors,onSubmit);else if(field.type==="password")checkPasswordField(field,errors,onSubmit);else if(field.type==="url")checkUrlField(field,errors);else if(field.pattern!==null)checkPatternField(field,errors);triggerCustomEvent(document,"frm_validate_field_value",{field:field,errors:errors,onSubmit:onSubmit})} +function checkRequiredField(field,errors){let checkGroup,tempVal,i,placeholder,val="",fieldID="",fileID=field.getAttribute("data-frmfile");if(field.type==="hidden"&&fileID===null&&!isAppointmentField(field)&&!isInlineDatepickerField(field))return errors;if(field.type==="checkbox"||field.type==="radio"){checkGroup=jQuery('input[name="'+field.name+'"]').closest(".frm_required_field").find("input:checked");jQuery(checkGroup).each(function(){val=this.value})}else if(field.type==="file"||fileID){if(typeof fileID=== +"undefined"){fileID=getFieldId(field,true);fileID=fileID.replace("file","")}if(typeof errors[fileID]==="undefined")val=getFileVals(fileID);fieldID=fileID}else{if(hasClass(field,"frm_pos_none"))return errors;val=jQuery(field).val();if(val===null)val="";else if(typeof val!=="string"){tempVal=val;val="";for(i=0;i';previousInput=container.find('input[name="recaptcha_checked"]');if(previousInput.length)previousInput.replaceWith(input);else container.append(input)}afterFormSubmitted(object,response)},delay)}else if(Object.keys(response.errors).length){removeSubmitLoading(jQuery(object), "enable");contSubmit=true;removeAllErrors();$fieldCont=null;for(key in response.errors){$fieldCont=jQuery(object).find("#frm_field_"+key+"_container");if($fieldCont.length){if(!$fieldCont.is(":visible")){inCollapsedSection=$fieldCont.closest(".frm_toggle_container");if(inCollapsedSection.length){frmTrigger=inCollapsedSection.prev();if(!frmTrigger.hasClass("frm_trigger"))frmTrigger=frmTrigger.prev(".frm_trigger");frmTrigger.trigger("click")}}if($fieldCont.is(":visible")){addFieldError($fieldCont,key, -response.errors);contSubmit=false}}}jQuery(object).find(".frm-g-recaptcha, .g-recaptcha, .h-captcha").each(function(){const $recaptcha=jQuery(this),recaptchaID=$recaptcha.data("rid");if(typeof grecaptcha!=="undefined"&&grecaptcha)if(recaptchaID)grecaptcha.reset(recaptchaID);else grecaptcha.reset();if(typeof hcaptcha!=="undefined"&&hcaptcha)hcaptcha.reset()});jQuery(document).trigger("frmFormErrors",[object,response]);fieldset.removeClass("frm_doing_ajax");scrollToFirstField(object);if(contSubmit)object.submit(); -else{object.insertAdjacentHTML("afterbegin",response.error_message);checkForErrorsAndMaybeSetFocus()}}else{showFileLoading(object);object.submit()}};error=function(){jQuery(object).find('input[type="submit"], input[type="button"]').prop("disabled",false);object.submit()};postToAjaxUrl(object,data,success,error)}function postToAjaxUrl(form,data,success,error){let ajaxUrl,action,ajaxParams;ajaxUrl=frm_js.ajax_url;action=form.getAttribute("action");if("string"===typeof action&&-1!==action.indexOf("?action=frm_forms_preview"))ajaxUrl= -action.split("?action=frm_forms_preview")[0];ajaxParams={type:"POST",url:ajaxUrl,data:data,success:success};if("function"===typeof error)ajaxParams.error=error;jQuery.ajax(ajaxParams)}function afterFormSubmitted(object,response){const formCompleted=jQuery(response.content).find(".frm_message");if(formCompleted.length)jQuery(document).trigger("frmFormComplete",[object,response]);else jQuery(document).trigger("frmPageChanged",[object,response])}function afterFormSubmittedBeforeReplace(object,response){const formCompleted= -jQuery(response.content).find(".frm_message");if(formCompleted.length)triggerCustomEvent(document,"frmFormCompleteBeforeReplace",{object,response})}function removeAddedScripts(formContainer,formID){const endReplace=jQuery(".frm_end_ajax_"+formID);if(endReplace.length){formContainer.nextUntil(".frm_end_ajax_"+formID).remove();endReplace.remove()}}function maybeSlideOut(oldContent,newContent){let c,newClass="frm_slideout";if(newContent.indexOf(" frm_slide")!==-1){c=oldContent.children();if(newContent.indexOf(" frm_going_back")!== --1)newClass+=" frm_going_back";c.removeClass("frm_going_back");c.addClass(newClass);return 300}return 0}function addUrlParam(response){let url;if(history.pushState&&typeof response.page!=="undefined"){url=addQueryVar("frm_page",response.page);window.history.pushState({"html":response.html},"","?"+url)}}function addQueryVar(key,value){let kvp,i,x;key=encodeURI(key);value=encodeURI(value);kvp=document.location.search.substr(1).split("&");i=kvp.length;while(i--){x=kvp[i].split("=");if(x[0]==key){x[1]= -value;kvp[i]=x.join("=");break}}if(i<0)kvp[kvp.length]=[key,value].join("=");return kvp.join("&")}function addFieldError($fieldCont,key,jsErrors){let input,id,describedBy,roleString;if($fieldCont.length&&$fieldCont.is(":visible")){$fieldCont.addClass("frm_blank_field");input=$fieldCont.find("input, select, textarea");id=getErrorElementId(key,input.get(0));describedBy=input.attr("aria-describedby");if(typeof frmThemeOverride_frmPlaceError==="function")frmThemeOverride_frmPlaceError(key,jsErrors);else{if(-1!== -jsErrors[key].indexOf("'+jsErrors[key]+"
")}if(typeof describedBy==="undefined")describedBy=id;else if(describedBy.indexOf(id)===-1&&describedBy.indexOf("frm_error_field_")===-1)if(input.data("error-first")===0)describedBy=describedBy+" "+id;else describedBy=id+" "+describedBy;input.attr("aria-describedby",describedBy)}input.attr("aria-invalid", -true);jQuery(document).trigger("frmAddFieldError",[$fieldCont,key,jsErrors])}}function getErrorElementId(key,input){if(isNaN(key)||!input||!input.id)return"frm_error_field_"+key;return"frm_error_"+input.id}function removeFieldError($fieldCont){const errorMessage=$fieldCont.find(".frm_error");const errorId=errorMessage.attr("id");const input=$fieldCont.find("input, select, textarea");let describedBy=input.attr("aria-describedby");const fieldContainer=$fieldCont.get(0);if(fieldContainer&&fieldContainer.classList)fieldContainer.classList.remove("frm_blank_field", -"has-error");errorMessage.remove();input.attr("aria-invalid",false);input.removeAttr("aria-describedby");if(typeof describedBy!=="undefined"){describedBy=describedBy.replace(errorId,"");input.attr("aria-describedby",describedBy)}}function removeAllErrors(){jQuery(".form-field").removeClass("frm_blank_field has-error");jQuery(".form-field .frm_error").replaceWith("");jQuery(".frm_error_style").remove()}function scrollToFirstField(object){if("function"===typeof object.get)object=object.get(0);const field= -object.querySelector(".frm_blank_field");if(field)frmFrontForm.scrollMsg(jQuery(field),object,true)}function showSubmitLoading($object){showLoadingIndicator($object);disableSubmitButton($object);disableSaveDraft($object)}function showLoadingIndicator($object){if(!$object.hasClass("frm_loading_form")&&!$object.hasClass("frm_loading_prev")){addLoadingClass($object);$object.trigger("frmStartFormLoading")}}function addLoadingClass($object){const loadingClass=isGoingToPrevPage($object)?"frm_loading_prev": -"frm_loading_form";$object.addClass(loadingClass)}function isGoingToPrevPage($object){return typeof frmProForm!=="undefined"&&frmProForm.goingToPreviousPage($object)}function removeSubmitLoading(_,enable,processesRunning){let loadingForm;if(processesRunning>0)return;loadingForm=jQuery(".frm_loading_form");loadingForm.removeClass("frm_loading_form");loadingForm.removeClass("frm_loading_prev");loadingForm.trigger("frmEndFormLoading");if(enable==="enable"){enableSubmitButton(loadingForm);enableSaveDraft(loadingForm)}} -function showFileLoading(object){let fileval,loading=document.getElementById("frm_loading");if(loading!==null){fileval=jQuery(object).find("input[type=file]").val();if(typeof fileval!=="undefined"&&fileval!=="")setTimeout(function(){jQuery(loading).fadeIn("slow")},2E3)}}function confirmClick(){const message=jQuery(this).data("frmconfirm");return confirm(message)}function onHoneypotFieldChange(){const css=jQuery(this).css("box-shadow");if(css.match(/inset/))this.parentNode.removeChild(this)}function maybeMakeHoneypotFieldsUntabbable(){document.addEventListener("keydown", -handleKeyUp);function handleKeyUp(event){let code;if("undefined"!==typeof event.key)code=event.key;else if("undefined"!==typeof event.keyCode&&9===event.keyCode)code="Tab";if("Tab"===code){makeHoneypotFieldsUntabbable();document.removeEventListener("keydown",handleKeyUp)}}function makeHoneypotFieldsUntabbable(){document.querySelectorAll(".frm_verify").forEach(function(input){if(input.id&&0===input.id.indexOf("frm_email_"))input.setAttribute("tabindex",-1)})}}function changeFocusWhenClickComboFieldLabel(){let label; -const comboInputsContainer=document.querySelectorAll(".frm_combo_inputs_container");comboInputsContainer.forEach(function(inputsContainer){if(!inputsContainer.closest(".frm_form_field"))return;label=inputsContainer.closest(".frm_form_field").querySelector(".frm_primary_label");if(!label)return;label.addEventListener("click",function(){inputsContainer.querySelector(".frm_form_field:first-child input, .frm_form_field:first-child select, .frm_form_field:first-child textarea").focus()})})}function maybeFocusOnComboSubField(element){if("FIELDSET"!== -element.nodeName)return false;if(!element.querySelector(".frm_combo_inputs_container"))return false;const comboSubfield=element.querySelector('[aria-invalid="true"]');if(comboSubfield){focusInput(comboSubfield);return true}return false}function checkForErrorsAndMaybeSetFocus(){let errors,element,timeoutCallback;if(!frm_js.focus_first_error)return;errors=document.querySelectorAll(".frm_form_field .frm_error");if(!errors.length)return;element=errors[0];do{element=element.previousSibling;if(-1!==["input", -"select","textarea"].indexOf(element.nodeName.toLowerCase())){focusInput(element);break}if(maybeFocusOnComboSubField(element))break;if("undefined"!==typeof element.classList){if(element.classList.contains("html-active"))timeoutCallback=function(){const textarea=element.querySelector("textarea");if(null!==textarea)textarea.focus()};else if(element.classList.contains("tmce-active"))timeoutCallback=function(){tinyMCE.activeEditor.focus()};if("function"===typeof timeoutCallback){setTimeout(timeoutCallback, -0);break}}}while(element.previousSibling)}function focusInput(input){if(input.offsetParent!==null)input.focus();else triggerCustomEvent(document,"frmMaybeDelayFocus",{input})}function documentOn(event,selector,handler,options){if("undefined"===typeof options)options=false;document.addEventListener(event,function(e){let target;for(target=e.target;target&&target!=this;target=target.parentNode)if(target&&target.matches&&target.matches(selector)){handler.call(target,e);break}},options)}function initFloatingLabels(){let checkFloatLabel, -checkDropdownLabel,runOnLoad,selector,floatClass;selector=".frm-show-form .frm_inside_container input, .frm-show-form .frm_inside_container select, .frm-show-form .frm_inside_container textarea";floatClass="frm_label_float_top";checkFloatLabel=function(input){let container,shouldFloatTop,firstOpt;container=input.closest(".frm_inside_container");if(!container)return;shouldFloatTop=input.value||document.activeElement===input;container.classList.toggle(floatClass,shouldFloatTop);if("SELECT"===input.tagName){firstOpt= -input.querySelector("option:first-child");if(shouldFloatTop){if(firstOpt.hasAttribute("data-label")){firstOpt.textContent=firstOpt.getAttribute("data-label");firstOpt.removeAttribute("data-label")}}else if(firstOpt.textContent){firstOpt.setAttribute("data-label",firstOpt.textContent);firstOpt.textContent=""}}};checkDropdownLabel=function(){document.querySelectorAll(".frm-show-form .frm_inside_container:not(."+floatClass+") select").forEach(function(input){const firstOpt=input.querySelector("option:first-child"); -if(firstOpt.textContent){firstOpt.setAttribute("data-label",firstOpt.textContent);firstOpt.textContent=""}})};["focus","blur","change"].forEach(function(eventName){documentOn(eventName,selector,function(event){checkFloatLabel(event.target)},true)});jQuery(document).on("change",selector,function(event){checkFloatLabel(event.target)});runOnLoad=function(firstLoad){if(firstLoad&&document.activeElement&&-1!==["INPUT","SELECT","TEXTAREA"].indexOf(document.activeElement.tagName))checkFloatLabel(document.activeElement); +response.errors);contSubmit=false}}}jQuery(object).find(".frm-g-recaptcha, .g-recaptcha, .h-captcha").each(function(){const $recaptcha=jQuery(this),recaptchaID=$recaptcha.data("rid");if(typeof grecaptcha!=="undefined"&&grecaptcha)if(recaptchaID)grecaptcha.reset(recaptchaID);else grecaptcha.reset();if(typeof hcaptcha!=="undefined"&&hcaptcha)hcaptcha.reset()});if(window.turnstile)object.querySelectorAll(".cf-turnstile").forEach(turnstileField=>turnstileField.dataset.rid&&turnstile.reset(turnstileField.dataset.rid)); +jQuery(document).trigger("frmFormErrors",[object,response]);fieldset.removeClass("frm_doing_ajax");scrollToFirstField(object);if(contSubmit)object.submit();else{object.insertAdjacentHTML("afterbegin",response.error_message);checkForErrorsAndMaybeSetFocus()}}else{showFileLoading(object);object.submit()}};error=function(){jQuery(object).find('input[type="submit"], input[type="button"]').prop("disabled",false);object.submit()};postToAjaxUrl(object,data,success,error)}function postToAjaxUrl(form,data, +success,error){let ajaxUrl,action,ajaxParams;ajaxUrl=frm_js.ajax_url;action=form.getAttribute("action");if("string"===typeof action&&-1!==action.indexOf("?action=frm_forms_preview"))ajaxUrl=action.split("?action=frm_forms_preview")[0];ajaxParams={type:"POST",url:ajaxUrl,data:data,success:success};if("function"===typeof error)ajaxParams.error=error;jQuery.ajax(ajaxParams)}function afterFormSubmitted(object,response){const formCompleted=jQuery(response.content).find(".frm_message");if(formCompleted.length)jQuery(document).trigger("frmFormComplete", +[object,response]);else jQuery(document).trigger("frmPageChanged",[object,response])}function afterFormSubmittedBeforeReplace(object,response){const formCompleted=jQuery(response.content).find(".frm_message");if(formCompleted.length)triggerCustomEvent(document,"frmFormCompleteBeforeReplace",{object,response})}function removeAddedScripts(formContainer,formID){const endReplace=jQuery(".frm_end_ajax_"+formID);if(endReplace.length){formContainer.nextUntil(".frm_end_ajax_"+formID).remove();endReplace.remove()}} +function maybeSlideOut(oldContent,newContent){let c,newClass="frm_slideout";if(newContent.indexOf(" frm_slide")!==-1){c=oldContent.children();if(newContent.indexOf(" frm_going_back")!==-1)newClass+=" frm_going_back";c.removeClass("frm_going_back");c.addClass(newClass);return 300}return 0}function addUrlParam(response){let url;if(history.pushState&&typeof response.page!=="undefined"){url=addQueryVar("frm_page",response.page);window.history.pushState({"html":response.html},"","?"+url)}}function addQueryVar(key, +value){let kvp,i,x;key=encodeURI(key);value=encodeURI(value);kvp=document.location.search.substr(1).split("&");i=kvp.length;while(i--){x=kvp[i].split("=");if(x[0]==key){x[1]=value;kvp[i]=x.join("=");break}}if(i<0)kvp[kvp.length]=[key,value].join("=");return kvp.join("&")}function addFieldError($fieldCont,key,jsErrors){let input,id,describedBy,roleString;if($fieldCont.length&&$fieldCont.is(":visible")){$fieldCont.addClass("frm_blank_field");input=$fieldCont.find("input, select, textarea");id=getErrorElementId(key, +input.get(0));describedBy=input.attr("aria-describedby");if(typeof frmThemeOverride_frmPlaceError==="function")frmThemeOverride_frmPlaceError(key,jsErrors);else{if(-1!==jsErrors[key].indexOf("'+jsErrors[key]+"")}if(typeof describedBy==="undefined")describedBy=id;else if(describedBy.indexOf(id)===-1&&describedBy.indexOf("frm_error_field_")=== +-1)if(input.data("error-first")===0)describedBy=describedBy+" "+id;else describedBy=id+" "+describedBy;input.attr("aria-describedby",describedBy)}input.attr("aria-invalid",true);jQuery(document).trigger("frmAddFieldError",[$fieldCont,key,jsErrors])}}function getErrorElementId(key,input){if(isNaN(key)||!input||!input.id)return"frm_error_field_"+key;return"frm_error_"+input.id}function removeFieldError($fieldCont){const errorMessage=$fieldCont.find(".frm_error");const errorId=errorMessage.attr("id"); +const input=$fieldCont.find("input, select, textarea");let describedBy=input.attr("aria-describedby");const fieldContainer=$fieldCont.get(0);if(fieldContainer&&fieldContainer.classList)fieldContainer.classList.remove("frm_blank_field","has-error");errorMessage.remove();input.attr("aria-invalid",false);input.removeAttr("aria-describedby");if(typeof describedBy!=="undefined"){describedBy=describedBy.replace(errorId,"");input.attr("aria-describedby",describedBy)}}function removeAllErrors(){jQuery(".form-field").removeClass("frm_blank_field has-error"); +jQuery(".form-field .frm_error").replaceWith("");jQuery(".frm_error_style").remove()}function scrollToFirstField(object){if("function"===typeof object.get)object=object.get(0);const field=object.querySelector(".frm_blank_field");if(field)frmFrontForm.scrollMsg(jQuery(field),object,true)}function showSubmitLoading($object){showLoadingIndicator($object);disableSubmitButton($object);disableSaveDraft($object)}function showLoadingIndicator($object){if(!$object.hasClass("frm_loading_form")&&!$object.hasClass("frm_loading_prev")){addLoadingClass($object); +$object.trigger("frmStartFormLoading")}}function addLoadingClass($object){const loadingClass=isGoingToPrevPage($object)?"frm_loading_prev":"frm_loading_form";$object.addClass(loadingClass)}function isGoingToPrevPage($object){return typeof frmProForm!=="undefined"&&frmProForm.goingToPreviousPage($object)}function removeSubmitLoading(_,enable,processesRunning){let loadingForm;if(processesRunning>0)return;loadingForm=jQuery(".frm_loading_form");loadingForm.removeClass("frm_loading_form");loadingForm.removeClass("frm_loading_prev"); +loadingForm.trigger("frmEndFormLoading");if(enable==="enable"){enableSubmitButton(loadingForm);enableSaveDraft(loadingForm)}}function showFileLoading(object){let fileval,loading=document.getElementById("frm_loading");if(loading!==null){fileval=jQuery(object).find("input[type=file]").val();if(typeof fileval!=="undefined"&&fileval!=="")setTimeout(function(){jQuery(loading).fadeIn("slow")},2E3)}}function confirmClick(){const message=jQuery(this).data("frmconfirm");return confirm(message)}function onHoneypotFieldChange(){const css= +jQuery(this).css("box-shadow");if(css.match(/inset/))this.parentNode.removeChild(this)}function maybeMakeHoneypotFieldsUntabbable(){document.addEventListener("keydown",handleKeyUp);function handleKeyUp(event){if("Tab"===event.key){makeHoneypotFieldsUntabbable();document.removeEventListener("keydown",handleKeyUp)}}function makeHoneypotFieldsUntabbable(){document.querySelectorAll(".frm_verify").forEach(function(input){if(input.id&&0===input.id.indexOf("frm_email_"))input.setAttribute("tabindex",-1)})} +}function changeFocusWhenClickComboFieldLabel(){let label;const comboInputsContainer=document.querySelectorAll(".frm_combo_inputs_container");comboInputsContainer.forEach(function(inputsContainer){if(!inputsContainer.closest(".frm_form_field"))return;label=inputsContainer.closest(".frm_form_field").querySelector(".frm_primary_label");if(!label)return;label.addEventListener("click",function(){inputsContainer.querySelector(".frm_form_field:first-child input, .frm_form_field:first-child select, .frm_form_field:first-child textarea").focus()})})} +function maybeFocusOnComboSubField(element){if("FIELDSET"!==element.nodeName)return false;if(!element.querySelector(".frm_combo_inputs_container"))return false;const comboSubfield=element.querySelector('[aria-invalid="true"]');if(comboSubfield){focusInput(comboSubfield);return true}return false}function checkForErrorsAndMaybeSetFocus(){let errors,element,timeoutCallback;if(!frm_js.focus_first_error)return;errors=document.querySelectorAll(".frm_form_field .frm_error");if(!errors.length)return;element= +errors[0];do{element=element.previousSibling;if(-1!==["input","select","textarea"].indexOf(element.nodeName.toLowerCase())){focusInput(element);break}if(maybeFocusOnComboSubField(element))break;if("undefined"!==typeof element.classList){if(element.classList.contains("html-active"))timeoutCallback=function(){const textarea=element.querySelector("textarea");if(null!==textarea)textarea.focus()};else if(element.classList.contains("tmce-active"))timeoutCallback=function(){tinyMCE.activeEditor.focus()}; +if("function"===typeof timeoutCallback){setTimeout(timeoutCallback,0);break}}}while(element.previousSibling)}function focusInput(input){if(input.offsetParent!==null)input.focus();else triggerCustomEvent(document,"frmMaybeDelayFocus",{input})}function documentOn(event,selector,handler,options){if("undefined"===typeof options)options=false;document.addEventListener(event,function(e){let target;for(target=e.target;target&&target!=this;target=target.parentNode)if(target&&target.matches&&target.matches(selector)){handler.call(target, +e);break}},options)}function initFloatingLabels(){let checkFloatLabel,checkDropdownLabel,runOnLoad,selector,floatClass;selector=".frm-show-form .frm_inside_container input, .frm-show-form .frm_inside_container select, .frm-show-form .frm_inside_container textarea";floatClass="frm_label_float_top";checkFloatLabel=function(input){let container,shouldFloatTop,firstOpt;container=input.closest(".frm_inside_container");if(!container)return;shouldFloatTop=input.value||document.activeElement===input;container.classList.toggle(floatClass, +shouldFloatTop);if("SELECT"===input.tagName){firstOpt=input.querySelector("option:first-child");if(shouldFloatTop){if(firstOpt.hasAttribute("data-label")){firstOpt.textContent=firstOpt.getAttribute("data-label");firstOpt.removeAttribute("data-label")}}else if(firstOpt.textContent){firstOpt.setAttribute("data-label",firstOpt.textContent);firstOpt.textContent=""}}};checkDropdownLabel=function(){document.querySelectorAll(".frm-show-form .frm_inside_container:not(."+floatClass+") select").forEach(function(input){const firstOpt= +input.querySelector("option:first-child");if(firstOpt.textContent){firstOpt.setAttribute("data-label",firstOpt.textContent);firstOpt.textContent=""}})};["focus","blur","change"].forEach(function(eventName){documentOn(eventName,selector,function(event){checkFloatLabel(event.target)},true)});jQuery(document).on("change",selector,function(event){checkFloatLabel(event.target)});runOnLoad=function(firstLoad){if(firstLoad&&document.activeElement&&-1!==["INPUT","SELECT","TEXTAREA"].indexOf(document.activeElement.tagName))checkFloatLabel(document.activeElement); else if(firstLoad)document.querySelectorAll(".frm_inside_container").forEach(function(container){const input=container.querySelector("input, select, textarea");if(input&&""!==input.value)checkFloatLabel(input)});checkDropdownLabel()};runOnLoad(true);jQuery(document).on("frmPageChanged",function(event){runOnLoad()});document.addEventListener("frm_after_start_over",function(event){runOnLoad()})}function shouldUpdateValidityMessage(target){if("INPUT"!==target.nodeName)return false;if(!target.dataset.invmsg)return false; if("text"!==target.getAttribute("type"))return false;if(target.classList.contains("frm_verify"))return false;return true}function maybeClearCustomValidityMessage(event,field){let key,isInvalid=false;if(!shouldUpdateValidityMessage(field))return;for(key in field.validity){if("customError"===key)continue;if("valid"!==key&&field.validity[key]===true){isInvalid=true;break}}if(!isInvalid)field.setCustomValidity("")}function maybeShowNewTabFallbackMessage(){let messageEl;if(!window.frmShowNewTabFallback)return; messageEl=document.querySelector("#frm_form_"+frmShowNewTabFallback.formId+"_container .frm_message");if(!messageEl)return;messageEl.insertAdjacentHTML("beforeend"," "+frmShowNewTabFallback.message)}function setCustomValidityMessage(){let forms,length,index;forms=document.getElementsByClassName("frm-show-form");length=forms.length;for(index=0;index