Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.1227 diff -u -p -r1.1227 common.inc --- includes/common.inc 25 Sep 2010 02:00:06 -0000 1.1227 +++ includes/common.inc 25 Sep 2010 14:22:34 -0000 @@ -4573,7 +4573,6 @@ function _drupal_bootstrap_full() { require_once DRUPAL_ROOT . '/includes/theme.inc'; require_once DRUPAL_ROOT . '/includes/pager.inc'; require_once DRUPAL_ROOT . '/' . variable_get('menu_inc', 'includes/menu.inc'); - require_once DRUPAL_ROOT . '/includes/tablesort.inc'; require_once DRUPAL_ROOT . '/includes/file.inc'; require_once DRUPAL_ROOT . '/includes/unicode.inc'; require_once DRUPAL_ROOT . '/includes/image.inc'; Index: includes/tablesort.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/tablesort.inc,v retrieving revision 1.58 diff -u -p -r1.58 tablesort.inc --- includes/tablesort.inc 5 Dec 2009 20:17:02 -0000 1.58 +++ includes/tablesort.inc 25 Sep 2010 14:24:14 -0000 @@ -16,7 +16,7 @@ class TableSort extends SelectQueryExtender { /** - * The array of fields that can be sorted by. + * An array of table header columns that can be sorted by, as described in theme_table(). * * @var array */ @@ -34,23 +34,22 @@ class TableSort extends SelectQueryExten /** * Order the query based on a header array. * - * @see theme_table() * @param $header - * Table header array. + * An array of table header columns as described in theme_table(). + * * @return SelectQueryInterface * The called object. + * + * @see theme_table() */ - public function orderByHeader(Array $header) { + public function orderByHeader(array $header) { $this->header = $header; $ts = $this->init(); - if (!empty($ts['sql'])) { - // Based on code from db_escape_table(), but this can also contain a dot. - $field = preg_replace('/[^A-Za-z0-9_.]+/', '', $ts['sql']); - + if (!empty($ts['field'])) { // Sort order can only be ASC or DESC. $sort = drupal_strtoupper($ts['sort']); $sort = in_array($sort, array('ASC', 'DESC')) ? $sort : ''; - $this->orderBy($field, $sort); + $this->orderBy($ts['field'], $sort); } return $this; } @@ -69,23 +68,12 @@ class TableSort extends SelectQueryExten * Determine the current sort direction. * * @param $headers - * An array of column headers in the format described in theme_table(). + * An array of table header columns as described in theme_table(). * @return * The current sort direction ("asc" or "desc"). */ protected function getSort() { - if (isset($_GET['sort'])) { - return ($_GET['sort'] == 'desc') ? 'desc' : 'asc'; - } - // User has not specified a sort. Use default if specified; otherwise use "asc". - else { - foreach ($this->header as $header) { - if (is_array($header) && array_key_exists('sort', $header)) { - return $header['sort']; - } - } - } - return 'asc'; + return tablesort_get_sort($this->header); } /** @@ -104,38 +92,13 @@ class TableSort extends SelectQueryExten /** * Determine the current sort criterion. * - * @param $headers - * An array of column headers in the format described in theme_table(). * @return * An associative array describing the criterion, containing the keys: - * - "name": The localized title of the table column. - * - "sql": The name of the database field to sort on. + * - name: The localized title of the table column. + * - field: The name of the database field to sort on. */ protected function order() { - $order = isset($_GET['order']) ? $_GET['order'] : ''; - foreach ($this->header as $header) { - if (isset($header['data']) && $order == $header['data']) { - return array('name' => $header['data'], 'sql' => isset($header['field']) ? $header['field'] : ''); - } - - if (isset($header['sort']) && ($header['sort'] == 'asc' || $header['sort'] == 'desc')) { - $default = array('name' => $header['data'], 'sql' => isset($header['field']) ? $header['field'] : ''); - } - } - - if (isset($default)) { - return $default; - } - else { - // The first column specified is initial 'order by' field unless otherwise specified - if (is_array($this->header[0])) { - $this->header[0] += array('data' => NULL, 'field' => NULL); - return array('name' => $this->header[0]['data'], 'sql' => $this->header[0]['field']); - } - else { - return array('name' => $this->header[0]); - } - } + return tablesort_get_order($this->header); } } @@ -158,7 +121,7 @@ function tablesort_init($header) { * @param $cell * The cell to format. * @param $header - * An array of column headers in the format described in theme_table(). + * An array of table header columns as described in theme_table(). * @param $ts * The current table sort context as returned from tablesort_init(). * @return @@ -168,7 +131,7 @@ function tablesort_header($cell, $header // Special formatting for the currently sorted column header. if (is_array($cell) && isset($cell['field'])) { $title = t('sort by @s', array('@s' => $cell['data'])); - if ($cell['data'] == $ts['name']) { + if ($cell['field'] == $ts['field']) { $ts['sort'] = (($ts['sort'] == 'asc') ? 'desc' : 'asc'); $cell['class'][] = 'active'; $image = theme('tablesort_indicator', array('style' => $ts['sort'])); @@ -178,7 +141,12 @@ function tablesort_header($cell, $header $ts['sort'] = 'asc'; $image = ''; } - $cell['data'] = l($cell['data'] . $image, $_GET['q'], array('attributes' => array('title' => $title), 'query' => array_merge($ts['query'], array('sort' => $ts['sort'], 'order' => $cell['data'])), 'html' => TRUE)); + $options = array( + 'attributes' => array('title' => $title), + 'query' => array_merge($ts['query'], array('sort' => $ts['sort'], 'order' => $cell['field'])), + 'html' => TRUE, + ); + $cell['data'] = l($cell['data'] . $image, $_GET['q'], $options); unset($cell['field'], $cell['sort']); } @@ -193,7 +161,7 @@ function tablesort_header($cell, $header * @param $cell * The cell to format. * @param $header - * An array of column headers in the format described in theme_table(). + * An array of table header columns as described in theme_table(). * @param $ts * The current table sort context as returned from tablesort_init(). * @param $i @@ -202,7 +170,7 @@ function tablesort_header($cell, $header * A properly formatted cell, ready for _theme_table_cell(). */ function tablesort_cell($cell, $header, $ts, $i) { - if (isset($header[$i]['data']) && $header[$i]['data'] == $ts['name'] && !empty($header[$i]['field'])) { + if (isset($header[$i]['field']) && $header[$i]['field'] == $ts['field']) { if (is_array($cell)) { $cell['class'][] = 'active'; } @@ -227,58 +195,65 @@ function tablesort_get_query_parameters( /** * Determine the current sort criterion. * - * @param $headers - * An array of column headers in the format described in theme_table(). + * @param $header + * An array of table header columns as described in theme_table(). * @return * An associative array describing the criterion, containing the keys: - * - "name": The localized title of the table column. - * - "sql": The name of the database field to sort on. + * - name: The localized title of the table column. + * - field: The name of the database field to sort on. */ -function tablesort_get_order($headers) { +function tablesort_get_order($header) { $order = isset($_GET['order']) ? $_GET['order'] : ''; - foreach ($headers as $header) { - if (isset($header['data']) && $order == $header['data']) { - return array('name' => $header['data'], 'sql' => isset($header['field']) ? $header['field'] : ''); + foreach ($header as $column) { + if (!is_array($column) || !isset($column['field'])) { + continue; } - - if (isset($header['sort']) && ($header['sort'] == 'asc' || $header['sort'] == 'desc')) { - $default = array('name' => $header['data'], 'sql' => isset($header['field']) ? $header['field'] : ''); + // Use the header column matching the URL parameter. + if ($order == $column['field']) { + return array('name' => $column['data'], 'field' => $column['field']); + } + // In case no header column will match the URL parameter, and this column + // defines 'sort', it is supposed to be the default sorting column. + if (isset($column['sort']) && ($column['sort'] == 'asc' || $column['sort'] == 'desc')) { + $default_column = array('name' => $column['data'], 'field' => $column['field']); + } + // In case there is no default sorting header column, store the first that + // defines a field. + elseif (!isset($first_column)) { + $first_column = array('name' => $column['data'], 'field' => $column['field']); } } - if (isset($default)) { - return $default; + // If there was a default sorting column, return that. + if (isset($default_column)) { + return $default_column; } - else { - // The first column specified is the initial 'order by' field unless otherwise specified. - $first = current($headers); - if (is_array($first)) { - $first += array('data' => NULL, 'field' => NULL); - return array('name' => $first['data'], 'sql' => $first['field']); - } - else { - return array('name' => $first, 'sql' => ''); - } + // Otherwise, use the first header column that defines a field. + if (isset($first_column)) { + return $first_column; } + // If we end up here, then a table header did not define any valid tablesort + // data. + throw new Exception(t('Invalid TableSort data; header needs to define at least one sorting field.')); } /** * Determine the current sort direction. * - * @param $headers - * An array of column headers in the format described in theme_table(). + * @param $header + * An array of table header columns as described in theme_table(). * @return * The current sort direction ("asc" or "desc"). */ -function tablesort_get_sort($headers) { +function tablesort_get_sort($header) { if (isset($_GET['sort'])) { return ($_GET['sort'] == 'desc') ? 'desc' : 'asc'; } // User has not specified a sort. Use default if specified; otherwise use "asc". else { - foreach ($headers as $header) { - if (is_array($header) && array_key_exists('sort', $header)) { - return $header['sort']; + foreach ($header as $column) { + if (is_array($column) && isset($column['sort'])) { + return $column['sort']; } } } Index: includes/theme.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/theme.inc,v retrieving revision 1.614 diff -u -p -r1.614 theme.inc --- includes/theme.inc 24 Sep 2010 21:20:08 -0000 1.614 +++ includes/theme.inc 25 Sep 2010 14:22:12 -0000 @@ -1677,22 +1677,28 @@ function theme_table($variables) { $rows[] = array(array('data' => $empty, 'colspan' => $header_count, 'class' => array('empty', 'message'))); } - // Format the table header: + // Format the table header. if (count($header)) { - $ts = tablesort_init($header); + // Determine whether we need to load tablesort. + foreach ($header as $column) { + if (is_array($column) && isset($column['field'])) { + require_once DRUPAL_ROOT . '/includes/tablesort.inc'; + $ts = tablesort_init($header); + break; + } + } // HTML requires that the thead tag has tr tags in it followed by tbody // tags. Using ternary operator to check and see if we have any rows. $output .= (count($rows) ? ' ' : ' '); foreach ($header as $cell) { - $cell = tablesort_header($cell, $header, $ts); + if (isset($ts)) { + $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 $output .= (count($rows) ? " \n" : "\n"); } - else { - $ts = array(); - } // Format the table rows: if (count($rows)) { @@ -1727,7 +1733,9 @@ function theme_table($variables) { $output .= ' '; $i = 0; foreach ($cells as $cell) { - $cell = tablesort_cell($cell, $header, $ts, $i++); + if (isset($ts)) { + $cell = tablesort_cell($cell, $header, $ts, $i++); + } $output .= _theme_table_cell($cell); } $output .= " \n"; Index: modules/forum/forum.module =================================================================== RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v retrieving revision 1.576 diff -u -p -r1.576 forum.module --- modules/forum/forum.module 24 Sep 2010 00:37:42 -0000 1.576 +++ modules/forum/forum.module 25 Sep 2010 14:33:52 -0000 @@ -59,7 +59,7 @@ function forum_theme() { return array( 'forums' => array( 'template' => 'forums', - 'variables' => array('forums' => NULL, 'topics' => NULL, 'parents' => NULL, 'tid' => NULL, 'sortby' => NULL, 'forum_per_page' => NULL), + 'variables' => array('forums' => NULL, 'topics' => array(), 'parents' => NULL, 'tid' => NULL, 'header' => array(), 'forum_per_page' => NULL), ), 'forum_list' => array( 'template' => 'forum-list', @@ -67,7 +67,7 @@ function forum_theme() { ), 'forum_topic_list' => array( 'template' => 'forum-topic-list', - 'variables' => array('tid' => NULL, 'topics' => NULL, 'sortby' => NULL, 'forum_per_page' => NULL), + 'variables' => array('tid' => NULL, 'topics' => array(), 'header' => array(), 'forum_per_page' => NULL), ), 'forum_icon' => array( 'template' => 'forum-icon', @@ -854,22 +854,8 @@ function _forum_topics_unread($term, $ui ->fetchField(); } -function forum_get_topics($tid, $sortby, $forum_per_page) { - global $user, $forum_topic_list_header; - - $forum_topic_list_header = array( - NULL, - array('data' => t('Topic'), 'field' => 'f.title'), - array('data' => t('Replies'), 'field' => 'f.comment_count'), - array('data' => t('Last reply'), 'field' => 'f.last_comment_timestamp'), - ); - - $order = _forum_get_topic_order($sortby); - for ($i = 0; $i < count($forum_topic_list_header); $i++) { - if ($forum_topic_list_header[$i]['field'] == $order['field']) { - $forum_topic_list_header[$i]['sort'] = $order['sort']; - } - } +function forum_get_topics($tid, $header, $forum_per_page) { + global $user; $query = db_select('forum_index', 'f')->extend('PagerDefault')->extend('TableSort'); $query->fields('f'); @@ -877,7 +863,7 @@ function forum_get_topics($tid, $sortby, ->condition('f.tid', $tid) ->addTag('node_access') ->orderBy('f.sticky', 'DESC') - ->orderByHeader($forum_topic_list_header) + ->orderByHeader($header) ->orderBy('f.last_comment_timestamp', 'DESC') ->limit($forum_per_page); @@ -939,7 +925,7 @@ function forum_get_topics($tid, $sortby, * - $topics * - $parents * - $tid - * - $sortby + * - $header * - $forum_per_page * * @see forums.tpl.php @@ -1058,20 +1044,20 @@ function template_preprocess_forum_list( * $variables contains the following data: * - $tid * - $topics - * - $sortby + * - $header * - $forum_per_page * * @see forum-topic-list.tpl.php * @see theme_forum_topic_list() */ function template_preprocess_forum_topic_list(&$variables) { - global $forum_topic_list_header; - - // Create the tablesorting header. - $ts = tablesort_init($forum_topic_list_header); + // Render the table header; this is required, because the forum topic list + // table does not use theme_table(). + require_once DRUPAL_ROOT . '/includes/tablesort.inc'; + $ts = tablesort_init($variables['header']); $header = ''; - foreach ($forum_topic_list_header as $cell) { - $cell = tablesort_header($cell, $forum_topic_list_header, $ts); + foreach ($variables['header'] as $cell) { + $cell = tablesort_header($cell, $variables['header'], $ts); $header .= _theme_table_cell($cell, TRUE); } $variables['header'] = $header; @@ -1109,10 +1095,6 @@ function template_preprocess_forum_topic } } - else { - // Make this safe for the template - $variables['topics'] = array(); - } // Give meaning to $tid for themers. $tid actually stands for term id. $variables['topic_id'] = $variables['tid']; unset($variables['tid']); @@ -1180,16 +1162,15 @@ function _forum_get_topic_order($sortby) switch ($sortby) { case 1: return array('field' => 'ncs.last_comment_timestamp', 'sort' => 'desc'); - break; + case 2: return array('field' => 'ncs.last_comment_timestamp', 'sort' => 'asc'); - break; + case 3: return array('field' => 'ncs.comment_count', 'sort' => 'desc'); - break; + case 4: return array('field' => 'ncs.comment_count', 'sort' => 'asc'); - break; } } Index: modules/forum/forum.pages.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/forum/forum.pages.inc,v retrieving revision 1.4 diff -u -p -r1.4 forum.pages.inc --- modules/forum/forum.pages.inc 28 Apr 2010 05:54:55 -0000 1.4 +++ modules/forum/forum.pages.inc 25 Sep 2010 14:32:31 -0000 @@ -16,14 +16,26 @@ function forum_page($forum_term = NULL) } $forum_per_page = variable_get('forum_per_page', 25); - $sortby = variable_get('forum_order', 1); + + $header = array( + NULL, + array('data' => t('Topic'), 'field' => 'f.title'), + array('data' => t('Replies'), 'field' => 'f.comment_count'), + array('data' => t('Last reply'), 'field' => 'f.last_comment_timestamp'), + ); + $order = _forum_get_topic_order(variable_get('forum_order', 1)); + for ($i = 0; $i < count($header); $i++) { + if ($header[$i]['field'] == $order['field']) { + $header[$i]['sort'] = $order['sort']; + } + } if (empty($forum_term->container)) { - $topics = forum_get_topics($forum_term->tid, $sortby, $forum_per_page); + $topics = forum_get_topics($forum_term->tid, $header, $forum_per_page); } else { - $topics = ''; + $topics = array(); } - return theme('forums', array('forums' => $forum_term->forums, 'topics' => $topics, 'parents' => $forum_term->parents, 'tid' => $forum_term->tid, 'sortby' => $sortby, 'forums_per_page' => $forum_per_page)); + return theme('forums', array('forums' => $forum_term->forums, 'topics' => $topics, 'parents' => $forum_term->parents, 'tid' => $forum_term->tid, 'header' => $header, 'forums_per_page' => $forum_per_page)); } Index: modules/simpletest/tests/database_test.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/database_test.test,v retrieving revision 1.103 diff -u -p -r1.103 database_test.test --- modules/simpletest/tests/database_test.test 24 Sep 2010 02:05:55 -0000 1.103 +++ modules/simpletest/tests/database_test.test 25 Sep 2010 14:22:12 -0000 @@ -2269,10 +2269,10 @@ class DatabaseSelectTableSortDefaultTest */ function testTableSortQuery() { $sorts = array( - array('field' => t('Task ID'), 'sort' => 'desc', 'first' => 'perform at superbowl', 'last' => 'eat'), - array('field' => t('Task ID'), 'sort' => 'asc', 'first' => 'eat', 'last' => 'perform at superbowl'), - array('field' => t('Task'), 'sort' => 'asc', 'first' => 'code', 'last' => 'sleep'), - array('field' => t('Task'), 'sort' => 'desc', 'first' => 'sleep', 'last' => 'code'), + array('data' => t('Task ID'), 'field' => 'tid', 'sort' => 'desc', 'first' => 'perform at superbowl', 'last' => 'eat'), + array('data' => t('Task ID'), 'field' => 'tid', 'sort' => 'asc', 'first' => 'eat', 'last' => 'perform at superbowl'), + array('data' => t('Task'), 'field' => 'task', 'sort' => 'asc', 'first' => 'code', 'last' => 'sleep'), + array('data' => t('Task'), 'field' => 'task', 'sort' => 'desc', 'first' => 'sleep', 'last' => 'code'), // more elements here ); @@ -2295,10 +2295,10 @@ class DatabaseSelectTableSortDefaultTest */ function testTableSortQueryFirst() { $sorts = array( - array('field' => t('Task ID'), 'sort' => 'desc', 'first' => 'perform at superbowl', 'last' => 'eat'), - array('field' => t('Task ID'), 'sort' => 'asc', 'first' => 'eat', 'last' => 'perform at superbowl'), - array('field' => t('Task'), 'sort' => 'asc', 'first' => 'code', 'last' => 'sleep'), - array('field' => t('Task'), 'sort' => 'desc', 'first' => 'sleep', 'last' => 'code'), + array('data' => t('Task ID'), 'field' => 'tid', 'sort' => 'desc', 'first' => 'perform at superbowl', 'last' => 'eat'), + array('data' => t('Task ID'), 'field' => 'tid', 'sort' => 'asc', 'first' => 'eat', 'last' => 'perform at superbowl'), + array('data' => t('Task'), 'field' => 'task', 'sort' => 'asc', 'first' => 'code', 'last' => 'sleep'), + array('data' => t('Task'), 'field' => 'task', 'sort' => 'desc', 'first' => 'sleep', 'last' => 'code'), // more elements here );