diff --git a/classes/controllers/FrmFieldsController.php b/classes/controllers/FrmFieldsController.php index 1af403abaf..1f4feaa1df 100644 --- a/classes/controllers/FrmFieldsController.php +++ b/classes/controllers/FrmFieldsController.php @@ -910,6 +910,16 @@ private static function add_shortcodes_to_html( $field, array &$add_html ) { } foreach ( $field['shortcodes'] as $k => $v ) { + if ( isset( $field['subfield_name'] ) && 0 === strpos( $k, 'aria-invalid' ) ) { + $subfield_name = $field['subfield_name']; + if ( ! isset( $field['shortcodes'][ 'aria-invalid-' . $subfield_name ] ) ) { + continue; + } + // Change the key to the correct aria-invalid value so that $add_html is set correctly for the current subfield of a combo field. + $k = 'aria-invalid'; + $v = $field['shortcodes'][ 'aria-invalid-' . $subfield_name ]; + unset( $field['shortcodes'][ 'aria-invalid-' . $subfield_name ] ); + } if ( 'opt' === $k || ! self::should_allow_input_attribute( $k ) ) { continue; } @@ -923,7 +933,7 @@ private static function add_shortcodes_to_html( $field, array &$add_html ) { } unset( $k, $v ); - } + }//end foreach } /** diff --git a/classes/models/FrmFieldFormHtml.php b/classes/models/FrmFieldFormHtml.php index 7165c3fe37..98634b3431 100644 --- a/classes/models/FrmFieldFormHtml.php +++ b/classes/models/FrmFieldFormHtml.php @@ -394,7 +394,7 @@ private function prepare_input_shortcode_atts( $shortcode_atts ) { unset( $shortcode_atts['class'] ); } - $shortcode_atts['aria-invalid'] = isset( $this->pass_args['errors'][ 'field' . $this->field_id ] ) ? 'true' : 'false'; + $this->field_obj->set_aria_invalid_error( $shortcode_atts, $this->pass_args ); $this->field_obj->set_field_column( 'shortcodes', $shortcode_atts ); diff --git a/classes/models/fields/FrmFieldCombo.php b/classes/models/fields/FrmFieldCombo.php index 966d994f80..a68c720c62 100644 --- a/classes/models/fields/FrmFieldCombo.php +++ b/classes/models/fields/FrmFieldCombo.php @@ -77,6 +77,22 @@ protected function register_sub_fields( array $sub_fields ) { }//end foreach } + /** + * Set the aria-invalid attribute for subfields. + * + * @since x.x + * + * @param array $shortcode_atts + * @param array $args + * + * @return void + */ + public function set_aria_invalid_error( &$shortcode_atts, $args ) { + foreach ( $this->get_sub_fields() as $sub_field ) { + $shortcode_atts[ 'aria-invalid-' . $sub_field['name'] ] = isset( $args['errors'][ 'field' . $this->field_id . '-' . $sub_field['name'] ] ) ? 'true' : 'false'; + } + } + /** * Gets default sub field. * @@ -381,6 +397,9 @@ protected function print_input_atts( $args ) { // Fake it to avoid printing frm-val attribute. $field['default_value'] = ''; + if ( ! empty( $sub_field['name'] ) ) { + $field['subfield_name'] = $sub_field['name']; + } do_action( 'frm_field_input_html', $field ); // Print custom attributes. diff --git a/classes/models/fields/FrmFieldType.php b/classes/models/fields/FrmFieldType.php index 7fb7dc2b52..c958d0e8df 100644 --- a/classes/models/fields/FrmFieldType.php +++ b/classes/models/fields/FrmFieldType.php @@ -995,6 +995,20 @@ protected function get_input_class() { return ''; } + /** + * Set the aria-invalid attribute for field. + * + * @since x.x + * + * @param array $shortcode_atts + * @param array $args + * + * @return void + */ + public function set_aria_invalid_error( &$shortcode_atts, $args ) { + $shortcode_atts['aria-invalid'] = isset( $args['errors'][ 'field' . $this->field_id ] ) ? 'true' : 'false'; + } + /** * @param array $args * @param array $shortcode_atts diff --git a/css/_single_theme.css.php b/css/_single_theme.css.php index d83bcc7086..0f303dc212 100644 --- a/css/_single_theme.css.php +++ b/css/_single_theme.css.php @@ -166,7 +166,7 @@ . .form-field input:not([type=file]):not([type=range]):not([readonly]):focus, . select:focus, -. textarea:focus, +. .form-field textarea:focus, . .frm_focus_field input[type=text], . .frm_focus_field input[type=password], . .frm_focus_field input[type=email], diff --git a/js/formidable.js b/js/formidable.js index fffcda4ef5..45e408580d 100644 --- a/js/formidable.js +++ b/js/formidable.js @@ -1319,6 +1319,29 @@ function frmFrontFormJS() { }); } + /** + * Sets focus on a the first subfield of a combo field that has an error. + * + * @since x.x + * + * @param {HTMLElement} element + * @return {boolean} True if the focus was set on a combo field. + */ + 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; @@ -1339,6 +1362,10 @@ function frmFrontFormJS() { break; } + if ( maybeFocusOnComboSubField( element ) ) { + break; + } + if ( 'undefined' !== typeof element.classList ) { if ( element.classList.contains( 'html-active' ) ) { timeoutCallback = function() {