? .cvsignore ? privatemsg_tags_list.patch ? translations Index: privatemsg.module =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg.module,v retrieving revision 1.70.2.30.2.91.2.60 diff -u -p -r1.70.2.30.2.91.2.60 privatemsg.module --- privatemsg.module 17 Jul 2009 00:32:05 -0000 1.70.2.30.2.91.2.60 +++ privatemsg.module 18 Jul 2009 00:46:37 -0000 @@ -490,22 +490,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); Index: privatemsg.theme.inc =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/Attic/privatemsg.theme.inc,v retrieving revision 1.1.2.7 diff -u -p -r1.1.2.7 privatemsg.theme.inc --- privatemsg.theme.inc 17 Jul 2009 00:32:05 -0000 1.1.2.7 +++ privatemsg.theme.inc 18 Jul 2009 00:46:37 -0000 @@ -239,18 +239,30 @@ 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'); + 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'])]); + } + + // Load the themed list headers based on the available data. + $headers = _privatemsg_list_headers(!empty($form['#data']), $keys); // 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[] = drupal_render($form['threads'][$thread_id]); Index: privatemsg_filter/privatemsg_filter.module =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg_filter/privatemsg_filter.module,v retrieving revision 1.1.2.17 diff -u -p -r1.1.2.17 privatemsg_filter.module --- privatemsg_filter/privatemsg_filter.module 11 Jul 2009 13:37:31 -0000 1.1.2.17 +++ privatemsg_filter/privatemsg_filter.module 18 Jul 2009 00:46:38 -0000 @@ -305,14 +305,71 @@ function privatemsg_filter_create_get_qu } /** + * Implement hook_form_alter. + * + * Add tags to the list of possible columns. + */ +function privatemsg_filter_form_private_message_settings_alter(&$form, &$form_state) { + $form['privatemsg_listing']['privatemsg_display_fields']['#options']['tags'] = t('Tags'); +} + +/** * Implementation of hook_form_alter() to add a filter widget to the message listing pages. */ -function privatemsg_filter_form_privatemsg_list_alter(&$form, $form_state) { +function privatemsg_filter_form_privatemsg_list_alter(&$form, &$form_state) { + global $user; if (privatemsg_user_access('filter private messages')) { $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('used_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']; + } + } + } + +/** + * 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($tag, 'messages', array('query' => 'tags=' . $tag)); + } + return array( + 'data' => implode(', ', $tags), + 'class' => 'privatemsg-list-tags', + ); + } +} /** * Hook into the query builder to add the tagging info to the correct query @@ -383,7 +440,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('used_tags', 'privatemsg_filter'), $user, $thread_id); + $query = _privatemsg_assemble_query(array('used_tags', 'privatemsg_filter'), $user, array($thread_id)); $results = db_query($query['query']); $count = db_result(db_query($query['count'])); $tags = ''; @@ -515,25 +572,47 @@ function privatemsg_filter_privatemsg_sq * Query definition to get the tags in use by the specified user. * * @param $fragments - * Query fragments array. + * Query fragments array. * @param $user - * User object for whom we want the tags. - * @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_used_tags(&$fragments, $user, $thread_id = NULL) { +function privatemsg_filter_sql_used_tags(&$fragments, $user, $threads = array(), $limit = NULL) { $fragments['primary_table'] = '{pm_tags} t'; $fragments['select'][] = 't.tag'; $fragments['select'][] = 't.tag_id'; + $fragments['select'][] = 'ti.thread_id'; + $fragments['inner_join'][] = 'INNER JOIN {pm_tags_index} ti on ti.tag_id = t.tag_id'; - if (!empty($thread_id)) { - $fragments['where'][] = 'ti.thread_id = %d'; - $fragments['query_args']['where'][] = $thread_id; + if (!empty($threads)) { + $fragments['where'][] = 'ti.thread_id IN (' . db_placeholders($threads) . ')'; + $fragments['query_args']['where'] += $threads; } $fragments['where'][] = 'ti.uid = %d'; $fragments['query_args']['where'][] = $user->uid; - $fragments['order_by'][] = 't.tag ASC'; + // 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; + } + else { + $fragments['order_by'][] = 't.tag ASC'; + } } /**