diff --git a/core/includes/tablesort.inc b/core/includes/tablesort.inc index 5a0f4dc..0b3574f 100644 --- a/core/includes/tablesort.inc +++ b/core/includes/tablesort.inc @@ -30,27 +30,26 @@ function tablesort_init($header) { * If the cell in question is the column header for the current sort criterion, * it gets special formatting. All possible sort criteria become links. * - * @param $cell - * The cell to format. - * @param $header + * @param string $cell_content + * The cell content to format. Passed by reference. + * @param array $cell_attributes + * The cell attributes. Passed by reference. + * @param array $header * An array of column headers in the format described in '#type' => 'table'. - * @param $ts + * @param array $ts * The current table sort context as returned from tablesort_init(). - * - * @return - * A properly formatted cell. */ -function tablesort_header($cell, $header, $ts) { +function tablesort_header(&$cell_content, array &$cell_attributes, array $header, array $ts) { // Special formatting for the currently sorted column header. - if (isset($cell['field'])) { - $title = t('sort by @s', array('@s' => $cell['data'])); - if ($cell['data'] == $ts['name']) { + if (isset($cell_attributes['field'])) { + $title = t('sort by @s', array('@s' => $cell_content)); + if ($cell_content == $ts['name']) { // aria-sort is a WAI-ARIA property that indicates if items in a table // or grid are sorted in ascending or descending order. See // http://www.w3.org/TR/wai-aria/states_and_properties#aria-sort - $cell['attributes']['aria-sort'] = ($ts['sort'] == 'asc') ? 'ascending' : 'descending'; + $cell_attributes['aria-sort'] = ($ts['sort'] == 'asc') ? 'ascending' : 'descending'; $ts['sort'] = (($ts['sort'] == 'asc') ? 'desc' : 'asc'); - $cell['attributes']['class'][] = 'active'; + $cell_attributes['class'][] = 'active'; $tablesort_indicator = array( '#theme' => 'tablesort_indicator', '#style' => $ts['sort'], @@ -62,11 +61,17 @@ function tablesort_header($cell, $header, $ts) { $ts['sort'] = 'asc'; $image = ''; } - $cell['data'] = l($cell['data'] . $image, current_path(), array('attributes' => array('title' => $title), 'query' => array_merge($ts['query'], array('sort' => $ts['sort'], 'order' => $cell['data'])), 'html' => TRUE)); + $cell_content = l($cell_content . $image, current_path(), array( + 'attributes' => array('title' => $title), + 'query' => array_merge($ts['query'], array( + 'sort' => $ts['sort'], + 'order' => $cell_content, + )), + 'html' => TRUE, + )); - unset($cell['field'], $cell['sort']); + unset($cell_attributes['field'], $cell_attributes['sort']); } - return $cell; } /** diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 5bb1f56..e657ce8 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1547,42 +1547,45 @@ function theme_table($variables) { $i = 0; foreach ($header as $cell) { $i++; - // If the cell is not an array, make it one. if (!is_array($cell)) { - $cell = array('data' => $cell); + $cell_content = $cell; + $cell_attributes = ''; + $is_header = TRUE; } - $cell['data'] = isset($cell['data']) ? $cell['data'] : ''; - $cell['attributes'] = isset($cell['attributes']) ? $cell['attributes'] : array(); - - // Flag the cell as a header or not and remove the flag. - $is_header = isset($cell['header']) ? $cell['header'] : TRUE; - unset($cell['header']); - - // Track responsive classes for each column as needed. Only the header - // cells for a column are marked up with the responsive classes by a - // module developer or themer. The responsive classes on the header cells - // must be transferred to the content cells. - if (!empty($cell['class']) && is_array($cell['class'])) { - if (in_array(RESPONSIVE_PRIORITY_MEDIUM, $cell['class'])) { - $responsive[$i] = RESPONSIVE_PRIORITY_MEDIUM; + else { + $cell_content = ''; + if (isset($cell['data'])) { + $cell_content = $cell['data']; + unset($cell['data']); } - elseif (in_array(RESPONSIVE_PRIORITY_LOW, $cell['class'])) { - $responsive[$i] = RESPONSIVE_PRIORITY_LOW; + // Flag the cell as a header or not and remove the flag. + $is_header = isset($cell['header']) ? $cell['header'] : TRUE; + unset($cell['header']); + + // Track responsive classes for each column as needed. Only the header + // cells for a column are marked up with the responsive classes by a + // module developer or themer. The responsive classes on the header cells + // must be transferred to the content cells. + if (!empty($cell['class']) && is_array($cell['class'])) { + if (in_array(RESPONSIVE_PRIORITY_MEDIUM, $cell['class'])) { + $responsive[$i] = RESPONSIVE_PRIORITY_MEDIUM; + } + elseif (in_array(RESPONSIVE_PRIORITY_LOW, $cell['class'])) { + $responsive[$i] = RESPONSIVE_PRIORITY_LOW; + } } - } - $cell = tablesort_header($cell, $header, $ts); - // Move cell properties that are not data or attributes into attributes. - // Doing this after tablesort_header because it removes the sort and field - // keys. - $cell['attributes'] = array_diff_key($cell, array_flip(array('data', 'attributes'))) + $cell['attributes']; + if (is_array($cell_content)) { + $cell_content = drupal_render($cell_content); + } + + tablesort_header($cell_content, $cell, $header, $ts); - // Cell's data property can be a string or a renderable array. - if (is_array($cell['data'])) { - $cell['data'] = drupal_render($cell['data']); + // tablesort_header() removes the 'sort' and 'field' keys. + $cell_attributes = new Attribute($cell); } - $cell_tag = ($is_header) ? 'th' : 'td'; - $output .= '<' . $cell_tag . new Attribute($cell['attributes']) . '>' . $cell['data'] . ''; + $cell_tag = $is_header ? 'th' : 'td'; + $output .= '<' . $cell_tag . $cell_attributes . '>' . $cell_content . ''; } // Using ternary operator to close the tags based on whether or not there are rows $output .= (count($rows) ? " \n" : "\n"); @@ -1624,36 +1627,39 @@ function theme_table($variables) { $i = 0; foreach ($cells as $cell) { $i++; - // If the cell is not an array, make it one. if (!is_array($cell)) { - $cell = array('data' => $cell); + $cell_content = $cell; + $cell_attributes = array(); + $is_header = FALSE; } - $cell['data'] = isset($cell['data']) ? $cell['data'] : ''; - $cell['attributes'] = isset($cell['attributes']) ? $cell['attributes'] : array(); - - // 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']); - // Move cell properties that are not data or attributes - // into attributes. - $cell['attributes'] = array_diff_key($cell, array_flip(array('data', 'attributes'))) + $cell['attributes']; + $cell_attributes = $cell; + if (is_array($cell_content)) { + $cell_content = drupal_render($cell_content); + } + } // Add active class if needed for sortable tables. if (isset($header[$i]['data']) && $header[$i]['data'] == $ts['name'] && !empty($header[$i]['field'])) { - $cell['attributes']['class'][] = 'active'; + $cell_attributes['class'][] = 'active'; } // Copy RESPONSIVE_PRIORITY_LOW/RESPONSIVE_PRIORITY_MEDIUM // class from header to cell as needed. if (isset($responsive[$i])) { - $cell['attributes']['class'][] = $responsive[$i]; - } - // Cell's data property can be a string or a renderable array. - if (is_array($cell['data'])) { - $cell['data'] = drupal_render($cell['data']); + $cell_attributes['class'][] = $responsive[$i]; } - $cell_tag = ($is_header) ? 'th' : 'td'; - $output .= '<' . $cell_tag . new Attribute($cell['attributes']) . '>' . $cell['data'] . ''; + + $cell_tag = $is_header ? 'th' : 'td'; + $output .= '<' . $cell_tag . new Attribute($cell_attributes) . '>' . $cell_content . ''; } $output .= " \n"; } 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 2376399..26a0fd8 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Theme/TableTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/TableTest.php @@ -7,16 +7,24 @@ namespace Drupal\system\Tests\Theme; -use Drupal\simpletest\WebTestBase; +use Drupal\simpletest\DrupalUnitTestBase; /** * Unit tests for theme_table(). */ -class TableTest extends WebTestBase { +class TableTest extends DrupalUnitTestBase { + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = array('system'); + public static function getInfo() { return array( 'name' => 'Theme Table', - 'description' => 'Tests built-in theme functions.', + 'description' => 'Tests built-in table theme functions.', 'group' => 'Theme', ); } @@ -126,4 +134,38 @@ function testThemeTableHeaderCellOption() { $this->assertRaw('111', 'The th and td tags was printed correctly.'); } + /** + * Asserts that a raw string appears in $this->content. + * + * @param string $value + * The expected string. + * @param string $message + * (optional) A custom assertion message. + */ + protected function assertRaw($value, $message = NULL) { + if (!isset($message)) { + $message = String::format("Raw value @value found.", array( + '@value' => var_export($value, TRUE), + )); + } + $this->assert(strpos($this->content, $value) !== FALSE, $message); + } + + /** + * Asserts that a raw string does not appear in $this->content. + * + * @param string $value + * The not expected string. + * @param string $message + * (optional) A custom assertion message. + */ + protected function assertNoRaw($value, $message = NULL) { + if (!isset($message)) { + $message = String::format("Raw value @value not found.", array( + '@value' => var_export($value, TRUE), + )); + } + $this->assert(strpos($this->content, $value) === FALSE, $message); + } + }