diff options
Diffstat (limited to 'comm/suite/mailnews/content/msgViewNavigation.js')
-rw-r--r-- | comm/suite/mailnews/content/msgViewNavigation.js | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/comm/suite/mailnews/content/msgViewNavigation.js b/comm/suite/mailnews/content/msgViewNavigation.js new file mode 100644 index 0000000000..a7d0496210 --- /dev/null +++ b/comm/suite/mailnews/content/msgViewNavigation.js @@ -0,0 +1,243 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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 file contains the js functions necessary to implement view navigation within the 3 pane. */ + +const {FolderUtils} = ChromeUtils.import("resource:///modules/FolderUtils.jsm"); + +//NOTE: gMessengerBundle must be defined and set or this Overlay won't work + +function GetSubFoldersInFolderPaneOrder(folder) +{ + var msgFolders = folder.subFolders; + + function compareFolderSortKey(folder1, folder2) { + return folder1.compareSortKeys(folder2); + } + + // sort the subfolders + msgFolders.sort(compareFolderSortKey); + return msgFolders; +} + +function FindNextChildFolder(aParent, aAfter) +{ + // Search the child folders of aParent for unread messages + // but in the case that we are working up from the current folder + // we need to skip up to and including the current folder + // we skip the current folder in case a mail view is hiding unread messages + if (aParent.getNumUnread(true) > 0) { + var subFolders = GetSubFoldersInFolderPaneOrder(aParent); + var i = 0; + var folder = null; + + // Skip folders until after the specified child + while (folder != aAfter) + folder = subFolders[i++]; + + let ignoreFlags = Ci.nsMsgFolderFlags.Trash | Ci.nsMsgFolderFlags.SentMail | + Ci.nsMsgFolderFlags.Drafts | Ci.nsMsgFolderFlags.Queue | + Ci.nsMsgFolderFlags.Templates | Ci.nsMsgFolderFlags.Junk; + while (i < subFolders.length) { + folder = subFolders[i++]; + // if there is unread mail in the trash, sent, drafts, unsent messages + // templates or junk special folder, + // we ignore it when doing cross folder "next" navigation + if (!folder.isSpecialFolder(ignoreFlags, true)) { + if (folder.getNumUnread(false) > 0) + return folder; + + folder = FindNextChildFolder(folder, null); + if (folder) + return folder; + } + } + } + + return null; +} + +function FindNextFolder() +{ + // look for the next folder, this will only look on the current account + // and below us, in the folder pane + // note use of gDBView restricts this function to message folders + // otherwise you could go next unread from a server + var folder = FindNextChildFolder(gDBView.msgFolder, null); + if (folder) + return folder; + + // didn't find folder in children + // go up to the parent, and start at the folder after the current one + // unless we are at a server, in which case bail out. + for (folder = gDBView.msgFolder; !folder.isServer; ) { + + var parent = folder.parent; + folder = FindNextChildFolder(parent, folder); + if (folder) + return folder; + + // none at this level after the current folder. go up. + folder = parent; + } + + // nothing in the current account, start with the next account (below) + // and try until we hit the bottom of the folder pane + + // start at the account after the current account + var rootFolders = GetRootFoldersInFolderPaneOrder(); + for (var i = 0; i < rootFolders.length; i++) { + if (rootFolders[i].URI == gDBView.msgFolder.server.serverURI) + break; + } + + for (var j = i + 1; j < rootFolders.length; j++) { + folder = FindNextChildFolder(rootFolders[j], null); + if (folder) + return folder; + } + + // if nothing from the current account down to the bottom + // (of the folder pane), start again at the top. + for (j = 0; j <= i; j++) { + folder = FindNextChildFolder(rootFolders[j], null); + if (folder) + return folder; + } + return null; +} + +function GetRootFoldersInFolderPaneOrder() +{ + var accounts = FolderUtils.allAccountsSorted(false); + + var serversMsgFolders = []; + for (var account of accounts) + serversMsgFolders.push(account.incomingServer.rootMsgFolder); + + return serversMsgFolders; +} + +function CrossFolderNavigation(type) +{ + // do cross folder navigation for next unread message/thread and message history + if (type != nsMsgNavigationType.nextUnreadMessage && + type != nsMsgNavigationType.nextUnreadThread && + type != nsMsgNavigationType.forward && + type != nsMsgNavigationType.back) + return; + + if (type == nsMsgNavigationType.nextUnreadMessage || + type == nsMsgNavigationType.nextUnreadThread) + { + + var nextMode = Services.prefs.getIntPref("mailnews.nav_crosses_folders"); + // 0: "next" goes to the next folder, without prompting + // 1: "next" goes to the next folder, and prompts (the default) + // 2: "next" does nothing when there are no unread messages + + // not crossing folders, don't find next + if (nextMode == 2) + return; + + var folder = FindNextFolder(); + if (folder && (gDBView.msgFolder.URI != folder.URI)) + { + switch (nextMode) + { + case 0: + // do this unconditionally + gNextMessageAfterLoad = type; + SelectMsgFolder(folder); + break; + case 1: + default: + var promptText = gMessengerBundle.getFormattedString("advanceNextPrompt", [ folder.name ], 1); + if (Services.prompt.confirmEx(window, null, promptText, + Services.prompt.STD_YES_NO_BUTTONS, + null, null, null, null, {}) == 0) + { + gNextMessageAfterLoad = type; + SelectMsgFolder(folder); + } + break; + } + } + } + else + { + // if no message is loaded, relPos should be 0, to + // go back to the previously loaded message + var relPos = (type == nsMsgNavigationType.forward) + ? 1 : ((GetLoadedMessage()) ? -1 : 0); + var folderUri = messenger.getFolderUriAtNavigatePos(relPos); + var msgHdr = messenger.msgHdrFromURI(messenger.getMsgUriAtNavigatePos(relPos)); + gStartMsgKey = msgHdr.messageKey; + var curPos = messenger.navigatePos; + curPos += relPos; + messenger.navigatePos = curPos; + SelectMsgFolder(MailUtils.getFolderForURI(folderUri)); + } +} + + +function ScrollToMessage(type, wrap, selectMessage) +{ + try { + var treeView = gDBView.QueryInterface(Ci.nsITreeView); + var treeSelection = treeView.selection; + var currentIndex = treeSelection.currentIndex; + + var resultId = new Object; + var resultIndex = new Object; + var threadIndex = new Object; + + let elidedFlag = Ci.nsMsgMessageFlags.Elided; + let summarizeSelection = + Services.prefs.getBoolPref("mail.operate_on_msgs_in_collapsed_threads"); + + // if we're doing next unread, and a collapsed thread is selected, and + // the top level message is unread, just set the result manually to + // the top level message, without using gDBView.viewNavigate. + if (summarizeSelection && type == nsMsgNavigationType.nextUnreadMessage && + currentIndex != -1 && + gDBView.getFlagsAt(currentIndex) & elidedFlag && + gDBView.isContainer(currentIndex) && + ! (gDBView.getFlagsAt(currentIndex) & + Ci.nsMsgMessageFlags.Read)) { + resultIndex.value = currentIndex; + resultId.value = gDBView.getKeyAt(currentIndex); + } else { + gDBView.viewNavigate(type, resultId, resultIndex, threadIndex, true /* wrap */); + } + + // only scroll and select if we found something + if ((resultId.value != nsMsgViewIndex_None) && (resultIndex.value != nsMsgViewIndex_None)) { + if (gDBView.getFlagsAt(resultIndex.value) & elidedFlag && + summarizeSelection) + gDBView.toggleOpenState(resultIndex.value); + + if (selectMessage){ + treeSelection.select(resultIndex.value); + } + EnsureRowInThreadTreeIsVisible(resultIndex.value); + return true; + } + else { + return false; + } + } + catch (ex) { + return false; + } +} + +function GoNextMessage(type, startFromBeginning) +{ + if (!ScrollToMessage(type, startFromBeginning, true)) + CrossFolderNavigation(type); + + SetFocusThreadPaneIfNotOnMessagePane(); +} |