Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.321
diff -u -d -F^\s*function -r1.321 theme.inc
--- includes/theme.inc	17 Nov 2006 06:53:31 -0000	1.321
+++ includes/theme.inc	17 Nov 2006 22:11:23 -0000
@@ -779,6 +779,16 @@ function theme_table($header, $rows, $at
 }
 
 /**
+ * Returns a header cell for tables that have a select all functionality.
+ */
+function theme_table_select_header_cell() {
+  drupal_add_js(array('tableSelect' => array('selectAll' => t('Select all rows in this table'), 'selectNone' => t('Deselect all rows in this table'))), 'setting');
+  drupal_add_js('misc/tableselect.js');
+  
+  return array('class' => 'select-all');
+}
+
+/**
  * Return a themed sort icon.
  *
  * @param $style
Index: misc/tableselect.js
===================================================================
RCS file: misc/tableselect.js
diff -N misc/tableselect.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ misc/tableselect.js	17 Nov 2006 22:11:25 -0000
@@ -0,0 +1,75 @@
+// $Id: $
+
+Drupal.tableSelect = function() {
+  // Keep track of the table, which checkbox is checked and alias the settings.
+  var table = this, lastChecked, settings = Drupal.settings.tableSelect;
+  
+  // Store the select all checkbox in a variable as we need it quite often
+  var checkAll = $('<input type="checkbox" class="form-checkbox" title="'+ settings.selectAll +'" />').click(function() {
+    // Loop through all checkboxes and set their state to the select all checkbox' state
+    checkboxes.each(function() {
+      this.checked = checkAll[0].checked;
+      // Either add or remove the selected class based on the state of the check all checkbox.
+      $(this).parents('tr:first')[ this.checked ? 'addClass' : 'removeClass' ]('selected');
+    });
+    // Update the title and the state of the check all box.
+    checkAll.attr('title', checkAll[0].checked ? settings.selectNone : settings.selectAll);
+  });
+  
+  // Find all <th> with class select-all, and insert the check all checkbox
+  $('th.select-all', table).prepend(checkAll);
+
+  // For each of the checkboxes within the table
+  var checkboxes = $('input:checkbox', table).not(checkAll).click(function(e) {
+    // Either add or remove the selected class based on the state of the check all checkbox.
+    $(this).parents('tr:first')[ this.checked ? 'addClass' : 'removeClass' ]('selected');
+    
+    // If this is a shift click, we need to highlight everything in the range.
+    // Also make sure that we are actually checking checkboxes over a range and
+    // that a checkbox has been checked or unchecked before.
+    if (e.shiftKey && lastChecked && lastChecked != e.target) {
+      // We use the checkbox's parent TR to do our range searching.
+      Drupal.tableSelectRange($(e.target).parents('tr')[0], $(lastChecked).parents('tr')[0], e.target.checked);
+    }
+
+    // If all checkboxes are checked, make sure the select-all one is checked too, otherwise keep unchecked.
+    checkAll[0].checked = (checkboxes.length == $(checkboxes).filter(':checked').length);
+    // Set the title to the current action.
+    checkAll.attr('title', checkAll[0].checked ? settings.selectNone : settings.selectAll);
+
+    // Keep track of the last checked checkbox.
+    lastChecked = e.target;
+  });
+}
+
+Drupal.tableSelectRange = function(from, to, state) {
+  // We determine the looping mode based on the the order of from and to.
+  var mode = from.rowIndex > to.rowIndex ? 'previousSibling' : 'nextSibling';
+
+  // Traverse through the sibling nodes.
+  for (var i = from[mode]; i; i = i[mode]) {
+    // Make sure that we're only dealing with elements.
+    if (i.nodeType != 1) continue;
+
+    if (to.nodeType) {
+      // If we are at the end of the range, stop.
+      if (i == to) break;
+    } 
+    // A faster alternative to doing $(i).filter(to).length
+    else if (jQuery.filter(to, [i]).r.length) break;
+
+    // Either add or remove the selected class based on the state of the target checkbox.
+    $(i)[ state ? 'addClass' : 'removeClass' ]('selected');
+    $('input:checkbox', i).each(function() {
+      this.checked = state;
+    });
+  }
+}
+
+
+// Global Killswitch
+if (Drupal.jsEnabled) {
+  $(document).ready(function() {
+    $('table[th.select-all]').each(Drupal.tableSelect);
+  });
+}
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.496
diff -u -d -F^\s*function -r1.496 comment.module
--- modules/comment/comment.module	12 Nov 2006 00:11:15 -0000	1.496
+++ modules/comment/comment.module	17 Nov 2006 22:11:38 -0000
@@ -1044,7 +1044,7 @@ function comment_admin_overview($type = 
   // load the comments that we want to display
   $status = ($type == 'approval') ? COMMENT_NOT_PUBLISHED : COMMENT_PUBLISHED;
   $form['header'] = array('#type' => 'value', '#value' => array(
-    NULL,
+    theme_table_select_header_cell(),
     array('data' => t('Subject'), 'field' => 'subject'),
     array('data' => t('Author'), 'field' => 'name'),
     array('data' => t('Time'), 'field' => 'timestamp', 'sort' => 'desc'),
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.731
diff -u -d -F^\s*function -r1.731 node.module
--- modules/node/node.module	17 Nov 2006 07:01:38 -0000	1.731
+++ modules/node/node.module	17 Nov 2006 22:11:57 -0000
@@ -1533,7 +1533,7 @@ function node_admin_nodes() {
  */
 function theme_node_admin_nodes($form) {
   // Overview table:
-  $header = array(NULL, t('Title'), t('Type'), t('Author'), t('Status'), t('Operations'));
+  $header = array(theme_table_select_header_cell(), t('Title'), t('Type'), t('Author'), t('Status'), t('Operations'));
 
   $output .= drupal_render($form['options']);
   if (isset($form['title']) && is_array($form['title'])) {
Index: modules/system/system.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.css,v
retrieving revision 1.14
diff -u -d -F^\s*function -r1.14 system.css
--- modules/system/system.css	24 Oct 2006 19:36:52 -0000	1.14
+++ modules/system/system.css	17 Nov 2006 22:12:00 -0000
@@ -325,3 +325,10 @@
   display: block;
   padding: 1.5em 0 .5em;
 }
+
+/*
+** To be used with tableselect.js
+*/
+tr.selected td {
+  background: #ffc;
+}
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.711
diff -u -d -F^\s*function -r1.711 user.module
--- modules/user/user.module	16 Nov 2006 09:01:55 -0000	1.711
+++ modules/user/user.module	17 Nov 2006 22:12:20 -0000
@@ -2029,7 +2029,7 @@ function user_admin_account() {
 function theme_user_admin_account($form) {
   // Overview table:
   $header = array(
-    array(),
+    theme_table_select_header_cell(),
     array('data' => t('Username'), 'field' => 'u.name'),
     array('data' => t('Status'), 'field' => 'u.status'),
     t('Roles'),
