Index: wp-includes/script-loader.php
===================================================================
--- wp-includes/script-loader.php	(revision 10193)
+++ wp-includes/script-loader.php	(working copy)
@@ -161,7 +161,7 @@
 			'strong' => __('Strong'),
 			'l10n_print_after' => 'try{convertEntities(pwsL10n);}catch(e){};'
 		) );
-		$scripts->add( 'admin-comments', '/wp-admin/js/edit-comments.js', array('wp-lists', 'jquery-ui-resizable', 'quicktags'), '20081210' );
+		$scripts->add( 'admin-comments', '/wp-admin/js/edit-comments.js', array('wp-lists', 'jquery-ui-resizable', 'quicktags'), '20081211' );
 		$scripts->localize( 'admin-comments', 'adminCommentsL10n', array(
 			'hotkeys_highlight_first' => isset($_GET['hotkeys_highlight_first']),
 			'hotkeys_highlight_last' => isset($_GET['hotkeys_highlight_last'])
Index: wp-admin/edit-comments.php
===================================================================
--- wp-admin/edit-comments.php	(revision 10193)
+++ wp-admin/edit-comments.php	(working copy)
@@ -227,9 +227,12 @@
 <div class="tablenav-pages"><?php $page_links_text = sprintf( '<span class="displaying-num">' . __( 'Displaying %s&#8211;%s of %s' ) . '</span>%s',
 	number_format_i18n( $start + 1 ),
 	number_format_i18n( min( $page * $comments_per_page, $total ) ),
-	number_format_i18n( $total ),
+	'<span class="total-type-count">' . number_format_i18n( $total ) . '</span>',
 	$page_links
 ); echo $page_links_text; ?></div>
+<input type="hidden" name="_total" value="<?php echo $total; ?>" />
+<input type="hidden" name="_per_page" value="<?php echo $comments_per_page; ?>" />
+<input type="hidden" name="_page" value="<?php echo $page; ?>" />
 <?php endif; ?>
 
 <div class="alignleft actions">
Index: wp-admin/admin-ajax.php
===================================================================
--- wp-admin/admin-ajax.php	(revision 10193)
+++ wp-admin/admin-ajax.php	(working copy)
@@ -63,24 +63,85 @@
 endswitch;
 endif;
 
+/**
+ * Sends back current comment total and new page links if they need to be updated.
+ *
+ * Contrary to normal success AJAX response ("1"), die with time() on success.
+ *
+ * @since 2.7
+ *
+ * @param int $comment_id
+ * @return die
+ */
+function _wp_ajax_delete_comment_response( $comment_id ) {
+	$total = (int) @$_POST['_total'];
+	$per_page = (int) @$_POST['_per_page'];
+	$page = (int) @$_POST['_page'];
+	$url = clean_url( @$_POST['_url'], null, 'url' );
+	// JS didn't send us everything we need to know.  Just die with success message
+	if ( !$total || !$per_page || !$page || !$url )
+		die( (string) time() );
+
+	if ( --$total < 0 ) // Take the total from POST and decrement it (since we just deleted one)
+		$total = 0;
+
+	if ( 0 != $total % $per_page && 1 != mt_rand( 1, $per_page ) ) // Only do the expensive stuff on a page-break, and about 1 other time per page
+		die( (string) time() );
+
+	$status = 'total_comments'; // What type of comment count are we looking for?
+	$parsed = parse_url( $url );
+	if ( isset( $parsed['query'] ) ) {
+		parse_str( $parsed['query'], $query_vars );
+		if ( !empty( $query_vars['comment_status'] ) )
+			$status = $query_vars['comment_status'];
+	}
+
+	$comment_count = wp_count_comments();
+	$time = time(); // The time since the last comment count
+
+	if ( isset( $comment_count->$status ) ) // We're looking for a known type of comment count
+		$total = $comment_count->$status;
+	// else use the decremented value from above
+
+	$page_links = paginate_links( array(
+		'base' => add_query_arg( 'apage', '%#%', $url ),
+		'format' => '',
+		'prev_text' => __('&laquo;'),
+		'next_text' => __('&raquo;'),
+		'total' => ceil($total / $per_page),
+		'current' => $page
+	) );
+	$x = new WP_Ajax_Response( array(
+		'what' => 'comment',
+		'id' => $comment_id, // here for completeness - not used
+		'supplemental' => array(
+			'pageLinks' => $page_links,
+			'total' => $total,
+			'time' => $time
+		)
+	) );
+	$x->send();
+}
+
 $id = isset($_POST['id'])? (int) $_POST['id'] : 0;
 switch ( $action = $_POST['action'] ) :
-case 'delete-comment' :
+case 'delete-comment' : // On success, die with time() instead of 1
 	check_ajax_referer( "delete-comment_$id" );
 	if ( !$comment = get_comment( $id ) )
-		die('1');
+		die( (string) time() );
 	if ( !current_user_can( 'edit_post', $comment->comment_post_ID ) )
 		die('-1');
 
 	if ( isset($_POST['spam']) && 1 == $_POST['spam'] ) {
 		if ( 'spam' == wp_get_comment_status( $comment->comment_ID ) )
-			die('1');
+			die( (string) time() );
 		$r = wp_set_comment_status( $comment->comment_ID, 'spam' );
 	} else {
 		$r = wp_delete_comment( $comment->comment_ID );
 	}
-
-	die( $r ? '1' : '0' );
+	if ( $r ) // Decide if we need to send back '1' or a more complicated response including page links and comment counts
+		_wp_ajax_delete_comment_response( $comment->comment_ID );
+	die( '0' );
 	break;
 case 'delete-cat' :
 	check_ajax_referer( "delete-category_$id" );
@@ -195,7 +256,7 @@
 	else
 		die('0');
 	break;
-case 'dim-comment' :
+case 'dim-comment' : // On success, die with time() instead of 1
 	if ( !$comment = get_comment( $id ) )
 		die('0');
 
@@ -206,18 +267,21 @@
 
 	$current = wp_get_comment_status( $comment->comment_ID );
 	if ( $_POST['new'] == $current )
-		die('1');
+		die( (string) time() );
 
+	$r = 0;
 	if ( in_array( $current, array( 'unapproved', 'spam' ) ) ) {
 		check_ajax_referer( "approve-comment_$id" );
 		if ( wp_set_comment_status( $comment->comment_ID, 'approve' ) )
-			die('1');
+			$r = 1;
 	} else {
 		check_ajax_referer( "unapprove-comment_$id" );
 		if ( wp_set_comment_status( $comment->comment_ID, 'hold' ) )
-			die('1');
+			$r = 1;
 	}
-	die('0');
+	if ( $r ) // Decide if we need to send back '1' or a more complicated response including page links and comment counts
+		_wp_ajax_delete_comment_response( $comment->comment_ID );
+	die( '0' );
 	break;
 case 'add-category' : // On the Fly
 	check_ajax_referer( $action );
Index: wp-admin/js/edit-comments.js
===================================================================
--- wp-admin/js/edit-comments.js	(revision 10193)
+++ wp-admin/js/edit-comments.js	(working copy)
@@ -2,6 +2,11 @@
 (function($) {
 
 setCommentsList = function() {
+	var totalInput = $('#comments-form .tablenav :input[name="_total"]');
+	var perPageInput = $('#comments-form .tablenav :input[name="_per_page"]');
+	var pageInput = $('#comments-form .tablenav :input[name="_page"]');
+	var lastConfidentTime = 0;
+
 	var dimAfter = function( r, settings ) {
 		var c = $('#' + settings.element);
 
@@ -25,6 +30,36 @@
 		});
 	};
 
+	// Send current total, page, per_page and url
+	var delBefore = function( settings ) {
+		settings.data._total = totalInput.val();
+		settings.data._per_page = perPageInput.val();
+		settings.data._page = pageInput.val();
+		settings.data._url = document.location.href;
+		return settings;
+	};
+
+	/* Updates the current total (as displayed visibly)
+	*/
+	var updateTotalCount = function( total, time, setConfidentTime ) {
+		if ( time < lastConfidentTime ) {
+			return;
+		}
+		totalInput.val( total.toString() );
+		if ( setConfidentTime ) {
+			lastConfidentTime = time;
+		}
+		$('span.total-type-count').each( function() {
+			var a = $(this);
+			var n = totalInput.val().toString();
+			if ( n.length > 3 )
+				n = n.substr(0, n.length-3)+' '+n.substr(-3);
+			a.html(n);
+		});
+
+	};
+
+	// In admin-ajax.php, we send back the unix time stamp instead of 1 on success
 	var delAfter = function( r, settings ) {
 		$('span.pending-count').each( function() {
 			var a = $(this);
@@ -44,7 +79,7 @@
 			a.html(n);
 		});
 
-		$('span.spam-count' ).each( function() {
+		$('span.spam-count').each( function() {
 			var a = $(this);
 			var n = a.html().replace(/[ ,.]+/g, '');
 			n = parseInt(n,10);
@@ -61,6 +96,24 @@
 			a.html(n);
 		});
 
+		
+		// XML response
+		if ( ( 'object' == typeof r ) && lastConfidentTime < settings.parsed.responses[0].supplemental.time ) {
+			// Set the total to the known good value (even if this value is a little old, newer values should only be a few less, and so shouldn't mess up the page links)
+			updateTotalCount( settings.parsed.responses[0].supplemental.total, settings.parsed.responses[0].supplemental.time, true );
+			if ( $.trim( settings.parsed.responses[0].supplemental.pageLinks ) ) {
+				$('.tablenav-pages').find( '.page-numbers' ).remove().end().append( $( settings.parsed.responses[0].supplemental.pageLinks ) );
+			} else if ( 'undefined' != typeof settings.parsed.responses[0].supplemental.pageLinks ) {
+				$('.tablenav-pages').find( '.page-numbers' ).remove();
+			}
+		} else {
+			// Decrement the total
+			var total = parseInt( totalInput.val(), 10 );
+			if ( total-- < 0 )
+				total = 0;
+			updateTotalCount( total, r, false );
+		}
+
 		if ( theExtraList.size() == 0 || theExtraList.children().size() == 0 ) {
 			return;
 		}
@@ -70,7 +123,7 @@
 	};
 
 	theExtraList = $('#the-extra-comment-list').wpList( { alt: '', delColor: 'none', addColor: 'none' } );
-	theList = $('#the-comment-list').wpList( { alt: '', dimAfter: dimAfter, delAfter: delAfter, addColor: 'none' } );
+	theList = $('#the-comment-list').wpList( { alt: '', delBefore: delBefore, dimAfter: dimAfter, delAfter: delAfter, addColor: 'none' } );
 
 };
 
