Files
boc-uxp/mail/base/content/mail3PaneWindowCommands.js
T
2020-08-08 11:09:26 +08:00

1387 lines
45 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Functionality for the main application window (aka the 3pane) usually
* consisting of folder pane, thread pane and message pane.
*/
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource:///modules/MailUtils.js");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/PluralForm.jsm");
// Controller object for folder pane
var FolderPaneController =
{
supportsCommand: function(command)
{
switch ( command )
{
case "cmd_delete":
case "cmd_shiftDelete":
case "button_delete":
case "button_shiftDelete":
// Even if the folder pane has focus, don't do a folder delete if
// we have a selected message, but do a message delete instead.
// Return false here supportsCommand and let the command fall back
// to the DefaultController.
if (gFolderDisplay.selectedCount != 0)
return false;
// else fall through
case "cmd_cut":
case "cmd_copy":
case "cmd_paste":
return true;
default:
return false;
}
},
isCommandEnabled: function(command)
{
switch ( command )
{
case "cmd_cut":
case "cmd_copy":
case "cmd_paste":
return false;
case "cmd_delete":
case "cmd_shiftDelete":
case "button_delete":
case "button_shiftDelete":
{
// Make sure the button doesn't show "Undelete" for folders.
UpdateDeleteToolbarButton();
let folders = gFolderTreeView.getSelectedFolders();
if (folders.length) {
// XXX Figure out some better way/place to update the folder labels.
UpdateDeleteLabelsFromFolderCommand(folders[0], command);
return CanDeleteFolder(folders[0]) && folders[0].isCommandEnabled(command);
}
else
return false;
}
default:
return false;
}
},
doCommand: function(command)
{
// if the user invoked a key short cut then it is possible that we got here for a command which is
// really disabled. kick out if the command should be disabled.
if (!this.isCommandEnabled(command)) return;
switch ( command )
{
case "cmd_delete":
case "cmd_shiftDelete":
case "button_delete":
case "button_shiftDelete":
case "cmd_deleteFolder":
gFolderTreeController.deleteFolder();
break;
}
},
onEvent: function(event)
{
}
};
function UpdateDeleteLabelsFromFolderCommand(folder, command)
{
if (command != "cmd_delete")
return;
if (folder.getFlag(nsMsgFolderFlags.Virtual)) {
goSetMenuValue(command, "valueFolder");
}
else if (folder.server.type == "nntp") {
goSetMenuValue(command, "valueNewsgroup");
goSetAccessKey(command, "valueNewsgroupAccessKey");
}
else {
goSetMenuValue(command, "valueFolder");
}
}
// DefaultController object (handles commands when one of the trees does not have focus)
var DefaultController =
{
supportsCommand: function(command)
{
switch ( command )
{
case "cmd_createFilterFromPopup":
case "cmd_archive":
case "button_archive":
case "cmd_newMessage":
case "cmd_reply":
case "button_reply":
case "cmd_replySender":
case "cmd_replyGroup":
case "button_followup":
case "cmd_replyall":
case "button_replyall":
case "cmd_replylist":
case "button_replylist":
case "cmd_forward":
case "button_forward":
case "cmd_forwardInline":
case "cmd_forwardAttachment":
case "cmd_editAsNew":
case "cmd_editDraftMsg":
case "cmd_createFilterFromMenu":
case "cmd_delete":
case "cmd_cancel":
case "cmd_deleteFolder":
case "button_delete":
case "button_junk":
case "button_showconversation":
case "cmd_shiftDelete":
case "button_shiftDelete":
case "button_nextMsg":
case "cmd_nextMsg":
case "button_next":
case "cmd_nextUnreadMsg":
case "cmd_nextFlaggedMsg":
case "cmd_nextUnreadThread":
case "button_previousMsg":
case "cmd_previousMsg":
case "button_previous":
case "cmd_previousUnreadMsg":
case "cmd_previousFlaggedMsg":
case "button_goForward":
case "button_goBack":
case "cmd_goForward":
case "cmd_goBack":
case "cmd_goStartPage":
case "cmd_undoCloseTab":
case "cmd_viewClassicMailLayout":
case "cmd_viewWideMailLayout":
case "cmd_viewVerticalMailLayout":
case "cmd_toggleFolderPane":
case "cmd_toggleFolderPaneCols":
case "cmd_toggleMessagePane":
case "cmd_viewAllMsgs":
case "cmd_viewUnreadMsgs":
case "cmd_viewThreadsWithUnread":
case "cmd_viewWatchedThreadsWithUnread":
case "cmd_viewIgnoredThreads":
case "cmd_undo":
case "cmd_redo":
case "cmd_expandAllThreads":
case "cmd_collapseAllThreads":
case "cmd_renameFolder":
case "cmd_sendUnsentMsgs":
case "cmd_subscribe":
case "cmd_openMessage":
case "cmd_openConversation":
case "button_print":
case "cmd_print":
case "cmd_printpreview":
case "cmd_printSetup":
case "cmd_saveAsFile":
case "cmd_saveAsTemplate":
case "cmd_properties":
case "cmd_viewPageSource":
case "cmd_setFolderCharset":
case "cmd_reload":
case "button_getNewMessages":
case "cmd_getNewMessages":
case "cmd_getMsgsForAuthAccounts":
case "cmd_getNextNMessages":
case "cmd_find":
case "cmd_findAgain":
case "cmd_findPrevious":
case "cmd_search":
case "button_mark":
case "cmd_tag":
case "cmd_addTag":
case "cmd_manageTags":
case "cmd_removeTags":
case "cmd_tag1":
case "cmd_tag2":
case "cmd_tag3":
case "cmd_tag4":
case "cmd_tag5":
case "cmd_tag6":
case "cmd_tag7":
case "cmd_tag8":
case "cmd_tag9":
case "cmd_toggleRead":
case "cmd_markAsRead":
case "cmd_markAsUnread":
case "cmd_markAllRead":
case "cmd_markThreadAsRead":
case "cmd_markReadByDate":
case "cmd_markAsFlagged":
case "cmd_markAsJunk":
case "cmd_markAsNotJunk":
case "cmd_recalculateJunkScore":
case "cmd_displayMsgFilters":
case "cmd_applyFiltersToSelection":
case "cmd_applyFilters":
case "cmd_runJunkControls":
case "cmd_deleteJunk":
case "button_file":
case "cmd_emptyTrash":
case "cmd_compactFolder":
case "button_compact":
case "cmd_settingsOffline":
case "cmd_selectAll":
case "cmd_selectThread":
case "cmd_moveToFolderAgain":
case "cmd_selectFlagged":
case "cmd_fullZoomReduce":
case "cmd_fullZoomEnlarge":
case "cmd_fullZoomReset":
case "cmd_fullZoomToggle":
case "cmd_viewAllHeader":
case "cmd_viewNormalHeader":
case "cmd_stop":
case "cmd_watchThread":
case "cmd_killThread":
case "cmd_killSubthread":
return true;
case "cmd_downloadFlagged":
case "cmd_downloadSelected":
case "cmd_synchronizeOffline":
return MailOfflineMgr.isOnline();
case "cmd_newFolder":
case "cmd_newVirtualFolder":
return !!gFolderTreeController;
case "cmd_goFolder":
return !!gFolderTreeView;
default:
return false;
}
},
isCommandEnabled: function(command)
{
switch (command)
{
case "cmd_delete":
UpdateDeleteCommand();
// fall through
case "button_delete":
UpdateDeleteToolbarButton();
return gFolderDisplay.getCommandStatus(nsMsgViewCommandType.deleteMsg);
case "cmd_shiftDelete":
case "button_shiftDelete":
return gFolderDisplay.getCommandStatus(nsMsgViewCommandType.deleteNoTrash);
case "cmd_cancel":
return gFolderDisplay.selectedCount == 1 &&
gFolderDisplay.selectedMessageIsNews;
case "cmd_deleteFolder":
var folders = gFolderTreeView.getSelectedFolders();
if (folders.length == 1) {
let folder = folders[0];
if (folder.server.type == "nntp") {
// Just disable the command for news unless it is a Saved search folder.
return folder.getFlag(nsMsgFolderFlags.Virtual);
}
return CanDeleteFolder(folder);
}
return false;
case "button_junk":
UpdateJunkToolbarButton();
return gFolderDisplay.getCommandStatus(nsMsgViewCommandType.junk);
case "cmd_killThread":
case "cmd_killSubthread":
return gFolderDisplay.selectedCount > 0;
case "cmd_watchThread":
return gFolderDisplay.getCommandStatus(nsMsgViewCommandType.toggleThreadWatched);
case "cmd_createFilterFromPopup":
case "cmd_createFilterFromMenu":
return gFolderDisplay.selectedCount == 1 &&
gFolderDisplay.selectedMessage.folder &&
gFolderDisplay.selectedMessage.folder.server.canHaveFilters;
case "cmd_openConversation":
case "button_showconversation":
return gFolderDisplay.selectedCount == 1 &&
gConversationOpener.isSelectedMessageIndexed();
case "cmd_saveAsFile":
return gFolderDisplay.selectedCount > 0;
case "cmd_saveAsTemplate":
if (gFolderDisplay.selectedCount > 1)
return false; // else fall thru
case "cmd_reply":
case "button_reply":
case "cmd_replySender":
case "cmd_replyGroup":
case "button_followup":
case "cmd_replyall":
case "button_replyall":
case "cmd_replylist":
case "button_replylist":
case "cmd_forward":
case "button_forward":
case "cmd_forwardInline":
case "cmd_forwardAttachment":
case "cmd_editAsNew":
case "cmd_editDraftMsg":
case "cmd_openMessage":
case "button_print":
case "cmd_print":
case "cmd_viewPageSource":
case "cmd_reload":
case "cmd_applyFiltersToSelection":
let numSelected = gFolderDisplay.selectedCount;
if (command == "cmd_applyFiltersToSelection")
{
var whichText = "valueMessage";
if (numSelected > 1)
whichText = "valueSelection";
goSetMenuValue(command, whichText);
goSetAccessKey(command, whichText + "AccessKey");
}
if (numSelected > 0)
{
if (!gFolderDisplay.getCommandStatus(nsMsgViewCommandType.cmdRequiringMsgBody))
return false;
// Check if we have a collapsed thread selected and are summarizing it.
// If so, selectedIndices.length won't match numSelected. Also check
// that we're not displaying a message, which handles the case
// where we failed to summarize the selection and fell back to
// displaying a message.
if (gFolderDisplay.selectedIndices.length != numSelected &&
command != "cmd_applyFiltersToSelection" &&
gDBView && gDBView.currentlyDisplayedMessage == nsMsgViewIndex_None)
return false;
if (command == "cmd_reply" || command == "button_reply" ||
command == "cmd_replyall" ||command == "button_replyall")
return IsReplyEnabled();
if (command == "cmd_replylist" || command == "button_replylist")
return IsReplyListEnabled();
return true;
}
return false;
case "cmd_printpreview":
if (gFolderDisplay.selectedCount == 1)
return gFolderDisplay.getCommandStatus(nsMsgViewCommandType.cmdRequiringMsgBody);
return false;
case "cmd_newMessage":
// This enables Write button even without any accounts set up, so users might run into Bug 524863
case "cmd_printSetup":
case "cmd_viewAllHeader":
case "cmd_viewNormalHeader":
return true;
case "cmd_markAsFlagged":
case "button_file":
return gFolderDisplay.selectedCount > 0;
case "cmd_archive":
case "button_archive":
return gFolderDisplay.canArchiveSelectedMessages;
case "cmd_markAsJunk":
case "cmd_markAsNotJunk":
return gFolderDisplay.getCommandStatus(nsMsgViewCommandType.junk);
case "cmd_recalculateJunkScore":
// We're going to take a conservative position here, because we really
// don't want people running junk controls on folders that are not
// enabled for junk. The junk type picks up possible dummy message headers,
// while the runJunkControls will prevent running on XF virtual folders.
return gFolderDisplay.getCommandStatus(nsMsgViewCommandType.junk) &&
gFolderDisplay.getCommandStatus(nsMsgViewCommandType.runJunkControls);
case "cmd_displayMsgFilters":
return MailServices.accounts.accounts.length > 0;
case "cmd_applyFilters":
return gFolderDisplay.getCommandStatus(nsMsgViewCommandType.applyFilters);
case "cmd_runJunkControls":
return gFolderDisplay.getCommandStatus(nsMsgViewCommandType.runJunkControls);
case "cmd_deleteJunk":
return gFolderDisplay.getCommandStatus(nsMsgViewCommandType.deleteJunk);
case "button_mark":
case "cmd_tag":
case "cmd_addTag":
case "cmd_manageTags":
case "cmd_removeTags":
case "cmd_tag1":
case "cmd_tag2":
case "cmd_tag3":
case "cmd_tag4":
case "cmd_tag5":
case "cmd_tag6":
case "cmd_tag7":
case "cmd_tag8":
case "cmd_tag9":
case "cmd_toggleRead":
case "cmd_markThreadAsRead":
return gFolderDisplay.selectedCount > 0;
case "cmd_markAsRead":
return CanMarkMsgAsRead(true);
case "cmd_markAsUnread":
return CanMarkMsgAsRead(false);
case "button_nextMsg":
case "cmd_nextMsg":
case "button_next":
case "cmd_nextUnreadMsg":
case "cmd_nextUnreadThread":
case "button_previousMsg":
case "cmd_previousMsg":
case "button_previous":
case "cmd_previousUnreadMsg":
return IsViewNavigationItemEnabled();
case "button_goForward":
case "button_goBack":
case "cmd_goForward":
case "cmd_goBack":
if (gDBView)
return gDBView.navigateStatus((command == "cmd_goBack" || command == "button_goBack") ? nsMsgNavigationType.back : nsMsgNavigationType.forward);
return false;
case "cmd_goStartPage":
return document.getElementById("tabmail").selectedTab.mode.name == "folder" &&
!IsMessagePaneCollapsed();
case "cmd_undoCloseTab":
return (document.getElementById("tabmail").recentlyClosedTabs.length > 0);
case "cmd_markAllRead":
return IsFolderSelected() && gDBView && gDBView.msgFolder &&
gDBView.msgFolder.getNumUnread(false) > 0;
case "cmd_markReadByDate":
return IsFolderSelected();
case "cmd_find":
case "cmd_findAgain":
case "cmd_findPrevious":
// If we are a message tab, then we've got a message displayed, so
// always allow searching in the message
if (document.getElementById("tabmail").selectedTab.mode.name == "message")
return true;
// Otherwise, only allow searching if we're showing the message pane
// and have more than one message selected.
return (!IsMessagePaneCollapsed() && gFolderDisplay.selectedCount == 1);
case "cmd_search":
return MailServices.accounts.accounts.length > 0;
case "cmd_selectAll":
case "cmd_selectFlagged":
return !!gDBView;
// these are enabled on when we are in threaded mode
case "cmd_selectThread":
if (gFolderDisplay.selectedCount <= 0)
return false;
case "cmd_expandAllThreads":
case "cmd_collapseAllThreads":
return gFolderDisplay.view.showThreaded ||
gFolderDisplay.view.showGroupedBySort;
case "cmd_nextFlaggedMsg":
case "cmd_previousFlaggedMsg":
return IsViewNavigationItemEnabled();
case "cmd_viewClassicMailLayout":
case "cmd_viewWideMailLayout":
case "cmd_viewVerticalMailLayout":
case "cmd_toggleFolderPane":
case "cmd_toggleFolderPaneCols":
case "cmd_toggleMessagePane":
// this is overridden per-mail tab
return true;
case "cmd_viewAllMsgs":
case "cmd_viewIgnoredThreads":
return gDBView;
case "cmd_viewUnreadMsgs":
case "cmd_viewThreadsWithUnread":
case "cmd_viewWatchedThreadsWithUnread":
return !gFolderDisplay.view.isVirtual;
case "cmd_stop":
return window.MsgStatusFeedback._meteorsSpinning;
case "cmd_undo":
case "cmd_redo":
return SetupUndoRedoCommand(command);
case "cmd_renameFolder":
{
let folders = gFolderTreeView.getSelectedFolders();
return folders.length == 1 && folders[0].canRename &&
folders[0].isCommandEnabled("cmd_renameFolder");
}
case "cmd_sendUnsentMsgs":
return IsSendUnsentMsgsEnabled(null);
case "cmd_subscribe":
return IsSubscribeEnabled();
case "cmd_properties":
return IsPropertiesEnabled(command);
case "button_getNewMessages":
case "cmd_getNewMessages":
case "cmd_getMsgsForAuthAccounts":
return IsGetNewMessagesEnabled();
case "cmd_getNextNMessages":
return IsGetNextNMessagesEnabled();
case "cmd_emptyTrash":
{
let folder = GetSelectedMsgFolders()[0];
return folder && folder.server.canEmptyTrashOnExit ?
IsMailFolderSelected() : false;
}
case "button_compact":
{
let folders = gFolderTreeView.getSelectedFolders();
let canCompact = function canCompact(folder) {
return !folder.isServer &&
!(folder.flags & Components.interfaces.nsMsgFolderFlags.Virtual) &&
(folder.server.type != "imap" || folder.server.canCompactFoldersOnServer) &&
folder.isCommandEnabled("button_compact");
}
return folders && folders.every(canCompact);
}
case "cmd_compactFolder":
{
let folders = gFolderTreeView.getSelectedFolders();
let canCompactAll = function canCompactAll(folder) {
return (folder.server.type != "imap" ||
folder.server.canCompactFoldersOnServer) &&
folder.isCommandEnabled("cmd_compactFolder") ;
}
return folders && folders.every(canCompactAll);
}
case "cmd_setFolderCharset":
return IsFolderCharsetEnabled();
case "cmd_downloadFlagged":
return(IsFolderSelected() && MailOfflineMgr.isOnline());
case "cmd_downloadSelected":
return (IsFolderSelected() && MailOfflineMgr.isOnline() && gFolderDisplay.selectedCount > 0);
case "cmd_synchronizeOffline":
return MailOfflineMgr.isOnline();
case "cmd_settingsOffline":
return IsAccountOfflineEnabled();
case "cmd_moveToFolderAgain":
// Disable "Move to <folder> Again" for news and other read only
// folders since we can't really move messages from there - only copy.
if (Services.prefs.getBoolPref("mail.last_msg_movecopy_was_move"))
{
let loadedFolder = gFolderTreeView.getSelectedFolders()[0];
if (loadedFolder && !loadedFolder.canDeleteMessages)
return false;
}
let targetURI = Services.prefs.getCharPref("mail.last_msg_movecopy_target_uri");
if (!targetURI)
return false;
let targetFolder = MailUtils.getFolderForURI(targetURI);
// If parent is null, folder doesn't exist.
return targetFolder && targetFolder.parent &&
gFolderDisplay.selectedCount > 0;
case "cmd_fullZoomReduce":
case "cmd_fullZoomEnlarge":
case "cmd_fullZoomReset":
case "cmd_fullZoomToggle":
// If we are a message tab, then we've got a message displayed, so
// always allow zooming in the message
if (document.getElementById("tabmail").selectedTab.mode.name == "message")
return true;
return IsFolderSelected() && !IsMessagePaneCollapsed();
case "cmd_newFolder":
case "cmd_newVirtualFolder":
return !!gFolderTreeController;
case "cmd_goFolder":
return !!gFolderTreeView;
default:
return false;
}
return false;
},
doCommand: function(command, aTab)
{
// If the user invoked a key short cut then it is possible that we got here
// for a command which is really disabled. Kick out if the command should be disabled.
if (!this.isCommandEnabled(command))
return;
switch ( command )
{
case "button_getNewMessages":
case "cmd_getNewMessages":
MsgGetMessage();
break;
case "cmd_getMsgsForAuthAccounts":
MsgGetMessagesForAllAuthenticatedAccounts();
break;
case "cmd_getNextNMessages":
MsgGetNextNMessages();
break;
case "cmd_archive":
MsgArchiveSelectedMessages(null);
break;
case "cmd_newMessage":
MsgNewMessage(null);
break;
case "cmd_reply":
MsgReplyMessage(null);
break;
case "cmd_replySender":
MsgReplySender(null);
break;
case "cmd_replyGroup":
MsgReplyGroup(null);
break;
case "cmd_replyall":
MsgReplyToAllMessage(null);
break;
case "cmd_replylist":
MsgReplyToListMessage(null);
break;
case "cmd_forward":
MsgForwardMessage(null);
break;
case "cmd_forwardInline":
MsgForwardAsInline(null);
break;
case "cmd_forwardAttachment":
MsgForwardAsAttachment(null);
break;
case "cmd_editAsNew":
MsgEditMessageAsNew(null);
break;
case "cmd_editDraftMsg":
MsgEditDraftMessage(null);
break;
case "cmd_createFilterFromMenu":
MsgCreateFilter();
break;
case "cmd_createFilterFromPopup":
break;// This does nothing because the createfilter is invoked from the popupnode oncommand.
case "button_delete":
case "cmd_delete":
// if the user deletes a message before its mark as read timer goes off, we should mark it as read
// this ensures that we clear the biff indicator from the system tray when the user deletes the new message
MarkSelectedMessagesRead(true);
// If this is a right-click triggered delete, then do not hint about
// the deletion. Note: The code that swaps the selection back in will
// take care of ensuring that this deletion does not make the saved
// selection incorrect.
if (!gRightMouseButtonSavedSelection)
gFolderDisplay.hintAboutToDeleteMessages();
gFolderDisplay.doCommand(nsMsgViewCommandType.deleteMsg);
UpdateDeleteToolbarButton();
break;
case "cmd_cancel":
let message = gFolderDisplay.selectedMessage;
message.folder.QueryInterface(Components.interfaces.nsIMsgNewsFolder)
.cancelMessage(message, msgWindow);
break;
case "button_shiftDelete":
case "cmd_shiftDelete":
MarkSelectedMessagesRead(true);
gFolderDisplay.hintAboutToDeleteMessages();
gFolderDisplay.doCommand(nsMsgViewCommandType.deleteNoTrash);
UpdateDeleteToolbarButton();
break;
case "cmd_deleteFolder":
gFolderTreeController.deleteFolder();
break;
case "cmd_killThread":
if (!gFolderDisplay.selectedMessageIsNews) {
if (!gFolderDisplay.selectedMessageThreadIgnored) {
ShowIgnoredMessageNotification(gFolderDisplay.selectedMessages, false);
}
else {
document.getElementById("msg-footer-notification-box")
.removeTransientNotifications();
}
}
// kill thread kills the thread and then does a next unread
GoNextMessage(nsMsgNavigationType.toggleThreadKilled, true);
break;
case "cmd_killSubthread":
if (!gFolderDisplay.selectedMessageIsNews) {
if (!gFolderDisplay.selectedMessageSubthreadIgnored) {
ShowIgnoredMessageNotification(gFolderDisplay.selectedMessages, true);
}
else {
document.getElementById("msg-footer-notification-box")
.removeTransientNotifications();
}
}
GoNextMessage(nsMsgNavigationType.toggleSubthreadKilled, true);
break;
case "cmd_watchThread":
gFolderDisplay.doCommand(nsMsgViewCommandType.toggleThreadWatched);
break;
case "button_next":
case "cmd_nextUnreadMsg":
GoNextMessage(nsMsgNavigationType.nextUnreadMessage, true);
break;
case "cmd_nextUnreadThread":
GoNextMessage(nsMsgNavigationType.nextUnreadThread, true);
break;
case "button_nextMsg":
case "cmd_nextMsg":
GoNextMessage(nsMsgNavigationType.nextMessage, false);
break;
case "cmd_nextFlaggedMsg":
GoNextMessage(nsMsgNavigationType.nextFlagged, true);
break;
case "button_previousMsg":
case "cmd_previousMsg":
GoNextMessage(nsMsgNavigationType.previousMessage, false);
break;
case "button_previous":
case "cmd_previousUnreadMsg":
GoNextMessage(nsMsgNavigationType.previousUnreadMessage, true);
break;
case "cmd_previousFlaggedMsg":
GoNextMessage(nsMsgNavigationType.previousFlagged, true);
break;
case "button_goForward":
case "cmd_goForward":
GoNextMessage(nsMsgNavigationType.forward, true);
break;
case "button_goBack":
case "cmd_goBack":
GoNextMessage(nsMsgNavigationType.back, true);
break;
case "cmd_goStartPage":
HideMessageHeaderPane();
loadStartPage(true);
break;
case "cmd_undoCloseTab":
document.getElementById("tabmail").undoCloseTab();
break;
case "cmd_viewClassicMailLayout":
case "cmd_viewWideMailLayout":
case "cmd_viewVerticalMailLayout":
ChangeMailLayoutForCommand(command);
break;
case "cmd_toggleFolderPane":
MsgToggleFolderPane();
break;
case "cmd_toggleFolderPaneCols":
gFolderTreeView.toggleCols();
break;
case "cmd_toggleMessagePane":
MsgToggleMessagePane();
break;
case "cmd_viewAllMsgs":
case "cmd_viewThreadsWithUnread":
case "cmd_viewWatchedThreadsWithUnread":
case "cmd_viewUnreadMsgs":
case "cmd_viewIgnoredThreads":
SwitchView(command);
break;
case "cmd_undo":
messenger.undo(msgWindow);
break;
case "cmd_redo":
messenger.redo(msgWindow);
break;
case "cmd_expandAllThreads":
gFolderDisplay.doCommand(nsMsgViewCommandType.expandAll);
gFolderDisplay.ensureSelectionIsVisible();
break;
case "cmd_collapseAllThreads":
gFolderDisplay.selectSelectedThreadRoots();
gFolderDisplay.doCommand(nsMsgViewCommandType.collapseAll);
gFolderDisplay.ensureSelectionIsVisible();
break;
case "cmd_renameFolder":
gFolderTreeController.renameFolder();
return;
case "cmd_sendUnsentMsgs":
// if offline, prompt for sendUnsentMessages
if (MailOfflineMgr.isOnline())
SendUnsentMessages();
else
MailOfflineMgr.goOnlineToSendMessages(msgWindow);
return;
case "cmd_subscribe":
MsgSubscribe();
return;
case "cmd_openMessage":
MsgOpenSelectedMessages();
return;
case "cmd_openConversation":
case "button_showconversation":
gConversationOpener.openConversationForMessages(gFolderDisplay.selectedMessages);
return;
case "cmd_printSetup":
PrintUtils.showPageSetup();
return;
case "cmd_print":
PrintEnginePrint();
return;
case "cmd_printpreview":
PrintEnginePrintPreview();
return;
case "cmd_saveAsFile":
MsgSaveAsFile();
return;
case "cmd_saveAsTemplate":
MsgSaveAsTemplate();
return;
case "cmd_viewPageSource":
ViewPageSource(gFolderDisplay.selectedMessageUris);
return;
case "cmd_setFolderCharset":
gFolderTreeController.editFolder();
return;
case "cmd_reload":
ReloadMessage();
return;
case "cmd_find":
// Make sure the message pane has focus before we start a find since we
// only support searching within the message body.
SetFocusMessagePane();
document.getElementById("FindToolbar").onFindCommand();
return;
case "cmd_findAgain":
// Make sure the message pane has focus before we start a find since we
// only support searching within the message body.
SetFocusMessagePane();
document.getElementById("FindToolbar").onFindAgainCommand(false);
return;
case "cmd_findPrevious":
// Make sure the message pane has focus before we start a find since we
// only support searching within the message body.
SetFocusMessagePane();
document.getElementById("FindToolbar").onFindAgainCommand(true);
return;
case "cmd_markReadByDate":
MsgMarkReadByDate();
return;
case "cmd_properties":
gFolderTreeController.editFolder();
return;
case "cmd_search":
MsgSearchMessages();
return;
case "cmd_addTag":
AddTag();
return;
case "cmd_manageTags":
ManageTags();
return;
case "cmd_removeTags":
RemoveAllMessageTags();
return;
case "cmd_tag1":
case "cmd_tag2":
case "cmd_tag3":
case "cmd_tag4":
case "cmd_tag5":
case "cmd_tag6":
case "cmd_tag7":
case "cmd_tag8":
case "cmd_tag9":
var tagNumber = parseInt(command[7]);
ToggleMessageTagKey(tagNumber);
return;
case "button_mark":
case "cmd_toggleRead":
MsgMarkMsgAsRead();
return;
case "cmd_markAsRead":
MsgMarkMsgAsRead(true);
return;
case "cmd_markAsUnread":
MsgMarkMsgAsRead(false);
return;
case "cmd_markThreadAsRead":
ClearPendingReadTimer();
gFolderDisplay.doCommand(nsMsgViewCommandType.markThreadRead);
return;
case "cmd_markAllRead":
gFolderDisplay.doCommand(nsMsgViewCommandType.markAllRead);
return;
case "button_junk":
MsgJunk();
return;
case "cmd_stop":
msgWindow.StopUrls();
return;
case "cmd_markAsFlagged":
MsgMarkAsFlagged();
return;
case "cmd_viewAllHeader":
MsgViewAllHeaders();
return;
case "cmd_viewNormalHeader":
MsgViewNormalHeaders();
return;
case "cmd_markAsJunk":
JunkSelectedMessages(true);
return;
case "cmd_markAsNotJunk":
JunkSelectedMessages(false);
return;
case "cmd_recalculateJunkScore":
analyzeMessagesForJunk();
return;
case "cmd_displayMsgFilters":
MsgFilters(null, null);
return;
case "cmd_applyFiltersToSelection":
MsgApplyFiltersToSelection();
return;
case "cmd_applyFilters":
MsgApplyFilters(null);
return;
case "cmd_runJunkControls":
filterFolderForJunk();
return;
case "cmd_deleteJunk":
// Even though deleteJunkInFolder returns a value, we don't want to let
// it get past us
deleteJunkInFolder();
return;
case "cmd_emptyTrash":
gFolderTreeController.emptyTrash();
return;
case "cmd_compactFolder":
gFolderTreeController.compactAllFoldersForAccount();
return;
case "button_compact":
gFolderTreeController.compactFolders();
return;
case "cmd_downloadFlagged":
gFolderDisplay.doCommand(nsMsgViewCommandType.downloadFlaggedForOffline);
break;
case "cmd_downloadSelected":
gFolderDisplay.doCommand(nsMsgViewCommandType.downloadSelectedForOffline);
break;
case "cmd_synchronizeOffline":
MsgSynchronizeOffline();
break;
case "cmd_settingsOffline":
MailOfflineMgr.openOfflineAccountSettings();
break;
case "cmd_moveToFolderAgain":
var folder = MailUtils.getFolderForURI(
Services.prefs.getCharPref("mail.last_msg_movecopy_target_uri"));
if (Services.prefs.getBoolPref("mail.last_msg_movecopy_was_move"))
MsgMoveMessage(folder);
else
MsgCopyMessage(folder);
break;
case "cmd_selectAll":
// XXX If the message pane is selected but the tab focused, this ends
// closing the message tab. See bug 502834.
if (aTab.mode.name == "message")
break;
// move the focus so the user can delete the newly selected messages, not the folder
SetFocusThreadPane();
// if in threaded mode, the view will expand all before selecting all
gFolderDisplay.doCommand(nsMsgViewCommandType.selectAll);
break;
case "cmd_selectThread":
gFolderDisplay.doCommand(nsMsgViewCommandType.selectThread);
break;
case "cmd_selectFlagged":
gFolderDisplay.doCommand(nsMsgViewCommandType.selectFlagged);
break;
case "cmd_fullZoomReduce":
ZoomManager.reduce();
break;
case "cmd_fullZoomEnlarge":
ZoomManager.enlarge();
break;
case "cmd_fullZoomReset":
ZoomManager.reset();
break;
case "cmd_fullZoomToggle":
ZoomManager.toggleZoom();
break;
case "cmd_newFolder":
gFolderTreeController.newFolder();
break;
case "cmd_newVirtualFolder":
gFolderTreeController.newVirtualFolder();
break;
}
},
onEvent: function(event)
{
// on blur events set the menu item texts back to the normal values
if ( event == 'blur' )
{
goSetMenuValue('cmd_undo', 'valueDefault');
goSetMenuValue('cmd_redo', 'valueDefault');
}
}
};
/**
* Show a notification in the message pane footer, allowing the user to learn
* more about the ignore thread feature, and also allowing undo ignore thread.
* @param aMsgs the messages that were ignore
* @param aSubThread only boolean indicating if it was ignore subthread or
* ignore thread
*/
function ShowIgnoredMessageNotification(aMsgs, aSubthreadOnly) {
let notifyBox = document.getElementById("msg-footer-notification-box");
notifyBox.removeTransientNotifications(); // don't wanna pile these up
let bundle = new StringBundle("chrome://messenger/locale/messenger.properties");
let buttons = [
{
label: bundle.get("learnMoreAboutIgnoreThread"),
accessKey: bundle.get("learnMoreAboutIgnoreThreadAccessKey"),
popup: null,
callback: function(aNotificationBar, aButton) {
let url = Services.prefs.getCharPref("mail.ignore_thread.learn_more_url");
openContentTab(url);
return true; // keep notification open
}
},
{
label: bundle.get(!aSubthreadOnly ? "undoIgnoreThread":
"undoIgnoreSubthread"),
accessKey: bundle.get(!aSubthreadOnly ? "undoIgnoreThreadAccessKey":
"undoIgnoreSubthreadAccessKey"),
isDefault: true,
popup: null,
callback: function(aNotificationBar, aButton) {
aMsgs.forEach(function(msg) {
let msgDb = msg.folder.msgDatabase;
if (aSubthreadOnly) {
msgDb.MarkHeaderKilled(msg, false, gDBView);
}
else {
let thread = msgDb.GetThreadContainingMsgHdr(msg);
msgDb.MarkThreadIgnored(thread, thread.threadKey, false, gDBView);
}
});
return false; // close notification
}
}
];
let threadIds = new Set();
aMsgs.forEach(function(msg) {
if (!threadIds.has(msg.threadId))
threadIds.add(msg.threadId);
});
let nbrOfThreads = threadIds.size;
if (nbrOfThreads == 1) {
let ignoredThreadText = bundle.get(!aSubthreadOnly ?
"ignoredThreadFeedback": "ignoredSubthreadFeedback");
let subj = aMsgs[0].mime2DecodedSubject || "";
if (subj.length > 45)
subj = subj.substring(0, 45) + "…";
let text = ignoredThreadText.replace("#1", subj);
let notification = notifyBox.appendNotification(
text, "ignoreThreadInfo", null,
notifyBox.PRIORITY_INFO_MEDIUM, buttons);
}
else {
let ignoredThreadText = bundle.get(!aSubthreadOnly ?
"ignoredThreadsFeedback": "ignoredSubthreadsFeedback");
let text = PluralForm.get(nbrOfThreads, ignoredThreadText).replace("#1", nbrOfThreads);
let notification = notifyBox.appendNotification(
text, "ignoreThreadsInfo", null,
notifyBox.PRIORITY_INFO_MEDIUM, buttons);
}
}
function CloseTabOrWindow()
{
let tabmail = document.getElementById('tabmail');
if (tabmail.tabInfo.length == 1) {
if (Services.prefs.getBoolPref("mail.tabs.closeWindowWithLastTab"))
window.close();
}
else {
tabmail.removeCurrentTab();
}
}
function GetNumSelectedMessages()
{
// This global function is only for mailnews/ compatibility.
return gFolderDisplay.selectedCount;
}
var gLastFocusedElement=null;
function FocusRingUpdate_Mail()
{
if (!gFolderDisplay)
return;
// if the focusedElement is null, we're here on a blur.
// nsFocusController::Blur() calls nsFocusController::SetFocusedElement(null),
// which will update any commands listening for "focus".
// we really only care about nsFocusController::Focus() happens,
// which calls nsFocusController::SetFocusedElement(element)
var currentFocusedElement = gFolderDisplay.focusedPane;
if (currentFocusedElement != gLastFocusedElement) {
if (currentFocusedElement)
currentFocusedElement.setAttribute("focusring", "true");
if (gLastFocusedElement)
gLastFocusedElement.removeAttribute("focusring");
gLastFocusedElement = currentFocusedElement;
// since we just changed the pane with focus we need to update the toolbar to reflect this
// XXX TODO
// can we optimize
// and just update cmd_delete and button_delete?
UpdateMailToolbar("focus");
}
}
function RestoreFocusAfterHdrButton()
{
// I would love to really restore the focus to the pane that had
// focus before the user clicked on the hdr button, and gLastFocusedElement
// would almost do that, except that clicking on the hdr button sets
// gLastFocusedElement to the message pane. What I need is
// gPenultimateFocusedElement.
SetFocusThreadPane();
}
function SetupCommandUpdateHandlers()
{
// folder pane
var widget = document.getElementById("folderTree");
if ( widget )
widget.controllers.appendController(FolderPaneController);
}
function UnloadCommandUpdateHandlers()
{
}
function IsSendUnsentMsgsEnabled(unsentMsgsFolder)
{
// If no account has been configured, there are no messages for sending.
if (MailServices.accounts.accounts.length == 0)
return false;
var msgSendlater =
Components.classes["@mozilla.org/messengercompose/sendlater;1"]
.getService(Components.interfaces.nsIMsgSendLater);
// If we're currently sending unsent msgs, disable this cmd.
if (msgSendlater.sendingMessages)
return false;
if (unsentMsgsFolder) {
// If unsentMsgsFolder is non-null, it is the "Unsent Messages" folder.
// We're here because we've done a right click on the "Unsent Messages"
// folder (context menu), so we can use the folder and return true/false
// straight away.
return unsentMsgsFolder.getTotalMessages(false) > 0;
}
// Otherwise, we don't know where we are, so use the current identity and
// find out if we have messages or not via that.
let identity;
let folders = GetSelectedMsgFolders();
if (folders.length > 0)
identity = getIdentityForServer(folders[0].server);
if (!identity) {
let defaultAccount = MailServices.accounts.defaultAccount;
if (defaultAccount)
identity = defaultAccount.defaultIdentity;
if (!identity)
return false;
}
return msgSendlater.hasUnsentMessages(identity);
}
/**
* Determine whether there exists any server for which to show the Subscribe dialog.
*/
function IsSubscribeEnabled()
{
// If there are any IMAP or News servers, we can show the dialog any time and
// it will properly show those.
let servers = MailServices.accounts.allServers;
for (let server of fixIterator(servers,
Components.interfaces.nsIMsgIncomingServer)) {
if (server.type == "imap" || server.type == "nntp")
return true;
}
// RSS accounts use a separate Subscribe dialog that we can only show when
// such an account is selected.
let preselectedFolder = GetFirstSelectedMsgFolder();
if (preselectedFolder && preselectedFolder.server.type == "rss")
return true;
return false;
}
function IsFolderCharsetEnabled()
{
return IsFolderSelected();
}
function IsPropertiesEnabled(command)
{
var folders = GetSelectedMsgFolders();
if (!folders.length)
return false;
var folder = folders[0];
// when servers are selected it should be "Edit | Properties..."
if (folder.isServer)
goSetMenuValue(command, "valueGeneric");
else if (folder.getFlag(nsMsgFolderFlags.Virtual))
goSetMenuValue(command, "valueFolder");
else
goSetMenuValue(command, isNewsURI(folder.URI) ? "valueNewsgroup" : "valueFolder");
return (folders.length == 1);
}
function IsViewNavigationItemEnabled()
{
return IsFolderSelected();
}
function IsFolderSelected()
{
var folders = GetSelectedMsgFolders();
return folders.length == 1 && !folders[0].isServer;
}
function SetFocusThreadPaneIfNotOnMessagePane()
{
var focusedElement = gFolderDisplay.focusedPane;
if((focusedElement != GetThreadTree()) &&
(focusedElement != GetMessagePane()))
SetFocusThreadPane();
}
// 3pane related commands. Need to go in own file. Putting here for the moment.
/**
* Cycle through the various panes in the 3pane window (in reverse if the shift
* key is being held down).
*
* @param event the event that triggered us
*/
function SwitchPaneFocus(event)
{
let messagePane = GetMessagePane();
// First, build an array of panes to cycle through based on our current state.
// This will usually be something like [threadPane, messagePane, folderPane].
let panes = [GetThreadTree()];
if (!IsMessagePaneCollapsed())
panes.push(messagePane);
if (gFolderDisplay.folderPaneVisible)
panes.push(document.getElementById("folderTree"));
// Find our focused element in the array. If focus is not on one of the main
// panes (it's probably on the toolbar), then act as if it's on the thread
// tree.
let focusedElement = gFolderDisplay.focusedPane;
let focusedElementIndex = panes.indexOf(focusedElement);
if (focusedElementIndex == -1)
focusedElementIndex = 0;
if (event && event.shiftKey)
{
focusedElementIndex--;
if (focusedElementIndex == -1)
focusedElementIndex = panes.length-1;
}
else
{
focusedElementIndex++;
if (focusedElementIndex == panes.length)
focusedElementIndex = 0;
}
let newElem = panes[focusedElementIndex];
// We need to handle the message pane specially, since focusing it isn't as
// simple as just calling focus(). See SetFocusMessagePane below for more
// details.
if (newElem == messagePane)
SetFocusMessagePane();
else
newElem.focus();
}
function SetFocusThreadPane()
{
var threadTree = GetThreadTree();
threadTree.focus();
}
/**
* Set the focus to the currently-active message pane (either the single- or
* multi-message).
*/
function SetFocusMessagePane()
{
// Calling .focus() on content doesn't blur the previously focused chrome
// element, so we shift focus to the XUL pane first, to not leave another
// pane looking like it has focus.
GetMessagePane().focus();
if (gMessageDisplay.singleMessageDisplay)
GetMessagePaneFrame().focus();
else
document.getElementById("multimessage").focus();
}
//
// This function checks if the configured junk mail can be renamed or deleted.
//
function CanRenameDeleteJunkMail(aFolderUri)
{
if (!aFolderUri)
return false;
// Go through junk mail settings for all servers and see if the folder is set/used by anyone.
try
{
var allServers = accountManager.allServers;
for (var i = 0; i < allServers.length; i++)
{
var currentServer = allServers.queryElementAt(i, Components.interfaces.nsIMsgIncomingServer);
var settings = currentServer.spamSettings;
// If junk mail control or move junk mail to folder option is disabled then
// allow the folder to be removed/renamed since the folder is not used in this case.
if (!settings.level || !settings.moveOnSpam)
continue;
if (settings.spamFolderURI == aFolderUri)
return false;
}
}
catch(ex)
{
dump("Can't get all servers\n");
}
return true;
}
/** Check if this is a folder the user is allowed to delete. */
function CanDeleteFolder(folder)
{
if (folder.isServer)
return false;
var specialFolder = getSpecialFolderString(folder);
if (specialFolder == "Inbox" || specialFolder == "Trash" ||
specialFolder == "Drafts" || specialFolder == "Sent" ||
specialFolder == "Templates" || specialFolder == "Outbox" ||
(specialFolder == "Junk" && !CanRenameDeleteJunkMail(folder.URI)))
return false;
return true;
}