isCommandEnabled()

in mail/base/content/mailCommon.js [458:719]


  isCommandEnabled(command) {
    const type = typeof this._isCallbackEnabled[command];
    if (type == "function") {
      return this._isCallbackEnabled[command]();
    } else if (type == "boolean") {
      return this._isCallbackEnabled[command];
    }

    const hasIdentities = MailServices.accounts.allIdentities.length;
    switch (command) {
      case "cmd_newMessage":
        return hasIdentities;
      case "cmd_searchMessages":
        // TODO: This shouldn't be here, or should return false if there are no accounts.
        return true;
      case "cmd_space":
      case "cmd_manageTags":
        return true;
    }

    if (!gViewWrapper?.dbView) {
      return false;
    }

    const isDummyMessage = !gViewWrapper.isSynthetic && !gFolder;

    if (["cmd_goBack", "cmd_goForward"].includes(command)) {
      const activeMessageHistory = (
        window.messageBrowser?.contentWindow ?? window
      ).messageHistory;
      const relPos = command === "cmd_goBack" ? -1 : 1;
      if (relPos === -1 && activeMessageHistory.canPop(0)) {
        return !isDummyMessage;
      }
      return !isDummyMessage && activeMessageHistory.canPop(relPos);
    }

    if (command in this._navigationCommands) {
      return !isDummyMessage;
    }

    const numSelectedMessages = isDummyMessage
      ? 1
      : Number(gDBView?.numSelected);

    // Evaluate these properties only if needed, not once for each command.
    const folder = () => {
      if (gFolder) {
        return gFolder;
      }
      if (gDBView?.numSelected >= 1) {
        return gDBView.hdrForFirstSelectedMessage?.folder;
      }
      return null;
    };
    const isNewsgroup = () =>
      folder()?.isSpecialFolder(Ci.nsMsgFolderFlags.Newsgroup, true);
    const canMove = () =>
      numSelectedMessages >= 1 &&
      (folder()?.canDeleteMessages || gViewWrapper.isSynthetic) &&
      !gViewWrapper.isExpandedGroupedByHeaderAtIndex(
        gDBView.viewIndexForFirstSelectedMsg
      );

    switch (command) {
      case "cmd_cancel":
        if (numSelectedMessages == 1 && isNewsgroup()) {
          // Ensure author of message matches own identity
          const author = gDBView.hdrForFirstSelectedMessage.mime2DecodedAuthor;
          return MailServices.accounts
            .getIdentitiesForServer(folder().server)
            .some(id => id.fullAddress == author);
        }
        return false;
      case "cmd_openConversation":
        return (
          // This (instead of numSelectedMessages) is necessary to be able to
          // also open a collapsed thread in conversation.
          gDBView.selection.count == 1 &&
          ConversationOpener.isMessageIndexed(
            gDBView.hdrForFirstSelectedMessage
          )
        );
      case "cmd_replylist":
        if (
          !mailContextMenu.selectionIsOverridden &&
          hasIdentities &&
          numSelectedMessages == 1
        ) {
          return (window.messageBrowser?.contentWindow ?? window)
            .currentHeaderData?.["list-post"];
        }
        return false;
      case "cmd_viewPageSource":
        return numSelectedMessages > 0;
      case "cmd_saveAsTemplate":
        return numSelectedMessages == 1 && !isDummyMessage;
      case "cmd_reply":
      case "cmd_replySender":
      case "cmd_replyall":
      case "cmd_forward":
      case "cmd_forwardInline":
      case "cmd_forwardAttachment":
      case "cmd_redirect":
      case "cmd_editAsNew":
        return (
          hasIdentities &&
          (numSelectedMessages == 1 ||
            (numSelectedMessages > 1 &&
              // Exclude collapsed threads.
              numSelectedMessages == gDBView.selection.count))
        );
      case "cmd_copyMessage":
      case "cmd_saveAsFile":
        return numSelectedMessages >= 1;
      case "cmd_openMessage":
        return (
          (location.href == "about:3pane" ||
            parent.location.href == "about:3pane") &&
          numSelectedMessages >= 1 &&
          !isDummyMessage
        );
      case "cmd_tag":
      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_addTag":
      case "cmd_removeTags":
      case "cmd_toggleTag":
      case "cmd_toggleRead":
      case "cmd_markAsFlagged":
      case "cmd_applyFiltersToSelection":
        return numSelectedMessages >= 1 && !isDummyMessage;
      case "cmd_copyDecryptedTo": {
        let showDecrypt = numSelectedMessages > 1;
        if (numSelectedMessages == 1 && !isDummyMessage) {
          const msgURI = gDBView.URIForFirstSelectedMessage;
          if (msgURI) {
            showDecrypt = gEncryptedURIService.isEncrypted(msgURI);
          }
        }
        return showDecrypt;
      }
      case "cmd_editDraftMsg":
        return (
          numSelectedMessages >= 1 &&
          folder()?.isSpecialFolder(Ci.nsMsgFolderFlags.Drafts, true)
        );
      case "cmd_newMsgFromTemplate":
      case "cmd_editTemplateMsg":
        return (
          numSelectedMessages >= 1 &&
          folder()?.isSpecialFolder(Ci.nsMsgFolderFlags.Templates, true)
        );
      case "cmd_replyGroup":
        return (
          isNewsgroup() ||
          (window.messageBrowser?.contentWindow ?? window).currentHeaderData
            ?.newsgroups
        );
      case "cmd_markAsRead":
        return (
          numSelectedMessages >= 1 &&
          !isDummyMessage &&
          gViewWrapper.dbView.getSelectedMsgHdrs().some(msg => !msg.isRead)
        );
      case "cmd_markAsUnread":
        return (
          numSelectedMessages >= 1 &&
          !isDummyMessage &&
          gViewWrapper.dbView.getSelectedMsgHdrs().some(msg => msg.isRead)
        );
      case "cmd_markThreadAsRead": {
        if (numSelectedMessages == 0 || isDummyMessage) {
          return false;
        }
        const sel = gViewWrapper.dbView.selection;
        for (let i = 0; i < sel.getRangeCount(); i++) {
          const start = {};
          const end = {};
          sel.getRangeAt(i, start, end);
          for (let j = start.value; j <= end.value; j++) {
            if (
              gViewWrapper.dbView.getThreadContainingIndex(j)
                .numUnreadChildren > 0
            ) {
              return true;
            }
          }
        }
        return false;
      }
      case "cmd_markReadByDate":
      case "cmd_markAllRead":
        return gDBView?.msgFolder?.getNumUnread(false) > 0;
      case "cmd_markAsJunk":
      case "cmd_markAsNotJunk":
        return this._getViewCommandStatus(Ci.nsMsgViewCommandType.junk);
      case "cmd_archive":
        return (
          !isDummyMessage &&
          MessageArchiver.canArchive(
            gDBView.getSelectedMsgHdrs(),
            gViewWrapper.isSingleFolder
          )
        );
      case "cmd_moveMessage": {
        return canMove();
      }
      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.
        let canMoveAgain = numSelectedMessages >= 1;
        if (Services.prefs.getBoolPref("mail.last_msg_movecopy_was_move")) {
          canMoveAgain = canMove() && !isNewsgroup();
        }
        if (canMoveAgain) {
          const targetURI = Services.prefs.getStringPref(
            "mail.last_msg_movecopy_target_uri"
          );
          canMoveAgain = targetURI && MailUtils.getExistingFolder(targetURI);
        }
        return !!canMoveAgain;
      }
      case "cmd_deleteMessage":
        return canMove();
      case "cmd_shiftDeleteMessage":
        return this._getViewCommandStatus(
          Ci.nsMsgViewCommandType.deleteNoTrash
        );
      case "cmd_createFilterFromMenu":
        return (
          numSelectedMessages == 1 &&
          !isDummyMessage &&
          folder()?.server.canHaveFilters
        );
      case "cmd_watchThread": {
        if (gViewWrapper?.showGroupedBySort) {
          return false;
        }
        const enabledObj = {};
        const checkStatusObj = {};
        gViewWrapper.dbView.getCommandStatus(
          Ci.nsMsgViewCommandType.toggleThreadWatched,
          enabledObj,
          checkStatusObj
        );
        return enabledObj.value;
      }
      case "cmd_applyFilters": {
        return this._getViewCommandStatus(Ci.nsMsgViewCommandType.applyFilters);
      }
    }

    return false;
  },