diff --git a/core/modules/field/field.form.inc b/core/modules/field/field.form.inc index c7c2e05..84b80c1 100644 --- a/core/modules/field/field.form.inc +++ b/core/modules/field/field.form.inc @@ -9,44 +9,54 @@ use Drupal\Core\Field\FieldDefinitionInterface; /** - * Returns HTML for an individual form element. + * Prepares variables for individual form element templates. + * + * Default template: field-multiple-value-form.html.twig. * * Combines multiple values into a table with drag-n-drop reordering. * - * @param $variables + * @param array $variables * An associative array containing: * - element: A render element representing the form element. - * - * @ingroup themeable - * - * @todo Convert to a template. */ -function theme_field_multiple_value_form($variables) { +function template_preprocess_field_multiple_value_form(&$variables) { $element = $variables['element']; - $output = ''; + $variables['multiple'] = $element['#cardinality_multiple']; + + if ($variables['multiple']) { - if ($element['#cardinality_multiple']) { - $form_required_marker = array('#theme' => 'form_required_marker'); - $required = !empty($element['#required']) ? drupal_render($form_required_marker) : ''; $table_id = drupal_html_id($element['#field_name'] . '_values'); $order_class = $element['#field_name'] . '-delta-order'; $header = array( array( - 'data' => '

' . t('!title !required', array('!title' => $element['#title'], '!required' => $required)) . "

", + 'data' => array( + '#prefix' => '

', + 'title' => array( + '#markup' => $element['#title'], + ), + '#suffix' => '

', + ), 'colspan' => 2, 'class' => array('field-label'), ), t('Order', array(), array('context' => 'Sort order')), ); + if (!empty($element['#required'])) { + $header[0]['data']['required'] = array( + '#theme' => 'form_required_marker', + '#element' => $element, + ); + } $rows = array(); // Sort items according to '_weight' (needed when the form comes back after - // preview or failed validation) + // preview or failed validation). $items = array(); + $variables['button'] = array(); foreach (element_children($element) as $key) { if ($key === 'add_more') { - $add_more_button = &$element[$key]; + $variables['button'] = &$element[$key]; } else { $items[] = &$element[$key]; @@ -57,10 +67,15 @@ function theme_field_multiple_value_form($variables) { // Add the items as table rows. foreach ($items as $item) { $item['_weight']['#attributes']['class'] = array($order_class); - $delta_element = drupal_render($item['_weight']); + + // Remove weight form element from item render array so it can be rendered + // in a separate table column. + $delta_element = $item['_weight']; + unset($item['_weight']); + $cells = array( array('data' => '', 'class' => array('field-multiple-drag')), - drupal_render($item), + array('data' => $item), array('data' => $delta_element, 'class' => array('delta-order')), ); $rows[] = array( @@ -69,8 +84,8 @@ function theme_field_multiple_value_form($variables) { ); } - $table = array( - '#type' => 'table', + $variables['table'] = array( + '#theme' => 'table', '#header' => $header, '#rows' => $rows, '#attributes' => array( @@ -85,19 +100,15 @@ function theme_field_multiple_value_form($variables) { ), ), ); - $output = '
'; - $output .= drupal_render($table); - $output .= $element['#description'] ? '
' . $element['#description'] . '
' : ''; - $output .= '
' . drupal_render($add_more_button) . '
'; - $output .= '
'; + + $variables['description'] = $element['#description'] ? $element['#description'] : ''; } else { + $variables['elements'] = array(); foreach (element_children($element) as $key) { - $output .= drupal_render($element[$key]); + $variables['elements'][] = $element[$key]; } } - - return $output; } /** diff --git a/core/modules/field/field.module b/core/modules/field/field.module index 408d816..c127d92 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -7,6 +7,7 @@ use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Template\Attribute; +use Drupal\Component\Utility\String; /* * Load all public Field API functions. Drupal currently has no @@ -127,9 +128,12 @@ function field_theme() { return array( 'field' => array( 'render element' => 'element', + 'template' => 'field', ), 'field_multiple_value_form' => array( + 'file' => 'field.form.inc', 'render element' => 'element', + 'template' => 'field-multiple-value-form', ), ); } @@ -534,14 +538,11 @@ function field_theme_suggestions_field(array $variables) { function template_preprocess_field(&$variables, $hook) { $element = $variables['element']; - // There's some overhead in calling check_plain() so only call it if the label - // variable is being displayed. Otherwise, set it to NULL to avoid PHP - // warnings if a theme implementation accesses the variable even when it's - // supposed to be hidden. If a theme implementation needs to print a hidden - // label, it needs to supply a preprocess function that sets it to the - // sanitized element title or whatever else is wanted in its place. $variables['label_hidden'] = ($element['#label_display'] == 'hidden'); - $variables['label'] = check_plain($element['#title']); + // Always set the field label - allow themes to decide whether to display + // In addition the label should be rendered but hidden to support screen + // readers + $variables['label'] = String::checkPlain($element['#title']); // We want other preprocess functions and the theme implementation to have // fast access to the field item render arrays. The item render array keys @@ -596,7 +597,7 @@ function template_preprocess_field(&$variables, $hook) { // element in order have them rendered on the desired HTML element (e.g., on // the element of a field item being rendered as a link). Other field // formatters leave them within $element['#items'][$delta]['_attributes'] to - // be rendered on the item wrappers provided by theme_field(). + // be rendered on the item wrappers provided by field.html.twig. foreach ($variables['items'] as $delta => $item) { $variables['item_attributes'][$delta] = !empty($element['#items'][$delta]['_attributes']) ? new Attribute($element['#items'][$delta]['_attributes']) : clone($default_attributes); } @@ -607,87 +608,6 @@ function template_preprocess_field(&$variables, $hook) { */ /** - * Returns HTML for a field. - * - * This is the default theme implementation to display the value of a field. - * Theme developers who are comfortable with overriding theme functions may do - * so in order to customize this markup. This function can be overridden with - * varying levels of specificity. For example, for a field named 'body' - * displayed on the 'article' content type, any of the following functions will - * override this default implementation. The first of these functions that - * exists is used: - * - THEMENAME_field__body__article() - * - THEMENAME_field__article() - * - THEMENAME_field__body() - * - THEMENAME_field() - * - * Theme developers who prefer to customize templates instead of overriding - * functions may copy the "field.html.twig" from the "modules/field/theme" - * folder of the Drupal installation to somewhere within the theme's folder and - * customize it, just like customizing other Drupal templates such as - * page.html.twig or node.html.twig. However, it takes longer for the server to - * process templates than to call a function, so for websites with many fields - * displayed on a page, this can result in a noticeable slowdown of the website. - * For these websites, developers are discouraged from placing a field.html.twig - * file into the theme's folder, but may customize templates for specific - * fields. For example, for a field named 'body' displayed on the 'article' - * content type, any of the following templates will override this default - * implementation. The first of these templates that exists is used: - * - field--body--article.html.twig - * - field--article.html.twig - * - field--body.html.twig - * - field.html.twig - * So, if the body field on the article content type needs customization, a - * field--body--article.html.twig file can be added within the theme's folder. - * Because it's a template, it will result in slightly more time needed to - * display that field, but it will not impact other fields, and therefore, is - * unlikely to cause a noticeable change in website performance. A very rough - * guideline is that if a page is being displayed with more than 100 fields and - * they are all themed with a template instead of a function, it can add up to - * 5% to the time it takes to display that page. This is a guideline only and - * the exact performance impact depends on the server configuration and the - * details of the website. - * - * @param array $variables - * An associative array containing: - * - label_hidden: A boolean indicating whether to show or hide the field - * label. - * - title_attributes: A string containing the attributes for the title. - * - label: The label for the field. - * - content_attributes: A string containing the attributes for the content's - * div. - * - items: An array of field items. - * - item_attributes: An array of attributes for each item. - * - classes: A string containing the classes for the wrapping div. - * - attributes: A string containing the attributes for the wrapping div. - * - * @see template_preprocess_field() - * @see field.html.twig - * - * @ingroup themeable - */ -function theme_field($variables) { - $output = ''; - - // Render the label, if it's not hidden. - if (!$variables['label_hidden']) { - $output .= '
' . $variables['label'] . '
'; - } - - // Render the items. - $output .= '
'; - foreach ($variables['items'] as $delta => $item) { - $output .= '
' . drupal_render($item) . '
'; - } - $output .= '
'; - - // Render the top-level DIV. - $output = '' . $output . ''; - - return $output; -} - -/** * Assembles a partial entity structure with initial IDs. * * @param object $ids diff --git a/core/modules/field/templates/field-multiple-value-form.html.twig b/core/modules/field/templates/field-multiple-value-form.html.twig new file mode 100644 index 0000000..02d046e --- /dev/null +++ b/core/modules/field/templates/field-multiple-value-form.html.twig @@ -0,0 +1,38 @@ +{# +/** + * @file + * Default theme implementation for an individual form element. + * + * Available variables for all fields: + * - multiple: Whether there are multiple instances of the field. + * + * Available variables for single cardinality fields: + * - elements: Form elements to be rendered. + * + * Available variables when there are multiple fields. + * - table: Table of field items. + * - description: Description text for the form element. + * - button: "Add another item" button. + * + * @see template_preprocess_field_multiple_value_form() + * + * @ingroup themeable + */ +#} +{% if multiple %} +
+ {{ table }} + {% spaceless %} + {% if description %} +
{{ description }}
+ {% endif %} + {% if button %} +
{{ button }}
+ {% endif %} + {% endspaceless %} +
+{% else %} + {% for element in elements %} + {{ element }} + {% endfor %} +{% endif %} diff --git a/core/modules/field/templates/field.html.twig b/core/modules/field/templates/field.html.twig index d5873f4..a0d527a 100644 --- a/core/modules/field/templates/field.html.twig +++ b/core/modules/field/templates/field.html.twig @@ -25,17 +25,10 @@ * - item_attributes: List of HTML attributes for each item. * * @see template_preprocess_field() - * @see theme_field() * * @ingroup themeable */ #} - {% if not label_hidden %}
{{ label }}: 
diff --git a/core/themes/bartik/bartik.theme b/core/themes/bartik/bartik.theme index ab4683c..1539f76 100644 --- a/core/themes/bartik/bartik.theme +++ b/core/themes/bartik/bartik.theme @@ -6,6 +6,7 @@ */ use Drupal\Core\Template\RenderWrapper; +use Drupal\Core\Template\Attribute; /** * Implements hook_preprocess_HOOK() for page templates. @@ -175,25 +176,20 @@ function bartik_menu_tree__shortcut_default($variables) { } /** - * Implements theme_field__field_type(). + * Implements theme_preprocess_HOOK() for field templates. + * + * @see template_preprocess_field() + * + * @todo Use bartik_theme_prepare_field__taxonomy_term_reference when + * https://drupal.org/node/2035055 is resolved */ -function bartik_field__taxonomy_term_reference($variables) { - $output = ''; - - // Render the label either as a visible list or make it visually hidden for accessibility. - $hidden_class = empty($variables['label_hidden']) ? '' : ' visually-hidden'; - $output .= '

' . $variables['label'] . ':

'; - - // Render the items. - $output .= ($variables['element']['#label_display'] == 'inline') ? '