? .cvsignore ? privatemsg_tags_list.patch ? privatemsg_tags_list2.patch ? privatemsg_tags_list3.patch ? privatemsg_tags_list4.patch ? privatemsg_tags_list5.patch ? taglist.png ? tags2.png ? tags3.png Index: privatemsg.module =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg.module,v retrieving revision 1.70.2.30.2.91.2.92 diff -u -p -r1.70.2.30.2.91.2.92 privatemsg.module --- privatemsg.module 9 Nov 2009 20:08:09 -0000 1.70.2.30.2.91.2.92 +++ privatemsg.module 10 Nov 2009 19:26:53 -0000 @@ -573,22 +573,12 @@ function privatemsg_list(&$form_state, $ while ($row = db_fetch_array($result)) { // Store the raw row data. $form['#data'][$row['thread_id']] = $row; - // Store the themed row data. - $form['#rows'][$row['thread_id']] = _privatemsg_list_thread($row); // store thread id for the checkboxes array $threads[$row['thread_id']] = ''; } - if (empty($form['#data'])) { - // If no threads are displayed, use these default columns. - $keys = array('subject', 'author', 'last_updated'); - } - else { - // Load the keys of the first row in data, we don't know the key - $keys = array_keys($form['#data'][key($form['#data'])]); + if (!empty($form['#data'])) { $form['actions'] = _privatemsg_action_form(); } - // Load the themed list headers based on the available data - $form['#headers'] = _privatemsg_list_headers(!empty($form['#data']), $keys); // Define checkboxes, pager and theme $form['threads'] = array('#type' => 'checkboxes', '#options' => $threads); @@ -1048,7 +1038,7 @@ function privatemsg_sql_list(&$fragments // tablesort_sql() generates a ORDER BY string. However, the "ORDER BY " part // is not needed and added by the query builder. Discard the first 9 // characters of the string. - $order_by = drupal_substr(tablesort_sql(_privatemsg_list_headers( FALSE, array('subject', 'last_updated') + $fields), 'MAX(pmi.is_new) DESC,'), 9); + $order_by = drupal_substr(tablesort_sql(_privatemsg_list_headers( FALSE, array_merge(array('subject', 'last_updated'), $fields)), 'MAX(pmi.is_new) DESC,'), 9); $fragments['order_by'][] = $order_by; } Index: privatemsg.theme.inc =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/Attic/privatemsg.theme.inc,v retrieving revision 1.1.2.9 diff -u -p -r1.1.2.9 privatemsg.theme.inc --- privatemsg.theme.inc 6 Nov 2009 13:06:26 -0000 1.1.2.9 +++ privatemsg.theme.inc 10 Nov 2009 19:26:54 -0000 @@ -238,18 +238,24 @@ function phptemplate_privatemsg_list_hea * by the header and field theme patterns. */ function theme_privatemsg_list($form) { - $has_posts = !empty($form['#rows']); + $has_posts = !empty($form['#data']); drupal_add_css(drupal_get_path('module', 'privatemsg') .'/styles/privatemsg-list.css'); + // Load the table columns. + $columns = array_merge(array('subject', 'last_updated'), array_filter(variable_get('privatemsg_display_fields', array('participants')))); + + // Load the themed list headers based on the available data. + $headers = _privatemsg_list_headers(!empty($form['#data']), $columns); // sort the headers array based on the #weight property. - $headers = $form['#headers']; usort($headers, 'element_sort'); $themed_rows = array(); // Check if there is atleast a single thread. if ($has_posts) { - foreach ($form['#rows'] as $thread_id => $row) { + foreach ($form['#data'] as $thread_id => $data) { + // Theme the row. + $row = _privatemsg_list_thread($data); $data = array(); // Render the checkbox. $data[] = array('data' => drupal_render($form['threads'][$thread_id]), 'class' => 'privatemsg-list-select'); Index: privatemsg_filter/privatemsg_filter.module =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg_filter/privatemsg_filter.module,v retrieving revision 1.1.2.27 diff -u -p -r1.1.2.27 privatemsg_filter.module --- privatemsg_filter/privatemsg_filter.module 6 Nov 2009 13:06:26 -0000 1.1.2.27 +++ privatemsg_filter/privatemsg_filter.module 10 Nov 2009 19:26:58 -0000 @@ -153,6 +153,8 @@ function privatemsg_filter_form_private_ '#title' => t('Choose the default list option'), '#description' => t('Choose which of the two lists are shown by default when following the messages link.'), ); + // Add tags to the list of possible columns. + $form['privatemsg_listing']['privatemsg_display_fields']['#options']['tags'] = t('Tags'); $form['#submit'][] = 'privatemsg_filter_settings_submit'; } @@ -483,6 +485,21 @@ function privatemsg_filter_form_privatem $form += privatemsg_filter_dropdown($form_state, $form['#account']); } + $fields = array_filter(variable_get('privatemsg_display_fields', array('participants'))); + if (in_array('tags', $fields)) { + // Load thread id's of the current list. + $threads = array_keys($form['#data']); + + // Fetch all tags of those threads. + $query = _privatemsg_assemble_query(array('tags', 'privatemsg_filter'), $user, $threads, 3); + + // Add them to #data + $result = db_query($query['query']); + while ($tag = db_fetch_array($result)) { + $form['#data'][$tag['thread_id']]['tags'][$tag['tag_id']] = $tag['tag']; + } + } + $tags = privatemsg_filter_get_tags_data($user); if (privatemsg_user_access('filter private messages') && !empty($tags) && !empty($form['#data'])) { $options = array(); @@ -521,6 +538,43 @@ function privatemsg_filter_form_privatem } /** + * Define the header for the tags column. + * + * @see theme_privatemsg_list_header() + */ +function phptemplate_privatemsg_list_header__tags() { + return array( + 'data' => t('Tags'), + 'key' => 'tags', + 'class' => 'privatemsg-header-tags', + '#weight' => -42, + ); +} + + +/** + * Default theme pattern function to display tags. + * + * @see theme_privatemsg_list_field() + */ +function phptemplate_privatemsg_list_field__tags($thread) { + if (!empty($thread['tags'])) { + $tags = array(); + + foreach ($thread['tags'] as $tag_id => $tag) { + $tags[] = l(strlen($tag) > 15 ? substr($tag, 0, 13) . '...' : $tag, 'messages', array( + 'attributes' => array('title' => $tag), + 'query' => array('tags' => $tag) + )); + } + return array( + 'data' => implode(', ', $tags), + 'class' => 'privatemsg-list-tags', + ); + } +} + +/** * Form callback for adding a tag to threads. */ function privatemsg_filter_add_tag_submit($form, &$form_state) { @@ -617,7 +671,7 @@ function privatemsg_filter_form(&$form_s $thread_id = arg(2); // Get a list of current tags for this thread - $query = _privatemsg_assemble_query(array('tags', 'privatemsg_filter'), $user, $thread_id); + $query = _privatemsg_assemble_query(array('tags', 'privatemsg_filter'), $user, array($thread_id)); $results = db_query($query['query']); $count = db_result(db_query($query['count'])); $tags = ''; @@ -734,21 +788,23 @@ function privatemsg_filter_privatemsg_sq * @param $fragments * Query fragments array. * @param $user - * User object for whom we want the tags. Defaults to all users. - * @param $thread_id - * The thread_id - Only needed if we want the tags for a specific thread - * instead of all used tags on any thread. + * User object for whom we want the tags. + * @param $threads + * Array of thread ids, defaults to all threads of a user. + * @param $limit + * Limit the number of tags *per thread*. */ -function privatemsg_filter_sql_tags(&$fragments, $user = NULL, $thread_id = NULL) { +function privatemsg_filter_sql_tags(&$fragments, $user = NULL, $threads = NULL, $limit = NULL) { $fragments['primary_table'] = '{pm_tags} t'; $fragments['select'][] = 't.tag'; $fragments['select'][] = 't.tag_id'; $fragments['select'][] = 't.public'; - if (!empty($thread_id)) { + if (!empty($threads)) { + $fragments['select'][] = 'ti.thread_id'; $fragments['inner_join'][] = 'INNER JOIN {pm_tags_index} ti on ti.tag_id = t.tag_id'; - $fragments['where'][] = 'ti.thread_id = %d'; - $fragments['query_args']['where'][] = $thread_id; + $fragments['where'][] = 'ti.thread_id IN (' . db_placeholders($threads) . ')'; + $fragments['query_args']['where'] += $threads; } else { $fragments['select'][] = 'COUNT(ti.thread_id) as count'; @@ -761,7 +817,25 @@ function privatemsg_filter_sql_tags(&$fr $fragments['where'][] = 'ti.uid = %d'; $fragments['query_args']['where'][] = $user->uid; } - if (!empty($thread_id) || !empty($user)) { + + + // Only select n tags per thread (ordered per tag_id), see + // http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/. + // + // It does select how many tags for that thread/uid combination exist that + // have a lower tag_id and does only select those that have less than $limit. + // + // This should only have a very minor performance impact as most users won't + // tag a thread with 1000 different tags. + // + if ($limit) { + $fragments['where'][] = '(SELECT count(*) FROM {pm_tags_index} AS pmtic + WHERE pmtic.thread_id = ti.thread_id + AND pmtic.uid = ti.uid + AND pmtic.tag_id < ti.tag_id) < %d'; + $fragments['query_args']['where'][] = $limit; + } + elseif (!empty($thread_id) || !empty($user)) { $fragments['order_by'][] = 't.tag ASC'; } } Index: styles/privatemsg-list.css =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/styles/privatemsg-list.css,v retrieving revision 1.1.2.2 diff -u -p -r1.1.2.2 privatemsg-list.css --- styles/privatemsg-list.css 17 Jul 2009 00:32:05 -0000 1.1.2.2 +++ styles/privatemsg-list.css 10 Nov 2009 19:26:58 -0000 @@ -9,3 +9,11 @@ .privatemsg-list-count { text-align: center; } + +.privatemsg-list-subject { + min-width: 35%; +} + +.privatemsg-list-date { + min-width: 20%; +}