diff --git a/core/includes/form.inc b/core/includes/form.inc
index 5d4a943..daa17a6 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -2687,6 +2687,9 @@ function form_process_file($element) {
/**
* Returns HTML for a form element.
+ * Prepares variables for form element templates.
+ *
+ * Default template: form-element.html.twig.
*
* Each form element is wrapped in a DIV container having the following CSS
* classes:
@@ -2723,7 +2726,7 @@ function form_process_file($element) {
* but the parent element should have neither. Use this carefully because a
* field without an associated label can cause accessibility challenges.
*
- * @param $variables
+ * @param array $variables
* An associative array containing:
* - element: An associative array containing the properties of the element.
* Properties used: #title, #title_display, #description, #id, #required,
@@ -2731,7 +2734,7 @@ function form_process_file($element) {
*
* @ingroup themeable
*/
-function theme_form_element($variables) {
+function template_preprocess_form_element(&$variables) {
$element = &$variables['element'];
// This function is invoked as theme wrapper, but the rendered form element
@@ -2743,64 +2746,57 @@ function theme_form_element($variables) {
// Take over any #wrapper_attributes defined by the element.
// @todo Temporary hack for #type 'item'.
// @see http://drupal.org/node/1829202
+ $variables['attributes'] = array();
if (isset($element['#wrapper_attributes'])) {
- $attributes = $element['#wrapper_attributes'];
+ $variables['attributes'] = $element['#wrapper_attributes'];
}
+
// Add element #id for #type 'item'.
if (isset($element['#markup']) && !empty($element['#id'])) {
- $attributes['id'] = $element['#id'];
+ $variables['attributes']['id'] = $element['#id'];
}
+
// Add element's #type and #name as class to aid with JS/CSS selectors.
- $attributes['class'][] = 'form-item';
+ $variables['attributes']['class'][] = 'form-item';
if (!empty($element['#type'])) {
- $attributes['class'][] = 'form-type-' . strtr($element['#type'], '_', '-');
+ $variables['attributes']['class'][] = 'form-type-' . strtr($element['#type'], '_', '-');
}
if (!empty($element['#name'])) {
- $attributes['class'][] = 'form-item-' . strtr($element['#name'], array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
+ $variables['attributes']['class'][] = 'form-item-' . strtr($element['#name'], array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
}
// Add a class for disabled elements to facilitate cross-browser styling.
if (!empty($element['#attributes']['disabled'])) {
- $attributes['class'][] = 'form-disabled';
+ $variables['attributes']['class'][] = 'form-disabled';
}
- $output = '
' . "\n";
// If #title is not set, we don't display any label or required marker.
if (!isset($element['#title'])) {
$element['#title_display'] = 'none';
}
- $prefix = isset($element['#field_prefix']) ? '
' . $element['#field_prefix'] . ' ' : '';
- $suffix = isset($element['#field_suffix']) ? '
' . $element['#field_suffix'] . '' : '';
-
- switch ($element['#title_display']) {
- case 'before':
- case 'invisible':
- $output .= ' ' . theme('form_element_label', $variables);
- $output .= ' ' . $prefix . $element['#children'] . $suffix . "\n";
- break;
-
- case 'after':
- $output .= ' ' . $prefix . $element['#children'] . $suffix;
- $output .= ' ' . theme('form_element_label', $variables) . "\n";
- break;
-
- case 'none':
- case 'attribute':
- // Output no label and no required marker, only the children.
- $output .= ' ' . $prefix . $element['#children'] . $suffix . "\n";
- break;
- }
+ $variables['prefix'] = isset($element['#field_prefix']) ? $element['#field_prefix'] : NULL;
+ $variables['suffix'] = isset($element['#field_suffix']) ? $element['#field_suffix'] : NULL;
+ $variables['description'] = NULL;
if (!empty($element['#description'])) {
- $attributes = array('class' => 'description');
+ $description_attributes = array('class' => 'description');
if (!empty($element['#id'])) {
- $attributes['id'] = $element['#id'] . '--description';
+ $description_attributes['id'] = $element['#id'] . '--description';
}
- $output .= '
' . $element['#description'] . "
\n";
+ $variables['description']['attributes'] = new Attribute($description_attributes);
+ $variables['description']['content'] = $element['#description'];
}
- $output .= "
\n";
+ // Add label_display and label variables to template.
+ $variables['label_display'] = $element['#title_display'];
+ $variables['label'] = array(
+ '#theme' => 'form_element_label',
+ '#required' => isset($element['#required']) ? $element['#required'] : '',
+ '#title' => isset($element['#title']) ? $element['#title'] : '',
+ '#title_display' => isset($element['#title_display']) ? $element['#title_display'] : '',
+ '#id' => isset($element['#id']) ? $element['#id'] : '',
+ );
- return $output;
+ $variables['children'] = $element['#children'];
}
/**
@@ -2845,7 +2841,6 @@ function theme_form_required_marker($variables) {
*/
function theme_form_element_label($variables) {
$element = $variables['element'];
-
// If title and required marker are both empty, output no label.
if ((!isset($element['#title']) || $element['#title'] === '') && empty($element['#required'])) {
return '';
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 96a0466..e464081 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -2732,6 +2732,7 @@ function drupal_common_theme() {
),
'form_element' => array(
'render element' => 'element',
+ 'template' => 'form-element',
),
'form_required_marker' => array(
'render element' => 'element',
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 6c83611..17a9ef5 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -233,7 +233,7 @@ function hook_queue_info_alter(&$queues) {
* - "#post_render": array of callables taking $children and $element.
* - "#submit": array of callback functions taking $form and $form_state.
* - "#title_display": optional string indicating if and how #title should be
- * displayed, see theme_form_element() and theme_form_element_label().
+ * displayed, see the form-element template and theme_form_element_label().
*
* @see hook_element_info_alter()
* @see system_element_info()
diff --git a/core/modules/system/templates/form-element.html.twig b/core/modules/system/templates/form-element.html.twig
new file mode 100644
index 0000000..ea4d90f
--- /dev/null
+++ b/core/modules/system/templates/form-element.html.twig
@@ -0,0 +1,58 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a form element.
+ *
+ * Available variables:
+ * - attributes: HTML attributes for the containing element.
+ * - prefix: (optional) The form element prefix, may not be set.
+ * - suffix: (optional) The form element suffix, may not be set.
+ * - required: The required marker, or empty if the associated form element is
+ * not required.
+ * - label: A rendered label element.
+ * - label_display: Label display setting. It can have these values:
+ * - before: The label is output before the element. This is the default.
+ * The label includes the #title and the required marker, if #required.
+ * - after: The label is output after the element. For example, this is used
+ * for radio and checkbox #type elements as set in system_element_info().
+ * If the #title is empty but the field is #required, the label will
+ * contain only the required marker.
+ * - invisible: Labels are critical for screen readers to enable them to
+ * properly navigate through forms but can be visually distracting. This
+ * 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 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.
+ * - description: (optional) A list of description properties containing:
+ * - content: A description of the form element, may not be set.
+ * - attributes: (optional) A list of HTML attributes to apply to the
+ * description content wrapper. Will only be set when description is set.
+ *
+ * @see template_preprocess_form_element()
+ *
+ * @ingroup themeable
+ */
+#}
+
+ {% if label_display in ['before', 'invisible'] %}
+ {{ label }}
+ {% endif %}
+ {% if prefix is not empty %}
+
{{ prefix }}
+ {% endif %}
+ {{ children }}
+ {% if suffix is not empty %}
+
{{ suffix }}
+ {% endif %}
+ {% if label_display == 'after' %}
+ {{ label }}
+ {% endif %}
+ {% if description.content %}
+
+ {{ description.content }}
+
+ {% endif %}
+