From 1c7cf179804a1a2f0e7fcae1dd97153ce95a4349 Mon Sep 17 00:00:00 2001 From: Alex Pott Date: Fri, 11 Jul 2014 23:46:29 +0100 Subject: [PATCH] Issue #806982 by lokapujya, gnuget, miqmago, shashi1028, Floydm, bfroehle, kathyh, sreynen: Tables should take an optional footer variable and produce . --- core/includes/theme.inc | 166 +++++++++--------- .../system/src/Tests/Theme/TableTest.php | 22 +++ core/modules/system/templates/table.html.twig | 14 ++ 3 files changed, 122 insertions(+), 80 deletions(-) diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 81c328c74c8..678a1e104a3 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1428,32 +1428,32 @@ function drupal_pre_render_table(array $element) { * - header: An array containing the table headers. Each element of the array * can be either a localized string or an associative array with the * following keys: - * - "data": The localized title of the table column. - * - "field": The database field represented in the table column (required + * - data: The localized title of the table column. + * - field: The database field represented in the table column (required * if user is to be able to sort on this column). - * - "sort": A default sort order for this column ("asc" or "desc"). Only - * one column should be given a default sort order because table sorting - * only applies to one column at a time. - * - "class": An array of values for the 'class' attribute. In particular, - * the least important columns that can be hidden on narrow and medium - * width screens should have a 'priority-low' class, referenced with the - * RESPONSIVE_PRIORITY_LOW constant. Columns that should be shown on - * medium+ wide screens should be marked up with a class of - * 'priority-medium', referenced by with the RESPONSIVE_PRIORITY_MEDIUM - * constant. Themes may hide columns with one of these two classes on - * narrow viewports to save horizontal space. + * - sort: A default sort order for this column ("asc" or "desc"). Only + * one column should be given a default sort order because table sorting + * only applies to one column at a time. + * - class: An array of values for the 'class' attribute. In particular, + * the least important columns that can be hidden on narrow and medium + * width screens should have a 'priority-low' class, referenced with the + * RESPONSIVE_PRIORITY_LOW constant. Columns that should be shown on + * medium+ wide screens should be marked up with a class of + * 'priority-medium', referenced by with the RESPONSIVE_PRIORITY_MEDIUM + * constant. Themes may hide columns with one of these two classes on + * narrow viewports to save horizontal space. * - Any HTML attributes, such as "colspan", to apply to the column header * cell. * - rows: An array of table rows. Every row is an array of cells, or an * associative array with the following keys: - * - "data": an array of cells + * - data: An array of cells. * - Any HTML attributes, such as "class", to apply to the table row. - * - "no_striping": a boolean indicating that the row should receive no + * - no_striping: A Boolean indicating that the row should receive no * 'even / odd' styling. Defaults to FALSE. * Each cell can be either a string or an associative array with the * following keys: - * - "data": The string to display in the table cell. - * - "header": Indicates this cell is a header. + * - data: The string to display in the table cell. + * - header: Indicates this cell is a header. * - Any HTML attributes, such as "colspan", to apply to the table cell. * Here's an example for $rows: * @code @@ -1465,9 +1465,11 @@ function drupal_pre_render_table(array $element) { * // Row with attributes on the row and some of its cells. * array( * 'data' => array('Cell 1', array('data' => 'Cell 2', 'colspan' => 2)), 'class' => array('funky') - * ) + * ), * ); * @endcode + * - footer: An array of table rows which will be printed within a + * tag, in the same format as the rows element (see above). * - attributes: An array of HTML attributes to apply to the table tag. * - caption: A localized string to use for the tag. * - colgroups: An array of column groups. Each element of the array can be @@ -1612,77 +1614,81 @@ function template_preprocess_table(&$variables) { } } - if (!empty($variables['rows'])) { - $flip = array('even' => 'odd', 'odd' => 'even'); - $class = 'even'; - foreach ($variables['rows'] as $row_key => $row) { - // Check if we're dealing with a simple or complex row - if (isset($row['data'])) { - $cells = $row['data']; - $no_striping = isset($row['no_striping']) ? $row['no_striping'] : FALSE; - - // Set the attributes array and exclude 'data' and 'no_striping'. - $row_attributes = $row; - unset($row_attributes['data']); - unset($row_attributes['no_striping']); - } - else { + // Rows and footer have the same structure. + $sections = array('rows' , 'footer'); + foreach ($sections as $section) { + if (!empty($variables[$section])) { + $flip = array('even' => 'odd', 'odd' => 'even'); + $class = 'even'; + foreach ($variables[$section] as $row_key => $row) { $cells = $row; $row_attributes = array(); - $no_striping = FALSE; - } + $no_striping = $section === 'footer'; - // Add odd/even class. - if (!$no_striping) { - $class = $flip[$class]; - $row_attributes['class'][] = $class; - } + // Check if we're dealing with a simple or complex row + if (isset($row['data'])) { + $cells = $row['data']; + $no_striping = isset($row['no_striping']) ? $row['no_striping'] : $no_striping; - // Build row. - $variables['rows'][$row_key] = array(); - $variables['rows'][$row_key]['attributes'] = new Attribute($row_attributes); - $variables['rows'][$row_key]['cells'] = array(); - if (!empty($cells)) { - // Reset the responsive index. - $responsive_index = -1; - foreach ($cells as $col_key => $cell) { - // Increase the responsive index. - $responsive_index++; + // Set the attributes array and exclude 'data' and 'no_striping'. + $row_attributes = $row; + unset($row_attributes['data']); + unset($row_attributes['no_striping']); + } - if (!is_array($cell)) { - $cell_content = $cell; - $cell_attributes = array(); - $is_header = FALSE; - } - else { - $cell_content = ''; - if (isset($cell['data'])) { - $cell_content = $cell['data']; - unset($cell['data']); + // Add odd/even class. + if (!$no_striping) { + $class = $flip[$class]; + $row_attributes['class'][] = $class; + } + + + // Build row. + $variables[$section][$row_key] = array(); + $variables[$section][$row_key]['attributes'] = new Attribute($row_attributes); + $variables[$section][$row_key]['cells'] = array(); + if (!empty($cells)) { + // Reset the responsive index. + $responsive_index = -1; + foreach ($cells as $col_key => $cell) { + // Increase the responsive index. + $responsive_index++; + + if (!is_array($cell)) { + $cell_content = $cell; + $cell_attributes = array(); + $is_header = FALSE; } - // Flag the cell as a header or not and remove the flag. - $is_header = !empty($cell['header']); - unset($cell['header']); + else { + $cell_content = ''; + if (isset($cell['data'])) { + $cell_content = $cell['data']; + unset($cell['data']); + } - $cell_attributes = $cell; + // Flag the cell as a header or not and remove the flag. + $is_header = !empty($cell['header']); + unset($cell['header']); - if (is_array($cell_content)) { - $cell_content = drupal_render($cell_content); + $cell_attributes = $cell; + + if (is_array($cell_content)) { + $cell_content = drupal_render($cell_content); + } } + // Add active class if needed for sortable tables. + if (isset($variables['header'][$col_key]['data']) && $variables['header'][$col_key]['data'] == $ts['name'] && !empty($variables['header'][$col_key]['field'])) { + $cell_attributes['class'][] = 'active'; + } + // Copy RESPONSIVE_PRIORITY_LOW/RESPONSIVE_PRIORITY_MEDIUM + // class from header to cell as needed. + if (isset($responsive_classes[$responsive_index])) { + $cell_attributes['class'][] = $responsive_classes[$responsive_index]; + } + $variables[$section][$row_key]['cells'][$col_key]['tag'] = $is_header ? 'th' : 'td'; + $variables[$section][$row_key]['cells'][$col_key]['attributes'] = new Attribute($cell_attributes); + $variables[$section][$row_key]['cells'][$col_key]['content'] = $cell_content; } - // Add active class if needed for sortable tables. - if (isset($variables['header'][$col_key]['data']) && $variables['header'][$col_key]['data'] == $ts['name'] && !empty($variables['header'][$col_key]['field'])) { - $cell_attributes['class'][] = 'active'; - } - // Copy RESPONSIVE_PRIORITY_LOW/RESPONSIVE_PRIORITY_MEDIUM - // class from header to cell as needed. - if (isset($responsive_classes[$responsive_index])) { - $cell_attributes['class'][] = $responsive_classes[$responsive_index]; - } - - $variables['rows'][$row_key]['cells'][$col_key]['tag'] = $is_header ? 'th' : 'td'; - $variables['rows'][$row_key]['cells'][$col_key]['attributes'] = new Attribute($cell_attributes); - $variables['rows'][$row_key]['cells'][$col_key]['content'] = $cell_content; } } } @@ -2561,7 +2567,7 @@ function drupal_common_theme() { 'template' => 'breadcrumb', ), 'table' => array( - 'variables' => array('header' => NULL, 'rows' => NULL, 'attributes' => array(), 'caption' => NULL, 'colgroups' => array(), 'sticky' => FALSE, 'responsive' => TRUE, 'empty' => ''), + 'variables' => array('header' => NULL, 'rows' => NULL, 'footer' => NULL, 'attributes' => array(), 'caption' => NULL, 'colgroups' => array(), 'sticky' => FALSE, 'responsive' => TRUE, 'empty' => ''), 'template' => 'table', ), 'tablesort_indicator' => array( diff --git a/core/modules/system/src/Tests/Theme/TableTest.php b/core/modules/system/src/Tests/Theme/TableTest.php index 435e79fe83f..b781d20d6f2 100644 --- a/core/modules/system/src/Tests/Theme/TableTest.php +++ b/core/modules/system/src/Tests/Theme/TableTest.php @@ -110,6 +110,28 @@ class TableTest extends DrupalUnitTestBase { $this->assertNoRaw('no_striping', 'No invalid no_striping HTML attribute was printed.'); } + /** + * Test that the 'footer' option works correctly. + */ + function testThemeTableFooter() { + $footer = array( + array( + 'data' => array(1), + ), + array('Foo'), + ); + + $table = array( + '#type' => 'table', + '#rows' => array(), + '#footer' => $footer, + ); + + $this->render($table); + $this->removeWhiteSpace(); + $this->assertRaw('1Foo', 'Table footer found.'); + } + /** * Tests that the 'header' option in cells works correctly. */ diff --git a/core/modules/system/templates/table.html.twig b/core/modules/system/templates/table.html.twig index ce69286108b..9c1cb05328b 100644 --- a/core/modules/system/templates/table.html.twig +++ b/core/modules/system/templates/table.html.twig @@ -28,6 +28,7 @@ * - attributes: Any HTML attributes, such as "colspan", to apply to the * table cell. * - content: The string to display in the table cell. + * - footer: Table footer rows, in the same format as the rows variable. * - empty: The message to display in an extra row if table does not have * any rows. * @@ -78,4 +79,17 @@ {% endfor %} {% endif %} + {% if footer %} + + {% for row in footer %} + + {% for cell in row.cells %} + <{{ cell.tag }}{{ cell.attributes }}> + {{- cell.content -}} + + {% endfor %} + + {% endfor %} + + {% endif %}