diff --git a/core/includes/form.inc b/core/includes/form.inc index ce5779c..4d70112 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -939,7 +939,7 @@ function form_get_options($element, $key) { * An associative array containing: * - element: An associative array containing the properties of the element. * Properties used: #attributes, #children, #collapsed, #description, #id, - * #title, #value. + * #title, #title_display, #value. * * @ingroup themeable */ @@ -954,27 +954,38 @@ function theme_fieldset($variables) { } $legend_attributes = array(); + $legend_attributes['class'][] = 'fieldset-legend'; if (isset($element['#title_display']) && $element['#title_display'] == 'invisible') { $legend_attributes['class'][] = 'visually-hidden'; } - $output = ''; + // Hide box for fieldset by default. + $element['#attributes']['class'][] = 'fieldset-no-border'; + + // Add a class for disabled elements to facilitate cross-browser styling. + if (!empty($element['#attributes']['disabled'])) { + $element['#attributes']['class'][] = 'form-disabled'; + } + $prefix = isset($element['#field_prefix']) ? '' . $element['#field_prefix'] . ' ' : ''; + $suffix = isset($element['#field_suffix']) ? ' ' . $element['#field_suffix'] . '' : ''; + + $output = '
'; + $output .= $prefix . ''; if (!empty($element['#title'])) { + $required = !empty($element['#required']) ? theme('form_required_marker', array('element' => $element)) : ''; + + $title = filter_xss_admin($element['#title']); // Always wrap fieldset legends in a SPAN for CSS positioning. - $output .= '' . $element['#title'] . ''; + $output .= '' . $title . '' . $required . ''; } - $output .= '
'; if (!empty($element['#description'])) { $attributes = array('class' => 'fieldset-description', 'id' => $description_id); $output .= '' . $element['#description'] . '
'; } $output .= $element['#children']; - if (isset($element['#value'])) { - $output .= $element['#value']; - } + $output .= "\n" . $suffix; $output .= '
'; - $output .= "\n"; return $output; } @@ -1241,11 +1252,15 @@ function theme_checkboxes($variables) { } /** - * Adds form element theming to an element if its title or description is set. + * Adds theming to composite form elements such as checkboxes and radios. * - * This is used as a pre render function for checkboxes and radios. + * If either the title or description is set for the composite element as a * whole, then this adds either a 'fieldset' or 'form_element' theme wrapper to + * render them. A fieldset is generally preferred to assist screen readers + * (http://webaim.org/techniques/forms/screen_reader#group), but is not used + * when #title_display is set to an option impossible to render as a fieldset + * legend. */ -function form_pre_render_conditional_form_element($element) { +function form_pre_render_composite_form_element($element) { // Set the element's title attribute to show #title as a tooltip, if needed. if (isset($element['#title']) && $element['#title_display'] == 'attribute') { $element['#attributes']['title'] = $element['#title']; @@ -1256,7 +1271,16 @@ function form_pre_render_conditional_form_element($element) { } if (isset($element['#title']) || isset($element['#description'])) { - $element['#theme_wrappers'][] = 'form_element'; + // To assist screen readers, use a fieldset wrapper when possible, but + // fieldset legends are only compatible with the 'before' and 'invisible' + // options for #title_display. + if (!isset($element['#title_display']) || in_array($element['#title_display'], array('before', 'invisible'))) { + $wrapper = 'fieldset'; + } + else { + $wrapper = 'form_element'; + } + $element['#theme_wrappers'][] = $wrapper; } return $element; } @@ -2713,7 +2737,7 @@ function form_process_file($element) { * property hides the label for everyone except screen readers. * - attribute: Set the title attribute on the element to create a tooltip * but output no label element. This is supported only for checkboxes - * and radios in form_pre_render_conditional_form_element(). It is used + * and radios in form_pre_render_composite_form_element(). It is used * where a visual label is not needed, such as a table of checkboxes where * the row and column provide the context. The tooltip will include the * title and required marker. diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/ElementsLabelsTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/ElementsLabelsTest.php index 6c51a04..02bc1d9 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Form/ElementsLabelsTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Form/ElementsLabelsTest.php @@ -78,10 +78,10 @@ function testFormLabels() { $this->assertFalse(isset($elements[0]), 'No label tag when title set not to display.'); // Check #field_prefix and #field_suffix placement. - $elements = $this->xpath('//span[@class="field-prefix"]/following-sibling::div[@id="edit-form-radios-test"]'); + $elements = $this->xpath('//span[@class="field-prefix"]/following-sibling::fieldset[@id="edit-form-radios-test"]'); $this->assertTrue(isset($elements[0]), 'Properly placed the #field_prefix element after the label and before the field.'); - $elements = $this->xpath('//span[@class="field-suffix"]/preceding-sibling::div[@id="edit-form-radios-test"]'); + $elements = $this->xpath('//span[@class="field-suffix"]/preceding-sibling::fieldset[@id="edit-form-radios-test"]'); $this->assertTrue(isset($elements[0]), 'Properly places the #field_suffix element immediately after the form field.'); // Check #prefix and #suffix placement. diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/FormTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/FormTest.php index 5424f66..172b2a1 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Form/FormTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Form/FormTest.php @@ -94,7 +94,7 @@ function testRequiredFields() { $elements['file']['empty_values'] = $empty_strings; // Regular expression to find the expected marker on required elements. - $required_marker_preg = '@