summaryrefslogtreecommitdiffstats
path: root/comm/suite/mailnews/content/msgViewNavigation.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/suite/mailnews/content/msgViewNavigation.js')
-rw-r--r--comm/suite/mailnews/content/msgViewNavigation.js243
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();
+}