summaryrefslogtreecommitdiffstats
path: root/comm/mail/base/content/messageWindow.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/base/content/messageWindow.js')
-rw-r--r--comm/mail/base/content/messageWindow.js742
1 files changed, 742 insertions, 0 deletions
diff --git a/comm/mail/base/content/messageWindow.js b/comm/mail/base/content/messageWindow.js
new file mode 100644
index 0000000000..2b93de1fc9
--- /dev/null
+++ b/comm/mail/base/content/messageWindow.js
@@ -0,0 +1,742 @@
+/**
+ * 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/. */
+
+/* This is where functions related to the standalone message window are kept */
+
+/* import-globals-from ../../../../toolkit/content/viewZoomOverlay.js */
+/* import-globals-from ../../../mailnews/base/prefs/content/accountUtils.js */
+/* import-globals-from ../../components/customizableui/content/panelUI.js */
+/* import-globals-from mail-offline.js */
+/* import-globals-from mailCommands.js */
+/* import-globals-from mailCore.js */
+/* import-globals-from mailWindowOverlay.js */
+/* import-globals-from messenger-customization.js */
+/* import-globals-from toolbarIconColor.js */
+
+/* globals messenger, CreateMailWindowGlobals, InitMsgWindow, OnMailWindowUnload */ // From mailWindow.js
+
+var { AppConstants } = ChromeUtils.importESModule(
+ "resource://gre/modules/AppConstants.sys.mjs"
+);
+var { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ BondOpenPGP: "chrome://openpgp/content/BondOpenPGP.jsm",
+ UIDensity: "resource:///modules/UIDensity.jsm",
+ UIFontSize: "resource:///modules/UIFontSize.jsm",
+});
+
+var messageBrowser;
+
+function getBrowser() {
+ return document
+ .getElementById("messageBrowser")
+ .contentDocument.getElementById("messagepane");
+}
+
+this.__defineGetter__("browser", getBrowser);
+
+window.addEventListener("DOMContentLoaded", event => {
+ if (event.target != document) {
+ return;
+ }
+
+ messageBrowser = document.getElementById("messageBrowser");
+ messageBrowser.addEventListener("messageURIChanged", () => {
+ // Update toolbar buttons.
+ goUpdateCommand("cmd_getNewMessages");
+ goUpdateCommand("cmd_print");
+ goUpdateCommand("cmd_delete");
+ document.commandDispatcher.updateCommands("create-menu-go");
+ document.commandDispatcher.updateCommands("create-menu-message");
+ });
+ messageBrowser.addEventListener(
+ "load",
+ event => (messageBrowser.contentWindow.tabOrWindow = window),
+ true
+ );
+});
+window.addEventListener("load", OnLoadMessageWindow);
+window.addEventListener("unload", OnUnloadMessageWindow);
+
+// we won't show the window until the onload() handler is finished
+// so we do this trick (suggested by hyatt / blaker)
+function OnLoadMessageWindow() {
+ // Set a sane starting width/height for all resolutions on new profiles.
+ // Do this before the window loads.
+ if (!document.documentElement.hasAttribute("width")) {
+ // Prefer 860xfull height.
+ let defaultHeight = screen.availHeight;
+ let defaultWidth = screen.availWidth >= 860 ? 860 : screen.availWidth;
+
+ // On small screens, default to maximized state.
+ if (defaultHeight <= 600) {
+ document.documentElement.setAttribute("sizemode", "maximized");
+ }
+
+ document.documentElement.setAttribute("width", defaultWidth);
+ document.documentElement.setAttribute("height", defaultHeight);
+ // Make sure we're safe at the left/top edge of screen
+ document.documentElement.setAttribute("screenX", screen.availLeft);
+ document.documentElement.setAttribute("screenY", screen.availTop);
+ }
+
+ updateTroubleshootMenuItem();
+ ToolbarIconColor.init();
+ BondOpenPGP.init();
+ PanelUI.init();
+ gExtensionsNotifications.init();
+
+ setTimeout(delayedOnLoadMessageWindow, 0); // when debugging, set this to 5000, so you can see what happens after the window comes up.
+
+ messageBrowser.addEventListener("DOMTitleChanged", () => {
+ if (messageBrowser.contentTitle) {
+ if (AppConstants.platform == "macosx") {
+ document.title = messageBrowser.contentTitle;
+ } else {
+ document.title =
+ messageBrowser.contentTitle +
+ document.documentElement.getAttribute("titlemenuseparator") +
+ document.documentElement.getAttribute("titlemodifier");
+ }
+ } else {
+ document.title = document.documentElement.getAttribute("titlemodifier");
+ }
+ });
+
+ UIDensity.registerWindow(window);
+ UIFontSize.registerWindow(window);
+}
+
+function delayedOnLoadMessageWindow() {
+ HideMenus();
+ ShowMenus();
+ MailOfflineMgr.init();
+ CreateMailWindowGlobals();
+
+ // Run menubar initialization first, to avoid TabsInTitlebar code picking
+ // up mutations from it and causing a reflow.
+ if (AppConstants.platform != "macosx") {
+ AutoHideMenubar.init();
+ }
+
+ InitMsgWindow();
+
+ // initialize the customizeDone method on the customizeable toolbar
+ var toolbox = document.getElementById("mail-toolbox");
+ toolbox.customizeDone = function (aEvent) {
+ MailToolboxCustomizeDone(aEvent, "CustomizeMailToolbar");
+ };
+
+ SetupCommandUpdateHandlers();
+
+ setTimeout(actuallyLoadMessage, 0);
+}
+
+function actuallyLoadMessage() {
+ /*
+ * Our actual use cases that drive the arguments we take are:
+ * 1) Displaying a message from disk or that was an attachment on a message.
+ * Such messages have no (real) message header and must come in the form of
+ * a URI. (The message display code creates a 'dummy' header.)
+ * 2) Displaying a message that has a header available, either as a result of
+ * the user selecting a message in another window to spawn us or through
+ * some indirection like displaying a message by message-id. (The
+ * newsgroup UI exposes this, as well as the spotlight/vista indexers.)
+ *
+ * We clone views when possible for:
+ * - Consistency of navigation within the message display. Users would find
+ * it odd if they showed a message from a cross-folder view but ended up
+ * navigating around the message's actual folder.
+ * - Efficiency. It's faster to clone a view than open a new one.
+ *
+ * Our argument idioms for the use cases are thus:
+ * 1) [{msgHdr: A message header, viewWrapperToClone: (optional) a view
+ * wrapper to clone}]
+ * 2) [A Message header, (optional) the origin DBViewWraper]
+ * 3) [A Message URI] where the URI is an nsIURL corresponding to a message
+ * on disk or that is an attachment part on another message.
+ *
+ * Our original set of arguments, in case these get passed in and you're
+ * wondering why we explode, was:
+ * 0: A message URI, string or nsIURI.
+ * 1: A folder URI. If arg 0 was an nsIURI, it may have had a folder attribute.
+ * 2: The nsIMsgDBView used to open us.
+ */
+ if (window.arguments && window.arguments.length) {
+ let contentWindow = messageBrowser.contentWindow;
+ if (window.arguments[0] instanceof Ci.nsIURI) {
+ contentWindow.displayMessage(window.arguments[0].spec);
+ return;
+ }
+
+ let msgHdr, viewWrapperToClone;
+ // message header as an object?
+ if ("wrappedJSObject" in window.arguments[0]) {
+ let hdrObject = window.arguments[0].wrappedJSObject;
+ ({ msgHdr, viewWrapperToClone } = hdrObject);
+ } else if (window.arguments[0] instanceof Ci.nsIMsgDBHdr) {
+ // message header as a separate param?
+ msgHdr = window.arguments[0];
+ viewWrapperToClone = window.arguments[1];
+ }
+
+ contentWindow.displayMessage(
+ msgHdr.folder.getUriForMsg(msgHdr),
+ viewWrapperToClone
+ );
+ }
+
+ // set focus to the message pane
+ window.content.focus();
+}
+
+/**
+ * Load the given message into this window, and bring it to the front. This is
+ * supposed to be called whenever a message is supposed to be displayed in this
+ * window.
+ *
+ * @param aMsgHdr the message to display
+ * @param aViewWrapperToClone [optional] a DB view wrapper to clone for the
+ * message window
+ */
+function displayMessage(aMsgHdr, aViewWrapperToClone) {
+ let contentWindow = messageBrowser.contentWindow;
+ contentWindow.displayMessage(
+ aMsgHdr.folder.getUriForMsg(aMsgHdr),
+ aViewWrapperToClone
+ );
+
+ // bring this window to the front
+ window.focus();
+}
+
+function ShowMenus() {
+ var openMail3Pane_menuitem = document.getElementById("tasksMenuMail");
+ if (openMail3Pane_menuitem) {
+ openMail3Pane_menuitem.removeAttribute("hidden");
+ }
+}
+
+/* eslint-disable complexity */
+function HideMenus() {
+ // TODO: Seems to be a lot of repetitive code.
+ // Can we just fold this into an array of element IDs and loop over them?
+ var message_menuitem = document.getElementById("menu_showMessage");
+ if (message_menuitem) {
+ message_menuitem.setAttribute("hidden", "true");
+ }
+
+ message_menuitem = document.getElementById("appmenu_showMessage");
+ if (message_menuitem) {
+ message_menuitem.setAttribute("hidden", "true");
+ }
+
+ var folderPane_menuitem = document.getElementById("menu_showFolderPane");
+ if (folderPane_menuitem) {
+ folderPane_menuitem.setAttribute("hidden", "true");
+ }
+
+ folderPane_menuitem = document.getElementById("appmenu_showFolderPane");
+ if (folderPane_menuitem) {
+ folderPane_menuitem.setAttribute("hidden", "true");
+ }
+
+ var showSearch_showMessage_Separator = document.getElementById(
+ "menu_showSearch_showMessage_Separator"
+ );
+ if (showSearch_showMessage_Separator) {
+ showSearch_showMessage_Separator.setAttribute("hidden", "true");
+ }
+
+ var expandOrCollapseMenu = document.getElementById("menu_expandOrCollapse");
+ if (expandOrCollapseMenu) {
+ expandOrCollapseMenu.setAttribute("hidden", "true");
+ }
+
+ var menuDeleteFolder = document.getElementById("menu_deleteFolder");
+ if (menuDeleteFolder) {
+ menuDeleteFolder.hidden = true;
+ }
+
+ var renameFolderMenu = document.getElementById("menu_renameFolder");
+ if (renameFolderMenu) {
+ renameFolderMenu.setAttribute("hidden", "true");
+ }
+
+ var viewLayoutMenu = document.getElementById("menu_MessagePaneLayout");
+ if (viewLayoutMenu) {
+ viewLayoutMenu.setAttribute("hidden", "true");
+ }
+
+ viewLayoutMenu = document.getElementById("appmenu_MessagePaneLayout");
+ if (viewLayoutMenu) {
+ viewLayoutMenu.setAttribute("hidden", "true");
+ }
+
+ let paneViewSeparator = document.getElementById("appmenu_paneViewSeparator");
+ if (paneViewSeparator) {
+ paneViewSeparator.setAttribute("hidden", "true");
+ }
+
+ var viewFolderMenu = document.getElementById("menu_FolderViews");
+ if (viewFolderMenu) {
+ viewFolderMenu.setAttribute("hidden", "true");
+ }
+
+ viewFolderMenu = document.getElementById("appmenu_FolderViews");
+ if (viewFolderMenu) {
+ viewFolderMenu.setAttribute("hidden", "true");
+ }
+
+ var viewMessagesMenu = document.getElementById("viewMessagesMenu");
+ if (viewMessagesMenu) {
+ viewMessagesMenu.setAttribute("hidden", "true");
+ }
+
+ viewMessagesMenu = document.getElementById("appmenu_viewMessagesMenu");
+ if (viewMessagesMenu) {
+ viewMessagesMenu.setAttribute("hidden", "true");
+ }
+
+ var viewMessageViewMenu = document.getElementById("viewMessageViewMenu");
+ if (viewMessageViewMenu) {
+ viewMessageViewMenu.setAttribute("hidden", "true");
+ }
+
+ var viewMessagesMenuSeparator = document.getElementById(
+ "viewMessagesMenuSeparator"
+ );
+ if (viewMessagesMenuSeparator) {
+ viewMessagesMenuSeparator.setAttribute("hidden", "true");
+ }
+
+ var openMessageMenu = document.getElementById("openMessageWindowMenuitem");
+ if (openMessageMenu) {
+ openMessageMenu.setAttribute("hidden", "true");
+ }
+
+ openMessageMenu = document.getElementById(
+ "appmenu_openMessageWindowMenuitem"
+ );
+ if (openMessageMenu) {
+ openMessageMenu.setAttribute("hidden", "true");
+ }
+
+ var viewSortMenuSeparator = document.getElementById("viewSortMenuSeparator");
+ if (viewSortMenuSeparator) {
+ viewSortMenuSeparator.setAttribute("hidden", "true");
+ }
+
+ viewSortMenuSeparator = document.getElementById(
+ "appmenu_viewAfterThreadsSeparator"
+ );
+ if (viewSortMenuSeparator) {
+ viewSortMenuSeparator.setAttribute("hidden", "true");
+ }
+
+ var viewSortMenu = document.getElementById("viewSortMenu");
+ if (viewSortMenu) {
+ viewSortMenu.setAttribute("hidden", "true");
+ }
+
+ var emptryTrashMenu = document.getElementById("menu_emptyTrash");
+ if (emptryTrashMenu) {
+ emptryTrashMenu.setAttribute("hidden", "true");
+ }
+
+ emptryTrashMenu = document.getElementById("appmenu_emptyTrash");
+ if (emptryTrashMenu) {
+ emptryTrashMenu.setAttribute("hidden", "true");
+ }
+
+ var menuPropertiesSeparator = document.getElementById(
+ "editPropertiesSeparator"
+ );
+ if (menuPropertiesSeparator) {
+ menuPropertiesSeparator.setAttribute("hidden", "true");
+ }
+
+ menuPropertiesSeparator = document.getElementById(
+ "appmenu_editPropertiesSeparator"
+ );
+ if (menuPropertiesSeparator) {
+ menuPropertiesSeparator.setAttribute("hidden", "true");
+ }
+
+ var menuProperties = document.getElementById("menu_properties");
+ if (menuProperties) {
+ menuProperties.setAttribute("hidden", "true");
+ }
+
+ menuProperties = document.getElementById("appmenu_properties");
+ if (menuProperties) {
+ menuProperties.setAttribute("hidden", "true");
+ }
+
+ var favoriteFolder = document.getElementById("menu_favoriteFolder");
+ if (favoriteFolder) {
+ favoriteFolder.setAttribute("disabled", "true");
+ favoriteFolder.setAttribute("hidden", "true");
+ }
+
+ favoriteFolder = document.getElementById("appmenu_favoriteFolder");
+ if (favoriteFolder) {
+ favoriteFolder.setAttribute("disabled", "true");
+ favoriteFolder.setAttribute("hidden", "true");
+ }
+
+ var compactFolderMenu = document.getElementById("menu_compactFolder");
+ if (compactFolderMenu) {
+ compactFolderMenu.setAttribute("hidden", "true");
+ }
+
+ let trashSeparator = document.getElementById("trashMenuSeparator");
+ if (trashSeparator) {
+ trashSeparator.setAttribute("hidden", "true");
+ }
+
+ let goStartPageSeparator = document.getElementById("goNextSeparator");
+ if (goStartPageSeparator) {
+ goStartPageSeparator.hidden = true;
+ }
+
+ let goRecentlyClosedTabsSeparator = document.getElementById(
+ "goRecentlyClosedTabsSeparator"
+ );
+ if (goRecentlyClosedTabsSeparator) {
+ goRecentlyClosedTabsSeparator.setAttribute("hidden", "true");
+ }
+
+ let goFolder = document.getElementById("goFolderMenu");
+ if (goFolder) {
+ goFolder.hidden = true;
+ }
+
+ goFolder = document.getElementById("goFolderSeparator");
+ if (goFolder) {
+ goFolder.hidden = true;
+ }
+
+ let goStartPage = document.getElementById("goStartPage");
+ if (goStartPage) {
+ goStartPage.hidden = true;
+ }
+
+ let quickFilterBar = document.getElementById("appmenu_quickFilterBar");
+ if (quickFilterBar) {
+ quickFilterBar.hidden = true;
+ }
+
+ var menuFileClose = document.getElementById("menu_close");
+ var menuFileQuit = document.getElementById("menu_FileQuitItem");
+ if (menuFileClose && menuFileQuit) {
+ menuFileQuit.parentNode.replaceChild(menuFileClose, menuFileQuit);
+ }
+}
+/* eslint-enable complexity */
+
+function OnUnloadMessageWindow() {
+ UnloadCommandUpdateHandlers();
+ ToolbarIconColor.uninit();
+ PanelUI.uninit();
+ OnMailWindowUnload();
+}
+
+// MessageWindowController object (handles commands when one of the trees does not have focus)
+var MessageWindowController = {
+ supportsCommand(command) {
+ switch (command) {
+ case "cmd_undo":
+ case "cmd_redo":
+ case "cmd_getMsgsForAuthAccounts":
+ case "cmd_newMessage":
+ case "cmd_getNextNMessages":
+ case "cmd_find":
+ case "cmd_findAgain":
+ case "cmd_findPrevious":
+ case "cmd_reload":
+ case "cmd_getNewMessages":
+ case "cmd_settingsOffline":
+ case "cmd_fullZoomReduce":
+ case "cmd_fullZoomEnlarge":
+ case "cmd_fullZoomReset":
+ case "cmd_fullZoomToggle":
+ case "cmd_viewAllHeader":
+ case "cmd_viewNormalHeader":
+ case "cmd_stop":
+ case "cmd_chat":
+ return true;
+ case "cmd_synchronizeOffline":
+ return MailOfflineMgr.isOnline();
+ default:
+ return false;
+ }
+ },
+
+ isCommandEnabled(command) {
+ switch (command) {
+ case "cmd_newMessage":
+ return MailServices.accounts.allIdentities.length > 0;
+ case "cmd_reload":
+ case "cmd_find":
+ case "cmd_stop":
+ return false;
+ case "cmd_getNewMessages":
+ case "cmd_getMsgsForAuthAccounts":
+ return IsGetNewMessagesEnabled();
+ case "cmd_getNextNMessages":
+ return IsGetNextNMessagesEnabled();
+ case "cmd_synchronizeOffline":
+ return MailOfflineMgr.isOnline();
+ case "cmd_settingsOffline":
+ return IsAccountOfflineEnabled();
+ case "cmd_findAgain":
+ case "cmd_findPrevious":
+ case "cmd_fullZoomReduce":
+ case "cmd_fullZoomEnlarge":
+ case "cmd_fullZoomReset":
+ case "cmd_fullZoomToggle":
+ case "cmd_viewAllHeader":
+ case "cmd_viewNormalHeader":
+ return true;
+ case "cmd_undo":
+ case "cmd_redo":
+ return SetupUndoRedoCommand(command);
+ case "cmd_chat":
+ return true;
+ default:
+ return false;
+ }
+ },
+
+ doCommand(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_getNewMessages":
+ MsgGetMessage();
+ break;
+ case "cmd_undo":
+ messenger.undo(msgWindow);
+ break;
+ case "cmd_redo":
+ messenger.redo(msgWindow);
+ break;
+ case "cmd_getMsgsForAuthAccounts":
+ MsgGetMessagesForAllAuthenticatedAccounts();
+ break;
+ case "cmd_getNextNMessages":
+ MsgGetNextNMessages();
+ break;
+ case "cmd_newMessage":
+ MsgNewMessage(null);
+ break;
+ case "cmd_reload":
+ ReloadMessage();
+ break;
+ case "cmd_find":
+ document.getElementById("FindToolbar").onFindCommand();
+ break;
+ case "cmd_findAgain":
+ document.getElementById("FindToolbar").onFindAgainCommand(false);
+ break;
+ case "cmd_findPrevious":
+ document.getElementById("FindToolbar").onFindAgainCommand(true);
+ break;
+ case "cmd_viewAllHeader":
+ MsgViewAllHeaders();
+ return;
+ case "cmd_viewNormalHeader":
+ MsgViewNormalHeaders();
+ return;
+ case "cmd_synchronizeOffline":
+ MsgSynchronizeOffline();
+ return;
+ case "cmd_settingsOffline":
+ MailOfflineMgr.openOfflineAccountSettings();
+ return;
+ 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_stop":
+ msgWindow.StopUrls();
+ break;
+ case "cmd_chat":
+ let win = Services.wm.getMostRecentWindow("mail:3pane");
+ if (win) {
+ win.focus();
+ win.showChatTab();
+ } else {
+ window.openDialog(
+ "chrome://messenger/content/messenger.xhtml",
+ "_blank",
+ "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar",
+ null,
+ { tabType: "chat", tabParams: {} }
+ );
+ }
+ break;
+ }
+ },
+
+ onEvent(event) {},
+};
+
+function SetupCommandUpdateHandlers() {
+ top.controllers.insertControllerAt(0, MessageWindowController);
+ top.controllers.insertControllerAt(
+ 0,
+ messageBrowser.contentWindow.commandController
+ );
+}
+
+function UnloadCommandUpdateHandlers() {
+ top.controllers.removeController(MessageWindowController);
+ top.controllers.removeController(
+ messageBrowser.contentWindow.commandController
+ );
+}
+
+/**
+ * Message history popup implementation from mail-go-button ported for the old
+ * mail toolbar.
+ *
+ * @param {XULPopupElement} popup
+ */
+function messageHistoryMenu_init(popup) {
+ const { messageHistory } = messageBrowser.contentWindow;
+ const { entries, currentIndex } = messageHistory.getHistory();
+
+ // For populating the back menu, we want the most recently visited
+ // messages first in the menu. So we go backward from curPos to 0.
+ // For the forward menu, we want to go forward from curPos to the end.
+ const items = [];
+ const relativePositionBase = entries.length - 1 - currentIndex;
+ for (const [index, entry] of entries.reverse().entries()) {
+ const folder = MailServices.folderLookup.getFolderForURL(entry.folderURI);
+ if (!folder) {
+ // Where did the folder go?
+ continue;
+ }
+
+ let menuText = "";
+ let msgHdr;
+ try {
+ msgHdr = MailServices.messageServiceFromURI(
+ entry.messageURI
+ ).messageURIToMsgHdr(entry.messageURI);
+ } catch (ex) {
+ // Let's just ignore this history entry.
+ continue;
+ }
+ const messageSubject = msgHdr.mime2DecodedSubject;
+ const messageAuthor = msgHdr.mime2DecodedAuthor;
+
+ if (!messageAuthor && !messageSubject) {
+ // Avoid empty entries in the menu. The message was most likely (re)moved.
+ continue;
+ }
+
+ // If the message was not being displayed via the current folder, prepend
+ // the folder name. We do not need to check underlying folders for
+ // virtual folders because 'folder' is the display folder, not the
+ // underlying one.
+ if (folder != messageBrowser.contentWindow.gFolder) {
+ menuText = folder.prettyName + " - ";
+ }
+
+ let subject = "";
+ if (msgHdr.flags & Ci.nsMsgMessageFlags.HasRe) {
+ subject = "Re: ";
+ }
+ if (messageSubject) {
+ subject += messageSubject;
+ }
+ if (subject) {
+ menuText += subject + " - ";
+ }
+
+ menuText += messageAuthor;
+ const newMenuItem = document.createXULElement("menuitem");
+ newMenuItem.setAttribute("label", menuText);
+ const relativePosition = relativePositionBase - index;
+ newMenuItem.setAttribute("value", relativePosition);
+ newMenuItem.addEventListener("command", commandEvent => {
+ navigateToUri(commandEvent.target);
+ commandEvent.stopPropagation();
+ });
+ if (relativePosition === 0 && !messageHistory.canPop(0)) {
+ newMenuItem.setAttribute("checked", true);
+ newMenuItem.setAttribute("type", "radio");
+ }
+ items.push(newMenuItem);
+ }
+ popup.replaceChildren(...items);
+}
+
+/**
+ * Select the message in the appropriate folder for the history popup entry.
+ * Finds the message based on the value of the item, which is the relative
+ * index of the item in the message history.
+ *
+ * @param {Element} target
+ */
+function navigateToUri(target) {
+ const nsMsgViewIndex_None = 0xffffffff;
+ const historyIndex = Number.parseInt(target.getAttribute("value"), 10);
+ const currentWindow = messageBrowser.contentWindow;
+ const { messageHistory } = currentWindow;
+ if (!messageHistory || !messageHistory.canPop(historyIndex)) {
+ return;
+ }
+ const item = messageHistory.pop(historyIndex);
+
+ if (
+ currentWindow.displayFolder &&
+ currentWindow.gFolder?.URI !== item.folderURI
+ ) {
+ const folder = MailServices.folderLookup.getFolderForURL(item.folderURI);
+ currentWindow.displayFolder(folder);
+ }
+ const msgHdr = MailServices.messageServiceFromURI(
+ item.messageURI
+ ).messageURIToMsgHdr(item.messageURI);
+ const index = currentWindow.gDBView.findIndexOfMsgHdr(msgHdr, true);
+ if (index != nsMsgViewIndex_None) {
+ currentWindow.gViewWrapper.dbView.selection.select(index);
+ currentWindow.displayMessage(
+ currentWindow.gViewWrapper.dbView.URIForFirstSelectedMessage,
+ currentWindow.gViewWrapper
+ );
+ }
+}
+
+function backToolbarMenu_init(popup) {
+ messageHistoryMenu_init(popup);
+}
+
+function forwardToolbarMenu_init(popup) {
+ messageHistoryMenu_init(popup);
+}
+
+function GetSelectedMsgFolders() {
+ return [messageBrowser.contentWindow.gFolder];
+}