Issue #2152217 by joelpittet, mgifford, vijaycs85, jjcarrion, sun: Remove theme_form_required_marker() from the theme system - use CSS instead.

8.0.x
Nathaniel Catchpole 2014-05-08 14:40:44 +01:00
parent 240056969a
commit 82aaa8af0a
11 changed files with 45 additions and 81 deletions

View File

@ -1068,31 +1068,20 @@ function template_preprocess_fieldset(&$variables) {
_form_set_attributes($element, array('form-wrapper')); _form_set_attributes($element, array('form-wrapper'));
$variables['attributes'] = $element['#attributes']; $variables['attributes'] = $element['#attributes'];
$variables['attributes']['class'][] = 'form-item'; $variables['attributes']['class'][] = 'form-item';
// If the element is required, a required marker is appended to the label.
$variables['required'] = '';
if (!empty($element['#required'])) {
$variables['required'] = array(
'#theme' => 'form_required_marker',
'#element' => $element,
);
}
$variables['prefix'] = isset($element['#field_prefix']) ? $element['#field_prefix'] : NULL; $variables['prefix'] = isset($element['#field_prefix']) ? $element['#field_prefix'] : NULL;
$variables['suffix'] = isset($element['#field_suffix']) ? $element['#field_suffix'] : NULL; $variables['suffix'] = isset($element['#field_suffix']) ? $element['#field_suffix'] : NULL;
$variables['children'] = $element['#children']; $variables['children'] = $element['#children'];
// Build legend properties.
$variables['legend'] = array();
$legend_attributes = array(); $legend_attributes = array();
if (isset($element['#title_display']) && $element['#title_display'] == 'invisible') { if (isset($element['#title_display']) && $element['#title_display'] == 'invisible') {
$legend_attributes['class'][] = 'visually-hidden'; $legend_attributes['class'][] = 'visually-hidden';
} }
$variables['legend']['attributes'] = new Attribute($legend_attributes); $variables['legend']['attributes'] = new Attribute($legend_attributes);
$variables['legend']['title'] = (isset($element['#title']) && $element['#title'] !== '') ? Xss::filterAdmin($element['#title']) : ''; $variables['legend']['title'] = (isset($element['#title']) && $element['#title'] !== '') ? Xss::filterAdmin($element['#title']) : '';
$legend_span_attributes = array('class' => array('fieldset-legend'));
// Build description properties. if (!empty($element['#required'])) {
$variables['description'] = array(); $legend_span_attributes['class'][] = 'form-required';
$variables['legend_span']['attributes'] = new Attribute($legend_span_attributes);
}
if (!empty($element['#description'])) { if (!empty($element['#description'])) {
$description_id = $element['#attributes']['id'] . '--description'; $description_id = $element['#attributes']['id'] . '--description';
$description_attributes = array( $description_attributes = array(
@ -2932,7 +2921,7 @@ function template_preprocess_form_element(&$variables) {
$variables['attributes']['class'][] = 'form-disabled'; $variables['attributes']['class'][] = 'form-disabled';
} }
// If #title is not set, we don't display any label or required marker. // If #title is not set, we don't display any label.
if (!isset($element['#title'])) { if (!isset($element['#title'])) {
$element['#title_display'] = 'none'; $element['#title_display'] = 'none';
} }
@ -2957,23 +2946,6 @@ function template_preprocess_form_element(&$variables) {
$variables['children'] = $element['#children']; $variables['children'] = $element['#children'];
} }
/**
* Returns HTML for a marker for required form elements.
*
* @param $variables
* An associative array containing:
* - element: An associative array containing the properties of the element.
*
* @ingroup themeable
*/
function theme_form_required_marker($variables) {
$attributes = array(
'class' => 'form-required',
'aria-hidden' => 'true',
);
return '<span' . new Attribute($attributes) . '>*</span>';
}
/** /**
* Returns HTML for a form element label and required marker. * Returns HTML for a form element label and required marker.
* *
@ -3004,26 +2976,16 @@ function theme_form_element_label($variables) {
return ''; return '';
} }
// If the element is required, a required marker is appended to the label.
$required = '';
if (!empty($element['#required'])) {
$marker = array(
'#theme' => 'form_required_marker',
'#element' => $element,
);
$required = drupal_render($marker);
}
$title = Xss::filterAdmin($element['#title']); $title = Xss::filterAdmin($element['#title']);
$attributes = array(); $attributes = array();
// Style the label as class option to display inline with the element. // Style the label as class option to display inline with the element.
if ($element['#title_display'] == 'after') { if ($element['#title_display'] == 'after') {
$attributes['class'] = 'option'; $attributes['class'][] = 'option';
} }
// Show label only to screen readers to avoid disruption in visual flows. // Show label only to screen readers to avoid disruption in visual flows.
elseif ($element['#title_display'] == 'invisible') { elseif ($element['#title_display'] == 'invisible') {
$attributes['class'] = 'visually-hidden'; $attributes['class'][] = 'visually-hidden';
} }
// A #for property of a dedicated #type 'label' element as precedence. // A #for property of a dedicated #type 'label' element as precedence.
@ -3040,7 +3002,13 @@ function theme_form_element_label($variables) {
$attributes['for'] = $element['#id']; $attributes['for'] = $element['#id'];
} }
return '<label' . new Attribute($attributes) . '>' . t('!title!required', array('!title' => $title, '!required' => $required)) . '</label>'; // For required elements a 'form-required' class is appended to the
// label attributes.
if (!empty($element['#required'])) {
$attributes['class'][] = 'form-required';
}
return '<label' . new Attribute($attributes) . '>' . $title . '</label>';
} }
/** /**

View File

@ -2662,9 +2662,6 @@ function drupal_common_theme() {
'render element' => 'element', 'render element' => 'element',
'template' => 'form-element', 'template' => 'form-element',
), ),
'form_required_marker' => array(
'render element' => 'element',
),
'form_element_label' => array( 'form_element_label' => array(
'render element' => 'element', 'render element' => 'element',
), ),

View File

@ -522,12 +522,12 @@
if (e.value) { if (e.value) {
var $label = $(e.target).attr({ 'required': 'required', 'aria-required': 'aria-required' }).closest('.form-item, .form-wrapper').find('label'); var $label = $(e.target).attr({ 'required': 'required', 'aria-required': 'aria-required' }).closest('.form-item, .form-wrapper').find('label');
// Avoids duplicate required markers on initialization. // Avoids duplicate required markers on initialization.
if (!$label.find('.form-required').length) { if (!$label.hasClass('form-required').length) {
$label.append(Drupal.theme('requiredMarker')); $label.addClass('form-required');
} }
} }
else { else {
$(e.target).removeAttr('required aria-required').closest('.form-item, .form-wrapper').find('label .form-required').remove(); $(e.target).removeAttr('required aria-required').closest('.form-item, .form-wrapper').find('label.form-required').removeClass('form-required');
} }
} }
}); });
@ -573,10 +573,4 @@
return (a === b) ? (typeof a === 'undefined' ? a : true) : (typeof a === 'undefined' || typeof b === 'undefined'); return (a === b) ? (typeof a === 'undefined' ? a : true) : (typeof a === 'undefined' || typeof b === 'undefined');
} }
$.extend(Drupal.theme, {
requiredMarker: function () {
return '<abbr class="form-required" title="' + Drupal.t('This field is required.') + '">*</abbr>';
}
});
})(jQuery); })(jQuery);

View File

@ -226,13 +226,6 @@ function template_preprocess_datetime_form(&$variables) {
function template_preprocess_datetime_wrapper(&$variables) { function template_preprocess_datetime_wrapper(&$variables) {
$element = $variables['element']; $element = $variables['element'];
// If the element is required, a required marker is appended to the label.
$form_required_marker = array(
'#theme' => 'form_required_marker',
'#element' => $element,
);
$variables['required'] = !empty($element['#required']) ? drupal_render($form_required_marker) : '';
if (!empty($element['#title'])) { if (!empty($element['#title'])) {
$variables['title'] = $element['#title']; $variables['title'] = $element['#title'];
} }
@ -241,6 +234,13 @@ function template_preprocess_datetime_wrapper(&$variables) {
$variables['description'] = $element['#description']; $variables['description'] = $element['#description'];
} }
$title_attributes = array('class' => array('label'));
// For required datetime fields a 'form-required' class is appended to the
// label attributes.
if (!empty($element['#required'])) {
$title_attributes['class'][] = 'form-required';
}
$variables['title_attributes'] = new Attribute($title_attributes);
$variables['content'] = $element['#children']; $variables['content'] = $element['#children'];
} }

View File

@ -98,7 +98,7 @@ class DateTimeFieldTest extends WebTestBase {
// Display creation form. // Display creation form.
$this->drupalGet('entity_test/add'); $this->drupalGet('entity_test/add');
$this->assertFieldByName("{$field_name}[0][value][date]", '', 'Date element found.'); $this->assertFieldByName("{$field_name}[0][value][date]", '', 'Date element found.');
$this->assertFieldByXPath('//*[@id="edit-' . $field_name . '-wrapper"]/h4/span', '*', 'Required markup found'); $this->assertFieldByXPath('//*[@id="edit-' . $field_name . '-wrapper"]/h4[contains(@class, "form-required")]', TRUE, 'Required markup found');
$this->assertNoFieldByName("{$field_name}[0][value][time]", '', 'Time element not found.'); $this->assertNoFieldByName("{$field_name}[0][value][time]", '', 'Time element not found.');
// Submit a valid date and ensure it is accepted. // Submit a valid date and ensure it is accepted.

View File

@ -6,8 +6,7 @@
* Available variables: * Available variables:
* - content: The form element to be output, usually a datelist, or datetime. * - content: The form element to be output, usually a datelist, or datetime.
* - title: The title of the form element. * - title: The title of the form element.
* - attributes: HTML attributes for the form wrapper. * - title_attributes: HTML attributes for the title wrapper.
* - required: (optional) A marker indicating that the form element is required.
* - description: Description text for the form element. * - description: Description text for the form element.
* *
* @see template_preprocess_datetime_wrapper() * @see template_preprocess_datetime_wrapper()
@ -16,9 +15,7 @@
*/ */
#} #}
{% if title %} {% if title %}
<h4 class="label"> <h4{{ title_attributes }}>{{ title }}</h4>
{% trans %}{{ title|passthrough }}{{ required|passthrough }}{% endtrans %}
</h4>
{% endif %} {% endif %}
{{ content }} {{ content }}
{% if description %} {% if description %}

View File

@ -79,11 +79,20 @@ h4.label {
.form-type-checkbox .description { .form-type-checkbox .description {
margin-left: 2.4em; margin-left: 2.4em;
} }
.marker, .marker {
.form-required {
color: #e00; color: #e00;
} }
abbr.form-required, abbr.tabledrag-changed, abbr.ajax-changed {
.form-required:after {
color: #e00;
/* Use a Unicode symbol to prevent screen-readers from announcing the text. */
content: " \204E ";
line-height: 1;
vertical-align: super;
}
abbr.tabledrag-changed,
abbr.ajax-changed {
border-bottom: none; border-bottom: none;
} }
.form-item input.error, .form-item input.error,

View File

@ -59,10 +59,10 @@ class ElementsLabelsTest extends WebTestBase {
// Exercise various defaults for textboxes and modifications to ensure // Exercise various defaults for textboxes and modifications to ensure
// appropriate override and correct behavior. // appropriate override and correct behavior.
$elements = $this->xpath('//label[@for="edit-form-textfield-test-title-and-required"]/child::span[@class="form-required"]/parent::*/following-sibling::input[@id="edit-form-textfield-test-title-and-required"]'); $elements = $this->xpath('//label[@for="edit-form-textfield-test-title-and-required" and @class="form-required"]/following-sibling::input[@id="edit-form-textfield-test-title-and-required"]');
$this->assertTrue(isset($elements[0]), 'Label precedes textfield, with required marker inside label.'); $this->assertTrue(isset($elements[0]), 'Label precedes textfield, with required marker inside label.');
$elements = $this->xpath('//input[@id="edit-form-textfield-test-no-title-required"]/preceding-sibling::label[@for="edit-form-textfield-test-no-title-required"]/span[@class="form-required"]'); $elements = $this->xpath('//input[@id="edit-form-textfield-test-no-title-required"]/preceding-sibling::label[@for="edit-form-textfield-test-no-title-required" and @class="form-required"]');
$this->assertTrue(isset($elements[0]), 'Label tag with required marker precedes required textfield with no title.'); $this->assertTrue(isset($elements[0]), 'Label tag with required marker precedes required textfield with no title.');
$elements = $this->xpath('//input[@id="edit-form-textfield-test-title-invisible"]/preceding-sibling::label[@for="edit-form-textfield-test-title-invisible" and @class="visually-hidden"]'); $elements = $this->xpath('//input[@id="edit-form-textfield-test-title-invisible"]/preceding-sibling::label[@for="edit-form-textfield-test-title-invisible" and @class="visually-hidden"]');

View File

@ -97,8 +97,7 @@ class FormTest extends WebTestBase {
$elements['file']['empty_values'] = $empty_strings; $elements['file']['empty_values'] = $empty_strings;
// Regular expression to find the expected marker on required elements. // Regular expression to find the expected marker on required elements.
$required_marker_preg = '@<(?:label|legend).*<span class="form-required" aria-hidden="true">\*</span>.*</(?:label|legend)>@'; $required_marker_preg = '@<.*?class=".*?form-required.*?">@';
// Go through all the elements and all the empty values for them. // Go through all the elements and all the empty values for them.
foreach ($elements as $type => $data) { foreach ($elements as $type => $data) {
foreach ($data['empty_values'] as $key => $empty) { foreach ($data['empty_values'] as $key => $empty) {

View File

@ -25,7 +25,7 @@
<fieldset{{ attributes }}> <fieldset{{ attributes }}>
{% if legend.title is not empty or required -%} {% if legend.title is not empty or required -%}
{# Always wrap fieldset legends in a SPAN for CSS positioning. #} {# Always wrap fieldset legends in a SPAN for CSS positioning. #}
<legend{{ legend.attributes }}><span class="fieldset-legend">{{ legend.title }}{{ required }}</span></legend> <legend{{ legend.attributes }}><span class="{{ legend_span.attributes.class }}">{{ legend.title }}{{ required }}</span></legend>
{%- endif %} {%- endif %}
<div class="fieldset-wrapper"> <div class="fieldset-wrapper">
{% if prefix %} {% if prefix %}

View File

@ -440,7 +440,7 @@ h1.site-name {
background: #fff; background: #fff;
background: rgba(255, 255, 255, 0.8); background: rgba(255, 255, 255, 0.8);
} }
.region-header .form-required { .region-header .form-required:after {
color: #eee; color: #eee;
color: rgba(255, 255, 255, 0.7); color: rgba(255, 255, 255, 0.7);
} }