diff --git a/mail/base/content/folderDisplay.js b/mail/base/content/folderDisplay.js index 3390648bd4..0ab37f0f0b 100644 --- a/mail/base/content/folderDisplay.js +++ b/mail/base/content/folderDisplay.js @@ -2298,6 +2298,38 @@ FolderDisplayWidget.prototype = { }); }, + /** + * The maximum number of messages canMarkThreadAsRead will look through. + * If the number exceeds this limit, as a performance measure, we return + * true rather than looking looking through the messages and possible + * submessages. + */ + MAX_COUNT_FOR_MARK_THREAD: 1000, + + /** + * Check if the thread for the currently-selected message can be marked as + * read. A thread can be marked as read if and only if it has at least one + * unread message. + */ + get canMarkThreadAsRead() { + let hasUnread = this.displayedFolder.getNumUnread(false) > 0; + if (this.displayedFolder && hasUnread) { + // If the messages limit is exceeded we bail out early and return true. + if (this.selectedIndices.length > this.MAX_COUNT_FOR_MARK_THREAD) { + return true; + } + + for (let i of this.selectedIndices) { + if ( + this.view.dbView.getThreadContainingIndex(i).numUnreadChildren > 0 + ) { + return true; + } + } + } + return false; + }, + /** * @return true if all the selected messages can be deleted from their * folders, false otherwise. diff --git a/mail/base/content/mail3PaneWindowCommands.js b/mail/base/content/mail3PaneWindowCommands.js index 949b60d6b4..9caa8c586a 100644 --- a/mail/base/content/mail3PaneWindowCommands.js +++ b/mail/base/content/mail3PaneWindowCommands.js @@ -478,8 +478,9 @@ var DefaultController = { case "cmd_tag8": case "cmd_tag9": case "cmd_toggleRead": - case "cmd_markThreadAsRead": return gFolderDisplay.selectedCount > 0; + case "cmd_markThreadAsRead": + return gFolderDisplay.canMarkThreadAsRead; case "cmd_markAsRead": return CanMarkMsgAsRead(true); case "cmd_markAsUnread": diff --git a/mail/base/content/messageWindow.js b/mail/base/content/messageWindow.js index f6263e54f9..2e065eada8 100644 --- a/mail/base/content/messageWindow.js +++ b/mail/base/content/messageWindow.js @@ -443,6 +443,7 @@ function delayedOnLoadMessageWindow() { SetupCommandUpdateHandlers(); gMessageDisplay = new StandaloneMessageDisplayWidget(); + // eslint-disable-next-line no-global-assign gFolderDisplay = new StandaloneFolderDisplayWidget(gMessageDisplay); gFolderDisplay.msgWindow = msgWindow; gFolderDisplay.messenger = messenger; @@ -1133,7 +1134,6 @@ var MessageWindowController = { case "cmd_tag8": case "cmd_tag9": case "button_mark": - case "cmd_markThreadAsRead": case "cmd_markReadByDate": case "cmd_viewAllHeader": case "cmd_viewNormalHeader": @@ -1142,6 +1142,8 @@ var MessageWindowController = { return true; case "cmd_markAllRead": return false; + case "cmd_markThreadAsRead": + return gFolderDisplay.canMarkThreadAsRead; case "cmd_markAsRead": return CanMarkMsgAsRead(true); case "cmd_markAsUnread": diff --git a/mail/test/browser/folder-display/browser_messageCommands.js b/mail/test/browser/folder-display/browser_messageCommands.js index 53145606d2..2573c2c41c 100644 --- a/mail/test/browser/folder-display/browser_messageCommands.js +++ b/mail/test/browser/folder-display/browser_messageCommands.js @@ -308,6 +308,69 @@ add_task(function test_mark_all_read() { Assert.ok(allReadDisabled, "Mark All Read menu item should be disabled!"); }); +add_task(function test_mark_thread_as_read() { + let unreadThreadFolder = create_folder("UnreadThreadFolder"); + add_sets_to_folders([unreadThreadFolder], [create_thread(3)]); + be_in_folder(unreadThreadFolder); + make_display_threaded(); + + let serviceState = Services.prefs.getBoolPref( + "mailnews.mark_message_read.auto" + ); + if (serviceState) { + // If mailnews.mark_message_read.auto is true, then we set it to false. + Services.prefs.setBoolPref("mailnews.mark_message_read.auto", false); + } + + // Make sure Mark Thread as Read is enabled with >0 messages in thread unread. + right_click_on_row(0); + wait_for_popup_to_open(mc.e("mailContext")); + mc.click_menus_in_sequence(mc.e("mailContext"), [{ id: "mailContext-mark" }]); + + let markThreadAsReadDisabled = mc.e("mailContext-markThreadAsRead").disabled; + Assert.ok( + !markThreadAsReadDisabled, + "Mark Thread as read menu item should not be disabled!" + ); + + // Make sure messages are read when Mark Thread as Read is clicked. + right_click_on_row(0); + wait_for_popup_to_open(mc.e("mailContext")); + mc.click_menus_in_sequence(mc.e("mailContext"), [ + { id: "mailContext-mark" }, + { id: "mailContext-markThreadAsRead" }, + ]); + close_popup(mc, mc.eid("mailContext")); + + let curMessage = select_click_row(0); + Assert.ok(curMessage.isRead, "Message should have been marked read!"); + + // Make sure Mark Thread as Read is now disabled with all messages read. + right_click_on_row(0); + wait_for_popup_to_open(mc.e("mailContext")); + mc.click_menus_in_sequence(mc.e("mailContext"), [{ id: "mailContext-mark" }]); + + markThreadAsReadDisabled = mc.e("mailContext-markThreadAsRead").disabled; + Assert.ok( + markThreadAsReadDisabled, + "Mark Thread as read menu item should be disabled!" + ); + + // Make sure that adding an unread message enables Mark Thread as Read once more. + curMessage.markRead(false); + right_click_on_row(0); + wait_for_popup_to_open(mc.e("mailContext")); + mc.click_menus_in_sequence(mc.e("mailContext"), [{ id: "mailContext-mark" }]); + + markThreadAsReadDisabled = mc.e("mailContext-markThreadAsRead").disabled; + Assert.ok( + !markThreadAsReadDisabled, + "Mark Thread as read menu item should not be disabled!" + ); + + Services.prefs.setBoolPref("mailnews.mark_message_read.auto", true); +}); + add_task(function test_shift_delete_prompt() { be_in_folder(shiftDeleteFolder); let curMessage = select_click_row(0);