diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 2b06429..09fb7bf 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1463,6 +1463,32 @@ 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 +1627,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;
+ }
}
}
}
@@ -2560,7 +2589,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 6b9c5ef..b7a6e3b 100644
--- a/core/modules/system/src/Tests/Theme/TableTest.php
+++ b/core/modules/system/src/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('Foo'),
+ );
+
+ $table = array(
+ '#type' => 'table',
+ '#rows' => array(),
+ '#footer' => $footer,
+ );
+
+ $this->render($table);
+ $this->removeWhiteSpace();
+ $this->assertRaw('1 |
Foo |
', '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 -}}
+ {{ cell.tag }}>
+ {% endfor %}
+
+ {% endfor %}
+
+ {% endif %}