diff --git a/includes/common.inc b/includes/common.inc
index 44ff460787..ad8516f2fb 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -6952,7 +6952,16 @@ function drupal_common_theme() {
'variables' => array(),
),
'table' => array(
- 'variables' => array('header' => NULL, 'rows' => NULL, 'attributes' => array(), 'caption' => NULL, 'colgroups' => array(), 'sticky' => TRUE, 'empty' => ''),
+ 'variables' => array(
+ 'header' => NULL,
+ 'footer' => NULL,
+ 'rows' => NULL,
+ 'attributes' => array(),
+ 'caption' => NULL,
+ 'colgroups' => array(),
+ 'sticky' => TRUE,
+ 'empty' => '',
+ ),
),
'tablesort_indicator' => array(
'variables' => array('style' => NULL),
diff --git a/includes/theme.inc b/includes/theme.inc
index a926b764ed..c9d80584b5 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -1911,7 +1911,7 @@ function theme_breadcrumb($variables) {
/**
* Returns HTML for a table.
*
- * @param $variables
+ * @param array $variables
* An associative array containing:
* - header: An array containing the table headers. Each element of the array
* can be either a localized string or an associative array with the
@@ -1948,6 +1948,8 @@ function theme_breadcrumb($variables) {
* )
* );
* @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
@@ -1984,8 +1986,11 @@ function theme_breadcrumb($variables) {
* - sticky: Use a "sticky" table header.
* - empty: The message to display in an extra row if table does not have any
* rows.
+ *
+ * @return string
+ * The HTML output.
*/
-function theme_table($variables) {
+function theme_table(array $variables) {
$header = $variables['header'];
$rows = $variables['rows'];
$attributes = $variables['attributes'];
@@ -2049,17 +2054,31 @@ function theme_table($variables) {
if (!empty($header)) {
foreach ($header as $header_cell) {
if (is_array($header_cell)) {
- $header_count += isset($header_cell['colspan']) ? $header_cell['colspan'] : 1;
+ $header_count += isset($header_cell['colspan']) ?
+ $header_cell['colspan'] : 1;
}
else {
$header_count++;
}
}
}
- $rows[] = array(array('data' => $empty, 'colspan' => $header_count, 'class' => array('empty', 'message')));
+ $rows[] = array(
+ array(
+ 'data' => $empty,
+ 'colspan' => $header_count,
+ 'class' => array(
+ 'empty',
+ 'message'
+ ),
+ ),
+ );
}
- // Format the table header:
+ // Assigning back the $rows variable into $variables as we won't modify it
+ // anymore.
+ $variables['rows'] = $rows;
+
+ // Format the table header.
if (!empty($header)) {
$ts = tablesort_init($header);
// HTML requires that the thead tag has tr tags in it followed by tbody
@@ -2069,23 +2088,38 @@ function theme_table($variables) {
$cell = tablesort_header($cell, $header, $ts);
$output .= _theme_table_cell($cell, TRUE);
}
- // Using ternary operator to close the tags based on whether or not there are rows
+ // Using ternary operator to close the tags based on whether
+ // or not there are rows.
$output .= (!empty($rows) ? " \n" : "\n");
}
else {
$ts = array();
}
- // Format the table rows:
+ $sections = array();
+
if (!empty($rows)) {
- $output .= "\n";
+ $sections['tbody'] = $rows;
+ }
+
+ if (!empty($variables['footer'])) {
+ $sections['tfoot'] = $variables['footer'];
+ }
+
+ // tbody and tfoot have the same structure and are built using the same
+ // procedure.
+ foreach ($sections as $tag => $content) {
+ $output .= "<" . $tag . ">\n";
$flip = array('even' => 'odd', 'odd' => 'even');
$class = 'even';
- foreach ($rows as $number => $row) {
- // Check if we're dealing with a simple or complex row
+ $no_striping = $tag === 'tfoot';
+
+ foreach ($content as $number => $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;
+ $no_striping = isset($row['no_striping']) ?
+ $row['no_striping'] : $no_striping;
// Set the attributes array and exclude 'data' and 'no_striping'.
$attributes = $row;
@@ -2097,14 +2131,15 @@ function theme_table($variables) {
$attributes = array();
$no_striping = FALSE;
}
+
if (!empty($cells)) {
- // Add odd/even class
+ // Add odd/even class.
if (!$no_striping) {
$class = $flip[$class];
$attributes['class'][] = $class;
}
- // Build row
+ // Build row.
$output .= ' ';
$i = 0;
foreach ($cells as $cell) {
@@ -2114,10 +2149,12 @@ function theme_table($variables) {
$output .= "
\n";
}
}
- $output .= "\n";
+
+ $output .= "" . $tag . ">\n";
}
$output .= "\n";
+
return $output;
}
diff --git a/modules/simpletest/tests/theme.test b/modules/simpletest/tests/theme.test
index 5f095bd558..710a56e5ef 100644
--- a/modules/simpletest/tests/theme.test
+++ b/modules/simpletest/tests/theme.test
@@ -238,6 +238,27 @@ class ThemeTableTestCase extends DrupalWebTestCase {
$this->assertNoRaw('class="odd"', 'Odd/even classes were not added because $no_striping = TRUE.');
$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(
+ 'rows' => array(),
+ 'footer' => $footer,
+ );
+
+ $this->content = theme('table', $table);
+ $this->content = preg_replace('@>\s+<@', '><', $this->content);
+ $this->assertRaw('1 |
Foo |
', 'Table footer found.');
+ }
}
/**