diff --git a/core/includes/theme.inc b/core/includes/theme.inc index e44f13d..cf2f1f2 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1463,6 +1463,33 @@ function drupal_pre_render_table(array $element) { * ) * ); * @endcode + * - footer: An array of table rows which will be printed within a + * tag. + * Every row is an array of cells, or an associative array with the + * following keys: + * - "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 + * 'even / odd' styling. Defaults to TRUE. + * 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. + * - Any HTML attributes, such as "colspan", to apply to the table cell. + * Here's an example for $rows: + * @code + * $footer = array( + * // Simple row + * array( + * 'Cell 1', 'Cell 2', 'Cell 3' + * ), + * // 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 + * - 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 @@ -1601,72 +1628,75 @@ 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 === 'rows') ? FALSE : TRUE; - // 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)) { - foreach ($cells as $col_key => $cell) { - 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']); + // Set the attributes array and exclude 'data' and 'no_striping'. + $row_attributes = $row; + unset($row_attributes['data']); + unset($row_attributes['no_striping']); + } + + // 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)) { + foreach ($cells as $col_key => $cell) { + 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']); + } + // Flag the cell as a header or not and remove the flag. + $is_header = !empty($cell['header']); + unset($cell['header']); - $cell_attributes = $cell; + $cell_attributes = $cell; - if (is_array($cell_content)) { - $cell_content = drupal_render($cell_content); + 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[$col_key])) { + $cell_attributes['class'][] = $responsive_classes[$col_key]; } - } - // 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[$col_key])) { - $cell_attributes['class'][] = $responsive_classes[$col_key]; - } - $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; + $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; + } } } } @@ -2562,7 +2592,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/lib/Drupal/system/Tests/Theme/TableTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/TableTest.php index 6b9c5ef..98d98b0 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Theme/TableTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/TableTest.php @@ -118,6 +118,28 @@ function testThemeTableWithNoStriping() { } /** + * Test that the 'footer' option works correctly. + */ + function testThemeTableFooter() { + $footer = array( + array( + 'data' => array(1), + ), + array('1'), + ); + + $table = array( + '#type' => 'table', + '#rows' => array(), + '#footer' => $footer, + ); + + $this->render($table); + $this->removeWhiteSpace(); + $this->assertRaw('11', 'Table footer found.'); + } + + /** * Tests that the 'header' option in cells works correctly. */ function testThemeTableHeaderCellOption() { diff --git a/core/modules/system/templates/table.html.twig b/core/modules/system/templates/table.html.twig index ce69286..04ed606 100644 --- a/core/modules/system/templates/table.html.twig +++ b/core/modules/system/templates/table.html.twig @@ -28,6 +28,16 @@ * - 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. Each row contains the following properties: + * - attributes: HTML attributes to apply to the tag. + * - data: Table cells. + * - no_striping: A flag indicating that the row should receive no + * 'even / odd' styling. Defaults to FALSE. + * - cells: Table cells of the row. Each cell contains the following keys: + * - tag: The HTML tag name to use; either TH or TD. + * - attributes: Any HTML attributes, such as "colspan", to apply to the + * table cell. + * - content: The string to display in the table cell. * - empty: The message to display in an extra row if table does not have * any rows. * @@ -78,4 +88,17 @@ {% endfor %} {% endif %} + {% if footer %} + + {% for row in footer %} + + {% for cell in row.cells %} + <{{ cell.tag }}{{ cell.attributes }}> + {{- cell.content -}} + + {% endfor %} + + {% endfor %} + + {% endif %}