Index: privatemsg-list.js
===================================================================
RCS file: privatemsg-list.js
diff -N privatemsg-list.js
--- privatemsg-list.js	7 Dec 2009 16:41:54 -0000	1.1.2.1.2.2
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,11 +0,0 @@
-(function ($) {
-  Drupal.behaviors.hideButtons = {
-    attach: function (context) {
-      $("div.privatemsg-op-button").hide();
-
-      $('#privatemsg-list #edit-operation').change(function () {
-        $('#edit-submit').click();
-      });
-    }
-  }
-})(jQuery);
\ No newline at end of file
Index: privatemsg.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/privatemsg/privatemsg.module,v
retrieving revision 1.70.2.30.2.91.2.64.2.94
diff -u -p -r1.70.2.30.2.91.2.64.2.94 privatemsg.module
--- privatemsg.module	24 Nov 2010 20:10:42 -0000	1.70.2.30.2.91.2.64.2.94
+++ privatemsg.module	29 Nov 2010 17:52:19 -0000
@@ -1011,12 +1011,12 @@ function privatemsg_sql_list($account, $
     if (db_driver() == 'pgsql') {
       $query->addExpression("array_to_string(array(SELECT DISTINCT pmia.recipient
                                                           FROM {pm_index} pmia
-                                                          WHERE pmia.type = 'user' AND pmia.thread_id = pmi.thread_id), ',')", 'participants');
+                                                          WHERE pmia.type = 'user' AND pmia.thread_id = pmi.thread_id AND pmia.recipient <> :current), ',')", 'participants', array(':current' => $account->uid));
     }
     else {
       $query->addExpression("(SELECT GROUP_CONCAT(DISTINCT pmia.recipient SEPARATOR ',')
                                      FROM {pm_index} pmia
-                                     WHERE pmia.type = 'user' AND pmia.thread_id = pmi.thread_id)", 'participants');
+                                     WHERE pmia.type = 'user' AND pmia.thread_id = pmi.thread_id AND pmia.recipient <> :current)", 'participants', array(':current' => $account->uid));
     }
   }
   if (in_array('thread_started', $fields)) {
@@ -2166,10 +2166,12 @@ function privatemsg_privatemsg_thread_op
   );
   if (privatemsg_user_access('delete privatemsg')) {
     $operations['delete'] = array(
+      'label' => t('Delete'),
       'callback' => 'privatemsg_thread_change_delete',
       'callback arguments' => array('delete' => 1),
       'undo callback' => 'privatemsg_thread_change_delete',
       'undo callback arguments' => array('delete' => 0),
+      'button' => TRUE,
     );
   }
   return $operations;
Index: privatemsg.pages.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/privatemsg/privatemsg.pages.inc,v
retrieving revision 1.1.2.33
diff -u -p -r1.1.2.33 privatemsg.pages.inc
--- privatemsg.pages.inc	24 Nov 2010 20:09:44 -0000	1.1.2.33
+++ privatemsg.pages.inc	29 Nov 2010 17:52:22 -0000
@@ -20,48 +20,64 @@
  * @return
  *   The FAPI definitions for the thread action form.
  */
-function _privatemsg_action_form() {
+function _privatemsg_action_form($type) {
   $form = array(
-      '#type'        => 'fieldset',
-      '#title'       => t('Actions'),
       '#prefix'      => '<div class="container-inline">',
       '#suffix'      => '</div>',
-      '#collapsible' => TRUE,
-      '#collapsed'   => FALSE,
-      '#weight'      => 15,
+      '#weight'      => -5,
   );
-  if (privatemsg_user_access('delete privatemsg')) {
-    $form['delete'] = array(
-        '#type'   => 'submit',
-        '#value'  => t('Delete'),
-    );
-  }
   // Display all operations which have a label.
-  $options = array(0 => t('More actions...'));
-  foreach (module_invoke_all('privatemsg_thread_operations') as $operation => $array) {
-    if (isset($array['label'])) {
+  $operations = module_invoke_all('privatemsg_thread_operations', $type);
+  drupal_alter('privatemsg_thread_operations', $operations, $type);
+  foreach ($operations as $operation => $array) {
+    if (!empty($array['button'])) {
+      $form[$operation] = array(
+        '#type'   => 'submit',
+        '#value'  => $array['label'],
+        '#ajax' => array(
+          'callback' => 'privatemsg_list_js',
+          'wrapper' => 'privatemsg-list-form',
+          'effect' => 'fade',
+        ),
+      );
+    }
+    elseif (isset($array['label'])) {
       $options[$operation] = $array['label'];
     }
   }
-  $form['operation'] = array(
+  if (!empty($options)) {
+    array_unshift($options, t('Actions...'));
+    $form['operation'] = array(
       '#type'          => 'select',
       '#options'       => $options,
-      '#default_value' => 0,
-      // Execute the submit button if a operation has been selected.
-      '#attributes'    => array('onchange' => "(function ($) { $('#edit-submit').click() })(jQuery);"),
-  );
-  $form['submit'] = array(
-      '#prefix'     => '<div class="privatemsg-op-button">',
-      '#suffix'    => '</div>',
+      '#ajax' => array(
+        'callback' => 'privatemsg_list_js',
+        'wrapper' => 'privatemsg-list-form',
+        'effect' => 'fade',
+      ),
+      '#executes_submit_callback' => TRUE,
+    );
+    $form['submit'] = array(
       '#type'       => 'submit',
       '#value'      => t('Execute'),
-      '#submit'     => array('privatemsg_list_submit'),
-  );
-  // JS for hiding the execute button.
-  drupal_add_js(drupal_get_path('module', 'privatemsg') .'/privatemsg-list.js');
+      '#attributes' => array('class' => array('form-item')),
+      '#states' => array(
+        'visible' => array(
+          // This is never true, button is always hidden when JS is enabled.
+          ':input[name=operation]' => array('value' => 'fake'),
+        ),
+      ),
+    );
+  }
   return $form;
 }
 
+/**
+ * AJAX callback to return the form again.
+ */
+function privatemsg_list_js($form, $form_state) {
+  return $form['updated'];
+}
 
 function privatemsg_delete($form, $form_state, $thread, $message) {
   $form['pmid'] = array(
@@ -149,8 +165,15 @@ function privatemsg_list($form, &$form_s
   $headers = _privatemsg_list_headers($columns);
   uasort($headers, 'element_sort');
 
-  $form = array('#list_argument' => $argument);
-  $form['list'] = array(
+  $form = array(
+    '#list_argument' => $argument,
+    '#submit' => array('privatemsg_list_submit'),
+    'updated' => array(
+      '#prefix' => '<div id="privatemsg-list-form">',
+      '#suffix' => '</div>',
+    ),
+  );
+  $form['updated']['list'] = array(
     '#type' => 'tableselect',
     '#header' => $headers,
     '#options' => array(),
@@ -164,24 +187,21 @@ function privatemsg_list($form, &$form_s
   $i = 0;
   foreach ($query->execute() as $row) {
     // Store the raw row data.
-    $form['list']['#options'][$row->thread_id] = (array)$row;
+    $form['updated']['list']['#options'][$row->thread_id] = (array)$row;
     // Tableselect sorts the options, set a weight so that the order doesn't get
     // changed.
-    $form['list']['#options'][$row->thread_id]['#weight'] = $i++;
+    $form['updated']['list']['#options'][$row->thread_id]['#weight'] = $i++;
   }
 
-  if (!empty($form['list']['#options'])) {
-    $form['actions'] = _privatemsg_action_form();
+  if (!empty($form['updated']['list']['#options'])) {
+    $form['updated']['actions'] = _privatemsg_action_form($argument);
   }
 
   // Save the currently active account, used for actions.
   $form['account'] = array('#type' => 'value', '#value' => $account);
 
   // Define checkboxes, pager and theme
-  $form['pager'] = array('#theme' => 'pager', '#weight' => 20);
-
-  // Store the account for which the threads are displayed.
-  $form['#account'] = $account;
+  $form['updated']['pager'] = array('#theme' => 'pager', '#weight' => 20);
   return $form;
 }
 
@@ -194,7 +214,8 @@ function privatemsg_list($form, &$form_s
  */
 function privatemsg_list_submit($form, &$form_state) {
   // Load all available operation definitions.
-  $operations = module_invoke_all('privatemsg_thread_operations');
+  $operations = module_invoke_all('privatemsg_thread_operations', $form['#list_argument']);
+  drupal_alter('privatemsg_thread_operations', $operations, $for['#list_argument']);
 
   // Default "default" operation, which won't do anything.
   $operation = array('callback' => 0);
@@ -218,6 +239,9 @@ function privatemsg_list_submit($form, &
   if (!empty($operation['callback'])) {
     privatemsg_operation_execute($operation, $form_state['values']['list'], $form_state['values']['account']);
   }
+
+  $form_state['rebuild'] = TRUE;
+  $form_state['input'] = array();
 }
 
 
Index: privatemsg.theme.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/privatemsg/privatemsg.theme.inc,v
retrieving revision 1.1.2.7.2.13
diff -u -p -r1.1.2.7.2.13 privatemsg.theme.inc
--- privatemsg.theme.inc	6 Oct 2010 19:41:08 -0000	1.1.2.7.2.13
+++ privatemsg.theme.inc	29 Nov 2010 17:52:26 -0000
@@ -134,7 +134,12 @@ function theme_privatemsg_list_field__co
  */
 function theme_privatemsg_list_field__last_updated($variables) {
   $thread = $variables['thread'];
-  $field['data'] = format_date($thread['last_updated'], 'small');
+  if (REQUEST_TIME - $thread['last_updated'] < 86400 * 28) {
+    $field['data'] = t('@span ago', array('@span' => format_interval(REQUEST_TIME - $thread['last_updated'], 1)));
+  }
+  else {
+    $field['data'] = format_date($thread['last_updated'], 'small');
+  }
   $field['class'][] = 'privatemsg-list-date';
   return $field;
 }
Index: privatemsg_filter/privatemsg-filter-list.js
===================================================================
RCS file: privatemsg_filter/privatemsg-filter-list.js
diff -N privatemsg_filter/privatemsg-filter-list.js
--- privatemsg_filter/privatemsg-filter-list.js	7 Dec 2009 16:43:09 -0000	1.2.2.2
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,16 +0,0 @@
-(function ($) {
-  Drupal.behaviors.hideButtons = {
-    attach: function (context) {
-      $("div.privatemsg-tag-add-submit").hide();
-      $("div.privatemsg-tag-remove-submit").hide();
-
-      $('#privatemsg-list #edit-tag-add').change(function () {
-        $('#edit-tag-add-submit').click();
-      });
-
-      $('#privatemsg-list #edit-tag-remove').change(function () {
-        $('#edit-tag-remove-submit').click();
-      });
-    }
-  }
-})(jQuery);
\ No newline at end of file
Index: privatemsg_filter/privatemsg_filter.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/privatemsg/privatemsg_filter/privatemsg_filter.module,v
retrieving revision 1.1.2.17.2.31
diff -u -p -r1.1.2.17.2.31 privatemsg_filter.module
--- privatemsg_filter/privatemsg_filter.module	24 Nov 2010 20:09:44 -0000	1.1.2.17.2.31
+++ privatemsg_filter/privatemsg_filter.module	29 Nov 2010 17:52:31 -0000
@@ -506,49 +506,45 @@ function privatemsg_filter_create_get_qu
  */
 function privatemsg_filter_form_privatemsg_list_alter(&$form, $form_state) {
   global $user;
-  if (privatemsg_user_access('filter private messages') && !empty($form['list']['#options']) || privatemsg_filter_get_filter($user)) {
-    $form += privatemsg_filter_dropdown($form_state, $form['#account']);
+  if (privatemsg_user_access('filter private messages') && !empty($form['updated']['list']['#options']) || privatemsg_filter_get_filter($user)) {
+    $form += privatemsg_filter_dropdown($form_state, $form['account']['#value']);
   }
 
   $fields = array_filter(variable_get('privatemsg_display_fields', array('participants')));
-  if (privatemsg_user_access('tag private messages') && in_array('tags', $fields) && !empty($form['list']['#options'])) {
+  if (privatemsg_user_access('tag private messages') && in_array('tags', $fields) && !empty($form['updated']['list']['#options'])) {
     // Load thread id's of the current list.
-    $threads = array_keys($form['list']['#options']);
+    $threads = array_keys($form['updated']['list']['#options']);
 
     // Fetch all tags of those threads.
     $query = _privatemsg_assemble_query(array('tags', 'privatemsg_filter'), $user, $threads, 3);
 
     // Add them to tableselect options.
     foreach ($query->execute() as $tag) {
-      $form['list']['#options'][$tag->thread_id]['tags'][$tag->tag_id] = $tag->tag;
+      $form['updated']['list']['#options'][$tag->thread_id]['tags'][$tag->tag_id] = $tag->tag;
     }
     // Avoid notices for threads without tags.
-    foreach ($form['list']['#options'] as &$thread) {
+    foreach ($form['updated']['list']['#options'] as &$thread) {
       if (empty($thread['tags'])) {
         $thread['tags'] = array();
       }
     }
   }
 
-  if ($form['#list_argument'] == 'inbox' && !empty($form['list']['#options'])) {
-    $form['actions']['archive'] = array(
-      '#type'   => 'submit',
-      '#value'  => t('Archive'),
-      '#submit' => array('privatemsg_filter_archive_submit'),
-      '#weight' => -10,
+  if (privatemsg_user_access('tag private messages') && !empty( $form['updated']['list']['#options'])) {
+    $form['updated']['actions']['tag-add'] = array(
+       '#type'               => 'textfield',
+       '#size'               => 15,
+       '#autocomplete_path'  => 'messages/filter/tag-autocomplete',
     );
-  }
-
-  if (privatemsg_user_access('tag private messages') && !empty( $form['list']['#options'])) {
-    $form['actions']['tag-add'] = array(
-     '#type'               => 'textfield',
-     '#size'               => 15,
-     '#autocomplete_path'  => 'messages/filter/tag-autocomplete',
-    );
-    $form['actions']['tag-add-submit'] = array(
-        '#type'       => 'submit',
-        '#value'      => t('Apply Tag'),
-        '#submit'     => array('privatemsg_filter_add_tag_submit'),
+    $form['updated']['actions']['tag-add-submit'] = array(
+      '#type'       => 'submit',
+      '#value'      => t('Apply Tag'),
+      '#submit'     => array('privatemsg_filter_add_tag_submit'),
+      '#ajax' => array(
+        'callback' => 'privatemsg_list_js',
+        'wrapper' => 'privatemsg-list-form',
+        'effect' => 'fade',
+      ),
     );
     $tags = privatemsg_filter_get_tags_data($user);
     if (!empty($tags)) {
@@ -556,37 +552,49 @@ function privatemsg_filter_form_privatem
       foreach ($tags as $tag_id => $tag) {
         $options[$tag_id] = $tag;
       }
-      $form['actions']['tag-remove'] = array(
+      $form['updated']['actions']['tag-remove'] = array(
         '#type'          => 'select',
         '#options'       => $options,
         '#default_value' => 0,
+        '#ajax' => array(
+          'callback' => 'privatemsg_list_js',
+          'wrapper' => 'privatemsg-list-form',
+          'effect' => 'fade',
+        ),
+        '#submit'     => array('privatemsg_filter_remove_tag_submit'),
+        '#executes_submit_callback' => TRUE,
       );
-      $form['actions']['tag-remove-submit'] = array(
-        '#prefix'     => '<div class="privatemsg-tag-remove-submit">',
-        '#suffix'    => '</div>',
+      $form['updated']['actions']['tag-remove-submit'] = array(
         '#type'       => 'submit',
         '#value'      => t('Remove Tag'),
         '#submit'     => array('privatemsg_filter_remove_tag_submit'),
+        '#attributes' => array('class' => array('form-item')),
+        '#states' => array(
+          'visible' => array(
+            // This is never true, button is always hidden when JS is enabled.
+            ':input[name=operation]' => array('value' => 'fake'),
+          ),
+        ),
       );
     }
-
-    // JS for hiding the submit buttons.
-    drupal_add_js(drupal_get_path('module', 'privatemsg_filter') .'/privatemsg-filter-list.js');
   }
 }
 
 /**
  * Form callback for removing a tag to threads.
  */
-function privatemsg_filter_archive_submit($form, &$form_state) {
-  $operation = array(
-    'callback' => 'privatemsg_filter_remove_tags',
-    'callback arguments' => array('tag_id' => variable_get('privatemsg_filter_inbox_tag', '')),
-    'success message' => t('The messages have been archived.'),
-    'undo callback' => 'privatemsg_filter_add_tags',
-    'undo callback arguments' => array('tag_id' => variable_get('privatemsg_filter_inbox_tag', '')),
-  );
-  privatemsg_operation_execute($operation, $form_state['values']['list']);
+function privatemsg_filter_privatemsg_thread_operations($type) {
+  if ($type == 'inbox') {
+    $archive = array(
+      'label' => t('Archive'),
+      'callback' => 'privatemsg_filter_remove_tags',
+      'callback arguments' => array('tag_id' => variable_get('privatemsg_filter_inbox_tag', '')),
+      'success message' => t('The messages have been archived.'),
+      'undo callback' => 'privatemsg_filter_add_tags',
+      'undo callback arguments' => array('tag_id' => variable_get('privatemsg_filter_inbox_tag', '')),
+    );
+    return array('archive' => $archive);
+  }
 }
 
 /**
@@ -655,6 +663,8 @@ function privatemsg_filter_add_tag_submi
     'undo callback arguments' => array('tag_id' => $tag_ids),
   );
   privatemsg_operation_execute($operation, $form_state['values']['list']);
+  $form_state['rebuild'] = TRUE;
+  $form_state['input'] = array();
 }
 
 /**
@@ -669,6 +679,8 @@ function privatemsg_filter_remove_tag_su
     'undo callback arguments' => array('tag_id' => $form_state['values']['tag-remove']),
   );
   privatemsg_operation_execute($operation, $form_state['values']['list']);
+  $form_state['rebuild'] = TRUE;
+  $form_state['input'] = array();
 }
 
 /**
Index: styles/privatemsg-list.css
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/privatemsg/styles/privatemsg-list.css,v
retrieving revision 1.1.2.2.2.2
diff -u -p -r1.1.2.2.2.2 privatemsg-list.css
--- styles/privatemsg-list.css	9 Jul 2010 20:19:05 -0000	1.1.2.2.2.2
+++ styles/privatemsg-list.css	29 Nov 2010 17:52:33 -0000
@@ -17,3 +17,7 @@
 .privatemsg-list-date {
   min-width: 20%;
 }
+
+form#privatemsg-list div.container-inline * {
+  margin: 0 2px;
+}
