2009-09-01 01:46:26 +04:00
|
|
|
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-30 20:48:24 +04:00
|
|
|
/* 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/. */
|
2008-07-22 16:21:15 +04:00
|
|
|
|
|
|
|
/* This file contains the js functions necessary to implement view navigation within the 3 pane. */
|
|
|
|
|
2012-10-30 18:10:53 +04:00
|
|
|
Components.utils.import("resource:///modules/folderUtils.jsm");
|
|
|
|
|
2008-07-22 16:21:15 +04:00
|
|
|
//NOTE: gMessengerBundle must be defined and set or this Overlay won't work
|
|
|
|
|
|
|
|
function GetSubFoldersInFolderPaneOrder(folder)
|
|
|
|
{
|
|
|
|
var subFolders = folder.subFolders;
|
|
|
|
var msgFolders = Array();
|
|
|
|
|
|
|
|
// get all the subfolders
|
|
|
|
while (subFolders.hasMoreElements()) {
|
|
|
|
msgFolders[msgFolders.length] =
|
|
|
|
subFolders.getNext().QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
}
|
|
|
|
|
|
|
|
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++];
|
|
|
|
|
2009-07-30 11:50:34 +04:00
|
|
|
const nsMsgFolderFlags = Components.interfaces.nsMsgFolderFlags;
|
|
|
|
let ignoreFlags = nsMsgFolderFlags.Trash | nsMsgFolderFlags.SentMail |
|
|
|
|
nsMsgFolderFlags.Drafts | nsMsgFolderFlags.Queue |
|
|
|
|
nsMsgFolderFlags.Templates | nsMsgFolderFlags.Junk;
|
2008-07-22 16:21:15 +04:00
|
|
|
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
|
2009-07-30 11:50:34 +04:00
|
|
|
if (!folder.isSpecialFolder(ignoreFlags, true)) {
|
2008-07-22 16:21:15 +04:00
|
|
|
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; ) {
|
|
|
|
|
2009-08-20 01:48:55 +04:00
|
|
|
var parent = folder.parent;
|
2008-07-22 16:21:15 +04:00
|
|
|
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();
|
2009-08-18 04:42:16 +04:00
|
|
|
for (var i = 0; i < rootFolders.length; i++) {
|
2008-07-22 16:21:15 +04:00
|
|
|
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()
|
|
|
|
{
|
2012-10-30 18:10:53 +04:00
|
|
|
var accounts = allAccountsSorted(false);
|
2008-07-22 16:21:15 +04:00
|
|
|
|
2012-10-30 18:10:53 +04:00
|
|
|
var serversMsgFolders = [];
|
|
|
|
for each (var account in accounts)
|
|
|
|
serversMsgFolders.push(account.incomingServer.rootMsgFolder);
|
2008-07-22 16:21:15 +04:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
|
2012-11-19 23:05:51 +04:00
|
|
|
var nextMode = Services.prefs.getIntPref("mailnews.nav_crosses_folders");
|
2008-07-22 16:21:15 +04:00
|
|
|
// 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;
|
|
|
|
SelectFolder(folder.URI);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
default:
|
|
|
|
var promptText = gMessengerBundle.getFormattedString("advanceNextPrompt", [ folder.name ], 1);
|
2011-08-15 13:49:36 +04:00
|
|
|
if (Services.prompt.confirmEx(window, null, promptText,
|
|
|
|
Services.prompt.STD_YES_NO_BUTTONS,
|
|
|
|
null, null, null, null, {}) == 0)
|
2008-07-22 16:21:15 +04:00
|
|
|
{
|
|
|
|
gNextMessageAfterLoad = type;
|
|
|
|
SelectFolder(folder.URI);
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
SelectFolder(folderUri);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function ScrollToMessage(type, wrap, selectMessage)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
var treeView = gDBView.QueryInterface(Components.interfaces.nsITreeView);
|
|
|
|
var treeSelection = treeView.selection;
|
|
|
|
var currentIndex = treeSelection.currentIndex;
|
|
|
|
|
|
|
|
var resultId = new Object;
|
|
|
|
var resultIndex = new Object;
|
|
|
|
var threadIndex = new Object;
|
|
|
|
|
2009-06-05 19:13:23 +04:00
|
|
|
let elidedFlag = Components.interfaces.nsMsgMessageFlags.Elided;
|
|
|
|
let summarizeSelection =
|
2012-11-19 23:05:51 +04:00
|
|
|
Services.prefs.getBoolPref("mail.operate_on_msgs_in_collapsed_threads");
|
2009-06-05 19:13:23 +04:00
|
|
|
|
|
|
|
// 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) &
|
|
|
|
Components.interfaces.nsMsgMessageFlags.Read)) {
|
|
|
|
resultIndex.value = currentIndex;
|
|
|
|
resultId.value = gDBView.getKeyAt(currentIndex);
|
|
|
|
} else {
|
|
|
|
gDBView.viewNavigate(type, resultId, resultIndex, threadIndex, true /* wrap */);
|
|
|
|
}
|
2008-07-22 16:21:15 +04:00
|
|
|
|
|
|
|
// only scroll and select if we found something
|
|
|
|
if ((resultId.value != nsMsgViewIndex_None) && (resultIndex.value != nsMsgViewIndex_None)) {
|
2009-06-05 19:13:23 +04:00
|
|
|
if (gDBView.getFlagsAt(resultIndex.value) & elidedFlag &&
|
|
|
|
summarizeSelection)
|
|
|
|
gDBView.toggleOpenState(resultIndex.value);
|
|
|
|
|
2008-07-22 16:21:15 +04:00
|
|
|
if (selectMessage){
|
|
|
|
treeSelection.select(resultIndex.value);
|
|
|
|
}
|
|
|
|
EnsureRowInThreadTreeIsVisible(resultIndex.value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (ex) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function GoNextMessage(type, startFromBeginning)
|
|
|
|
{
|
2008-11-14 23:01:52 +03:00
|
|
|
if (!ScrollToMessage(type, startFromBeginning, true))
|
|
|
|
CrossFolderNavigation(type);
|
2008-07-22 16:21:15 +04:00
|
|
|
|
|
|
|
SetFocusThreadPaneIfNotOnMessagePane();
|
|
|
|
}
|
|
|
|
|