summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/unifiedtoolbar/content/items/mail-go-button.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/unifiedtoolbar/content/items/mail-go-button.mjs')
-rw-r--r--comm/mail/components/unifiedtoolbar/content/items/mail-go-button.mjs183
1 files changed, 183 insertions, 0 deletions
diff --git a/comm/mail/components/unifiedtoolbar/content/items/mail-go-button.mjs b/comm/mail/components/unifiedtoolbar/content/items/mail-go-button.mjs
new file mode 100644
index 0000000000..df9266d077
--- /dev/null
+++ b/comm/mail/components/unifiedtoolbar/content/items/mail-go-button.mjs
@@ -0,0 +1,183 @@
+/* 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/. */
+
+import { MailTabButton } from "chrome://messenger/content/unifiedtoolbar/mail-tab-button.mjs";
+
+const { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+/**
+ * Map from the direction attribute value to the command the button executes on
+ * click.
+ *
+ * @type {{[string]: string}}
+ */
+const COMMAND_FOR_DIRECTION = {
+ forward: "cmd_goForward",
+ back: "cmd_goBack",
+};
+
+/**
+ * Unified toolbar button to add the selected message to a calendar as event or
+ * task.
+ * Attributes:
+ * - direction: "forward" or "back".
+ */
+class MailGoButton extends MailTabButton {
+ /**
+ * @type {?XULPopupElement}
+ */
+ #contextMenu = null;
+
+ connectedCallback() {
+ if (!this.hasConnected) {
+ const command = COMMAND_FOR_DIRECTION[this.getAttribute("direction")];
+ if (!command) {
+ throw new Error(
+ `Unknown direction "${this.getAttribute("direction")}"`
+ );
+ }
+ this.setAttribute("command", command);
+ this.#contextMenu = document.getElementById("messageHistoryPopup");
+ this.addEventListener("contextmenu", this.#handleContextMenu, true);
+ }
+ super.connectedCallback();
+ }
+
+ /**
+ * Build and show the history popup containing a list of messages to navigate
+ * to. Messages that can't be found or that were in folders we can't find are
+ * ignored. The currently displayed message is marked.
+ *
+ * @param {MouseEvent} event - Event triggering the context menu.
+ */
+ #handleContextMenu = event => {
+ event.preventDefault();
+ event.stopPropagation();
+
+ const tabmail = document.getElementById("tabmail");
+ const currentWindow = tabmail.currentTabInfo.chromeBrowser.contentWindow;
+ const { messageHistory } = tabmail.currentAboutMessage;
+ 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 != currentWindow.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 => {
+ this.#navigateToUri(commandEvent.target);
+ commandEvent.stopPropagation();
+ });
+ if (relativePosition === 0 && !messageHistory.canPop(0)) {
+ newMenuItem.setAttribute("checked", true);
+ newMenuItem.setAttribute("type", "radio");
+ }
+ items.push(newMenuItem);
+ }
+ this.#contextMenu.replaceChildren(...items);
+
+ this.#contextMenu.openPopupAtScreen(
+ event.screenX,
+ event.screenY,
+ true,
+ event
+ );
+ };
+
+ /**
+ * 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
+ */
+ #navigateToUri(target) {
+ const nsMsgViewIndex_None = 0xffffffff;
+ const historyIndex = Number.parseInt(target.getAttribute("value"), 10);
+ const tabmail = document.getElementById("tabmail");
+ const currentWindow = tabmail.currentTabInfo.chromeBrowser.contentWindow;
+ const messageHistory = tabmail.currentAboutMessage.messageHistory;
+ 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) {
+ if (currentWindow.threadTree) {
+ currentWindow.threadTree.selectedIndex = index;
+ currentWindow.threadTree.table.body.focus();
+ } else {
+ currentWindow.gViewWrapper.dbView.selection.select(index);
+ currentWindow.displayMessage(
+ currentWindow.gViewWrapper.dbView.URIForFirstSelectedMessage
+ );
+ }
+ }
+ }
+}
+customElements.define("mail-go-button", MailGoButton, {
+ extends: "button",
+});