mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-26 02:17:34 +09:00
Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1
This commit is contained in:
parent
23e0d82436
commit
e400f4130a
1564 changed files with 510348 additions and 0 deletions
5
mailnews/base/content/charsetList.css
Normal file
5
mailnews/base/content/charsetList.css
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
|
||||
menulist[type="charset"] {
|
||||
-moz-binding: url("chrome://messenger/content/charsetList.xml#charsetpicker");
|
||||
}
|
||||
69
mailnews/base/content/charsetList.xml
Normal file
69
mailnews/base/content/charsetList.xml
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- 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/.
|
||||
-->
|
||||
|
||||
<bindings id="charsetListBinding"
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xbl="http://www.mozilla.org/xbl"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<binding id="charsetpicker"
|
||||
extends="chrome://global/content/bindings/menulist.xml#menulist">
|
||||
<implementation>
|
||||
<constructor><![CDATA[
|
||||
let charsetValues = "";
|
||||
|
||||
if (this.getAttribute("subset") == "sending")
|
||||
charsetValues = ["UTF-8", "EUC-KR", "gbk", "gb18030", "ISO-2022-JP",
|
||||
"ISO-8859-1", "ISO-8859-7", "windows-1252"];
|
||||
|
||||
else if (!this.getAttribute("subset")
|
||||
|| this.getAttribute("subset") == "viewing")
|
||||
charsetValues = ["UTF-8", "Big5", "EUC-KR", "gbk", "ISO-2022-JP",
|
||||
"ISO-8859-1", "ISO-8859-2", "ISO-8859-7",
|
||||
"windows-874", "windows-1250", "windows-1251",
|
||||
"windows-1252", "windows-1255", "windows-1256",
|
||||
"windows-1257", "windows-1258"];
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let charsetBundle = Services.strings.createBundle(
|
||||
"chrome://messenger/locale/charsetTitles.properties");
|
||||
let aMenuList = this;
|
||||
let menuLabels = [];
|
||||
|
||||
charsetValues.forEach(function(item) {
|
||||
let strCharset = charsetBundle.GetStringFromName(
|
||||
item.toLowerCase() + ".title");
|
||||
|
||||
menuLabels.push({label: strCharset, value: item});
|
||||
});
|
||||
|
||||
menuLabels.sort(function(a, b) {
|
||||
if (a.value == "UTF-8" || a.label < b.label)
|
||||
return -1;
|
||||
else if (b.value == "UTF-8" || a.label > b.label)
|
||||
return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
menuLabels.forEach(function(item) {
|
||||
aMenuList.appendItem(item.label, item.value);
|
||||
});
|
||||
|
||||
// Selecting appropiate menu item corresponding to preference stored
|
||||
// value.
|
||||
if (this.hasAttribute("preference")) {
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
let preference = Services.prefs.getComplexValue(
|
||||
this.getAttribute("preference"), Ci.nsIPrefLocalizedString);
|
||||
this.value = preference.data;
|
||||
}
|
||||
]]></constructor>
|
||||
</implementation>
|
||||
</binding>
|
||||
</bindings>
|
||||
225
mailnews/base/content/dateFormat.js
Normal file
225
mailnews/base/content/dateFormat.js
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var gSearchDateFormat = 0;
|
||||
var gSearchDateSeparator;
|
||||
var gSearchDateLeadingZeros;
|
||||
|
||||
/**
|
||||
* Get the short date format option of the current locale.
|
||||
* This supports the common case which the date separator is
|
||||
* either '/', '-', '.' and using Christian year.
|
||||
*/
|
||||
function initLocaleShortDateFormat()
|
||||
{
|
||||
// default to mm/dd/yyyy
|
||||
gSearchDateFormat = 3;
|
||||
gSearchDateSeparator = "/";
|
||||
gSearchDateLeadingZeros = true;
|
||||
|
||||
try {
|
||||
var dateFormatService = Components.classes["@mozilla.org/intl/scriptabledateformat;1"]
|
||||
.getService(Components.interfaces.nsIScriptableDateFormat);
|
||||
var dateString = dateFormatService.FormatDate("",
|
||||
dateFormatService.dateFormatShort,
|
||||
1999,
|
||||
12,
|
||||
1);
|
||||
|
||||
// find out the separator
|
||||
var possibleSeparators = "/-.";
|
||||
var arrayOfStrings;
|
||||
for ( var i = 0; i < possibleSeparators.length; ++i )
|
||||
{
|
||||
arrayOfStrings = dateString.split( possibleSeparators[i] );
|
||||
if ( arrayOfStrings.length == 3 )
|
||||
{
|
||||
gSearchDateSeparator = possibleSeparators[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check the format option
|
||||
if ( arrayOfStrings.length != 3 ) // no successfull split
|
||||
{
|
||||
dump("getLocaleShortDateFormat: could not analyze the date format, defaulting to mm/dd/yyyy\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// the date will contain a zero if that system settings include leading zeros
|
||||
gSearchDateLeadingZeros = dateString.includes("0");
|
||||
|
||||
// match 1 as number, since that will match both "1" and "01"
|
||||
if ( arrayOfStrings[0] == 1 )
|
||||
{
|
||||
// 01.12.1999 or 01.1999.12
|
||||
gSearchDateFormat = arrayOfStrings[1] == "12" ? 5 : 6;
|
||||
}
|
||||
else if ( arrayOfStrings[1] == 1 )
|
||||
{
|
||||
// 12.01.1999 or 1999.01.12
|
||||
gSearchDateFormat = arrayOfStrings[0] == "12" ? 3 : 2;
|
||||
}
|
||||
else // implies arrayOfStrings[2] == 1
|
||||
{
|
||||
// 12.1999.01 or 1999.12.01
|
||||
gSearchDateFormat = arrayOfStrings[0] == "12" ? 4 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
dump("getLocaleShortDateFormat: caught an exception!\n");
|
||||
}
|
||||
}
|
||||
|
||||
function initializeSearchDateFormat()
|
||||
{
|
||||
if (gSearchDateFormat)
|
||||
return;
|
||||
|
||||
// get a search date format option and a seprator
|
||||
try {
|
||||
gSearchDateFormat =
|
||||
Services.prefs.getComplexValue("mailnews.search_date_format",
|
||||
Components.interfaces.nsIPrefLocalizedString);
|
||||
gSearchDateFormat = parseInt(gSearchDateFormat);
|
||||
|
||||
// if the option is 0 then try to use the format of the current locale
|
||||
if (gSearchDateFormat == 0)
|
||||
initLocaleShortDateFormat();
|
||||
else
|
||||
{
|
||||
// initialize the search date format based on preferences
|
||||
if ( gSearchDateFormat < 1 || gSearchDateFormat > 6 )
|
||||
gSearchDateFormat = 3;
|
||||
|
||||
gSearchDateSeparator =
|
||||
Services.prefs.getComplexValue("mailnews.search_date_separator",
|
||||
Components.interfaces.nsIPrefLocalizedString);
|
||||
|
||||
gSearchDateLeadingZeros =
|
||||
(Services.prefs.getComplexValue(
|
||||
"mailnews.search_date_leading_zeros",
|
||||
Components.interfaces.nsIPrefLocalizedString).data == "true");
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
Components.utils.reportError("initializeSearchDateFormat: caught an exception: " + e);
|
||||
// set to mm/dd/yyyy in case of error
|
||||
gSearchDateFormat = 3;
|
||||
gSearchDateSeparator = "/";
|
||||
gSearchDateLeadingZeros = true;
|
||||
}
|
||||
}
|
||||
|
||||
function convertPRTimeToString(tm)
|
||||
{
|
||||
var time = new Date();
|
||||
// PRTime is in microseconds, JavaScript time is in milliseconds
|
||||
// so divide by 1000 when converting
|
||||
time.setTime(tm / 1000);
|
||||
|
||||
return convertDateToString(time);
|
||||
}
|
||||
|
||||
function convertDateToString(time)
|
||||
{
|
||||
initializeSearchDateFormat();
|
||||
|
||||
var year = time.getFullYear();
|
||||
var month = time.getMonth() + 1; // since js month is 0-11
|
||||
if ( gSearchDateLeadingZeros && month < 10 )
|
||||
month = "0" + month;
|
||||
var date = time.getDate();
|
||||
if ( gSearchDateLeadingZeros && date < 10 )
|
||||
date = "0" + date;
|
||||
|
||||
var dateStr;
|
||||
var sep = gSearchDateSeparator;
|
||||
|
||||
switch (gSearchDateFormat)
|
||||
{
|
||||
case 1:
|
||||
dateStr = year + sep + month + sep + date;
|
||||
break;
|
||||
case 2:
|
||||
dateStr = year + sep + date + sep + month;
|
||||
break;
|
||||
case 3:
|
||||
dateStr = month + sep + date + sep + year;
|
||||
break;
|
||||
case 4:
|
||||
dateStr = month + sep + year + sep + date;
|
||||
break;
|
||||
case 5:
|
||||
dateStr = date + sep + month + sep + year;
|
||||
break;
|
||||
case 6:
|
||||
dateStr = date + sep + year + sep + month;
|
||||
break;
|
||||
default:
|
||||
dump("valid search date format option is 1-6\n");
|
||||
}
|
||||
|
||||
return dateStr;
|
||||
}
|
||||
|
||||
function convertStringToPRTime(str)
|
||||
{
|
||||
initializeSearchDateFormat();
|
||||
|
||||
var arrayOfStrings = str.split(gSearchDateSeparator);
|
||||
var year, month, date;
|
||||
|
||||
// set year, month, date based on the format option
|
||||
switch (gSearchDateFormat)
|
||||
{
|
||||
case 1:
|
||||
year = arrayOfStrings[0];
|
||||
month = arrayOfStrings[1];
|
||||
date = arrayOfStrings[2];
|
||||
break;
|
||||
case 2:
|
||||
year = arrayOfStrings[0];
|
||||
month = arrayOfStrings[2];
|
||||
date = arrayOfStrings[1];
|
||||
break;
|
||||
case 3:
|
||||
year = arrayOfStrings[2];
|
||||
month = arrayOfStrings[0];
|
||||
date = arrayOfStrings[1];
|
||||
break;
|
||||
case 4:
|
||||
year = arrayOfStrings[1];
|
||||
month = arrayOfStrings[0];
|
||||
date = arrayOfStrings[2];
|
||||
break;
|
||||
case 5:
|
||||
year = arrayOfStrings[2];
|
||||
month = arrayOfStrings[1];
|
||||
date = arrayOfStrings[0];
|
||||
break;
|
||||
case 6:
|
||||
year = arrayOfStrings[1];
|
||||
month = arrayOfStrings[2];
|
||||
date = arrayOfStrings[0];
|
||||
break;
|
||||
default:
|
||||
dump("valid search date format option is 1-6\n");
|
||||
}
|
||||
|
||||
month -= 1; // since js month is 0-11
|
||||
|
||||
var time = new Date(year, month, date);
|
||||
|
||||
// JavaScript time is in milliseconds, PRTime is in microseconds
|
||||
// so multiply by 1000 when converting
|
||||
return (time.getTime() * 1000);
|
||||
}
|
||||
|
||||
387
mailnews/base/content/folderProps.js
Normal file
387
mailnews/base/content/folderProps.js
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
/* 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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource:///modules/gloda/gloda.js");
|
||||
|
||||
var gMsgFolder;
|
||||
var gLockedPref = null;
|
||||
|
||||
// The folderPropsSink is the class that gets notified of an imap folder's properties
|
||||
|
||||
var gFolderPropsSink = {
|
||||
setFolderType: function(folderTypeString)
|
||||
{
|
||||
var typeLabel = document.getElementById("folderType.text");
|
||||
if (typeLabel)
|
||||
{
|
||||
typeLabel.setAttribute("value",folderTypeString);
|
||||
}
|
||||
// get the element for the folder type label and set value on it.
|
||||
},
|
||||
|
||||
setFolderTypeDescription: function(folderDescription)
|
||||
{
|
||||
var folderTypeLabel = document.getElementById("folderDescription.text");
|
||||
if (folderTypeLabel)
|
||||
folderTypeLabel.setAttribute("value", folderDescription);
|
||||
},
|
||||
|
||||
setFolderPermissions: function(folderPermissions)
|
||||
{
|
||||
var permissionsLabel = document.getElementById("folderPermissions.text");
|
||||
var descTextNode = document.createTextNode(folderPermissions);
|
||||
permissionsLabel.appendChild(descTextNode);
|
||||
},
|
||||
|
||||
serverDoesntSupportACL : function()
|
||||
{
|
||||
var typeLabel = document.getElementById("folderTypeLabel");
|
||||
if (typeLabel)
|
||||
typeLabel.setAttribute("hidden", "true");
|
||||
var permissionsLabel = document.getElementById("permissionsDescLabel");
|
||||
if (permissionsLabel)
|
||||
permissionsLabel.setAttribute("hidden", "true");
|
||||
|
||||
},
|
||||
|
||||
setQuotaStatus : function(folderQuotaStatus)
|
||||
{
|
||||
var quotaStatusLabel = document.getElementById("folderQuotaStatus");
|
||||
if(quotaStatusLabel)
|
||||
quotaStatusLabel.setAttribute("value", folderQuotaStatus);
|
||||
},
|
||||
|
||||
showQuotaData : function(showData)
|
||||
{
|
||||
var quotaStatusLabel = document.getElementById("folderQuotaStatus");
|
||||
var folderQuotaData = document.getElementById("folderQuotaData");
|
||||
|
||||
if(quotaStatusLabel && folderQuotaData)
|
||||
{
|
||||
quotaStatusLabel.hidden = showData;
|
||||
folderQuotaData.hidden = ! showData;
|
||||
}
|
||||
},
|
||||
|
||||
setQuotaData : function(root, usedKB, maxKB)
|
||||
{
|
||||
var quotaRoot = document.getElementById("quotaRoot");
|
||||
if (quotaRoot)
|
||||
quotaRoot.setAttribute("value", '"' + root + '"');
|
||||
|
||||
var percentage = (maxKB != 0) ? Math.round(usedKB / maxKB * 100) : 0;
|
||||
|
||||
var quotaPercentageBar = document.getElementById("quotaPercentageBar");
|
||||
if (quotaPercentageBar)
|
||||
quotaPercentageBar.setAttribute("value", percentage);
|
||||
|
||||
var bundle = document.getElementById("bundle_messenger");
|
||||
if(bundle)
|
||||
{
|
||||
var usedFreeCaption = bundle.getFormattedString("quotaUsedFree", [usedKB, maxKB], 2);
|
||||
var quotaCaption = document.getElementById("quotaUsedFree");
|
||||
if(quotaCaption)
|
||||
quotaCaption.setAttribute("value", usedFreeCaption);
|
||||
|
||||
var percentUsedCaption = bundle.getFormattedString("quotaPercentUsed", [percentage], 1);
|
||||
var percentUsed = document.getElementById("quotaPercentUsed");
|
||||
if(percentUsed)
|
||||
percentUsed.setAttribute("value", percentUsedCaption);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function doEnabling()
|
||||
{
|
||||
var nameTextbox = document.getElementById("name");
|
||||
document.documentElement.getButton("accept").disabled = !nameTextbox.value;
|
||||
}
|
||||
|
||||
function folderPropsOKButton()
|
||||
{
|
||||
if (gMsgFolder)
|
||||
{
|
||||
const nsMsgFolderFlags = Components.interfaces.nsMsgFolderFlags;
|
||||
// set charset attributes
|
||||
var folderCharsetList = document.getElementById("folderCharsetList");
|
||||
|
||||
// Log to the Error Console the charset value for the folder
|
||||
// if it is unknown to us. Value will be preserved by the menu-item.
|
||||
if (folderCharsetList.selectedIndex == -1)
|
||||
{
|
||||
Components.utils.reportError("Unknown folder encoding; folder=" +
|
||||
gMsgFolder.name + ", charset=" + gMsgFolder.charset);
|
||||
}
|
||||
|
||||
gMsgFolder.charset = folderCharsetList.getAttribute("value");
|
||||
gMsgFolder.charsetOverride = document.getElementById("folderCharsetOverride")
|
||||
.checked;
|
||||
|
||||
if(document.getElementById("offline.selectForOfflineFolder").checked ||
|
||||
document.getElementById("offline.selectForOfflineNewsgroup").checked)
|
||||
gMsgFolder.setFlag(nsMsgFolderFlags.Offline);
|
||||
else
|
||||
gMsgFolder.clearFlag(nsMsgFolderFlags.Offline);
|
||||
|
||||
if(document.getElementById("folderCheckForNewMessages").checked)
|
||||
gMsgFolder.setFlag(nsMsgFolderFlags.CheckNew);
|
||||
else
|
||||
gMsgFolder.clearFlag(nsMsgFolderFlags.CheckNew);
|
||||
|
||||
let glodaCheckbox = document.getElementById("folderIncludeInGlobalSearch");
|
||||
if (!glodaCheckbox.hidden) {
|
||||
if(glodaCheckbox.checked) {
|
||||
// We pass true here so that folders such as trash and junk can still
|
||||
// have a priority set.
|
||||
Gloda.resetFolderIndexingPriority(gMsgFolder, true);
|
||||
} else {
|
||||
Gloda.setFolderIndexingPriority(gMsgFolder,
|
||||
Gloda.getFolderForFolder(gMsgFolder).kIndexingNeverPriority);
|
||||
}
|
||||
}
|
||||
|
||||
var retentionSettings = saveCommonRetentionSettings(gMsgFolder.retentionSettings);
|
||||
retentionSettings.useServerDefaults = document.getElementById("retention.useDefault").checked;
|
||||
gMsgFolder.retentionSettings = retentionSettings;
|
||||
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// This throws an exception when an illegal folder name was entered.
|
||||
okCallback(document.getElementById("name").value, window.arguments[0].name,
|
||||
gMsgFolder.URI);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function folderPropsOnLoad()
|
||||
{
|
||||
// look in arguments[0] for parameters
|
||||
if (window.arguments && window.arguments[0]) {
|
||||
if ( window.arguments[0].title ) {
|
||||
document.title = window.arguments[0].title;
|
||||
}
|
||||
if ( window.arguments[0].okCallback ) {
|
||||
top.okCallback = window.arguments[0].okCallback;
|
||||
}
|
||||
}
|
||||
|
||||
// fill in folder name, based on what they selected in the folder pane
|
||||
if (window.arguments[0].folder) {
|
||||
gMsgFolder = window.arguments[0].folder;
|
||||
} else {
|
||||
dump("passed null for folder, do nothing\n");
|
||||
}
|
||||
|
||||
if(window.arguments[0].name)
|
||||
{
|
||||
// Initialize name textbox with the given name and remember this
|
||||
// value so we can tell whether the folder needs to be renamed
|
||||
// when the dialog is accepted.
|
||||
var nameTextbox = document.getElementById("name");
|
||||
nameTextbox.value = window.arguments[0].name;
|
||||
|
||||
// name.setSelectionRange(0,-1);
|
||||
// name.focusTextField();
|
||||
}
|
||||
|
||||
const nsMsgFolderFlags = Components.interfaces.nsMsgFolderFlags;
|
||||
const serverType = window.arguments[0].serverType;
|
||||
|
||||
// Do this first, because of gloda we may want to override some of the hidden
|
||||
// statuses.
|
||||
hideShowControls(serverType);
|
||||
|
||||
if (gMsgFolder) {
|
||||
// We really need a functioning database, so we'll detect problems
|
||||
// and create one if we have to.
|
||||
try {
|
||||
var db = gMsgFolder.getDatabase(null);
|
||||
}
|
||||
catch (e) {
|
||||
gMsgFolder.updateFolder(window.arguments[0].msgWindow);
|
||||
}
|
||||
|
||||
var locationTextbox = document.getElementById("location");
|
||||
|
||||
// Decode the displayed mailbox:// URL as it's useful primarily for debugging,
|
||||
// whereas imap and news urls are sent around.
|
||||
locationTextbox.value = (serverType == "imap" || serverType == "nntp") ?
|
||||
gMsgFolder.folderURL : decodeURI(gMsgFolder.folderURL);
|
||||
|
||||
if (gMsgFolder.canRename)
|
||||
document.getElementById("name").removeAttribute("readonly");
|
||||
|
||||
if (gMsgFolder.flags & nsMsgFolderFlags.Offline) {
|
||||
|
||||
if(serverType == "imap" || serverType == "pop3")
|
||||
document.getElementById("offline.selectForOfflineFolder").checked = true;
|
||||
|
||||
if(serverType == "nntp")
|
||||
document.getElementById("offline.selectForOfflineNewsgroup").checked = true;
|
||||
}
|
||||
else {
|
||||
if(serverType == "imap" || serverType == "pop3")
|
||||
document.getElementById("offline.selectForOfflineFolder").checked = false;
|
||||
|
||||
if(serverType == "nntp")
|
||||
document.getElementById("offline.selectForOfflineNewsgroup").checked = false;
|
||||
}
|
||||
|
||||
// select the menu item
|
||||
var folderCharsetList = document.getElementById("folderCharsetList");
|
||||
folderCharsetList.value = gMsgFolder.charset;
|
||||
|
||||
// set override checkbox
|
||||
document.getElementById("folderCharsetOverride").checked = gMsgFolder.charsetOverride;
|
||||
|
||||
// set check for new mail checkbox
|
||||
document.getElementById("folderCheckForNewMessages").checked = gMsgFolder.flags & nsMsgFolderFlags.CheckNew;
|
||||
|
||||
// if gloda indexing is off, hide the related checkbox
|
||||
var glodaCheckbox = document.getElementById("folderIncludeInGlobalSearch");
|
||||
var glodaEnabled = Services.prefs
|
||||
.getBoolPref("mailnews.database.global.indexer.enabled");
|
||||
if (!glodaEnabled || (gMsgFolder.flags & (nsMsgFolderFlags.Queue |
|
||||
nsMsgFolderFlags.Newsgroup))) {
|
||||
glodaCheckbox.hidden = true;
|
||||
} else {
|
||||
// otherwise, the user can choose whether this file gets indexed
|
||||
let glodaFolder = Gloda.getFolderForFolder(gMsgFolder);
|
||||
glodaCheckbox.checked =
|
||||
glodaFolder.indexingPriority != glodaFolder.kIndexingNeverPriority;
|
||||
}
|
||||
}
|
||||
|
||||
if (serverType == "imap")
|
||||
{
|
||||
var imapFolder = gMsgFolder.QueryInterface(Components.interfaces.nsIMsgImapMailFolder);
|
||||
if (imapFolder)
|
||||
imapFolder.fillInFolderProps(gFolderPropsSink);
|
||||
}
|
||||
|
||||
var retentionSettings = gMsgFolder.retentionSettings;
|
||||
initCommonRetentionSettings(retentionSettings);
|
||||
document.getElementById("retention.useDefault").checked = retentionSettings.useServerDefaults;
|
||||
|
||||
// set folder sizes
|
||||
let numberOfMsgs = gMsgFolder.getTotalMessages(false);
|
||||
if (numberOfMsgs >= 0)
|
||||
document.getElementById("numberOfMessages").value = numberOfMsgs;
|
||||
|
||||
try {
|
||||
let sizeOnDisk = Components.classes["@mozilla.org/messenger;1"]
|
||||
.createInstance(Components.interfaces.nsIMessenger)
|
||||
.formatFileSize(gMsgFolder.sizeOnDisk, true);
|
||||
document.getElementById("sizeOnDisk").value = sizeOnDisk;
|
||||
} catch (e) { }
|
||||
|
||||
// select the initial tab
|
||||
if (window.arguments[0].tabID) {
|
||||
try {
|
||||
document.getElementById("folderPropTabBox").selectedTab =
|
||||
document.getElementById(window.arguments[0].tabID);
|
||||
}
|
||||
catch (ex) {}
|
||||
}
|
||||
onCheckKeepMsg();
|
||||
onUseDefaultRetentionSettings();
|
||||
}
|
||||
|
||||
function hideShowControls(serverType)
|
||||
{
|
||||
let controls = document.querySelectorAll("[hidefor]");
|
||||
var len = controls.length;
|
||||
for (var i=0; i<len; i++) {
|
||||
var control = controls[i];
|
||||
var hideFor = control.getAttribute("hidefor");
|
||||
if (!hideFor)
|
||||
throw "hidefor empty";
|
||||
|
||||
// hide unsupported server type
|
||||
// adding support for hiding multiple server types using hideFor="server1,server2"
|
||||
var hideForBool = false;
|
||||
var hideForTokens = hideFor.split(",");
|
||||
for (var j = 0; j < hideForTokens.length; j++) {
|
||||
if (hideForTokens[j] == serverType) {
|
||||
hideForBool = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
control.hidden = hideForBool;
|
||||
}
|
||||
|
||||
// hide the priviliges button if the imap folder doesn't have an admin url
|
||||
// mabye should leave this hidden by default and only show it in this case instead
|
||||
try {
|
||||
var imapFolder = gMsgFolder.QueryInterface(Components.interfaces.nsIMsgImapMailFolder);
|
||||
if (imapFolder)
|
||||
{
|
||||
var privilegesButton = document.getElementById("imap.FolderPrivileges");
|
||||
if (privilegesButton)
|
||||
{
|
||||
if (!imapFolder.hasAdminUrl)
|
||||
privilegesButton.setAttribute("hidden", "true");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ex) {}
|
||||
|
||||
if (gMsgFolder)
|
||||
{
|
||||
const nsMsgFolderFlags = Components.interfaces.nsMsgFolderFlags;
|
||||
// Hide "check for new mail" checkbox if this is an Inbox.
|
||||
if (gMsgFolder.flags & nsMsgFolderFlags.Inbox)
|
||||
document.getElementById("folderCheckForNewMessages").hidden = true;
|
||||
// Retention policy doesn't apply to Drafts/Templates/Outbox.
|
||||
if (gMsgFolder.isSpecialFolder(nsMsgFolderFlags.Drafts |
|
||||
nsMsgFolderFlags.Templates |
|
||||
nsMsgFolderFlags.Queue, true))
|
||||
document.getElementById("Retention").hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
function onOfflineFolderDownload()
|
||||
{
|
||||
// we need to create a progress window and pass that in as the second parameter here.
|
||||
gMsgFolder.downloadAllForOffline(null, window.arguments[0].msgWindow);
|
||||
}
|
||||
|
||||
function onFolderPrivileges()
|
||||
{
|
||||
var imapFolder = gMsgFolder.QueryInterface(Components.interfaces.nsIMsgImapMailFolder);
|
||||
if (imapFolder)
|
||||
imapFolder.folderPrivileges(window.arguments[0].msgWindow);
|
||||
// let's try closing the modal dialog to see if it fixes the various problems running this url
|
||||
window.close();
|
||||
}
|
||||
|
||||
|
||||
function onUseDefaultRetentionSettings()
|
||||
{
|
||||
var useDefault = document.getElementById("retention.useDefault").checked;
|
||||
document.getElementById('retention.keepMsg').disabled = useDefault;
|
||||
document.getElementById('retention.keepNewMsgMinLabel').disabled = useDefault;
|
||||
document.getElementById('retention.keepOldMsgMinLabel').disabled = useDefault;
|
||||
|
||||
var keepMsg = document.getElementById("retention.keepMsg").value;
|
||||
const nsIMsgRetentionSettings = Components.interfaces.nsIMsgRetentionSettings;
|
||||
document.getElementById('retention.keepOldMsgMin').disabled =
|
||||
useDefault || (keepMsg != nsIMsgRetentionSettings.nsMsgRetainByAge);
|
||||
document.getElementById('retention.keepNewMsgMin').disabled =
|
||||
useDefault || (keepMsg != nsIMsgRetentionSettings.nsMsgRetainByNumHeaders);
|
||||
}
|
||||
|
||||
function RebuildSummaryInformation()
|
||||
{
|
||||
window.arguments[0].rebuildSummaryCallback(gMsgFolder);
|
||||
}
|
||||
216
mailnews/base/content/folderProps.xul
Normal file
216
mailnews/base/content/folderProps.xul
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
<?xml version="1.0"?> <!-- -*- Mode: SGML; indent-tabs-mode: nil; -*- -->
|
||||
<!--
|
||||
|
||||
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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://messenger/skin/preferences/preferences.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://messenger/content/charsetList.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/folderProps.dtd">
|
||||
|
||||
<dialog
|
||||
id="folderPropertiesDialog"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="&folderProps.windowtitle.label;"
|
||||
buttons="accept,cancel"
|
||||
onload="folderPropsOnLoad();" style="width: 56ch;"
|
||||
ondialogaccept="return folderPropsOKButton();">
|
||||
|
||||
<stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
|
||||
<script type="application/javascript" src="chrome://messenger/content/retention.js"/>
|
||||
<script type="application/javascript" src="chrome://messenger/content/folderProps.js"/>
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Services.obs.notifyObservers(null, "charsetmenu-selected", "other");
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<tabbox id="folderPropTabBox">
|
||||
<tabs id="folderPropTabs">
|
||||
<tab id="GeneralTab" label="&generalInfo.label;"/>
|
||||
<tab id="Retention" label="&retention.label;"/>
|
||||
<tab id="SynchronizationTab" hidefor="movemail,pop3,rss,none" label="&folderSynchronizationTab.label;"/>
|
||||
<tab id="SharingTab" hidefor="movemail,pop3,rss,none,nntp" label="&folderSharingTab.label;"/>
|
||||
<tab id="QuotaTab" hidefor="movemail,pop3,rss,none,nntp" label="&folderQuotaTab.label;"/>
|
||||
</tabs>
|
||||
<tabpanels id="folderPropTabPanels">
|
||||
|
||||
<vbox id="GeneralPanel">
|
||||
<hbox id="nameBox" align="center">
|
||||
<label value="&folderProps.name.label;" control="name"
|
||||
accesskey="&folderProps.name.accesskey;"/>
|
||||
<textbox id="name" readonly="true" oninput="doEnabling();" flex="1"/>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<label value="&folderProps.location.label;" control="location"
|
||||
accesskey="&folderProps.location.accesskey;"/>
|
||||
<textbox id="location" readonly="true" flex="1" class="uri-element"/>
|
||||
</hbox>
|
||||
<vbox>
|
||||
<spacer height="2"/>
|
||||
<hbox align="center">
|
||||
<label value="&numberOfMessages.label;"/>
|
||||
<label id="numberOfMessages" value="&numberUnknown.label;"/>
|
||||
<spacer flex="1"/>
|
||||
<label value="&sizeOnDisk.label;"/>
|
||||
<label id="sizeOnDisk" value="&sizeUnknown.label;"/>
|
||||
</hbox>
|
||||
<spacer height="2"/>
|
||||
</vbox>
|
||||
<checkbox id="folderIncludeInGlobalSearch" hidefor="nntp"
|
||||
label="&folderIncludeInGlobalSearch.label;"
|
||||
accesskey="&folderIncludeInGlobalSearch.accesskey;"/>
|
||||
<checkbox hidefor="movemail,pop3,none,nntp"
|
||||
id="folderCheckForNewMessages"
|
||||
label="&folderCheckForNewMessages2.label;"
|
||||
accesskey="&folderCheckForNewMessages2.accesskey;"/>
|
||||
<vbox>
|
||||
<hbox align="center" valign="middle">
|
||||
<label value="&folderCharsetFallback2.label;"
|
||||
accesskey="&folderCharsetFallback2.accesskey;"
|
||||
control="folderCharsetList"/>
|
||||
<menulist id="folderCharsetList" type="charset"/>
|
||||
</hbox>
|
||||
<checkbox class="indent" id="folderCharsetOverride"
|
||||
label="&folderCharsetEnforce2.label;"
|
||||
accesskey="&folderCharsetEnforce2.accesskey;"/>
|
||||
</vbox>
|
||||
<groupbox id="folderRebuildSummaryGroupBox" align="baseline">
|
||||
<grid>
|
||||
<columns>
|
||||
<column flex="1"/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<description id="folderRebuildSummaryExplanation">&folderRebuildSummaryFile.explanation;</description>
|
||||
<vbox>
|
||||
<button id="folderRebuildSummaryButton"
|
||||
label="&folderRebuildSummaryFile2.label;"
|
||||
oncommand="RebuildSummaryInformation();"
|
||||
accesskey="&folderRebuildSummaryFile2.accesskey;"
|
||||
tooltiptext="&folderRebuildSummaryFileTip2.label;"
|
||||
align="center"/>
|
||||
</vbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</groupbox>
|
||||
</vbox>
|
||||
|
||||
<vbox id="RetentionPanel" align="start">
|
||||
<description hidefor="imap,pop3" class="desc">&retentionCleanup.label;</description>
|
||||
<description hidefor="movemail,pop3,rss,none,nntp" class="desc">&retentionCleanupImap.label;</description>
|
||||
<description hidefor="movemail,imap,rss,none,nntp" class="desc">&retentionCleanupPop.label;</description>
|
||||
|
||||
<hbox align="center" class="indent">
|
||||
<checkbox wsm_persist="true" id="retention.useDefault" accesskey="&retentionUseAccount.accesskey;"
|
||||
label="&retentionUseAccount.label;" checked="true" oncommand="onUseDefaultRetentionSettings()"/>
|
||||
</hbox>
|
||||
<vbox class="indent">
|
||||
<hbox class="indent">
|
||||
<radiogroup wsm_persist="true" id="retention.keepMsg" aria-labelledby="retention.useDefault">
|
||||
<radio wsm_persist="true" value="1" accesskey="&retentionKeepAll.accesskey;"
|
||||
label="&retentionKeepAll.label;" oncommand="onCheckKeepMsg();"/>
|
||||
<hbox flex="1" align="center">
|
||||
<radio wsm_persist="true" id="keepNewMsg" accesskey="&retentionKeepRecent.accesskey;"
|
||||
value="3" label="&retentionKeepRecent.label;" oncommand="onCheckKeepMsg();"/>
|
||||
<textbox wsm_persist="true" id="retention.keepNewMsgMin"
|
||||
type="number" min="1" increment="10" size="4" value="2000"
|
||||
aria-labelledby="keepNewMsg retention.keepNewMsgMin retention.keepNewMsgMinLabel"/>
|
||||
<label value="&message.label;" control="retention.keepNewMsgMin" id="retention.keepNewMsgMinLabel"/>
|
||||
</hbox>
|
||||
<hbox flex="1" align="center">
|
||||
<radio wsm_persist="true" id="keepMsg" accesskey="&retentionDeleteMsg.accesskey;"
|
||||
value="2" label="&retentionDeleteMsg.label;" oncommand="onCheckKeepMsg();"/>
|
||||
<textbox wsm_persist="true" id="retention.keepOldMsgMin"
|
||||
type="number" min="1" size="2" value="30"
|
||||
aria-labelledby="keepMsg retention.keepOldMsgMin retention.keepOldMsgMinLabel"/>
|
||||
<label value="&daysOld.label;" control="retention.keepOldMsgMin" id="retention.keepOldMsgMinLabel"/>
|
||||
</hbox>
|
||||
</radiogroup>
|
||||
</hbox>
|
||||
<hbox class="indent">
|
||||
<checkbox id="retention.applyToFlagged" wsm_persist="true"
|
||||
label="&retentionApplyToFlagged.label;"
|
||||
accesskey="&retentionApplyToFlagged.accesskey;"
|
||||
observes="retention.keepMsg" checked="true"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
||||
<vbox id="SyncPanel" valign="top" align="start">
|
||||
<vbox>
|
||||
<checkbox hidefor="nntp"
|
||||
wsm_persist="true" id="offline.selectForOfflineFolder"
|
||||
label="&offlineFolder.check.label;"
|
||||
accesskey="&offlineFolder.check.accesskey;"/>
|
||||
<checkbox hidefor="imap"
|
||||
wsm_persist="true" id="offline.selectForOfflineNewsgroup"
|
||||
label="&selectofflineNewsgroup.check.label;"
|
||||
accesskey="&selectofflineNewsgroup.check.accesskey;"/>
|
||||
</vbox>
|
||||
<button hidefor="nntp" label="&offlineFolder.button.label;"
|
||||
oncommand="onOfflineFolderDownload();" accesskey="&offlineFolder.button.accesskey;"
|
||||
id="offline.offlineFolderDownloadButton" orient="right"/>
|
||||
<button hidefor="imap" label="&offlineNewsgroup.button.label;"
|
||||
oncommand="onOfflineFolderDownload();" accesskey="&offlineNewsgroup.button.accesskey;"
|
||||
id="offline.offlineNewsgroupDownloadButton" orient="right"/>
|
||||
</vbox>
|
||||
|
||||
<vbox id="SharingPanel" valign="top">
|
||||
<hbox align="start">
|
||||
<label value="&folderType.label;" id="folderTypeLabel"/>
|
||||
<label value="" id="folderType.text"/>
|
||||
</hbox>
|
||||
<vbox align="start">
|
||||
<label value="" id="folderDescription.text"/>
|
||||
<label value=" "/>
|
||||
<label value="&permissionsDesc.label;" id="permissionsDescLabel"/>
|
||||
|
||||
<description id="folderPermissions.text"></description>
|
||||
</vbox>
|
||||
<spacer flex="100%"/>
|
||||
<vbox align="start">
|
||||
<button hidefor="movemail,pop3,none,rss,nntp" label="&privileges.button.label;"
|
||||
oncommand="onFolderPrivileges();" accesskey="&privileges.button.accesskey;"
|
||||
id="imap.FolderPrivileges" orient="right"/>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
||||
<vbox id="QuotaPanel" valign="top">
|
||||
<label id="folderQuotaStatus" flex="1"/>
|
||||
|
||||
<grid id="folderQuotaData" hidden="true" flex="1">
|
||||
<columns>
|
||||
<column/>
|
||||
<column flex="1"/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row align="center">
|
||||
<label value="&folderQuotaRoot.label;" control="quotaRoot"/>
|
||||
<textbox id="quotaRoot" readonly="true"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="&folderQuotaUsage.label;"/>
|
||||
<description id="quotaUsedFree"/>
|
||||
</row>
|
||||
<row align="center">
|
||||
<label value="&folderQuotaStatus.label;"/>
|
||||
<hbox align="center">
|
||||
<progressmeter id="quotaPercentageBar" mode="determined" value="0%"/>
|
||||
<label id="quotaPercentUsed"/>
|
||||
</hbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</vbox>
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
|
||||
</dialog>
|
||||
829
mailnews/base/content/folderWidgets.xml
Normal file
829
mailnews/base/content/folderWidgets.xml
Normal file
|
|
@ -0,0 +1,829 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- 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/.
|
||||
-->
|
||||
|
||||
<bindings id="mailFolderBindings"
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xbl="http://www.mozilla.org/xbl"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<binding id="folder-menupopup"
|
||||
extends="chrome://global/content/bindings/popup.xml#popup">
|
||||
<implementation>
|
||||
<constructor><![CDATA[
|
||||
Components.utils.import("resource:///modules/FeedUtils.jsm", this);
|
||||
Components.utils.import("resource:///modules/folderUtils.jsm", this);
|
||||
Components.utils.import("resource:///modules/iteratorUtils.jsm", this);
|
||||
Components.utils.import("resource:///modules/mailServices.js", this);
|
||||
Components.utils.import("resource:///modules/MailUtils.js", this);
|
||||
Components.utils.import("resource:///modules/StringBundle.js", this);
|
||||
this._stringBundle = new this
|
||||
.StringBundle("chrome://messenger/locale/folderWidgets.properties");
|
||||
|
||||
// Get the displayformat if set.
|
||||
if (this.parentNode && this.parentNode.localName == "menulist")
|
||||
this._displayformat = this.parentNode.getAttribute("displayformat");
|
||||
|
||||
// Find out if we are in a wrapper (customize toolbars mode is active).
|
||||
let inWrapper = false;
|
||||
let node = this;
|
||||
while (node instanceof XULElement) {
|
||||
if (node.id.startsWith("wrapper-")) {
|
||||
inWrapper = true;
|
||||
break;
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
|
||||
if (!inWrapper) {
|
||||
if (this.hasAttribute("original-width")) {
|
||||
// If we were in a wrapper before and have a width stored, restore it now.
|
||||
if (this.getAttribute("original-width") == "none")
|
||||
this.removeAttribute("width");
|
||||
else
|
||||
this.setAttribute("width", this.getAttribute("original-width"));
|
||||
|
||||
this.removeAttribute("original-width");
|
||||
}
|
||||
|
||||
// If we are a child of a menulist, and we aren't in a wrapper, we
|
||||
// need to build our content right away, otherwise the menulist
|
||||
// won't have proper sizing.
|
||||
if (this.parentNode && this.parentNode.localName == "menulist")
|
||||
this._ensureInitialized();
|
||||
} else {
|
||||
// But if we're in a wrapper, remove our children, because we're
|
||||
// getting re-created when the toolbar customization closes.
|
||||
this._teardown();
|
||||
|
||||
// Store our current width and set a safe small width when we show
|
||||
// in a wrapper.
|
||||
if (!this.hasAttribute("original-width")) {
|
||||
this.setAttribute("original-width", this.hasAttribute("width") ?
|
||||
this.getAttribute("width") : "none");
|
||||
this.setAttribute("width", "100");
|
||||
}
|
||||
}
|
||||
]]></constructor>
|
||||
<destructor><![CDATA[
|
||||
// Clean up when being destroyed.
|
||||
this._removeListener();
|
||||
]]></destructor>
|
||||
<!--
|
||||
- Make sure we remove our listener when the window is being destroyed
|
||||
- or the widget teared down.
|
||||
-->
|
||||
<method name="_removeListener">
|
||||
<body><![CDATA[
|
||||
if (!this._initialized)
|
||||
return;
|
||||
|
||||
this.MailServices.mailSession.RemoveFolderListener(this._listener);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<field name="_stringBundle">null</field>
|
||||
|
||||
<!--
|
||||
- If non-null, the subFolders of this nsIMsgFolder will be used to
|
||||
- populate this menu. If this is null, the menu will be populated
|
||||
- using the root-folders for all accounts
|
||||
-->
|
||||
<field name="_parentFolder">null</field>
|
||||
<property name="parentFolder"
|
||||
onget="return this._parentFolder;"
|
||||
onset="return this._parentFolder = val;"/>
|
||||
|
||||
<!--
|
||||
- Various filtering modes can be used with this menu-binding. To use
|
||||
- one of them, append the mode="foo" attribute to the element. When
|
||||
- building the menu, we will then use this._filters[mode] as a filter
|
||||
- function to eliminate folders that should not be shown.
|
||||
-
|
||||
- Note that extensions should feel free to plug in here!
|
||||
-->
|
||||
<field name="_filters"><![CDATA[({
|
||||
// Returns true if messages can be filed in the folder
|
||||
filing: function filter_filing(aFolder) {
|
||||
if (!aFolder.server.canFileMessagesOnServer)
|
||||
return false;
|
||||
|
||||
return (aFolder.canFileMessages || aFolder.hasSubFolders);
|
||||
},
|
||||
|
||||
// Returns true if we can get mail for this folder. (usually this just
|
||||
// means the "root" fake folder)
|
||||
getMail: function filter_getMail(aFolder) {
|
||||
if (aFolder.isServer && aFolder.server.type != "none")
|
||||
return true;
|
||||
if (aFolder.server.type == "nntp" || aFolder.server.type == "rss")
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
|
||||
// Returns true if we can add filters to this folder/account
|
||||
filters: function filter_filter(aFolder) {
|
||||
// We can always filter news
|
||||
if (aFolder.server.type == "nntp")
|
||||
return true;
|
||||
|
||||
return aFolder.server.canHaveFilters;
|
||||
},
|
||||
|
||||
subscribe: function filter_subscribe(aFolder) {
|
||||
return aFolder.canSubscribe;
|
||||
},
|
||||
|
||||
newFolder: function filter_newFolder(aFolder) {
|
||||
return aFolder.canCreateSubfolders &&
|
||||
aFolder.server.canCreateFoldersOnServer;
|
||||
},
|
||||
|
||||
deferred: function filter_defered(aFolder) {
|
||||
return aFolder.server.canCreateFoldersOnServer &&
|
||||
!aFolder.supportsOffline;
|
||||
},
|
||||
|
||||
// Folders that are not in a deferred account
|
||||
notDeferred: function(aFolder) {
|
||||
let server = aFolder.server;
|
||||
return !(server instanceof Components.interfaces.nsIPop3IncomingServer &&
|
||||
server.deferredToAccount);
|
||||
},
|
||||
|
||||
// Folders that can be searched.
|
||||
search: function filter_search(aFolder) {
|
||||
if (!aFolder.server.canSearchMessages ||
|
||||
aFolder.getFlag(Components.interfaces.nsMsgFolderFlags.Virtual))
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
|
||||
// Folders that can subscribe feeds.
|
||||
feeds: function filter_feeds(aFolder) {
|
||||
if (aFolder.server.type != "rss" ||
|
||||
aFolder.getFlag(Components.interfaces.nsMsgFolderFlags.Trash) ||
|
||||
aFolder.getFlag(Components.interfaces.nsMsgFolderFlags.Virtual))
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
|
||||
junk: function filter_junk(aFolder) {
|
||||
// Don't show servers (nntp & any others) which do not allow search or filing
|
||||
// I don't really understand why canSearchMessages is needed, but it was included in
|
||||
// earlier code, so I include it as well.
|
||||
if (!aFolder.server.canFileMessagesOnServer || !aFolder.server.canSearchMessages)
|
||||
return false;
|
||||
// show parents that might have usable subfolders, or usable folders
|
||||
return aFolder.hasSubFolders || aFolder.canFileMessages;
|
||||
}
|
||||
})]]></field>
|
||||
|
||||
<!--
|
||||
- The maximum number of entries in the "Recent" menu
|
||||
-->
|
||||
<field name="_MAXRECENT">15</field>
|
||||
|
||||
<!--
|
||||
- Is this list containing only servers (accounts) and no real folders?
|
||||
-->
|
||||
<field name="_serversOnly">true</field>
|
||||
|
||||
<!--
|
||||
- Our listener to let us know when folders change/appear/disappear so
|
||||
- we can know to rebuild ourselves.
|
||||
-->
|
||||
<field name="_listener">
|
||||
<![CDATA[({
|
||||
_menu: this,
|
||||
_clearMenu: function(aMenu) {
|
||||
if (aMenu._teardown)
|
||||
aMenu._teardown();
|
||||
},
|
||||
OnItemAdded: function act_add(aRDFParentItem, aItem) {
|
||||
if (!(aItem instanceof Components.interfaces.nsIMsgFolder))
|
||||
return;
|
||||
if (this._filterFunction && !this._filterFunction(aItem)) {
|
||||
return;
|
||||
}
|
||||
//xxx we can optimize this later
|
||||
//xxx I'm not quite sure why this isn't always a function
|
||||
if (this._menu._teardown)
|
||||
this._menu._teardown();
|
||||
},
|
||||
|
||||
OnItemRemoved: function act_remove(aRDFParentItem, aItem) {
|
||||
if (!(aItem instanceof Components.interfaces.nsIMsgFolder))
|
||||
return;
|
||||
if (this._filterFunction && !this._filterFunction(aItem)) {
|
||||
return;
|
||||
}
|
||||
//xxx we can optimize this later
|
||||
if (this._menu._teardown)
|
||||
this._menu._teardown();
|
||||
},
|
||||
|
||||
//xxx I stole this listener list from nsMsgFolderDatasource.cpp, but
|
||||
// someone should really document what events are fired when, so that
|
||||
// we make sure we're updating at the right times.
|
||||
OnItemPropertyChanged: function(aItem, aProperty, aOld, aNew) {},
|
||||
OnItemIntPropertyChanged: function(aItem, aProperty, aOld, aNew) {
|
||||
var child = this._getChildForItem(aItem);
|
||||
if (child)
|
||||
this._menu._setCssSelectors(child._folder, child);
|
||||
},
|
||||
OnItemBoolPropertyChanged: function(aItem, aProperty, aOld, aNew) {
|
||||
var child = this._getChildForItem(aItem);
|
||||
if (child)
|
||||
this._menu._setCssSelectors(child._folder, child);
|
||||
},
|
||||
OnItemUnicharPropertyChanged: function(aItem, aProperty, aOld, aNew) {
|
||||
var child = this._getChildForItem(aItem);
|
||||
if (child)
|
||||
this._menu._setCssSelectors(child._folder, child);
|
||||
},
|
||||
OnItemPropertyFlagChanged: function(aItem, aProperty, aOld, aNew) {},
|
||||
OnItemEvent: function(aFolder, aEvent) {
|
||||
if (aEvent.toString() == "MRMTimeChanged") {
|
||||
if (this._menu.getAttribute("showRecent") != "true" ||
|
||||
!this._menu.firstChild || !this._menu.firstChild.firstChild)
|
||||
return;
|
||||
// if this folder is already in the recent menu, return.
|
||||
if (this._getChildForItem(aFolder,
|
||||
this._menu.firstChild.firstChild))
|
||||
return;
|
||||
}
|
||||
// Special casing folder renames here, since they require more work
|
||||
// since sort-order may have changed.
|
||||
else if (aEvent.toString() == "RenameCompleted") {
|
||||
if (!this._getChildForItem(aFolder))
|
||||
return;
|
||||
}
|
||||
else
|
||||
return;
|
||||
// folder renamed, or new recent folder, so rebuild.
|
||||
setTimeout(this._clearMenu, 0, this._menu);
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper function to check and see whether we have a menuitem for this
|
||||
* particular nsIMsgFolder
|
||||
*
|
||||
* @param aItem the nsIMsgFolder to check
|
||||
* @param aMenu (optional) menu to look in, defaults to this._menu.
|
||||
* @returns null if no child for that folder exists, otherwise the
|
||||
* menuitem for that child
|
||||
*/
|
||||
_getChildForItem: function act__itemIsChild(aItem, aMenu) {
|
||||
aMenu = aMenu || this._menu;
|
||||
if (!aMenu || !aMenu.childNodes)
|
||||
return null;
|
||||
|
||||
if (!(aItem instanceof Components.interfaces.nsIMsgFolder))
|
||||
return null;
|
||||
for (let i = 0; i < aMenu.childNodes.length; i++) {
|
||||
let folder = aMenu.childNodes[i]._folder;
|
||||
if (folder && folder.URI == aItem.URI)
|
||||
return aMenu.childNodes[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
})]]></field>
|
||||
|
||||
<!--
|
||||
- True if we have already built our menu-items and are now just
|
||||
- listening for changes
|
||||
-->
|
||||
<field name="_initialized">false</field>
|
||||
|
||||
<!--
|
||||
- Call this if you are unsure whether the menu-items have been built,
|
||||
- but know that they need to be built now if they haven't.
|
||||
-->
|
||||
<method name="_ensureInitialized">
|
||||
<body><![CDATA[
|
||||
if (this._initialized)
|
||||
return;
|
||||
|
||||
// I really wish they'd just make this global...
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
let folders;
|
||||
|
||||
// Figure out which folders to build. If we don't have a parent, then
|
||||
// we assume we should build the top-level accounts. (Actually we
|
||||
// build the fake root folders for those accounts.)
|
||||
if (!this._parentFolder) {
|
||||
let accounts = this.allAccountsSorted(true);
|
||||
|
||||
// Now generate our folder-list. Note that we'll special case this
|
||||
// situation below, to avoid destroying the sort order we just made
|
||||
folders = accounts.map(acct => acct.incomingServer.rootFolder);
|
||||
} else {
|
||||
// If we do have a parent folder, then we just build based on those
|
||||
// subFolders for that parent.
|
||||
folders = this.toArray(this.fixIterator(this._parentFolder.subFolders,
|
||||
Ci.nsIMsgFolder));
|
||||
}
|
||||
|
||||
this._build(folders);
|
||||
|
||||
// Lastly, we add a listener to get notified of changes in the folder
|
||||
// structure.
|
||||
this.MailServices.mailSession.AddFolderListener(this._listener,
|
||||
Ci.nsIFolderListener.all);
|
||||
|
||||
this._initialized = true;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
- Actually constructs the menu-items based on the folders given.
|
||||
-
|
||||
- @param aFolders An array of nsIMsgFolders to use for building.
|
||||
-->
|
||||
<method name="_build">
|
||||
<parameter name="aFolders"/>
|
||||
<body><![CDATA[
|
||||
let folders;
|
||||
let excludeServers = [];
|
||||
let disableServers = [];
|
||||
|
||||
// excludeServers attribute is a comma separated list of server keys.
|
||||
if (this.hasAttribute("excludeServers"))
|
||||
excludeServers = this.getAttribute("excludeServers").split(",");
|
||||
|
||||
// disableServers attribute is a comma separated list of server keys.
|
||||
if (this.hasAttribute("disableServers"))
|
||||
disableServers = this.getAttribute("disableServers").split(",");
|
||||
|
||||
// Extensions and other consumers can add to these modes too, see the
|
||||
// above note on the _filters field.
|
||||
var mode = this.getAttribute("mode");
|
||||
if (mode && mode != "") {
|
||||
var filterFunction = this._filters[mode];
|
||||
folders = aFolders.filter(filterFunction);
|
||||
this._listener._filterFunction = filterFunction;
|
||||
} else {
|
||||
folders = aFolders;
|
||||
}
|
||||
|
||||
if (excludeServers.length > 0) {
|
||||
folders = folders.filter(function(aFolder) {
|
||||
return !(excludeServers.indexOf(aFolder.server.key) != -1); });
|
||||
}
|
||||
|
||||
/* This code block will do the following: Add a menu item that refers
|
||||
back to the parent folder when there is a showFileHereLabel
|
||||
attribute or no mode attribute. However the code won't add such a
|
||||
menu item if one of the following conditions is met:
|
||||
(*) There is no parent folder
|
||||
(*) Folder is server and showAccountsFileHere is explicitly false
|
||||
(*) Current folder has a mode, the parent folder can be selected,
|
||||
no messages can be filed into the parent folder (e.g. when the
|
||||
parent folder is a news group or news server) and the folder
|
||||
mode is not equal to newFolder
|
||||
|
||||
The menu item will have the value of the fileHereLabel attribute as
|
||||
label or if the attribute does not exist the name of the parent
|
||||
folder instead.
|
||||
*/
|
||||
let parent = this._parentFolder;
|
||||
if (parent && (this.getAttribute("showFileHereLabel") == "true" || !mode)) {
|
||||
let showAccountsFileHere = this.getAttribute("showAccountsFileHere");
|
||||
if ((!parent.isServer || showAccountsFileHere != "false") &&
|
||||
(!mode || mode == "newFolder" || parent.noSelect ||
|
||||
parent.canFileMessages || showAccountsFileHere == "true")) {
|
||||
var menuitem = document.createElement("menuitem");
|
||||
menuitem._folder = this._parentFolder;
|
||||
menuitem.setAttribute("generated", "true");
|
||||
if (this.hasAttribute("fileHereLabel")) {
|
||||
menuitem.setAttribute("label", this.getAttribute("fileHereLabel"));
|
||||
menuitem.setAttribute("accesskey", this.getAttribute("fileHereAccessKey"));
|
||||
} else {
|
||||
menuitem.setAttribute("label", this._parentFolder.prettyName);
|
||||
menuitem.setAttribute("class", "folderMenuItem menuitem-iconic");
|
||||
this._setCssSelectors(this._parentFolder, menuitem);
|
||||
}
|
||||
// Eww. have to support some legacy code here...
|
||||
menuitem.setAttribute("id", this._parentFolder.URI);
|
||||
this.appendChild(menuitem);
|
||||
|
||||
if (this._parentFolder.noSelect)
|
||||
menuitem.setAttribute("disabled", "true");
|
||||
|
||||
var sep= document.createElement("menuseparator");
|
||||
sep.setAttribute("generated", "true");
|
||||
this.appendChild(sep);
|
||||
}
|
||||
}
|
||||
|
||||
let globalInboxFolder = null;
|
||||
// See if this is the toplevel menu (usually with accounts).
|
||||
if (!this._parentFolder) {
|
||||
// Some menus want a "Recent" option, but that should only be on our
|
||||
// top-level menu
|
||||
if (this.getAttribute("showRecent") == "true")
|
||||
this._buildRecentMenu();
|
||||
// If we are showing the accounts for deferring, move Local Folders to the top.
|
||||
if (mode == "deferred") {
|
||||
globalInboxFolder = this.MailServices.accounts.localFoldersServer
|
||||
.rootFolder;
|
||||
let localFoldersIndex = folders.indexOf(globalInboxFolder);
|
||||
if (localFoldersIndex != -1) {
|
||||
folders.splice(localFoldersIndex, 1);
|
||||
folders.unshift(globalInboxFolder);
|
||||
}
|
||||
}
|
||||
// If we're the root of the folder hierarchy, then we actually don't
|
||||
// want to sort the folders, but rather the accounts to which the
|
||||
// folders belong. Since that sorting was already done, we don't need
|
||||
// to do anything for that case here.
|
||||
} else {
|
||||
// Sorts the list of folders. We give first priority to the sortKey
|
||||
// property if it is available, otherwise a case-insensitive
|
||||
// comparison of names.
|
||||
folders = folders.sort(function nameCompare(a, b) {
|
||||
return a.compareSortKeys(b);
|
||||
});
|
||||
}
|
||||
|
||||
/* In some cases, the user wants to have a list of subfolders for only
|
||||
* some account types (or maybe all of them). So we use this to
|
||||
* determine what the user wanted.
|
||||
*/
|
||||
var shouldExpand;
|
||||
var labels = null;
|
||||
if (this.getAttribute("expandFolders") == "true" ||
|
||||
!this.hasAttribute("expandFolders")) {
|
||||
shouldExpand = function (e) { return true; };
|
||||
} else if (this.getAttribute("expandFolders") == "false") {
|
||||
shouldExpand = function (e) { return false; };
|
||||
} else {
|
||||
/* We want a subfolder list for only some servers. We also may need
|
||||
* to create headers to select the servers. If so, then headlabels
|
||||
* is a comma-delimited list of labels corresponding to the server
|
||||
* types specified in expandFolders.
|
||||
*/
|
||||
var types = this.getAttribute("expandFolders").split(/ *, */);
|
||||
// Set the labels. labels[type] = label
|
||||
if (this.hasAttribute("headlabels")) {
|
||||
var labelNames = this.getAttribute("headlabels").split(/ *, */);
|
||||
labels = {};
|
||||
// If the length isn't equal, don't give them any of the labels,
|
||||
// since any combination will probably be wrong.
|
||||
if (labelNames.length == types.length) {
|
||||
for (var index in types)
|
||||
labels[types[index]] = labelNames[index];
|
||||
}
|
||||
}
|
||||
shouldExpand = function (e) { return types.indexOf(e) != -1; };
|
||||
}
|
||||
|
||||
// We need to call this, or hasSubFolders will always return false.
|
||||
// Remove this workaround when Bug 502900 is fixed.
|
||||
this.MailUtils.discoverFolders();
|
||||
this._serversOnly = true;
|
||||
|
||||
for (let folder of folders) {
|
||||
let node;
|
||||
if (!folder.isServer)
|
||||
this._serversOnly = false;
|
||||
|
||||
// If we're going to add subFolders, we need to make menus, not
|
||||
// menuitems.
|
||||
if (!folder.hasSubFolders || !shouldExpand(folder.server.type)) {
|
||||
node = document.createElement("menuitem");
|
||||
// Grumble, grumble, legacy code support
|
||||
node.setAttribute("id", folder.URI);
|
||||
node.setAttribute("class", "folderMenuItem menuitem-iconic");
|
||||
node.setAttribute("generated", "true");
|
||||
this.appendChild(node);
|
||||
} else {
|
||||
this._serversOnly = false;
|
||||
//xxx this is slightly problematic in that we haven't confirmed
|
||||
// whether any of the subfolders will pass the filter
|
||||
node = document.createElement("menu");
|
||||
node.setAttribute("class", "folderMenuItem menu-iconic");
|
||||
node.setAttribute("generated", "true");
|
||||
this.appendChild(node);
|
||||
|
||||
// Create the submenu
|
||||
// (We must use cloneNode here because on OS X the native menu
|
||||
// functionality and very sad limitations of XBL1 cause the bindings
|
||||
// to never get created for popup if we create a new element. We
|
||||
// perform a shallow clone to avoid picking up any of our children.)
|
||||
var popup = this.cloneNode(false);
|
||||
popup._parentFolder = folder;
|
||||
popup.setAttribute("class", this.getAttribute("class"));
|
||||
popup.setAttribute("type", this.getAttribute("type"));
|
||||
if (this.hasAttribute("fileHereLabel"))
|
||||
popup.setAttribute("fileHereLabel",
|
||||
this.getAttribute("fileHereLabel"));
|
||||
popup.setAttribute("showFileHereLabel",
|
||||
this.getAttribute("showFileHereLabel"));
|
||||
popup.setAttribute("oncommand",
|
||||
this.getAttribute("oncommand"));
|
||||
popup.setAttribute("mode",
|
||||
this.getAttribute("mode"));
|
||||
if (this.hasAttribute("disableServers"))
|
||||
popup.setAttribute("disableServers",
|
||||
this.getAttribute("disableServers"));
|
||||
if (this.hasAttribute("position"))
|
||||
popup.setAttribute("position",
|
||||
this.getAttribute("position"));
|
||||
|
||||
// If there are labels, add the labels now
|
||||
if (labels) {
|
||||
var serverNode = document.createElement("menuitem");
|
||||
serverNode.setAttribute("label", labels[folder.server.type]);
|
||||
serverNode._folder = folder;
|
||||
serverNode.setAttribute("generated", "true");
|
||||
popup.appendChild(serverNode);
|
||||
var sep = document.createElement("menuseparator");
|
||||
sep.setAttribute("generated", "true");
|
||||
popup.appendChild(sep);
|
||||
}
|
||||
|
||||
popup.setAttribute("generated", "true");
|
||||
node.appendChild(popup);
|
||||
}
|
||||
|
||||
if (disableServers.indexOf(folder.server.key) != -1)
|
||||
node.setAttribute("disabled", "true");
|
||||
|
||||
node._folder = folder;
|
||||
let label = "";
|
||||
if (mode == "deferred" && folder.isServer &&
|
||||
folder.server.rootFolder == globalInboxFolder) {
|
||||
label = this._stringBundle.get("globalInbox", [folder.prettyName]);
|
||||
} else {
|
||||
label = folder.prettyName;
|
||||
}
|
||||
node.setAttribute("label", label);
|
||||
this._setCssSelectors(folder, node);
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
- Builds a submenu with all of the recently used folders in it, to
|
||||
- allow for easy access.
|
||||
-->
|
||||
<method name="_buildRecentMenu">
|
||||
<body><![CDATA[
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
// Iterate through all folders in all accounts, and find 15 (_MAXRECENT)
|
||||
// of most recently modified ones.
|
||||
let allFolders = this.toArray(
|
||||
this.fixIterator(this.MailServices.accounts.allFolders, Ci.nsIMsgFolder));
|
||||
|
||||
allFolders = allFolders.filter(f => f.canFileMessages);
|
||||
|
||||
let recentFolders = this.getMostRecentFolders(allFolders,
|
||||
this._MAXRECENT,
|
||||
"MRMTime");
|
||||
|
||||
// Cache the pretty names so that they do not need to be fetched
|
||||
// _MAXRECENT^2 times later.
|
||||
recentFolders = recentFolders.map(
|
||||
function (f) { return { folder: f, name: f.prettyName } });
|
||||
|
||||
// Because we're scanning across multiple accounts, we can end up with
|
||||
// several folders with the same name. Find those dupes.
|
||||
let dupeNames = new Set();
|
||||
for (let i = 0; i < recentFolders.length; i++) {
|
||||
for (let j = i + 1; j < recentFolders.length; j++) {
|
||||
if (recentFolders[i].name == recentFolders[j].name)
|
||||
dupeNames.add(recentFolders[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
for (let folderItem of recentFolders) {
|
||||
// If this folder name appears multiple times in the recent list,
|
||||
// append the server name to disambiguate.
|
||||
// TODO:
|
||||
// - maybe this could use verboseFolderFormat from messenger.properties
|
||||
// instead of hardcoded " - ".
|
||||
// - disambiguate folders with same name in same account
|
||||
// (in different subtrees).
|
||||
let label = folderItem.name;
|
||||
if (dupeNames.has(label))
|
||||
label += " - " + folderItem.folder.server.prettyName;
|
||||
|
||||
folderItem.label = label;
|
||||
}
|
||||
|
||||
// Make sure the entries are sorted alphabetically.
|
||||
recentFolders.sort((a, b) => this.folderNameCompare(a.label, b.label));
|
||||
|
||||
// Now create the Recent folder and its children
|
||||
var menu = document.createElement("menu");
|
||||
menu.setAttribute("label", this.getAttribute("recentLabel"));
|
||||
menu.setAttribute("accesskey", this.getAttribute("recentAccessKey"));
|
||||
var popup = document.createElement("menupopup");
|
||||
popup.setAttribute("class", this.getAttribute("class"));
|
||||
popup.setAttribute("generated", "true");
|
||||
menu.appendChild(popup);
|
||||
|
||||
// Create entries for each of the recent folders.
|
||||
for (let folderItem of recentFolders) {
|
||||
let node = document.createElement("menuitem");
|
||||
|
||||
node.setAttribute("label", folderItem.label);
|
||||
node._folder = folderItem.folder;
|
||||
|
||||
node.setAttribute("class", "folderMenuItem menuitem-iconic");
|
||||
this._setCssSelectors(folderItem.folder, node);
|
||||
node.setAttribute("generated", "true");
|
||||
popup.appendChild(node);
|
||||
}
|
||||
menu.setAttribute("generated", "true");
|
||||
this.appendChild(menu);
|
||||
if (!recentFolders.length)
|
||||
menu.setAttribute("disabled", "true");
|
||||
|
||||
var sep = document.createElement("menuseparator");
|
||||
sep.setAttribute("generated", "true");
|
||||
this.appendChild(sep);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
- This function adds attributes on menu/menuitems to make it easier for
|
||||
- css to style them.
|
||||
-
|
||||
- @param aFolder the folder that corresponds to the menu/menuitem
|
||||
- @param aMenuNode the actual DOM node to set attributes on
|
||||
-->
|
||||
<method name="_setCssSelectors">
|
||||
<parameter name="aFolder"/>
|
||||
<parameter name="aMenuNode"/>
|
||||
<body><![CDATA[
|
||||
|
||||
// First set the SpecialFolder attribute
|
||||
aMenuNode.setAttribute("SpecialFolder", this.getSpecialFolderString(aFolder));
|
||||
|
||||
// Now set the biffState
|
||||
let biffStates = ["NewMail", "NoMail", "UnknownMail"];
|
||||
for (let state of biffStates) {
|
||||
if (aFolder.biffState ==
|
||||
Components.interfaces.nsIMsgFolder["nsMsgBiffState_" + state]) {
|
||||
aMenuNode.setAttribute("BiffState", state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
aMenuNode.setAttribute("IsServer", aFolder.isServer);
|
||||
aMenuNode.setAttribute("IsSecure", aFolder.server.isSecure);
|
||||
aMenuNode.setAttribute("ServerType", aFolder.server.type);
|
||||
aMenuNode.setAttribute("IsFeedFolder",
|
||||
(this.FeedUtils.getFeedUrlsInFolder(aFolder) ? true : false));
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
- This function returns a formatted display name for a menulist
|
||||
- selected folder. The desired format is set as the 'displayformat'
|
||||
- attribute of the folderpicker's <menulist>, one of:
|
||||
- 'name' (default) - Folder
|
||||
- 'verbose' - Folder on Account
|
||||
- 'path' - Account/Folder/Subfolder
|
||||
-
|
||||
- @param aFolder the folder that corresponds to the menu/menuitem
|
||||
- @return string display name
|
||||
-->
|
||||
<field name="_displayformat">null</field>
|
||||
<method name="getDisplayName">
|
||||
<parameter name="aFolder"/>
|
||||
<body><![CDATA[
|
||||
if (aFolder.isServer)
|
||||
return aFolder.prettyName;
|
||||
|
||||
if (this._displayformat == "verbose")
|
||||
return this._stringBundle.getFormattedString("verboseFolderFormat",
|
||||
[aFolder.prettyName, aFolder.server.prettyName]);
|
||||
|
||||
if (this._displayformat == "path")
|
||||
return this.FeedUtils.getFolderPrettyPath(aFolder) || aFolder.name;
|
||||
|
||||
return aFolder.name;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
- Makes a given folder selected.
|
||||
-
|
||||
- @param aFolder the folder to select (if none, then Choose Folder)
|
||||
- @note If aFolder is not in this popup, but is instead a descendant of
|
||||
- a member of the popup, that ancestor will be selected.
|
||||
- @return true if any usable folder was found, otherwise false.
|
||||
-->
|
||||
<method name="selectFolder">
|
||||
<parameter name="aFolder"/>
|
||||
<body><![CDATA[
|
||||
// Set the label of the menulist element as if aFolder had been selected.
|
||||
function setupParent(aFolder, aMenulist, aNoFolders) {
|
||||
let menupopup = aMenulist.menupopup;
|
||||
if (aFolder) {
|
||||
aMenulist.setAttribute("label", menupopup.getDisplayName(aFolder));
|
||||
} else {
|
||||
aMenulist.setAttribute("label", menupopup._stringBundle.getString(
|
||||
aNoFolders ? "noFolders" :
|
||||
(menupopup._serversOnly ? "chooseAccount" : "chooseFolder")));
|
||||
}
|
||||
aMenulist.setAttribute("value",
|
||||
aFolder ? aFolder.URI : "");
|
||||
aMenulist.setAttribute("IsServer",
|
||||
aFolder ? aFolder.isServer : false);
|
||||
aMenulist.setAttribute("IsSecure",
|
||||
aFolder ? aFolder.server.isSecure : false);
|
||||
aMenulist.setAttribute("ServerType",
|
||||
aFolder ? aFolder.server.type : "none");
|
||||
aMenulist.setAttribute("SpecialFolder",
|
||||
aFolder ? menupopup.getSpecialFolderString(aFolder) : "none");
|
||||
aMenulist.setAttribute("IsFeedFolder", Boolean(
|
||||
aFolder && menupopup.FeedUtils.getFeedUrlsInFolder(aFolder)));
|
||||
}
|
||||
|
||||
let folder;
|
||||
if (aFolder) {
|
||||
for (let child of this.childNodes) {
|
||||
if (child && child._folder && !child.disabled &&
|
||||
(child._folder.URI == aFolder.URI ||
|
||||
(child.tagName == "menu" &&
|
||||
child._folder.isAncestorOf(aFolder)))) {
|
||||
if (child._folder.URI == aFolder.URI)
|
||||
this.parentNode.selectedItem = child;
|
||||
folder = aFolder;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the caller specified a folder to select and it was not
|
||||
// found, or if the caller didn't pass a folder (meaning a logical
|
||||
// and valid folder wasn't determined), don't blow up but reset
|
||||
// attributes and set a nice Choose Folder label so the user may
|
||||
// select a valid folder per the filter for this picker. If there are
|
||||
// no children, then no folder passed the filter; disable the menulist
|
||||
// as there's nothing to choose from.
|
||||
let noFolders;
|
||||
if (!this.childElementCount)
|
||||
{
|
||||
this.parentNode.setAttribute("disabled", true);
|
||||
noFolders = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.parentNode.removeAttribute("disabled");
|
||||
noFolders = false;
|
||||
}
|
||||
|
||||
setupParent(folder, this.parentNode, noFolders);
|
||||
return folder ? true : false;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
- Removes all menu-items for this popup, resets all fields, and
|
||||
- removes the listener. This function is invoked when a change
|
||||
- that affects this menu is detected by our listener.
|
||||
-->
|
||||
<method name="_teardown">
|
||||
<body><![CDATA[
|
||||
for (let i = this.childNodes.length - 1; i >= 0; i--) {
|
||||
let child = this.childNodes[i];
|
||||
if (child.getAttribute("generated") != "true")
|
||||
continue;
|
||||
if ("_teardown" in child)
|
||||
child._teardown();
|
||||
child.remove();
|
||||
}
|
||||
|
||||
this._removeListener();
|
||||
|
||||
this._initialized = false;
|
||||
]]></body>
|
||||
</method>
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
<!--
|
||||
- In order to improve performance, we're not going to build any of the
|
||||
- menu until we're shown (unless we're the child of a menulist, see
|
||||
- note in the constructor).
|
||||
-
|
||||
- @note _ensureInitialized can be called repeatedly without issue, so
|
||||
- don't worry about it here.
|
||||
-->
|
||||
<handler event="popupshowing" phase="capturing">
|
||||
this._ensureInitialized();
|
||||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
</bindings>
|
||||
235
mailnews/base/content/jsTreeView.js
Normal file
235
mailnews/base/content/jsTreeView.js
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
/* 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 a prototype object designed to make the implementation of
|
||||
* nsITreeViews in javascript simpler. This object requires that consumers
|
||||
* override the _rebuild function. This function must set the _rowMap object to
|
||||
* an array of objects fitting the following interface:
|
||||
*
|
||||
* readonly attribute string id - a unique identifier for the row/object
|
||||
* readonly attribute integer level - the hierarchy level of the row
|
||||
* attribute boolean open - whether or not this item's children are exposed
|
||||
* string getText(aColName) - return the text to display for this row in the
|
||||
* specified column
|
||||
* string getProperties() - return the css-selectors
|
||||
* attribute array children - return an array of child-objects also meeting this
|
||||
* interface
|
||||
*/
|
||||
|
||||
function PROTO_TREE_VIEW() {
|
||||
this._tree = null;
|
||||
this._rowMap = [];
|
||||
this._persistOpenMap = [];
|
||||
}
|
||||
|
||||
PROTO_TREE_VIEW.prototype = {
|
||||
get rowCount() {
|
||||
return this._rowMap.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* CSS files will cue off of these. Note that we reach into the rowMap's
|
||||
* items so that custom data-displays can define their own properties
|
||||
*/
|
||||
getCellProperties: function jstv_getCellProperties(aRow, aCol) {
|
||||
return this._rowMap[aRow].getProperties(aCol);
|
||||
},
|
||||
|
||||
/**
|
||||
* The actual text to display in the tree
|
||||
*/
|
||||
getCellText: function jstv_getCellText(aRow, aCol) {
|
||||
return this._rowMap[aRow].getText(aCol.id);
|
||||
},
|
||||
|
||||
/**
|
||||
* The jstv items take care of assigning this when building children lists
|
||||
*/
|
||||
getLevel: function jstv_getLevel(aIndex) {
|
||||
return this._rowMap[aIndex].level;
|
||||
},
|
||||
|
||||
/**
|
||||
* This is easy since the jstv items assigned the _parent property when making
|
||||
* the child lists
|
||||
*/
|
||||
getParentIndex: function jstv_getParentIndex(aIndex) {
|
||||
return this._rowMap.indexOf(this._rowMap[aIndex]._parent);
|
||||
},
|
||||
|
||||
/**
|
||||
* This is duplicative for our normal jstv views, but custom data-displays may
|
||||
* want to do something special here
|
||||
*/
|
||||
getRowProperties: function jstv_getRowProperties(aRow) {
|
||||
return this._rowMap[aRow].getProperties();
|
||||
},
|
||||
|
||||
/**
|
||||
* If an item in our list has the same level and parent as us, it's a sibling
|
||||
*/
|
||||
hasNextSibling: function jstv_hasNextSibling(aIndex, aNextIndex) {
|
||||
let targetLevel = this._rowMap[aIndex].level;
|
||||
for (let i = aNextIndex + 1; i < this._rowMap.length; i++) {
|
||||
if (this._rowMap[i].level == targetLevel)
|
||||
return true;
|
||||
if (this._rowMap[i].level < targetLevel)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* If we have a child-list with at least one element, we are a container.
|
||||
*/
|
||||
isContainer: function jstv_isContainer(aIndex) {
|
||||
return this._rowMap[aIndex].children.length > 0;
|
||||
},
|
||||
|
||||
isContainerEmpty: function jstv_isContainerEmpty(aIndex) {
|
||||
// If the container has no children, the container is empty.
|
||||
return !this._rowMap[aIndex].children.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Just look at the jstv item here
|
||||
*/
|
||||
isContainerOpen: function jstv_isContainerOpen(aIndex) {
|
||||
return this._rowMap[aIndex].open;
|
||||
},
|
||||
|
||||
isEditable: function jstv_isEditable(aRow, aCol) {
|
||||
// We don't support editing rows in the tree yet.
|
||||
return false;
|
||||
},
|
||||
|
||||
isSeparator: function jstv_isSeparator(aIndex) {
|
||||
// There are no separators in our trees
|
||||
return false;
|
||||
},
|
||||
|
||||
isSorted: function jstv_isSorted() {
|
||||
// We do our own customized sorting
|
||||
return false;
|
||||
},
|
||||
|
||||
setTree: function jstv_setTree(aTree) {
|
||||
this._tree = aTree;
|
||||
},
|
||||
|
||||
recursivelyAddToMap: function jstv_recursivelyAddToMap(aChild, aNewIndex) {
|
||||
// When we add sub-children, we're going to need to increase our index
|
||||
// for the next add item at our own level.
|
||||
let currentCount = this._rowMap.length;
|
||||
if (aChild.children.length && aChild.open) {
|
||||
for (let [i, child] in Iterator(this._rowMap[aNewIndex].children)) {
|
||||
let index = aNewIndex + i + 1;
|
||||
this._rowMap.splice(index, 0, child);
|
||||
aNewIndex += this.recursivelyAddToMap(child, index);
|
||||
}
|
||||
}
|
||||
return this._rowMap.length - currentCount;
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens or closes a container with children. The logic here is a bit hairy, so
|
||||
* be very careful about changing anything.
|
||||
*/
|
||||
toggleOpenState: function jstv_toggleOpenState(aIndex) {
|
||||
|
||||
// Ok, this is a bit tricky.
|
||||
this._rowMap[aIndex]._open = !this._rowMap[aIndex].open;
|
||||
|
||||
if (!this._rowMap[aIndex].open) {
|
||||
// We're closing the current container. Remove the children
|
||||
|
||||
// Note that we can't simply splice out children.length, because some of
|
||||
// them might have children too. Find out how many items we're actually
|
||||
// going to splice
|
||||
let level = this._rowMap[aIndex].level;
|
||||
let row = aIndex + 1;
|
||||
while (row < this._rowMap.length && this._rowMap[row].level > level) {
|
||||
row++;
|
||||
}
|
||||
let count = row - aIndex - 1;
|
||||
this._rowMap.splice(aIndex + 1, count);
|
||||
|
||||
// Remove us from the persist map
|
||||
let index = this._persistOpenMap.indexOf(this._rowMap[aIndex].id);
|
||||
if (index != -1)
|
||||
this._persistOpenMap.splice(index, 1);
|
||||
|
||||
// Notify the tree of changes
|
||||
if (this._tree) {
|
||||
this._tree.rowCountChanged(aIndex + 1, -count);
|
||||
}
|
||||
} else {
|
||||
// We're opening the container. Add the children to our map
|
||||
|
||||
// Note that these children may have been open when we were last closed,
|
||||
// and if they are, we also have to add those grandchildren to the map
|
||||
let oldCount = this._rowMap.length;
|
||||
this.recursivelyAddToMap(this._rowMap[aIndex], aIndex);
|
||||
|
||||
// Add this container to the persist map
|
||||
let id = this._rowMap[aIndex].id;
|
||||
if (this._persistOpenMap.indexOf(id) == -1)
|
||||
this._persistOpenMap.push(id);
|
||||
|
||||
// Notify the tree of changes
|
||||
if (this._tree)
|
||||
this._tree.rowCountChanged(aIndex + 1, this._rowMap.length - oldCount);
|
||||
}
|
||||
|
||||
// Invalidate the toggled row, so that the open/closed marker changes
|
||||
if (this._tree)
|
||||
this._tree.invalidateRow(aIndex);
|
||||
},
|
||||
|
||||
// We don't implement any of these at the moment
|
||||
canDrop: function jstv_canDrop(aIndex, aOrientation) {},
|
||||
drop: function jstv_drop(aRow, aOrientation) {},
|
||||
performAction: function jstv_performAction(aAction) {},
|
||||
performActionOnCell: function jstv_performActionOnCell(aAction, aRow, aCol) {},
|
||||
performActionOnRow: function jstv_performActionOnRow(aAction, aRow) {},
|
||||
selectionChanged: function jstv_selectionChanged() {},
|
||||
setCellText: function jstv_setCellText(aRow, aCol, aValue) {},
|
||||
setCellValue: function jstv_setCellValue(aRow, aCol, aValue) {},
|
||||
getCellValue: function jstv_getCellValue(aRow, aCol) {},
|
||||
getColumnProperties: function jstv_getColumnProperties(aCol) { return ""; },
|
||||
getImageSrc: function jstv_getImageSrc(aRow, aCol) {},
|
||||
getProgressMode: function jstv_getProgressMode(aRow, aCol) {},
|
||||
cycleCell: function jstv_cycleCell(aRow, aCol) {},
|
||||
cycleHeader: function jstv_cycleHeader(aCol) {},
|
||||
|
||||
_tree: null,
|
||||
|
||||
/**
|
||||
* An array of jstv items, where each item corresponds to a row in the tree
|
||||
*/
|
||||
_rowMap: null,
|
||||
|
||||
/**
|
||||
* This is a javascript map of which containers we had open, so that we can
|
||||
* persist their state over-time. It is designed to be used as a JSON object.
|
||||
*/
|
||||
_persistOpenMap: null,
|
||||
|
||||
_restoreOpenStates: function jstv__restoreOpenStates() {
|
||||
// Note that as we iterate through here, .length may grow
|
||||
for (let i = 0; i < this._rowMap.length; i++) {
|
||||
if (this._persistOpenMap.indexOf(this._rowMap[i].id) != -1)
|
||||
this.toggleOpenState(i);
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: function QueryInterface(aIID) {
|
||||
if (aIID.equals(Components.interfaces.nsITreeView) ||
|
||||
aIID.equals(Components.interfaces.nsISupports))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
456
mailnews/base/content/junkCommands.js
Normal file
456
mailnews/base/content/junkCommands.js
Normal file
|
|
@ -0,0 +1,456 @@
|
|||
/* 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/. */
|
||||
|
||||
/* functions use for junk processing commands
|
||||
*
|
||||
* TODO: These functions make the false assumption that a view only contains
|
||||
* a single folder. This is not true for XF saved searches.
|
||||
*
|
||||
* globals prerequisites used:
|
||||
*
|
||||
* window.MsgStatusFeedback
|
||||
*
|
||||
* One of:
|
||||
* GetSelectedIndices(view) (in suite)
|
||||
* gFolderDisplay (in mail)
|
||||
*
|
||||
* messenger
|
||||
* gMessengerBundle
|
||||
* gDBView
|
||||
* either gMsgFolderSelected or gFolderDisplay
|
||||
* MsgJunkMailInfo(aCheckFirstUse)
|
||||
* SetNextMessageAfterDelete()
|
||||
* pref
|
||||
* msgWindow
|
||||
*/
|
||||
|
||||
Components.utils.import("resource:///modules/mailServices.js");
|
||||
Components.utils.import("resource:///modules/MailUtils.js");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/*
|
||||
* determineActionsForJunkMsgs
|
||||
*
|
||||
* Determines the actions that should be carried out on the messages
|
||||
* that are being marked as junk
|
||||
*
|
||||
* @param aFolder
|
||||
* the folder with messages being marked as junk
|
||||
*
|
||||
* @return an object with two properties: 'markRead' (boolean) indicating
|
||||
* whether the messages should be marked as read, and 'junkTargetFolder'
|
||||
* (nsIMsgFolder) specifying where the messages should be moved, or
|
||||
* null if they should not be moved.
|
||||
*/
|
||||
function determineActionsForJunkMsgs(aFolder)
|
||||
{
|
||||
var actions = { markRead: false, junkTargetFolder: null };
|
||||
var spamSettings = aFolder.server.spamSettings;
|
||||
|
||||
// note we will do moves/marking as read even if the spam
|
||||
// feature is disabled, since the user has asked to use it
|
||||
// despite the disabling
|
||||
|
||||
actions.markRead = spamSettings.markAsReadOnSpam;
|
||||
actions.junkTargetFolder = null;
|
||||
|
||||
// move only when the corresponding setting is activated
|
||||
// and the currently viewed folder is not the junk folder.
|
||||
if (spamSettings.moveOnSpam &&
|
||||
!(aFolder.flags & Components.interfaces.nsMsgFolderFlags.Junk))
|
||||
{
|
||||
var spamFolderURI = spamSettings.spamFolderURI;
|
||||
if (!spamFolderURI)
|
||||
{
|
||||
// XXX TODO
|
||||
// we should use nsIPromptService to inform the user of the problem,
|
||||
// e.g. when the junk folder was accidentally deleted.
|
||||
dump('determineActionsForJunkMsgs: no spam folder found, not moving.');
|
||||
}
|
||||
else
|
||||
actions.junkTargetFolder = MailUtils.getFolderForURI(spamFolderURI);
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* performActionsOnJunkMsgs
|
||||
*
|
||||
* Performs required operations on a list of newly-classified junk messages
|
||||
*
|
||||
* @param aFolder
|
||||
* the folder with messages being marked as junk
|
||||
*
|
||||
* @param aJunkMsgHdrs
|
||||
* nsIArray containing headers (nsIMsgDBHdr) of new junk messages
|
||||
*
|
||||
* @param aGoodMsgHdrs
|
||||
* nsIArray containing headers (nsIMsgDBHdr) of new good messages
|
||||
*/
|
||||
function performActionsOnJunkMsgs(aFolder, aJunkMsgHdrs, aGoodMsgHdrs)
|
||||
{
|
||||
if (aFolder instanceof Components.interfaces.nsIMsgImapMailFolder) // need to update IMAP custom flags
|
||||
{
|
||||
if (aJunkMsgHdrs.length)
|
||||
{
|
||||
var junkMsgKeys = new Array();
|
||||
for (var i = 0; i < aJunkMsgHdrs.length; i++)
|
||||
junkMsgKeys[i] = aJunkMsgHdrs.queryElementAt(i, Components.interfaces.nsIMsgDBHdr).messageKey;
|
||||
aFolder.storeCustomKeywords(null, "Junk", "NonJunk", junkMsgKeys, junkMsgKeys.length);
|
||||
}
|
||||
|
||||
if (aGoodMsgHdrs.length)
|
||||
{
|
||||
var goodMsgKeys = new Array();
|
||||
for (var i = 0; i < aGoodMsgHdrs.length; i++)
|
||||
goodMsgKeys[i] = aGoodMsgHdrs.queryElementAt(i, Components.interfaces.nsIMsgDBHdr).messageKey;
|
||||
aFolder.storeCustomKeywords(null, "NonJunk", "Junk", goodMsgKeys, goodMsgKeys.length);
|
||||
}
|
||||
}
|
||||
|
||||
if (aJunkMsgHdrs.length)
|
||||
{
|
||||
var actionParams = determineActionsForJunkMsgs(aFolder);
|
||||
if (actionParams.markRead)
|
||||
aFolder.markMessagesRead(aJunkMsgHdrs, true);
|
||||
|
||||
if (actionParams.junkTargetFolder)
|
||||
MailServices.copy
|
||||
.CopyMessages(aFolder, aJunkMsgHdrs, actionParams.junkTargetFolder,
|
||||
true /* isMove */, null, msgWindow, true /* allow undo */);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MessageClassifier
|
||||
*
|
||||
* Helper object storing the list of pending messages to process,
|
||||
* and implementing junk processing callback
|
||||
*
|
||||
* @param aFolder
|
||||
* the folder with messages to be analyzed for junk
|
||||
* @param aTotalMessages
|
||||
* Number of messages to process, used for progress report only
|
||||
*/
|
||||
|
||||
function MessageClassifier(aFolder, aTotalMessages)
|
||||
{
|
||||
this.mFolder = aFolder;
|
||||
this.mJunkMsgHdrs = Components.classes["@mozilla.org/array;1"]
|
||||
.createInstance(Components.interfaces.nsIMutableArray);
|
||||
this.mGoodMsgHdrs = Components.classes["@mozilla.org/array;1"]
|
||||
.createInstance(Components.interfaces.nsIMutableArray);
|
||||
this.mMessages = new Object();
|
||||
this.mMessageQueue = new Array();
|
||||
this.mTotalMessages = aTotalMessages;
|
||||
this.mProcessedMessages = 0;
|
||||
this.firstMessage = true;
|
||||
this.lastStatusTime = Date.now();
|
||||
}
|
||||
|
||||
MessageClassifier.prototype =
|
||||
{
|
||||
/**
|
||||
* analyzeMessage
|
||||
*
|
||||
* Starts the message classification process for a message. If the message
|
||||
* sender's address is whitelisted, the message is skipped.
|
||||
*
|
||||
* @param aMsgHdr
|
||||
* The header (nsIMsgDBHdr) of the message to classify.
|
||||
* @param aSpamSettings
|
||||
* nsISpamSettings object with information about whitelists
|
||||
*/
|
||||
analyzeMessage: function(aMsgHdr, aSpamSettings)
|
||||
{
|
||||
var junkscoreorigin = aMsgHdr.getStringProperty("junkscoreorigin");
|
||||
if (junkscoreorigin == "user") // don't override user-set junk status
|
||||
return;
|
||||
|
||||
// check whitelisting
|
||||
if (aSpamSettings.checkWhiteList(aMsgHdr))
|
||||
{
|
||||
// message is ham from whitelist
|
||||
var db = aMsgHdr.folder.msgDatabase;
|
||||
db.setStringProperty(aMsgHdr.messageKey, "junkscore",
|
||||
Components.interfaces.nsIJunkMailPlugin.IS_HAM_SCORE);
|
||||
db.setStringProperty(aMsgHdr.messageKey, "junkscoreorigin", "whitelist");
|
||||
this.mGoodMsgHdrs.appendElement(aMsgHdr, false);
|
||||
return;
|
||||
}
|
||||
|
||||
var messageURI = aMsgHdr.folder.generateMessageURI(aMsgHdr.messageKey) + "?fetchCompleteMessage=true";
|
||||
this.mMessages[messageURI] = aMsgHdr;
|
||||
if (this.firstMessage)
|
||||
{
|
||||
this.firstMessage = false;
|
||||
MailServices.junk.classifyMessage(messageURI, msgWindow, this);
|
||||
}
|
||||
else
|
||||
this.mMessageQueue.push(messageURI);
|
||||
},
|
||||
|
||||
/*
|
||||
* nsIJunkMailClassificationListener implementation
|
||||
* onMessageClassified
|
||||
*
|
||||
* Callback function from nsIJunkMailPlugin with classification results
|
||||
*
|
||||
* @param aClassifiedMsgURI
|
||||
* URI of classified message
|
||||
* @param aClassification
|
||||
* Junk classification (0: UNCLASSIFIED, 1: GOOD, 2: JUNK)
|
||||
* @param aJunkPercent
|
||||
* 0 - 100 indicator of junk likelihood, with 100 meaning probably junk
|
||||
*/
|
||||
onMessageClassified: function(aClassifiedMsgURI, aClassification, aJunkPercent)
|
||||
{
|
||||
if (!aClassifiedMsgURI)
|
||||
return; // ignore end of batch
|
||||
var nsIJunkMailPlugin = Components.interfaces.nsIJunkMailPlugin;
|
||||
var score = (aClassification == nsIJunkMailPlugin.JUNK) ?
|
||||
nsIJunkMailPlugin.IS_SPAM_SCORE : nsIJunkMailPlugin.IS_HAM_SCORE;
|
||||
const statusDisplayInterval = 1000; // milliseconds between status updates
|
||||
|
||||
// set these props via the db (instead of the message header
|
||||
// directly) so that the nsMsgDBView knows to update the UI
|
||||
//
|
||||
var msgHdr = this.mMessages[aClassifiedMsgURI];
|
||||
var db = msgHdr.folder.msgDatabase;
|
||||
db.setStringProperty(msgHdr.messageKey, "junkscore", score);
|
||||
db.setStringProperty(msgHdr.messageKey, "junkscoreorigin", "plugin");
|
||||
db.setStringProperty(msgHdr.messageKey, "junkpercent", aJunkPercent);
|
||||
|
||||
if (aClassification == nsIJunkMailPlugin.JUNK)
|
||||
this.mJunkMsgHdrs.appendElement(msgHdr, false);
|
||||
else if (aClassification == nsIJunkMailPlugin.GOOD)
|
||||
this.mGoodMsgHdrs.appendElement(msgHdr, false);
|
||||
|
||||
var nextMsgURI = this.mMessageQueue.shift();
|
||||
if (nextMsgURI)
|
||||
{
|
||||
++this.mProcessedMessages;
|
||||
if (Date.now() > this.lastStatusTime + statusDisplayInterval)
|
||||
{
|
||||
this.lastStatusTime = Date.now();
|
||||
var percentDone = 0;
|
||||
if (this.mTotalMessages)
|
||||
percentDone = Math.round(this.mProcessedMessages * 100 / this.mTotalMessages);
|
||||
var percentStr = percentDone + "%";
|
||||
window.MsgStatusFeedback.showStatusString(
|
||||
document.getElementById("bundle_messenger")
|
||||
.getFormattedString("junkAnalysisPercentComplete",
|
||||
[percentStr]));
|
||||
}
|
||||
|
||||
MailServices.junk.classifyMessage(nextMsgURI, msgWindow, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
window.MsgStatusFeedback.showStatusString(
|
||||
document.getElementById("bundle_messenger")
|
||||
.getString("processingJunkMessages"));
|
||||
performActionsOnJunkMsgs(this.mFolder, this.mJunkMsgHdrs, this.mGoodMsgHdrs);
|
||||
window.MsgStatusFeedback.showStatusString("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* filterFolderForJunk
|
||||
*
|
||||
* Filter all messages in the current folder for junk
|
||||
*/
|
||||
function filterFolderForJunk() { processFolderForJunk(true); }
|
||||
|
||||
/*
|
||||
* analyzeMessagesForJunk
|
||||
*
|
||||
* Filter selected messages in the current folder for junk
|
||||
*/
|
||||
function analyzeMessagesForJunk() { processFolderForJunk(false); }
|
||||
|
||||
/*
|
||||
* processFolderForJunk
|
||||
*
|
||||
* Filter messages in the current folder for junk
|
||||
*
|
||||
* @param aAll: true to filter all messages, else filter selection
|
||||
*/
|
||||
function processFolderForJunk(aAll)
|
||||
{
|
||||
MsgJunkMailInfo(true);
|
||||
|
||||
if (aAll)
|
||||
{
|
||||
// need to expand all threads, so we analyze everything
|
||||
gDBView.doCommand(nsMsgViewCommandType.expandAll);
|
||||
var treeView = gDBView.QueryInterface(Components.interfaces.nsITreeView);
|
||||
var count = treeView.rowCount;
|
||||
if (!count)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// suite uses GetSelectedIndices, mail uses gFolderDisplay.selectedMessages
|
||||
var indices = typeof GetSelectedIndices != "undefined" ?
|
||||
GetSelectedIndices(gDBView) :
|
||||
gFolderDisplay.selectedIndices;
|
||||
if (!indices || !indices.length)
|
||||
return;
|
||||
}
|
||||
var totalMessages = aAll ? count : indices.length;
|
||||
|
||||
// retrieve server and its spam settings via the header of an arbitrary message
|
||||
for (var i = 0; i < totalMessages; i++)
|
||||
{
|
||||
var index = aAll ? i : indices[i];
|
||||
try
|
||||
{
|
||||
var tmpMsgURI = gDBView.getURIForViewIndex(index);
|
||||
break;
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
// dummy headers will fail, so look for another
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!tmpMsgURI)
|
||||
return;
|
||||
|
||||
var tmpMsgHdr = messenger.messageServiceFromURI(tmpMsgURI).messageURIToMsgHdr(tmpMsgURI);
|
||||
var spamSettings = tmpMsgHdr.folder.server.spamSettings;
|
||||
|
||||
// create a classifier instance to classify messages in the folder.
|
||||
var msgClassifier = new MessageClassifier(tmpMsgHdr.folder, totalMessages);
|
||||
|
||||
for ( i = 0; i < totalMessages; i++)
|
||||
{
|
||||
var index = aAll ? i : indices[i];
|
||||
try
|
||||
{
|
||||
var msgURI = gDBView.getURIForViewIndex(index);
|
||||
var msgHdr = messenger.messageServiceFromURI(msgURI).messageURIToMsgHdr(msgURI);
|
||||
msgClassifier.analyzeMessage(msgHdr, spamSettings);
|
||||
}
|
||||
catch (ex)
|
||||
{
|
||||
// blow off errors here - dummy headers will fail
|
||||
var msgURI = null;
|
||||
}
|
||||
}
|
||||
if (msgClassifier.firstMessage) // the async plugin was not used, maybe all whitelisted?
|
||||
performActionsOnJunkMsgs(msgClassifier.mFolder,
|
||||
msgClassifier.mJunkMsgHdrs,
|
||||
msgClassifier.mGoodMsgHdrs);
|
||||
}
|
||||
|
||||
function JunkSelectedMessages(setAsJunk)
|
||||
{
|
||||
MsgJunkMailInfo(true);
|
||||
|
||||
// When the user explicitly marks a message as junk, we can mark it as read,
|
||||
// too. This is independent of the "markAsReadOnSpam" pref, which applies
|
||||
// only to automatically-classified messages.
|
||||
// Note that this behaviour should match the one in the back end for marking
|
||||
// as junk via clicking the 'junk' column.
|
||||
|
||||
if (setAsJunk && Services.prefs.getBoolPref("mailnews.ui.junk.manualMarkAsJunkMarksRead"))
|
||||
MarkSelectedMessagesRead(true);
|
||||
|
||||
gDBView.doCommand(setAsJunk ? nsMsgViewCommandType.junk
|
||||
: nsMsgViewCommandType.unjunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete junk messages in the current folder. This provides the guarantee that
|
||||
* the method will be synchronous if no messages are deleted.
|
||||
*
|
||||
* @returns The number of messages deleted.
|
||||
*/
|
||||
function deleteJunkInFolder()
|
||||
{
|
||||
MsgJunkMailInfo(true);
|
||||
|
||||
// use direct folder commands if possible so we don't mess with the selection
|
||||
let selectedFolder = gFolderDisplay.displayedFolder;
|
||||
if ( !(selectedFolder.flags & Components.interfaces.nsMsgFolderFlags.Virtual) )
|
||||
{
|
||||
var junkMsgHdrs = Components.classes["@mozilla.org/array;1"]
|
||||
.createInstance(Components.interfaces.nsIMutableArray);
|
||||
var enumerator = gDBView.msgFolder.messages;
|
||||
while (enumerator.hasMoreElements())
|
||||
{
|
||||
var msgHdr = enumerator.getNext().QueryInterface(Components.interfaces.nsIMsgDBHdr);
|
||||
var junkScore = msgHdr.getStringProperty("junkscore");
|
||||
if (junkScore == Components.interfaces.nsIJunkMailPlugin.IS_SPAM_SCORE)
|
||||
junkMsgHdrs.appendElement(msgHdr, false);
|
||||
}
|
||||
|
||||
if (junkMsgHdrs.length)
|
||||
gDBView.msgFolder.deleteMessages(junkMsgHdrs, msgWindow, false, false, null, true);
|
||||
return junkMsgHdrs.length;
|
||||
}
|
||||
|
||||
// Folder is virtual, let the view do the work (but we lose selection)
|
||||
|
||||
// need to expand all threads, so we find everything
|
||||
gDBView.doCommand(nsMsgViewCommandType.expandAll);
|
||||
|
||||
var treeView = gDBView.QueryInterface(Components.interfaces.nsITreeView);
|
||||
var count = treeView.rowCount;
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
var treeSelection = treeView.selection;
|
||||
|
||||
var clearedSelection = false;
|
||||
|
||||
// select the junk messages
|
||||
var messageUri;
|
||||
let numMessagesDeleted = 0;
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
try {
|
||||
messageUri = gDBView.getURIForViewIndex(i);
|
||||
}
|
||||
catch (ex) {continue;} // blow off errors for dummy rows
|
||||
var msgHdr = messenger.messageServiceFromURI(messageUri).messageURIToMsgHdr(messageUri);
|
||||
var junkScore = msgHdr.getStringProperty("junkscore");
|
||||
var isJunk = (junkScore == Components.interfaces.nsIJunkMailPlugin.IS_SPAM_SCORE);
|
||||
// if the message is junk, select it.
|
||||
if (isJunk)
|
||||
{
|
||||
// only do this once
|
||||
if (!clearedSelection)
|
||||
{
|
||||
// clear the current selection
|
||||
// since we will be deleting all selected messages
|
||||
treeSelection.clearSelection();
|
||||
clearedSelection = true;
|
||||
treeSelection.selectEventsSuppressed = true;
|
||||
}
|
||||
treeSelection.rangedSelect(i, i, true /* augment */);
|
||||
numMessagesDeleted++;
|
||||
}
|
||||
}
|
||||
|
||||
// if we didn't clear the selection
|
||||
// there was no junk, so bail.
|
||||
if (!clearedSelection)
|
||||
return 0;
|
||||
|
||||
treeSelection.selectEventsSuppressed = false;
|
||||
// delete the selected messages
|
||||
//
|
||||
// We'll leave no selection after the delete
|
||||
gNextMessageViewIndexAfterDelete = nsMsgViewIndex_None;
|
||||
gDBView.doCommand(nsMsgViewCommandType.deleteMsg);
|
||||
treeSelection.clearSelection();
|
||||
ClearMessagePane();
|
||||
return numMessagesDeleted;
|
||||
}
|
||||
|
||||
33
mailnews/base/content/junkLog.js
Normal file
33
mailnews/base/content/junkLog.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var gLogView;
|
||||
var gLogFile;
|
||||
|
||||
function onLoad()
|
||||
{
|
||||
gLogView = document.getElementById("logView");
|
||||
gLogView.docShell.allowJavascript = false; // for security, disable JS
|
||||
|
||||
gLogFile = Services.dirsvc.get("ProfD", Components.interfaces.nsIFile);
|
||||
gLogFile.append("junklog.html");
|
||||
|
||||
if (gLogFile.exists())
|
||||
{
|
||||
// convert the file to a URL so we can load it.
|
||||
gLogView.setAttribute("src", Services.io.newFileURI(gLogFile).spec);
|
||||
}
|
||||
}
|
||||
|
||||
function clearLog()
|
||||
{
|
||||
if (gLogFile.exists())
|
||||
{
|
||||
gLogFile.remove(false);
|
||||
gLogView.setAttribute("src", "about:blank"); // we don't have a log file to show
|
||||
}
|
||||
}
|
||||
46
mailnews/base/content/junkLog.xul
Normal file
46
mailnews/base/content/junkLog.xul
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
- 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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/junkLog.dtd">
|
||||
|
||||
<dialog id="viewLogWindow"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="onLoad();"
|
||||
title="&adaptiveJunkLog.title;"
|
||||
windowtype="mailnews:junklog"
|
||||
buttons="accept"
|
||||
buttonlabelaccept="&closeLog.label;"
|
||||
buttonaccesskeyaccept="&closeLog.accesskey;"
|
||||
ondialogaccept="window.close();"
|
||||
persist="screenX screenY width height"
|
||||
style="width: 40em; height: 25em;">
|
||||
|
||||
<script type="application/javascript" src="chrome://messenger/content/junkLog.js"/>
|
||||
|
||||
<vbox flex="1">
|
||||
<hbox>
|
||||
<label value="&adaptiveJunkLogInfo.label;"/>
|
||||
<spacer flex="1"/>
|
||||
<button label="&clearLog.label;"
|
||||
accesskey="&clearLog.accesskey;"
|
||||
oncommand="clearLog();"/>
|
||||
</hbox>
|
||||
<separator class="thin"/>
|
||||
<hbox flex="1">
|
||||
<browser id="logView"
|
||||
class="inset"
|
||||
type="content"
|
||||
disablehistory="true"
|
||||
disablesecurity="true"
|
||||
src="about:blank"
|
||||
autofind="false"
|
||||
flex="1"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</dialog>
|
||||
35
mailnews/base/content/junkMailInfo.xul
Normal file
35
mailnews/base/content/junkMailInfo.xul
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<!DOCTYPE dialog [
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
|
||||
%brandDTD;
|
||||
<!ENTITY % junkMailInfoDTD SYSTEM "chrome://messenger/locale/junkMailInfo.dtd" >
|
||||
%junkMailInfoDTD;
|
||||
]>
|
||||
|
||||
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://messenger/skin/primaryToolbar.css" type="text/css"?>
|
||||
|
||||
<dialog id="junkMailInfo"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="&window.title;"
|
||||
windowtype="mailnews:junkmailinfo"
|
||||
buttons="accept">
|
||||
|
||||
<vbox flex="1" width="&window.width;">
|
||||
<spacer/>
|
||||
<description>&info1a.label;<image align="center" id="junkIcon"/>&info1b.label;</description>
|
||||
<spacer/>
|
||||
<description>&info2.label;</description>
|
||||
<spacer/>
|
||||
<description>&info3.label;</description>
|
||||
#ifndef MOZ_THUNDERBIRD
|
||||
<spacer/>
|
||||
<description>&info4.label;</description>
|
||||
#endif
|
||||
</vbox>
|
||||
</dialog>
|
||||
133
mailnews/base/content/markByDate.js
Normal file
133
mailnews/base/content/markByDate.js
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
|
||||
|
||||
var MILLISECONDS_PER_HOUR = 60 * 60 * 1000;
|
||||
var MICROSECONDS_PER_DAY = 1000 * MILLISECONDS_PER_HOUR * 24;
|
||||
|
||||
function onLoad()
|
||||
{
|
||||
var upperDateBox = document.getElementById("upperDate");
|
||||
// focus the upper bound control - this is where we expect most users to enter
|
||||
// a date
|
||||
upperDateBox.focus();
|
||||
|
||||
// and give it an initial date - "yesterday"
|
||||
var initialDate = new Date();
|
||||
initialDate.setHours( 0 );
|
||||
initialDate.setTime( initialDate.getTime() - MILLISECONDS_PER_HOUR );
|
||||
// note that this is sufficient - though it is at the end of the previous day,
|
||||
// we convert it to a date string, and then the time part is truncated
|
||||
upperDateBox.value = convertDateToString( initialDate );
|
||||
upperDateBox.select(); // allows to start overwriting immediately
|
||||
}
|
||||
|
||||
function onAccept()
|
||||
{
|
||||
// get the times as entered by the user
|
||||
var lowerDateString = document.getElementById( "lowerDate" ).value;
|
||||
// the fallback for the lower bound, if not entered, is the "beginning of
|
||||
// time" (1970-01-01), which actually is simply 0 :)
|
||||
var prLower = lowerDateString ? convertStringToPRTime( lowerDateString ) : 0;
|
||||
|
||||
var upperDateString = document.getElementById( "upperDate" ).value;
|
||||
var prUpper;
|
||||
if ( upperDateString == "" )
|
||||
{
|
||||
// for the upper bound, the fallback is "today".
|
||||
var dateThisMorning = new Date();
|
||||
dateThisMorning.setMilliseconds( 0 );
|
||||
dateThisMorning.setSeconds( 0 );
|
||||
dateThisMorning.setMinutes( 0 );
|
||||
dateThisMorning.setHours( 0 );
|
||||
// Javascript time is in milliseconds, PRTime is in microseconds
|
||||
prUpper = dateThisMorning.getTime() * 1000;
|
||||
}
|
||||
else
|
||||
prUpper = convertStringToPRTime( upperDateString );
|
||||
|
||||
// for the upper date, we have to do a correction:
|
||||
// if the user enters a date, then she means (hopefully) that all messages sent
|
||||
// at this day should be marked, too, but the PRTime calculated from this would
|
||||
// point to the beginning of the day. So we need to increment it by
|
||||
// [number of micro seconds per day]. This will denote the first microsecond of
|
||||
// the next day then, which is later used as exclusive boundary
|
||||
prUpper += MICROSECONDS_PER_DAY;
|
||||
|
||||
markInDatabase( prLower, prUpper );
|
||||
|
||||
return true; // allow closing
|
||||
}
|
||||
|
||||
/** marks all headers in the database, whose time is between the two
|
||||
given times, as read.
|
||||
@param lower
|
||||
PRTime for the lower bound - this boundary is inclusive
|
||||
@param upper
|
||||
PRTime for the upper bound - this boundary is exclusive
|
||||
*/
|
||||
function markInDatabase( lower, upper )
|
||||
{
|
||||
var messageFolder;
|
||||
var messageDatabase;
|
||||
// extract the database
|
||||
if ( window.arguments && window.arguments[0] )
|
||||
{
|
||||
messageFolder = window.arguments[0];
|
||||
messageDatabase = messageFolder.msgDatabase;
|
||||
}
|
||||
|
||||
if ( !messageDatabase )
|
||||
{
|
||||
dump( "markByDate::markInDatabase: there /is/ no database to operate on!\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// the headers which are going to be marked
|
||||
var headers = Components.classes["@mozilla.org/array;1"].createInstance( Components.interfaces.nsIMutableArray );
|
||||
var searchSession = Components.classes["@mozilla.org/messenger/searchSession;1"].createInstance( Components.interfaces.nsIMsgSearchSession );
|
||||
var searchTerms = Components.classes["@mozilla.org/array;1"].createInstance( Components.interfaces.nsIMutableArray );
|
||||
searchSession.addScopeTerm( Components.interfaces.nsMsgSearchScope.offlineMail, messageFolder );
|
||||
|
||||
const nsMsgSearchAttrib = Components.interfaces.nsMsgSearchAttrib;
|
||||
const nsMsgSearchOp = Components.interfaces.nsMsgSearchOp;
|
||||
|
||||
var searchTerm = searchSession.createTerm();
|
||||
searchTerm.attrib = nsMsgSearchAttrib.Date;
|
||||
searchTerm.op = nsMsgSearchOp.IsBefore;
|
||||
var value = searchTerm.value;
|
||||
value.attrib = nsMsgSearchAttrib.Date;
|
||||
value.date = upper;
|
||||
searchTerm.value = value;
|
||||
searchTerms.appendElement( searchTerm, false );
|
||||
|
||||
if ( lower )
|
||||
{
|
||||
searchTerm = searchSession.createTerm();
|
||||
searchTerm.booleanAnd = true;
|
||||
searchTerm.attrib = nsMsgSearchAttrib.Date;
|
||||
searchTerm.op = nsMsgSearchOp.IsAfter;
|
||||
value = searchTerm.value;
|
||||
value.attrib = nsMsgSearchAttrib.Date;
|
||||
value.date = lower;
|
||||
searchTerm.value = value;
|
||||
searchTerms.appendElement( searchTerm, false );
|
||||
}
|
||||
|
||||
var filterEnumerator = messageDatabase.getFilterEnumerator( searchTerms );
|
||||
|
||||
if ( filterEnumerator )
|
||||
{
|
||||
var keepGoing;
|
||||
var numMatches = {};
|
||||
do
|
||||
{
|
||||
keepGoing = messageDatabase.nextMatchingHdrs(filterEnumerator, 0, 0, headers, numMatches);
|
||||
}
|
||||
while ( keepGoing );
|
||||
}
|
||||
|
||||
if ( headers.length )
|
||||
messageFolder.markMessagesRead( headers, true );
|
||||
}
|
||||
34
mailnews/base/content/markByDate.xul
Normal file
34
mailnews/base/content/markByDate.xul
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://messenger/skin/dialogs.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/markByDate.dtd">
|
||||
|
||||
<dialog
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="&messageMarkByDate.label;"
|
||||
buttons="accept,cancel"
|
||||
onload="onLoad();"
|
||||
ondialogaccept="return onAccept();">
|
||||
|
||||
<script type="application/javascript" src="chrome://messenger/content/markByDate.js"/>
|
||||
<script type="application/javascript" src="chrome://messenger/content/dateFormat.js"/>
|
||||
|
||||
<hbox align="center" pack="end">
|
||||
<label control="lowerDate"
|
||||
value="&markByDateLower.label;"
|
||||
accesskey="&markByDateLower.accesskey;"/>
|
||||
<textbox size="11" id="lowerDate"/>
|
||||
</hbox>
|
||||
<hbox align="center" pack="end">
|
||||
<label control="upperDate"
|
||||
value="&markByDateUpper.label;"
|
||||
accesskey="&markByDateUpper.accesskey;"/>
|
||||
<textbox size="11" id="upperDate"/>
|
||||
</hbox>
|
||||
|
||||
</dialog>
|
||||
341
mailnews/base/content/msgAccountCentral.js
Normal file
341
mailnews/base/content/msgAccountCentral.js
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var selectedServer = null;
|
||||
|
||||
function OnInit()
|
||||
{
|
||||
// Set the header for the page.
|
||||
// Title containts the brand name of the application and the account
|
||||
// type (mail/news) and the name of the account
|
||||
try {
|
||||
let msgFolder = null;
|
||||
let title;
|
||||
|
||||
// Get the brand name
|
||||
let brandName = document.getElementById("bundle_brand")
|
||||
.getString("brandShortName");
|
||||
let messengerBundle = document.getElementById("bundle_messenger");
|
||||
|
||||
selectedServer = GetSelectedServer();
|
||||
if (selectedServer) {
|
||||
// Get the account type
|
||||
let serverType = selectedServer.type;
|
||||
let acctType;
|
||||
if (serverType == "nntp")
|
||||
acctType = messengerBundle.getString("newsAcctType");
|
||||
else if (serverType == "rss")
|
||||
acctType = messengerBundle.getString("feedsAcctType");
|
||||
else
|
||||
acctType = messengerBundle.getString("mailAcctType");
|
||||
|
||||
// Get the account name
|
||||
msgFolder = GetSelectedMsgFolder();
|
||||
ArrangeAccountCentralItems(selectedServer, msgFolder);
|
||||
|
||||
let acctName = msgFolder.prettyName;
|
||||
// Display and collapse items presented to the user based on account type
|
||||
title = messengerBundle.getFormattedString("acctCentralTitleFormat",
|
||||
[brandName, acctType, acctName]);
|
||||
} else {
|
||||
// If there is no selectedServer, we are in a brand new profile with
|
||||
// no accounts - show the create account rows.
|
||||
title = brandName;
|
||||
SetItemDisplay("AccountsHeader", true);
|
||||
SetItemDisplay("CreateAccount", true);
|
||||
SetItemDisplay("CreateAccounts", true);
|
||||
}
|
||||
|
||||
// Set the title for the document
|
||||
document.getElementById("AccountCentralTitle").setAttribute("value", title);
|
||||
}
|
||||
catch(ex) {
|
||||
Components.utils.reportError("Error getting selected account: " + ex + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Show items in the AccountCentral page depending on the capabilities
|
||||
// of the given account
|
||||
function ArrangeAccountCentralItems(server, msgFolder)
|
||||
{
|
||||
let exceptions = [];
|
||||
let protocolInfo = null;
|
||||
try {
|
||||
protocolInfo = server.protocolInfo;
|
||||
} catch (e) {
|
||||
exceptions.push(e);
|
||||
}
|
||||
|
||||
// Is this a RSS account?
|
||||
let displayRssHeader = server && server.type == 'rss';
|
||||
|
||||
/***** Email header and items : Begin *****/
|
||||
|
||||
// Read Messages
|
||||
let canGetMessages = false;
|
||||
try {
|
||||
canGetMessages = protocolInfo && protocolInfo.canGetMessages;
|
||||
SetItemDisplay("ReadMessages", canGetMessages && !displayRssHeader);
|
||||
} catch (e) { exceptions.push(e); }
|
||||
|
||||
// Compose Messages link
|
||||
let showComposeMsgLink = false;
|
||||
try {
|
||||
showComposeMsgLink = protocolInfo && protocolInfo.showComposeMsgLink;
|
||||
SetItemDisplay("ComposeMessage", showComposeMsgLink);
|
||||
} catch (e) { exceptions.push(e); }
|
||||
|
||||
// Junk mail settings (false, until ready for prime time)
|
||||
let canControlJunkEmail = false
|
||||
try {
|
||||
canControlJunkEmail = false && protocolInfo &&
|
||||
protocolInfo.canGetIncomingMessages &&
|
||||
protocolInfo.canGetMessages;
|
||||
SetItemDisplay("JunkSettingsMail", canControlJunkEmail);
|
||||
} catch (e) { exceptions.push(e); }
|
||||
|
||||
// Display Email header, only if any of the items are displayed
|
||||
let displayEmailHeader = !displayRssHeader &&
|
||||
(canGetMessages || showComposeMsgLink ||
|
||||
canControlJunkEmail);
|
||||
SetItemDisplay("EmailHeader", displayEmailHeader);
|
||||
|
||||
/***** Email header and items : End *****/
|
||||
|
||||
/***** News header and items : Begin *****/
|
||||
|
||||
// Subscribe to Newsgroups
|
||||
let canSubscribe = false;
|
||||
try {
|
||||
canSubscribe = msgFolder && msgFolder.canSubscribe &&
|
||||
protocolInfo && !protocolInfo.canGetMessages;
|
||||
SetItemDisplay("SubscribeNewsgroups", canSubscribe);
|
||||
} catch (e) { exceptions.push(e); }
|
||||
|
||||
// Junk news settings (false, until ready for prime time)
|
||||
let canControlJunkNews = false;
|
||||
try {
|
||||
canControlJunkNews = false && protocolInfo &&
|
||||
protocolInfo.canGetIncomingMessages &&
|
||||
!protocolInfo.canGetMessages;
|
||||
SetItemDisplay("JunkSettingsNews", canControlJunkNews);
|
||||
} catch (e) { exceptions.push(e); }
|
||||
|
||||
// Display News header, only if any of the items are displayed
|
||||
let displayNewsHeader = canSubscribe || canControlJunkNews;
|
||||
SetItemDisplay("NewsHeader", displayNewsHeader);
|
||||
|
||||
/***** News header and items : End *****/
|
||||
|
||||
/***** RSS header and items : Begin *****/
|
||||
|
||||
// Display RSS header, only if this is RSS account
|
||||
SetItemDisplay("rssHeader", displayRssHeader);
|
||||
|
||||
// Subscribe to RSS Feeds
|
||||
SetItemDisplay("SubscribeRSS", displayRssHeader);
|
||||
|
||||
/***** RSS header and items : End *****/
|
||||
|
||||
// If either of above sections exists, show section separators
|
||||
SetItemDisplay("MessagesSection",
|
||||
displayNewsHeader || displayEmailHeader || displayRssHeader);
|
||||
|
||||
/***** Accounts : Begin *****/
|
||||
|
||||
// Account Settings if a server is found
|
||||
let canShowAccountSettings = server != null;
|
||||
SetItemDisplay("AccountSettings", canShowAccountSettings);
|
||||
|
||||
// Show New Mail Account Wizard if not prohibited by pref
|
||||
let canShowCreateAccount = false;
|
||||
try {
|
||||
canShowCreateAccount = !Services.prefs
|
||||
.prefIsLocked("mail.disable_new_account_addition");
|
||||
SetItemDisplay("CreateAccount", canShowCreateAccount);
|
||||
SetItemDisplay("CreateAccounts", canShowCreateAccount);
|
||||
} catch (e) { exceptions.push(e); }
|
||||
|
||||
// Display Accounts header, only if any of the items are displayed
|
||||
let displayAccountsHeader = canShowAccountSettings || canShowCreateAccount;
|
||||
SetItemDisplay("AccountsHeader", canShowCreateAccount);
|
||||
|
||||
/***** Accounts : End *****/
|
||||
|
||||
/***** Advanced Features header and items : Begin *****/
|
||||
|
||||
// Search Messages
|
||||
let canSearchMessages = false;
|
||||
try {
|
||||
canSearchMessages = server && server.canSearchMessages;
|
||||
SetItemDisplay("SearchMessages", canSearchMessages);
|
||||
} catch (e) { exceptions.push(e); }
|
||||
|
||||
// Create Filters
|
||||
let canHaveFilters = false;
|
||||
try {
|
||||
canHaveFilters = server && server.canHaveFilters;
|
||||
SetItemDisplay("CreateFilters", canHaveFilters);
|
||||
} catch (e) { exceptions.push(e); }
|
||||
|
||||
// Subscribe to IMAP Folders
|
||||
let canSubscribeImapFolders = false;
|
||||
try {
|
||||
canSubscribeImapFolders = msgFolder && msgFolder.canSubscribe &&
|
||||
protocolInfo && protocolInfo.canGetMessages;
|
||||
SetItemDisplay("SubscribeImapFolders", canSubscribeImapFolders);
|
||||
} catch (e) { exceptions.push(e); }
|
||||
|
||||
// Offline Settings
|
||||
let supportsOffline = false;
|
||||
try {
|
||||
supportsOffline = server && server.offlineSupportLevel != 0;
|
||||
SetItemDisplay("OfflineSettings", supportsOffline);
|
||||
} catch (e) { exceptions.push(e); }
|
||||
|
||||
// Display Adv Features header, only if any of the items are displayed
|
||||
let displayAdvFeatures = canSearchMessages || canHaveFilters ||
|
||||
canSubscribeImapFolders|| supportsOffline;
|
||||
SetItemDisplay("AdvancedFeaturesHeader", displayAdvFeatures);
|
||||
|
||||
/***** Advanced Featuers header and items : End *****/
|
||||
|
||||
// If either of above features exist, show section separators
|
||||
SetItemDisplay("AccountsSection", displayAdvFeatures);
|
||||
|
||||
while (exceptions.length) {
|
||||
Components.utils.reportError("Error in setting AccountCentral Items: "
|
||||
+ exceptions.pop() + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Show the item if the item feature is supported
|
||||
function SetItemDisplay(elemId, displayThisItem)
|
||||
{
|
||||
if (displayThisItem) {
|
||||
let elem = document.getElementById(elemId);
|
||||
if (elem)
|
||||
elem.setAttribute("collapsed", false);
|
||||
|
||||
let elemSpacer = document.getElementById(elemId + ".spacer");
|
||||
if (elemSpacer)
|
||||
elemSpacer.setAttribute("collapsed", false);
|
||||
}
|
||||
}
|
||||
|
||||
// From the current folder tree, return the selected server or null
|
||||
function GetSelectedServer()
|
||||
{
|
||||
let currentFolder = GetSelectedMsgFolder();
|
||||
return currentFolder ? currentFolder.server : null;
|
||||
}
|
||||
|
||||
// From the current folder tree, return the selected folder,
|
||||
// the root folder of default account or null
|
||||
function GetSelectedMsgFolder()
|
||||
{
|
||||
return window.parent.GetSelectedMsgFolders()[0] ||
|
||||
window.parent.GetDefaultAccountRootFolder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open Inbox for selected server.
|
||||
* If needed, open the twisty and select Inbox.
|
||||
*/
|
||||
function ReadMessages()
|
||||
{
|
||||
if (!selectedServer)
|
||||
return;
|
||||
try {
|
||||
window.parent.OpenInboxForServer(selectedServer);
|
||||
}
|
||||
catch(ex) {
|
||||
Components.utils
|
||||
.reportError("Error opening Inbox for server: " + ex + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger composer for a new message
|
||||
function ComposeAMessage(event)
|
||||
{
|
||||
// Pass event to allow holding Shift key for toggling HTML vs. plaintext format
|
||||
window.parent.MsgNewMessage(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open AccountManager to view settings for a given account
|
||||
* @param selectPage the xul file name for the viewing page,
|
||||
* null for the account main page, other pages are
|
||||
* 'am-server.xul', 'am-copies.xul', 'am-offline.xul',
|
||||
* 'am-addressing.xul', 'am-smtp.xul'
|
||||
*/
|
||||
function ViewSettings(selectPage)
|
||||
{
|
||||
window.parent.MsgAccountManager(selectPage);
|
||||
}
|
||||
|
||||
// Open AccountWizard to create an account
|
||||
function CreateNewAccount()
|
||||
{
|
||||
window.parent.msgOpenAccountWizard();
|
||||
}
|
||||
|
||||
function CreateNewAccountTB(type)
|
||||
{
|
||||
if (type == "mail") {
|
||||
if (Services.prefs.getBoolPref("mail.provider.enabled"))
|
||||
NewMailAccountProvisioner(null);
|
||||
else
|
||||
AddMailAccount();
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == "feeds") {
|
||||
AddFeedAccount();
|
||||
return;
|
||||
}
|
||||
|
||||
window.parent.msgOpenAccountWizard(
|
||||
function(state) {
|
||||
let win = getMostRecentMailWindow();
|
||||
if (state && win && win.gFolderTreeView && this.gCurrentAccount) {
|
||||
win.gFolderTreeView.selectFolder(
|
||||
this.gCurrentAccount.incomingServer.rootMsgFolder);
|
||||
}
|
||||
},
|
||||
type);
|
||||
}
|
||||
|
||||
// Bring up search interface for selected account
|
||||
function SearchMessages()
|
||||
{
|
||||
window.parent.MsgSearchMessages();
|
||||
}
|
||||
|
||||
// Open filters window
|
||||
function CreateMsgFilters()
|
||||
{
|
||||
window.parent.MsgFilters(null, null);
|
||||
}
|
||||
|
||||
// Open Subscribe dialog
|
||||
function Subscribe()
|
||||
{
|
||||
if (!selectedServer)
|
||||
return;
|
||||
if (selectedServer.type == 'rss')
|
||||
window.parent.openSubscriptionsDialog(selectedServer.rootFolder);
|
||||
else
|
||||
window.parent.MsgSubscribe();
|
||||
}
|
||||
|
||||
// Open junk mail settings dialog
|
||||
function JunkSettings()
|
||||
{
|
||||
// TODO: function does not exist yet, will throw an exception if exposed
|
||||
window.parent.MsgJunkMail();
|
||||
}
|
||||
251
mailnews/base/content/msgAccountCentral.xul
Normal file
251
mailnews/base/content/msgAccountCentral.xul
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://messenger/skin/accountCentral.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE page [
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
|
||||
%brandDTD;
|
||||
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
|
||||
%globalDTD;
|
||||
<!ENTITY % acctCentralDTD SYSTEM "chrome://messenger/locale/msgAccountCentral.dtd">
|
||||
%acctCentralDTD;
|
||||
]>
|
||||
|
||||
<page
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="OnInit();">
|
||||
|
||||
<stringbundle id="bundle_brand"
|
||||
src="chrome://branding/locale/brand.properties"/>
|
||||
<stringbundle id="bundle_messenger"
|
||||
src="chrome://messenger/locale/messenger.properties"/>
|
||||
<stringbundle id="bundle_prefs"
|
||||
src="chrome://messenger/locale/prefs.properties"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://messenger/content/AccountManager.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://messenger/content/accountUtils.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://messenger/content/commandglue.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://messenger/content/mailWindowOverlay.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://messenger/content/mailWindow.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://messenger/content/msgMail3PaneWindow.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://messenger/content/msgAccountCentral.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://messenger/content/mailCore.js"/>
|
||||
|
||||
<grid id="acctCentralGrid" flex="1" style="overflow: auto;">
|
||||
<columns id="acctCentralColumns">
|
||||
<column flex="40" id="acctCentralActionsColumn"/>
|
||||
<column flex="60" id="acctCentralHelpDataColumn"/>
|
||||
</columns>
|
||||
|
||||
<rows id="acctCentralRows">
|
||||
<row id="acctCentralHeaderRow">
|
||||
<label id="AccountCentralTitle"/>
|
||||
</row>
|
||||
<spacer id="acctCentralHeader.spacer" flex="2"/>
|
||||
|
||||
<row id="EmailHeader" class="acctCentralTitleRow" collapsed="true">
|
||||
<hbox class="acctCentralRowTitleBox">
|
||||
<description>&emailSectionHdr.label;</description>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="ReadMessages.spacer" flex="1" collapsed="true"/>
|
||||
<row id="ReadMessages" class="acctCentralRow" collapsed="true">
|
||||
<hbox>
|
||||
<label class="acctCentralText acctCentralLinkText"
|
||||
value="&readMsgsLink.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="ReadMessages();"/>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="ComposeMessage.spacer" flex="1" collapsed="true"/>
|
||||
<row id="ComposeMessage" class="acctCentralRow" collapsed="true">
|
||||
<hbox>
|
||||
<label class="acctCentralText acctCentralLinkText"
|
||||
value="&composeMsgLink.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="ComposeAMessage(event);"/>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="JunkSettingsMail.spacer" flex="1" collapsed="true"/>
|
||||
<row id="JunkSettingsMail" class="acctCentralRow" collapsed="true">
|
||||
<hbox>
|
||||
<label class="acctCentralText acctCentralLinkText"
|
||||
value="&junkSettings.label;"
|
||||
onclick="JunkSettings();"/>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="NewsHeader.spacer" flex="1" collapsed="true"/>
|
||||
<row id="NewsHeader" class="acctCentralTitleRow" collapsed="true">
|
||||
<hbox class="acctCentralRowTitleBox">
|
||||
<description>&newsSectionHdr.label;</description>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="SubscribeNewsgroups.spacer" flex="1" collapsed="true"/>
|
||||
<row id="SubscribeNewsgroups" class="acctCentralRow" collapsed="true">
|
||||
<hbox>
|
||||
<label class="acctCentralText acctCentralLinkText"
|
||||
value="&subscribeNewsLink.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="Subscribe();"/>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="JunkSettingsNews.spacer" flex="1" collapsed="true"/>
|
||||
<row id="JunkSettingsNews" class="acctCentralRow" collapsed="true">
|
||||
<hbox>
|
||||
<label class="acctCentralText acctCentralLinkText"
|
||||
value="&junkSettings.label;"
|
||||
onclick="JunkSettings();"/>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="rssHeader.spacer" flex="1" collapsed="true"/>
|
||||
<row id="rssHeader" class="acctCentralTitleRow" collapsed="true">
|
||||
<hbox class="acctCentralRowTitleBox">
|
||||
<description>&feedsSectionHdr.label;</description>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="SubscribeRSS.spacer" flex="1" collapsed="true"/>
|
||||
<row id="SubscribeRSS" class="acctCentralRow" collapsed="true">
|
||||
<hbox>
|
||||
<label class="acctCentralText acctCentralLinkText"
|
||||
value="&subscribeFeeds.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="Subscribe();"/>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="MessagesSection.spacer" class="big" flex="5" collapsed="true"/>
|
||||
|
||||
<row id="AccountsHeader" class="acctCentralTitleRow" collapsed="true">
|
||||
<hbox class="acctCentralRowTitleBox">
|
||||
<description>&accountsSectionHdr.label;</description>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="AccountSettings.spacer" flex="1" collapsed="true"/>
|
||||
<row id="AccountSettings" class="acctCentralRow" collapsed="true">
|
||||
<hbox>
|
||||
<label class="acctCentralText acctCentralLinkText"
|
||||
value="&settingsLink.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="ViewSettings(null);"/>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="CreateAccount.spacer" flex="1" collapsed="true"/>
|
||||
<row id="CreateAccount" class="acctCentralRow" collapsed="true">
|
||||
<hbox>
|
||||
#ifdef MOZ_THUNDERBIRD
|
||||
<label class="acctCentralText"
|
||||
value="&newAcct.label;"
|
||||
chromedir="&locale.dir;"/>
|
||||
#else
|
||||
<label class="acctCentralText acctCentralLinkText"
|
||||
value="&newAcctLink.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="CreateNewAccount();"/>
|
||||
#endif
|
||||
</hbox>
|
||||
</row>
|
||||
#ifdef MOZ_THUNDERBIRD
|
||||
<row id="CreateAccounts" class="acctCentralRow" collapsed="true">
|
||||
<vbox id="CreateAccountsList">
|
||||
<label id="CreateAccountMail"
|
||||
class="acctCentralNewAcctText acctCentralLinkText"
|
||||
value="&emailSectionHdr.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="CreateNewAccountTB('mail');"/>
|
||||
<label id="CreateAccountChat"
|
||||
class="acctCentralNewAcctText acctCentralLinkText"
|
||||
value="&chat.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="openIMAccountWizard();"/>
|
||||
<label id="CreateAccountNewsgroups"
|
||||
class="acctCentralNewAcctText acctCentralLinkText"
|
||||
value="&newsSectionHdr.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="CreateNewAccountTB('newsgroups');"/>
|
||||
<label id="CreateAccountRSS"
|
||||
class="acctCentralNewAcctText acctCentralLinkText"
|
||||
value="&feedsSectionHdr.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="CreateNewAccountTB('feeds');"/>
|
||||
#ifdef HAVE_MOVEMAIL
|
||||
<label id="CreateAccountMovemail"
|
||||
class="acctCentralNewAcctText acctCentralLinkText"
|
||||
value="&movemail.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="CreateNewAccountTB('movemail');"/>
|
||||
#endif
|
||||
</vbox>
|
||||
</row>
|
||||
#endif
|
||||
|
||||
<spacer id="AccountsSection.spacer" class="big" flex="5" collapsed="true"/>
|
||||
|
||||
<row id="AdvancedFeaturesHeader" class="acctCentralTitleRow" collapsed="true">
|
||||
<hbox class="acctCentralRowTitleBox">
|
||||
<description>&advFeaturesSectionHdr.label;</description>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="SearchMessages.spacer" flex="1" collapsed="true"/>
|
||||
<row id="SearchMessages" class="acctCentralRow" collapsed="true">
|
||||
<hbox>
|
||||
<label class="acctCentralText acctCentralLinkText"
|
||||
value="&searchMsgsLink.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="SearchMessages();"/>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="CreateFilters.spacer" flex="1" collapsed="true"/>
|
||||
<row id="CreateFilters" class="acctCentralRow" collapsed="true">
|
||||
<hbox>
|
||||
<label class="acctCentralText acctCentralLinkText"
|
||||
value="&filtersLink.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="CreateMsgFilters();"/>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="SubscribeImapFolders.spacer" flex="1" collapsed="true"/>
|
||||
<row id="SubscribeImapFolders" class="acctCentralRow" collapsed="true">
|
||||
<hbox>
|
||||
<label class="acctCentralText acctCentralLinkText"
|
||||
value="&subscribeImapFolders.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="Subscribe();"/>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<spacer id="OfflineSettings.spacer" flex="1" collapsed="true"/>
|
||||
<row id="OfflineSettings" class="acctCentralRow" collapsed="true">
|
||||
<hbox>
|
||||
<label class="acctCentralText acctCentralLinkText"
|
||||
value="&offlineLink.label;"
|
||||
chromedir="&locale.dir;"
|
||||
onclick="ViewSettings('am-offline.xul');"/>
|
||||
</hbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</page>
|
||||
99
mailnews/base/content/msgFolderPickerOverlay.js
Normal file
99
mailnews/base/content/msgFolderPickerOverlay.js
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
Components.utils.import("resource:///modules/MailUtils.js");
|
||||
|
||||
var gMessengerBundle;
|
||||
|
||||
// call this from dialog onload() to set the menu item to the correct value
|
||||
function MsgFolderPickerOnLoad(pickerID)
|
||||
{
|
||||
var uri = null;
|
||||
try {
|
||||
uri = window.arguments[0].preselectedURI;
|
||||
}
|
||||
catch (ex) {
|
||||
uri = null;
|
||||
}
|
||||
|
||||
if (uri) {
|
||||
//dump("on loading, set titled button to " + uri + "\n");
|
||||
|
||||
// verify that the value we are attempting to
|
||||
// pre-flight the menu with is valid for this
|
||||
// picker type
|
||||
var msgfolder = MailUtils.getFolderForURI(uri, true);
|
||||
if (!msgfolder) return;
|
||||
|
||||
var verifyFunction = null;
|
||||
|
||||
switch (pickerID) {
|
||||
case "msgNewFolderPicker":
|
||||
verifyFunction = msgfolder.canCreateSubfolders;
|
||||
break;
|
||||
case "msgRenameFolderPicker":
|
||||
verifyFunction = msgfolder.canRename;
|
||||
break;
|
||||
default:
|
||||
verifyFunction = msgfolder.canFileMessages;
|
||||
break;
|
||||
}
|
||||
|
||||
if (verifyFunction) {
|
||||
SetFolderPicker(uri,pickerID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function PickedMsgFolder(selection,pickerID)
|
||||
{
|
||||
var selectedUri = selection.getAttribute('id');
|
||||
SetFolderPicker(selectedUri,pickerID);
|
||||
}
|
||||
|
||||
function SetFolderPickerElement(uri, picker)
|
||||
{
|
||||
var msgfolder = MailUtils.getFolderForURI(uri, true);
|
||||
|
||||
if (!msgfolder)
|
||||
return;
|
||||
|
||||
var selectedValue = null;
|
||||
var serverName;
|
||||
|
||||
if (msgfolder.isServer)
|
||||
selectedValue = msgfolder.name;
|
||||
else {
|
||||
if (msgfolder.server)
|
||||
serverName = msgfolder.server.prettyName;
|
||||
else {
|
||||
dump("Can't find server for " + uri + "\n");
|
||||
serverName = "???";
|
||||
}
|
||||
|
||||
switch (picker.id) {
|
||||
case "runFiltersFolder":
|
||||
selectedValue = msgfolder.name;
|
||||
break;
|
||||
case "msgTrashFolderPicker":
|
||||
selectedValue = msgfolder.name;
|
||||
break;
|
||||
default:
|
||||
if (!gMessengerBundle)
|
||||
gMessengerBundle = document.getElementById("bundle_messenger");
|
||||
selectedValue = gMessengerBundle.getFormattedString("verboseFolderFormat",
|
||||
[msgfolder.name, serverName]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
picker.setAttribute("label",selectedValue);
|
||||
picker.setAttribute("uri",uri);
|
||||
}
|
||||
|
||||
function SetFolderPicker(uri,pickerID)
|
||||
{
|
||||
SetFolderPickerElement(uri, document.getElementById(pickerID));
|
||||
}
|
||||
209
mailnews/base/content/msgPrintEngine.js
Normal file
209
mailnews/base/content/msgPrintEngine.js
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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 is where functions related to the print engine are kept */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/* globals for a particular window */
|
||||
var printEngineContractID = "@mozilla.org/messenger/msgPrintEngine;1";
|
||||
var printEngineWindow;
|
||||
var printEngine;
|
||||
var printSettings = null;
|
||||
var printOpener = null;
|
||||
|
||||
var kMsgBundle = "chrome://messenger/locale/messenger.properties";
|
||||
|
||||
/* Functions related to startup */
|
||||
function OnLoadPrintEngine()
|
||||
{
|
||||
PrintEngineCreateGlobals();
|
||||
InitPrintEngineWindow();
|
||||
printEngine.startPrintOperation(printSettings);
|
||||
}
|
||||
|
||||
function PrintEngineCreateGlobals()
|
||||
{
|
||||
/* get the print engine instance */
|
||||
printEngine = Components.classes[printEngineContractID].createInstance();
|
||||
printEngine = printEngine.QueryInterface(Components.interfaces.nsIMsgPrintEngine);
|
||||
printSettings = PrintUtils.getPrintSettings();
|
||||
if (printSettings) {
|
||||
printSettings.isCancelled = false;
|
||||
}
|
||||
}
|
||||
|
||||
var PrintPreviewListener = {
|
||||
getPrintPreviewBrowser: function () {
|
||||
var browser = document.getElementById("ppBrowser");
|
||||
if (!browser) {
|
||||
browser = document.createElement("browser");
|
||||
browser.setAttribute("id", "ppBrowser");
|
||||
browser.setAttribute("flex", "1");
|
||||
browser.setAttribute("disablehistory", "true");
|
||||
browser.setAttribute("disablesecurity", "true");
|
||||
browser.setAttribute("type", "content");
|
||||
document.documentElement.appendChild(browser);
|
||||
}
|
||||
return browser;
|
||||
},
|
||||
getSourceBrowser: function () {
|
||||
return document.getElementById("content");
|
||||
},
|
||||
getNavToolbox: function () {
|
||||
return document.getElementById("content");
|
||||
},
|
||||
onEnter: function () {
|
||||
setPPTitle(document.getElementById("content").contentDocument.title);
|
||||
document.getElementById("content").collapsed = true;
|
||||
printEngine.showWindow(true);
|
||||
},
|
||||
onExit: function () {
|
||||
window.close();
|
||||
}
|
||||
};
|
||||
|
||||
function getBundle(aURI)
|
||||
{
|
||||
if (!aURI)
|
||||
return null;
|
||||
|
||||
var bundle = null;
|
||||
try
|
||||
{
|
||||
bundle = Services.strings.createBundle(aURI);
|
||||
}
|
||||
catch (ex)
|
||||
{
|
||||
bundle = null;
|
||||
debug("Exception getting bundle " + aURI + ": " + ex);
|
||||
}
|
||||
|
||||
return bundle;
|
||||
}
|
||||
|
||||
function setPPTitle(aTitle)
|
||||
{
|
||||
var title = aTitle;
|
||||
try {
|
||||
var gBrandBundle = document.getElementById("bundle_brand");
|
||||
if (gBrandBundle) {
|
||||
var msgBundle = this.getBundle(kMsgBundle);
|
||||
if (msgBundle) {
|
||||
var brandStr = gBrandBundle.getString("brandShortName")
|
||||
var array = [title, brandStr];
|
||||
title = msgBundle.formatStringFromName("PreviewTitle", array, array.length);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
document.title = title;
|
||||
}
|
||||
|
||||
// Pref listener constants
|
||||
var gStartupPPObserver =
|
||||
{
|
||||
observe: function(subject, topic, prefName)
|
||||
{
|
||||
PrintUtils.printPreview(PrintPreviewListener);
|
||||
}
|
||||
};
|
||||
|
||||
function ReplaceWithSelection()
|
||||
{
|
||||
if (!printOpener.content)
|
||||
return;
|
||||
|
||||
var selection = printOpener.content.getSelection();
|
||||
|
||||
if ( selection != "" ) {
|
||||
var range = selection.getRangeAt( 0 );
|
||||
var contents = range.cloneContents();
|
||||
|
||||
var aBody = window.content.document.querySelector( "body" );
|
||||
|
||||
/* Replace the content of <body> with the users' selection. */
|
||||
if ( aBody ) {
|
||||
aBody.innerHTML = "";
|
||||
aBody.appendChild( contents );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function InitPrintEngineWindow()
|
||||
{
|
||||
/* Store the current opener for later access in ReplaceWithSelection() */
|
||||
printOpener = opener;
|
||||
|
||||
/* Register the event listener to be able to replace the document
|
||||
* content with the user selection when loading is finished.
|
||||
*/
|
||||
document.getElementById("content").addEventListener("load", ReplaceWithSelection, true);
|
||||
|
||||
/* Tell the nsIPrintEngine object what window is rendering the email */
|
||||
printEngine.setWindow(window);
|
||||
|
||||
/* hide the printEngine window. see bug #73995 */
|
||||
|
||||
/* See if we got arguments.
|
||||
* Window was opened via window.openDialog. Copy argument
|
||||
* and perform compose initialization
|
||||
*/
|
||||
if ( window.arguments && window.arguments[0] != null ) {
|
||||
var numSelected = window.arguments[0];
|
||||
var uriArray = window.arguments[1];
|
||||
var statusFeedback = window.arguments[2];
|
||||
|
||||
if (window.arguments[3]) {
|
||||
printEngine.doPrintPreview = window.arguments[3];
|
||||
} else {
|
||||
printEngine.doPrintPreview = false;
|
||||
}
|
||||
printEngine.showWindow(false);
|
||||
|
||||
if (window.arguments.length > 4) {
|
||||
printEngine.setMsgType(window.arguments[4]);
|
||||
} else {
|
||||
printEngine.setMsgType(Components.interfaces.nsIMsgPrintEngine.MNAB_START);
|
||||
}
|
||||
|
||||
if (window.arguments.length > 5) {
|
||||
printEngine.setParentWindow(window.arguments[5]);
|
||||
} else {
|
||||
printEngine.setParentWindow(null);
|
||||
}
|
||||
|
||||
printEngine.setStatusFeedback(statusFeedback);
|
||||
printEngine.setStartupPPObserver(gStartupPPObserver);
|
||||
|
||||
if (numSelected > 0) {
|
||||
printEngine.setPrintURICount(numSelected);
|
||||
for (var i = 0; i < numSelected; i++) {
|
||||
printEngine.addPrintURI(uriArray[i]);
|
||||
//dump(uriArray[i] + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ClearPrintEnginePane()
|
||||
{
|
||||
if (window.frames["content"].location.href != "about:blank")
|
||||
window.frames["content"].location.href = "about:blank";
|
||||
}
|
||||
|
||||
function StopUrls()
|
||||
{
|
||||
printEngine.stopUrls();
|
||||
}
|
||||
|
||||
function PrintEnginePrint()
|
||||
{
|
||||
printEngineWindow = window.openDialog("chrome://messenger/content/msgPrintEngine.xul", "", "chrome,dialog=no,all,centerscreen", false);
|
||||
}
|
||||
|
||||
function PrintEnginePrintPreview()
|
||||
{
|
||||
printEngineWindow = window.openDialog("chrome://messenger/content/msgPrintEngine.xul", "", "chrome,dialog=no,all,centerscreen", true);
|
||||
}
|
||||
199
mailnews/base/content/msgSynchronize.js
Normal file
199
mailnews/base/content/msgSynchronize.js
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var gSynchronizeTree = null;
|
||||
var gParentMsgWindow;
|
||||
var gMsgWindow;
|
||||
|
||||
var gInitialFolderStates = {};
|
||||
|
||||
function OnLoad()
|
||||
{
|
||||
if (window.arguments && window.arguments[0]) {
|
||||
if (window.arguments[0].msgWindow) {
|
||||
gParentMsgWindow = window.arguments[0].msgWindow;
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("syncMail").checked =
|
||||
Services.prefs.getBoolPref("mailnews.offline_sync_mail");
|
||||
document.getElementById("syncNews").checked =
|
||||
Services.prefs.getBoolPref("mailnews.offline_sync_news");
|
||||
document.getElementById("sendMessage").checked =
|
||||
Services.prefs.getBoolPref("mailnews.offline_sync_send_unsent");
|
||||
document.getElementById("workOffline").checked =
|
||||
Services.prefs.getBoolPref("mailnews.offline_sync_work_offline");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function syncOkButton()
|
||||
{
|
||||
|
||||
var syncMail = document.getElementById("syncMail").checked;
|
||||
var syncNews = document.getElementById("syncNews").checked;
|
||||
var sendMessage = document.getElementById("sendMessage").checked;
|
||||
var workOffline = document.getElementById("workOffline").checked;
|
||||
|
||||
Services.prefs.setBoolPref("mailnews.offline_sync_mail", syncMail);
|
||||
Services.prefs.setBoolPref("mailnews.offline_sync_news", syncNews);
|
||||
Services.prefs.setBoolPref("mailnews.offline_sync_send_unsent", sendMessage);
|
||||
Services.prefs.setBoolPref("mailnews.offline_sync_work_offline", workOffline);
|
||||
|
||||
if (syncMail || syncNews || sendMessage || workOffline) {
|
||||
var offlineManager = Components.classes["@mozilla.org/messenger/offline-manager;1"]
|
||||
.getService(Components.interfaces.nsIMsgOfflineManager);
|
||||
if(offlineManager)
|
||||
offlineManager.synchronizeForOffline(syncNews, syncMail, sendMessage, workOffline, gParentMsgWindow)
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function OnSelect()
|
||||
{
|
||||
top.window.openDialog("chrome://messenger/content/msgSelectOffline.xul", "",
|
||||
"centerscreen,chrome,modal,titlebar,resizable=yes");
|
||||
return true;
|
||||
}
|
||||
|
||||
function selectOkButton()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function selectCancelButton()
|
||||
{
|
||||
var RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]
|
||||
.getService(Components.interfaces.nsIRDFService);
|
||||
for (var resourceValue in gInitialFolderStates) {
|
||||
var resource = RDF.GetResource(resourceValue);
|
||||
var folder = resource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
||||
if (gInitialFolderStates[resourceValue])
|
||||
folder.setFlag(Components.interfaces.nsMsgFolderFlags.Offline);
|
||||
else
|
||||
folder.clearFlag(Components.interfaces.nsMsgFolderFlags.Offline);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function selectOnLoad()
|
||||
{
|
||||
gMsgWindow = Components.classes["@mozilla.org/messenger/msgwindow;1"]
|
||||
.createInstance(Components.interfaces.nsIMsgWindow);
|
||||
gMsgWindow.domWindow = window;
|
||||
gMsgWindow.rootDocShell.appType = Components.interfaces.nsIDocShell.APP_TYPE_MAIL;
|
||||
|
||||
gSynchronizeTree = document.getElementById('synchronizeTree');
|
||||
|
||||
SortSynchronizePane('folderNameCol', '?folderTreeNameSort');
|
||||
}
|
||||
|
||||
function SortSynchronizePane(column, sortKey)
|
||||
{
|
||||
var node = FindInWindow(window, column);
|
||||
if(!node) {
|
||||
dump('Couldnt find sort column\n');
|
||||
return;
|
||||
}
|
||||
|
||||
node.setAttribute("sort", sortKey);
|
||||
node.setAttribute("sortDirection", "natural");
|
||||
var col = gSynchronizeTree.columns[column];
|
||||
gSynchronizeTree.view.cycleHeader(col);
|
||||
}
|
||||
|
||||
function FindInWindow(currentWindow, id)
|
||||
{
|
||||
var item = currentWindow.document.getElementById(id);
|
||||
if(item)
|
||||
return item;
|
||||
|
||||
for(var i = 0; i < currentWindow.frames.length; i++) {
|
||||
var frameItem = FindInWindow(currentWindow.frames[i], id);
|
||||
if(frameItem)
|
||||
return frameItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function onSynchronizeClick(event)
|
||||
{
|
||||
// we only care about button 0 (left click) events
|
||||
if (event.button != 0)
|
||||
return;
|
||||
|
||||
var row = {}
|
||||
var col = {}
|
||||
var elt = {}
|
||||
|
||||
gSynchronizeTree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, elt);
|
||||
if (row.value == -1)
|
||||
return;
|
||||
|
||||
if (elt.value == "twisty") {
|
||||
var folderResource = GetFolderResource(gSynchronizeTree, row.value);
|
||||
var folder = folderResource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
||||
|
||||
if (!(gSynchronizeTree.treeBoxObject.view.isContainerOpen(row.value))) {
|
||||
var serverType = folder.server.type;
|
||||
// imap is the only server type that does folder discovery
|
||||
if (serverType != "imap") return;
|
||||
|
||||
if (folder.isServer) {
|
||||
var server = folder.server;
|
||||
server.performExpand(gMsgWindow);
|
||||
}
|
||||
else {
|
||||
var imapFolder = folderResource.QueryInterface(Components.interfaces.nsIMsgImapMailFolder);
|
||||
if (imapFolder) {
|
||||
imapFolder.performExpand(gMsgWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (col.value.id == "syncCol") {
|
||||
UpdateNode(GetFolderResource(gSynchronizeTree, row.value), row.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onSynchronizeTreeKeyPress(event)
|
||||
{
|
||||
// for now, only do something on space key
|
||||
if (event.charCode != KeyEvent.DOM_VK_SPACE)
|
||||
return;
|
||||
|
||||
var treeSelection = gSynchronizeTree.view.selection;
|
||||
for (var i=0;i<treeSelection.getRangeCount();i++) {
|
||||
var start = {}, end = {};
|
||||
treeSelection.getRangeAt(i,start,end);
|
||||
for (var k=start.value;k<=end.value;k++)
|
||||
UpdateNode(GetFolderResource(gSynchronizeTree, k), k);
|
||||
}
|
||||
}
|
||||
|
||||
function UpdateNode(resource, row)
|
||||
{
|
||||
var folder = resource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
||||
|
||||
if (folder.isServer)
|
||||
return;
|
||||
|
||||
if (!(resource.Value in gInitialFolderStates)) {
|
||||
gInitialFolderStates[resource.Value] = folder.getFlag(Components.interfaces.nsMsgFolderFlags.Offline);
|
||||
}
|
||||
|
||||
folder.toggleFlag(Components.interfaces.nsMsgFolderFlags.Offline);
|
||||
}
|
||||
|
||||
function GetFolderResource(aTree, aIndex) {
|
||||
return aTree.builderView.getResourceAtIndex(aIndex);
|
||||
}
|
||||
43
mailnews/base/content/msgSynchronize.xul
Normal file
43
mailnews/base/content/msgSynchronize.xul
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
|
||||
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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://messenger/skin/dialogs.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/msgSynchronize.dtd" >
|
||||
<dialog xmlns:NC="http://home.netscape.com/NC-rdf#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
id="msg-synchronizer"
|
||||
title="&MsgSynchronize.label;"
|
||||
onload="OnLoad();"
|
||||
style="width: 35em;"
|
||||
ondialogaccept="return syncOkButton();">
|
||||
|
||||
<script type="application/javascript" src="chrome://messenger/content/msgSynchronize.js"/>
|
||||
|
||||
<keyset id="keyset"/>
|
||||
<label hidden="true" wsm_persist="true" id="server.type"/>
|
||||
|
||||
<description class="desc">&MsgSyncDesc.label;</description>
|
||||
<separator class="thin"/>
|
||||
<label value="&MsgSyncDirections.label;"/>
|
||||
|
||||
<vbox class="indent" align="start">
|
||||
<checkbox id="syncMail" hidable="true" hidefor="movemail,pop3" label="&syncTypeMail.label;"
|
||||
accesskey="&syncTypeMail.accesskey;"/>
|
||||
<checkbox id="syncNews" label="&syncTypeNews.label;" accesskey="&syncTypeNews.accesskey;"/>
|
||||
</vbox>
|
||||
<vbox align="start">
|
||||
<checkbox id="sendMessage" label="&sendMessage.label;" accesskey="&sendMessage.accesskey;"/>
|
||||
<checkbox id="workOffline" label="&workOffline.label;" accesskey="&workOffline.accesskey;"/>
|
||||
</vbox>
|
||||
<separator class="thin"/>
|
||||
<hbox align="right">
|
||||
<button id="select" label="&selectButton.label;" accesskey="&selectButton.accesskey;"
|
||||
oncommand="OnSelect();"/>
|
||||
</hbox>
|
||||
</dialog>
|
||||
85
mailnews/base/content/newFolderDialog.js
Normal file
85
mailnews/base/content/newFolderDialog.js
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
|
||||
|
||||
var FOLDERS = 1;
|
||||
var MESSAGES = 2;
|
||||
var dialog;
|
||||
|
||||
function onLoad()
|
||||
{
|
||||
var windowArgs = window.arguments[0];
|
||||
|
||||
dialog = {};
|
||||
|
||||
dialog.nameField = document.getElementById("name");
|
||||
dialog.nameField.focus();
|
||||
|
||||
// call this when OK is pressed
|
||||
dialog.okCallback = windowArgs.okCallback;
|
||||
|
||||
// pre select the folderPicker, based on what they selected in the folder pane
|
||||
dialog.folder = windowArgs.folder;
|
||||
try {
|
||||
document.getElementById("MsgNewFolderPopup").selectFolder(windowArgs.folder);
|
||||
} catch(ex) {
|
||||
// selected a child folder
|
||||
document.getElementById("msgNewFolderPicker")
|
||||
.setAttribute("label", windowArgs.folder.prettyName);
|
||||
}
|
||||
|
||||
// can folders contain both folders and messages?
|
||||
if (windowArgs.dualUseFolders) {
|
||||
dialog.folderType = FOLDERS | MESSAGES;
|
||||
|
||||
// hide the section when folder contain both folders and messages.
|
||||
var newFolderTypeBox = document.getElementById("newFolderTypeBox");
|
||||
newFolderTypeBox.setAttribute("hidden", "true");
|
||||
} else {
|
||||
// set our folder type by calling the default selected type's oncommand
|
||||
var selectedFolderType = document.getElementById("folderGroup").selectedItem;
|
||||
eval(selectedFolderType.getAttribute("oncommand"));
|
||||
}
|
||||
|
||||
doEnabling();
|
||||
}
|
||||
|
||||
function onFolderSelect(event) {
|
||||
dialog.folder = event.target._folder;
|
||||
document.getElementById("msgNewFolderPicker")
|
||||
.setAttribute("label", dialog.folder.prettyName);
|
||||
}
|
||||
|
||||
function onOK()
|
||||
{
|
||||
var name = dialog.nameField.value;
|
||||
var uri = dialog.folder;
|
||||
|
||||
// do name validity check?
|
||||
|
||||
// make sure name ends in "/" if folder to create can only contain folders
|
||||
if ((dialog.folderType == FOLDERS) && !name.endsWith("/"))
|
||||
dialog.okCallback(name + "/", dialog.folder);
|
||||
else
|
||||
dialog.okCallback(name, dialog.folder);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function onFoldersOnly()
|
||||
{
|
||||
dialog.folderType = FOLDERS;
|
||||
}
|
||||
|
||||
function onMessagesOnly()
|
||||
{
|
||||
dialog.folderType = MESSAGES;
|
||||
}
|
||||
|
||||
function doEnabling()
|
||||
{
|
||||
document.documentElement.getButton("accept").disabled = !dialog.nameField.value;
|
||||
}
|
||||
|
||||
57
mailnews/base/content/newFolderDialog.xul
Normal file
57
mailnews/base/content/newFolderDialog.xul
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://messenger/skin/dialogs.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://messenger/skin/folderMenus.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE dialog [
|
||||
<!ENTITY % newFolderDTD SYSTEM "chrome://messenger/locale/newFolderDialog.dtd">%newFolderDTD;
|
||||
]>
|
||||
|
||||
<dialog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="&newFolderDialog.title;"
|
||||
onload="onLoad();"
|
||||
buttonlabelaccept="&accept.label;"
|
||||
buttonaccesskeyaccept="&accept.accesskey;"
|
||||
ondialogaccept="return onOK();">
|
||||
|
||||
<stringbundleset id="stringbundleset"/>
|
||||
<script type="application/javascript" src="chrome://messenger/content/newFolderDialog.js"/>
|
||||
|
||||
<label value="&name.label;" accesskey="&name.accesskey;" control="name"/>
|
||||
<textbox id="name" oninput="doEnabling();"/>
|
||||
|
||||
<separator/>
|
||||
|
||||
<label value="&description.label;" accesskey="&description.accesskey;" control="msgNewFolderPicker"/>
|
||||
|
||||
<menulist id="msgNewFolderPicker" class="folderMenuItem"
|
||||
displayformat="verbose">
|
||||
<menupopup id="MsgNewFolderPopup" type="folder" showFileHereLabel="true"
|
||||
class="menulist-menupopup"
|
||||
mode="newFolder"
|
||||
oncommand="onFolderSelect(event)"/>
|
||||
</menulist>
|
||||
|
||||
<vbox id="newFolderTypeBox">
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<label value="&folderRestriction1.label;"/>
|
||||
<label value="&folderRestriction2.label;"/>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<radiogroup id="folderGroup" orient="horizontal" class="indent">
|
||||
<radio oncommand="onFoldersOnly();" label="&foldersOnly.label;"/>
|
||||
<radio oncommand="onMessagesOnly();" label="&messagesOnly.label;" selected="true"/>
|
||||
</radiogroup>
|
||||
|
||||
</vbox>
|
||||
|
||||
</dialog>
|
||||
35
mailnews/base/content/newmailalert.css
Normal file
35
mailnews/base/content/newmailalert.css
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* 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/. */
|
||||
|
||||
#alertContainer {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#alertContainer[noanimation] {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#alertContainer[fade-in] {
|
||||
animation-timing-function: ease-out;
|
||||
animation-duration: 2s;
|
||||
animation-fill-mode: both;
|
||||
animation-name: fade-in;
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
from {opacity: 0;}
|
||||
to {opacity: 1;}
|
||||
}
|
||||
|
||||
#alertContainer[fade-out] {
|
||||
animation-timing-function: ease-in;
|
||||
animation-duration: 2s;
|
||||
animation-fill-mode: both;
|
||||
animation-name: fade-out;
|
||||
}
|
||||
|
||||
@keyframes fade-out {
|
||||
from {opacity: 1;}
|
||||
to {opacity: 0;}
|
||||
}
|
||||
186
mailnews/base/content/newmailalert.js
Normal file
186
mailnews/base/content/newmailalert.js
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/* 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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource:///modules/iteratorUtils.jsm");
|
||||
|
||||
// Copied from nsILookAndFeel.h, see comments on eMetric_AlertNotificationOrigin
|
||||
var NS_ALERT_HORIZONTAL = 1;
|
||||
var NS_ALERT_LEFT = 2;
|
||||
var NS_ALERT_TOP = 4;
|
||||
|
||||
var gNumNewMsgsToShowInAlert = 4; // the more messages we show in the alert, the larger it will be
|
||||
var gOpenTime = 4000; // total time the alert should stay up once we are done animating.
|
||||
|
||||
var gAlertListener = null;
|
||||
var gPendingPreviewFetchRequests = 0;
|
||||
var gUserInitiated = false;
|
||||
var gOrigin = 0; // Default value: alert from bottom right.
|
||||
|
||||
function prefillAlertInfo()
|
||||
{
|
||||
const Ci = Components.interfaces;
|
||||
// unwrap all the args....
|
||||
// arguments[0] --> nsIArray of folders with new mail
|
||||
// arguments[1] --> the observer to call back with notifications about the alert
|
||||
// arguments[2] --> user initiated boolean. true if the user initiated opening the alert
|
||||
// (which means skip the fade effect and don't auto close the alert)
|
||||
// arguments[3] --> the alert origin returned by the look and feel
|
||||
var foldersWithNewMail = window.arguments[0];
|
||||
gAlertListener = window.arguments[1];
|
||||
gUserInitiated = window.arguments[2];
|
||||
gOrigin = window.arguments[3];
|
||||
|
||||
// For now just grab the first folder which should be a root folder
|
||||
// for the account that has new mail. If we can't find a folder, just
|
||||
// return to avoid the exception and empty dialog in upper left-hand corner.
|
||||
if (!foldersWithNewMail || foldersWithNewMail.length < 1)
|
||||
return;
|
||||
let rootFolder = foldersWithNewMail.queryElementAt(0, Ci.nsIWeakReference)
|
||||
.QueryReferent(Ci.nsIMsgFolder);
|
||||
|
||||
// Generate an account label string based on the root folder.
|
||||
var label = document.getElementById('alertTitle');
|
||||
var totalNumNewMessages = rootFolder.getNumNewMessages(true);
|
||||
var message = totalNumNewMessages == 1 ? "newMailNotification_message"
|
||||
: "newMailNotification_messages";
|
||||
label.value = document.getElementById('bundle_messenger')
|
||||
.getFormattedString(message,
|
||||
[rootFolder.prettiestName,
|
||||
totalNumNewMessages]);
|
||||
|
||||
// This is really the root folder and we have to walk through the list to
|
||||
// find the real folder that has new mail in it...:(
|
||||
let allFolders = rootFolder.descendants;
|
||||
var folderSummaryInfoEl = document.getElementById('folderSummaryInfo');
|
||||
folderSummaryInfoEl.mMaxMsgHdrsInPopup = gNumNewMsgsToShowInAlert;
|
||||
for (let folder in fixIterator(allFolders, Components.interfaces.nsIMsgFolder))
|
||||
{
|
||||
if (folder.hasNewMessages && !folder.getFlag(Ci.nsMsgFolderFlags.Virtual))
|
||||
{
|
||||
var asyncFetch = {};
|
||||
folderSummaryInfoEl.parseFolder(folder, new urlListener(folder), asyncFetch);
|
||||
if (asyncFetch.value)
|
||||
gPendingPreviewFetchRequests++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function urlListener(aFolder)
|
||||
{
|
||||
this.mFolder = aFolder;
|
||||
}
|
||||
|
||||
urlListener.prototype =
|
||||
{
|
||||
OnStartRunningUrl: function(aUrl)
|
||||
{
|
||||
},
|
||||
|
||||
OnStopRunningUrl: function(aUrl, aExitCode)
|
||||
{
|
||||
var folderSummaryInfoEl = document.getElementById('folderSummaryInfo');
|
||||
folderSummaryInfoEl.parseFolder(this.mFolder, null, {});
|
||||
gPendingPreviewFetchRequests--;
|
||||
|
||||
// when we are done running all of our urls for fetching the preview text,
|
||||
// start the alert.
|
||||
if (!gPendingPreviewFetchRequests)
|
||||
showAlert();
|
||||
}
|
||||
}
|
||||
|
||||
function onAlertLoad()
|
||||
{
|
||||
prefillAlertInfo();
|
||||
// read out our initial settings from prefs.
|
||||
try
|
||||
{
|
||||
gOpenTime = Services.prefs.getIntPref("alerts.totalOpenTime");
|
||||
} catch (ex) {}
|
||||
|
||||
// bogus call to make sure the window is moved offscreen until we are ready for it.
|
||||
resizeAlert(true);
|
||||
|
||||
// if we aren't waiting to fetch preview text, then go ahead and
|
||||
// start showing the alert.
|
||||
if (!gPendingPreviewFetchRequests)
|
||||
setTimeout(showAlert, 0); // let the JS thread unwind, to give layout
|
||||
// a chance to recompute the styles and widths for our alert text.
|
||||
}
|
||||
|
||||
// If the user initiated the alert, show it right away, otherwise start opening the alert with
|
||||
// the fade effect.
|
||||
function showAlert()
|
||||
{
|
||||
if (!document.getElementById("folderSummaryInfo").hasMessages) {
|
||||
closeAlert(); // no mail, so don't bother showing the alert...
|
||||
return;
|
||||
}
|
||||
|
||||
// resize the alert based on our current content
|
||||
resizeAlert(false);
|
||||
|
||||
var alertContainer = document.getElementById("alertContainer");
|
||||
// Don't fade in if the user opened the alert or the pref is true.
|
||||
if (gUserInitiated ||
|
||||
Services.prefs.getBoolPref("alerts.disableSlidingEffect")) {
|
||||
alertContainer.setAttribute("noanimation", true);
|
||||
setTimeout(closeAlert, gOpenTime);
|
||||
return;
|
||||
}
|
||||
|
||||
alertContainer.addEventListener("animationend", function hideAlert(event) {
|
||||
if (event.animationName == "fade-in") {
|
||||
alertContainer.removeEventListener("animationend", hideAlert, false);
|
||||
let remaining = Math.max(Math.round(gOpenTime - event.elapsedTime * 1000), 0);
|
||||
setTimeout(fadeOutAlert, remaining);
|
||||
}
|
||||
}, false);
|
||||
alertContainer.setAttribute("fade-in", true);
|
||||
}
|
||||
|
||||
function resizeAlert(aMoveOffScreen)
|
||||
{
|
||||
var alertTextBox = document.getElementById("alertTextBox");
|
||||
var alertImageBox = document.getElementById("alertImageBox");
|
||||
alertImageBox.style.minHeight = alertTextBox.scrollHeight + "px";
|
||||
|
||||
sizeToContent();
|
||||
|
||||
// leftover hack to get the window properly hidden when we first open it
|
||||
if (aMoveOffScreen)
|
||||
window.outerHeight = 1;
|
||||
|
||||
// Determine position
|
||||
var x = gOrigin & NS_ALERT_LEFT ? screen.availLeft :
|
||||
screen.availLeft + screen.availWidth - window.outerWidth;
|
||||
var y = gOrigin & NS_ALERT_TOP ? screen.availTop :
|
||||
screen.availTop + screen.availHeight - window.outerHeight;
|
||||
|
||||
// Offset the alert by 10 pixels from the edge of the screen
|
||||
y += gOrigin & NS_ALERT_TOP ? 10 : -10;
|
||||
x += gOrigin & NS_ALERT_LEFT ? 10 : -10;
|
||||
|
||||
window.moveTo(x, y);
|
||||
}
|
||||
|
||||
function fadeOutAlert()
|
||||
{
|
||||
var alertContainer = document.getElementById("alertContainer");
|
||||
alertContainer.addEventListener("animationend", function fadeOut(event) {
|
||||
if (event.animationName == "fade-out") {
|
||||
alertContainer.removeEventListener("animationend", fadeOut, false);
|
||||
closeAlert();
|
||||
}
|
||||
}, false);
|
||||
alertContainer.setAttribute("fade-out", true);
|
||||
}
|
||||
|
||||
function closeAlert()
|
||||
{
|
||||
if (gAlertListener)
|
||||
gAlertListener.observe(null, "alertfinished", "");
|
||||
window.close();
|
||||
}
|
||||
35
mailnews/base/content/newmailalert.xul
Normal file
35
mailnews/base/content/newmailalert.xul
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://messenger/content/newmailalert.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://messenger/skin/newmailalert.css" type="text/css"?>
|
||||
|
||||
<window id="newMailAlertNotification"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
windowtype="alert:alert"
|
||||
role="alert"
|
||||
align="start"
|
||||
onload="onAlertLoad()">
|
||||
|
||||
<stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
|
||||
<script type="application/javascript" src="chrome://messenger/content/newmailalert.js"/>
|
||||
|
||||
<stack id="alertContainer" mousethrough="always">
|
||||
<hbox id="alertBox">
|
||||
<hbox id ="alertImageBox" align="center" pack="center">
|
||||
<image id="alertImage"/>
|
||||
</hbox>
|
||||
|
||||
<vbox id="alertTextBox">
|
||||
<label id="alertTitle"/>
|
||||
<separator id="alertGroove" class="groove"/>
|
||||
<folderSummary id="folderSummaryInfo" mousethrough="never"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
<toolbarbutton id="closeButton" top="0" right="0" onclick="closeAlert();"/>
|
||||
</stack>
|
||||
</window>
|
||||
47
mailnews/base/content/renameFolderDialog.js
Normal file
47
mailnews/base/content/renameFolderDialog.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
|
||||
|
||||
var dialog;
|
||||
|
||||
function onLoad()
|
||||
{
|
||||
var windowArgs = window.arguments[0];
|
||||
|
||||
dialog = {};
|
||||
|
||||
dialog.OKButton = document.documentElement.getButton("accept");
|
||||
|
||||
dialog.nameField = document.getElementById("name");
|
||||
dialog.nameField.value = windowArgs.name;
|
||||
dialog.nameField.select();
|
||||
dialog.nameField.focus();
|
||||
|
||||
// call this when OK is pressed
|
||||
dialog.okCallback = windowArgs.okCallback;
|
||||
|
||||
// pre select the folderPicker, based on what they selected in the folder pane
|
||||
dialog.preselectedFolderURI = windowArgs.preselectedURI;
|
||||
|
||||
doEnabling();
|
||||
}
|
||||
|
||||
function onOK()
|
||||
{
|
||||
dialog.okCallback(dialog.nameField.value, dialog.preselectedFolderURI);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function doEnabling()
|
||||
{
|
||||
if (dialog.nameField.value) {
|
||||
if (dialog.OKButton.disabled)
|
||||
dialog.OKButton.disabled = false;
|
||||
} else {
|
||||
if (!dialog.OKButton.disabled)
|
||||
dialog.OKButton.disabled = true;
|
||||
}
|
||||
}
|
||||
23
mailnews/base/content/renameFolderDialog.xul
Normal file
23
mailnews/base/content/renameFolderDialog.xul
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0"?> <!-- -*- Mode: xml; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://messenger/skin/dialogs.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/renameFolderDialog.dtd">
|
||||
|
||||
<dialog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="&renameFolderDialog.title;"
|
||||
buttonlabelaccept="&accept.label;"
|
||||
buttonaccesskeyaccept="&accept.accesskey;"
|
||||
ondialogaccept="return onOK();"
|
||||
onload="onLoad();">
|
||||
|
||||
<stringbundleset id="stringbundleset"/>
|
||||
<script type="application/javascript" src="chrome://messenger/content/renameFolderDialog.js"/>
|
||||
|
||||
<label value="&rename.label;" accesskey="&rename.accesskey;" control="name"/>
|
||||
<textbox id="name" oninput="doEnabling();"/>
|
||||
</dialog>
|
||||
45
mailnews/base/content/retention.js
Normal file
45
mailnews/base/content/retention.js
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
|
||||
|
||||
|
||||
function initCommonRetentionSettings(retentionSettings)
|
||||
{
|
||||
document.getElementById("retention.keepMsg").value = retentionSettings.retainByPreference;
|
||||
document.getElementById("retention.keepOldMsgMin").value =
|
||||
(retentionSettings.daysToKeepHdrs > 0) ? retentionSettings.daysToKeepHdrs : 30;
|
||||
document.getElementById("retention.keepNewMsgMin").value =
|
||||
(retentionSettings.numHeadersToKeep > 0) ? retentionSettings.numHeadersToKeep : 2000;
|
||||
|
||||
document.getElementById("retention.applyToFlagged").checked =
|
||||
!retentionSettings.applyToFlaggedMessages;
|
||||
}
|
||||
|
||||
function saveCommonRetentionSettings(aRetentionSettings)
|
||||
{
|
||||
aRetentionSettings.retainByPreference = document.getElementById("retention.keepMsg").value;
|
||||
|
||||
aRetentionSettings.daysToKeepHdrs = document.getElementById("retention.keepOldMsgMin").value;
|
||||
aRetentionSettings.numHeadersToKeep = document.getElementById("retention.keepNewMsgMin").value;
|
||||
|
||||
aRetentionSettings.applyToFlaggedMessages =
|
||||
!document.getElementById("retention.applyToFlagged").checked;
|
||||
|
||||
return aRetentionSettings;
|
||||
}
|
||||
|
||||
function onCheckKeepMsg()
|
||||
{
|
||||
if (gLockedPref && gLockedPref["retention.keepMsg"]) {
|
||||
// if the pref associated with the radiobutton is locked, as indicated
|
||||
// by the gLockedPref, skip this function. All elements in this
|
||||
// radiogroup have been locked by the function onLockPreference.
|
||||
return;
|
||||
}
|
||||
|
||||
var keepMsg = document.getElementById("retention.keepMsg").value;
|
||||
document.getElementById("retention.keepOldMsgMin").disabled = keepMsg != 2;
|
||||
document.getElementById("retention.keepNewMsgMin").disabled = keepMsg != 3;
|
||||
}
|
||||
20
mailnews/base/content/shareglue.js
Normal file
20
mailnews/base/content/shareglue.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
/*
|
||||
* code in here is generic, shared utility code across all messenger
|
||||
* components. There should be no command or widget specific code here
|
||||
*/
|
||||
|
||||
function MessengerSetForcedCharacterSet(aCharset)
|
||||
{
|
||||
messenger.setDocumentCharset(aCharset);
|
||||
msgWindow.mailCharacterSet = aCharset;
|
||||
msgWindow.charsetOverride = true;
|
||||
|
||||
// DO NOT try to reload the message here. we do this automatically now in
|
||||
// messenger.SetDocumentCharset. You'll just break things and reak havoc
|
||||
// if you call ReloadMessage() here...
|
||||
}
|
||||
99
mailnews/base/content/shutdownWindow.js
Normal file
99
mailnews/base/content/shutdownWindow.js
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
# 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/.
|
||||
*/
|
||||
|
||||
var curTaskIndex = 0;
|
||||
var numTasks = 0;
|
||||
var stringBundle;
|
||||
|
||||
var msgShutdownService = Components.classes["@mozilla.org/messenger/msgshutdownservice;1"]
|
||||
.getService(Components.interfaces.nsIMsgShutdownService);
|
||||
|
||||
function onLoad()
|
||||
{
|
||||
numTasks = msgShutdownService.getNumTasks();
|
||||
|
||||
stringBundle = document.getElementById("bundle_shutdown");
|
||||
document.title = stringBundle.getString("shutdownDialogTitle");
|
||||
|
||||
updateTaskProgressLabel(1);
|
||||
updateProgressMeter(0);
|
||||
|
||||
msgShutdownService.startShutdownTasks();
|
||||
}
|
||||
|
||||
function updateProgressLabel(inTaskName)
|
||||
{
|
||||
var curTaskLabel = document.getElementById("shutdownStatus_label");
|
||||
curTaskLabel.value = inTaskName;
|
||||
}
|
||||
|
||||
function updateTaskProgressLabel(inCurTaskNum)
|
||||
{
|
||||
var taskProgressLabel = document.getElementById("shutdownTask_label");
|
||||
taskProgressLabel.value = stringBundle.getFormattedString("taskProgress", [inCurTaskNum, numTasks]);
|
||||
}
|
||||
|
||||
function updateProgressMeter(inPercent)
|
||||
{
|
||||
var taskProgressmeter = document.getElementById('shutdown_progressmeter');
|
||||
taskProgressmeter.value = inPercent;
|
||||
}
|
||||
|
||||
function onCancel()
|
||||
{
|
||||
msgShutdownService.cancelShutdownTasks();
|
||||
}
|
||||
|
||||
function nsMsgShutdownTaskListener()
|
||||
{
|
||||
msgShutdownService.setShutdownListener(this);
|
||||
}
|
||||
|
||||
nsMsgShutdownTaskListener.prototype =
|
||||
{
|
||||
QueryInterface : function(iid)
|
||||
{
|
||||
if (iid.equals(Components.interfaces.nsIWebProgressListener) ||
|
||||
iid.equals(Components.interfaces.nsISupportsWeakReference) ||
|
||||
iid.equals(Components.interfaces.nsISupports))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
},
|
||||
|
||||
onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus)
|
||||
{
|
||||
if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP)
|
||||
{
|
||||
window.close();
|
||||
}
|
||||
},
|
||||
|
||||
onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress)
|
||||
{
|
||||
updateProgressMeter(((aCurTotalProgress / aMaxTotalProgress) * 100));
|
||||
updateTaskProgressLabel(aCurTotalProgress + 1);
|
||||
},
|
||||
|
||||
onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags)
|
||||
{
|
||||
// we can ignore this notification
|
||||
},
|
||||
|
||||
onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage)
|
||||
{
|
||||
if (aMessage)
|
||||
updateProgressLabel(aMessage);
|
||||
},
|
||||
|
||||
onSecurityChange: function(aWebProgress, aRequest, state)
|
||||
{
|
||||
// we can ignore this notification
|
||||
}
|
||||
}
|
||||
|
||||
var MsgShutdownTaskListener = new nsMsgShutdownTaskListener();
|
||||
|
||||
31
mailnews/base/content/shutdownWindow.xul
Normal file
31
mailnews/base/content/shutdownWindow.xul
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
# 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/.
|
||||
-->
|
||||
|
||||
<?xml-stylesheet href="chrome://messenger/skin/dialogs.css" type="text/css"?>
|
||||
|
||||
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
style="padding: 20px; width: 350px"
|
||||
onload="onLoad()"
|
||||
buttons="cancel"
|
||||
ondialogcancel="return onCancel();">
|
||||
|
||||
<script type="application/javascript" src="chrome://messenger/content/shutdownWindow.js"/>
|
||||
<stringbundle id="bundle_shutdown" src="chrome://messenger/locale/shutdownWindow.properties"/>
|
||||
|
||||
<vbox align="center">
|
||||
<label id="shutdownStatus_label" value="" />
|
||||
<separator class="thin" />
|
||||
</vbox>
|
||||
|
||||
<progressmeter id="shutdown_progressmeter" mode="determined" />
|
||||
|
||||
<vbox align="center">
|
||||
<label id="shutdownTask_label" value="" />
|
||||
<separator class="thick" />
|
||||
</vbox>
|
||||
|
||||
</dialog>
|
||||
136
mailnews/base/content/virtualFolderListDialog.js
Normal file
136
mailnews/base/content/virtualFolderListDialog.js
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
|
||||
|
||||
Components.utils.import("resource:///modules/mailServices.js");
|
||||
Components.utils.import("resource:///modules/iteratorUtils.jsm");
|
||||
Components.utils.import("resource:///modules/MailUtils.js");
|
||||
|
||||
var gFolderPickerTree = null;
|
||||
|
||||
function onLoad()
|
||||
{
|
||||
gFolderPickerTree = document.getElementById("folderPickerTree");
|
||||
|
||||
if (window.arguments[0].searchFolderURIs)
|
||||
{
|
||||
// for each folder uri,
|
||||
var srchFolderUriArray = window.arguments[0].searchFolderURIs.split('|');
|
||||
// get the folder for each search URI and set the searchThisFolder flag on it
|
||||
for (var i in srchFolderUriArray)
|
||||
{
|
||||
var realFolder = MailUtils.getFolderForURI(srchFolderUriArray[i]);
|
||||
if (realFolder)
|
||||
realFolder.setInVFEditSearchScope(true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onUnLoad()
|
||||
{
|
||||
resetFolderToSearchAttribute();
|
||||
}
|
||||
|
||||
function onOK()
|
||||
{
|
||||
if ( window.arguments[0].okCallback )
|
||||
window.arguments[0].okCallback(generateFoldersToSearchList());
|
||||
}
|
||||
|
||||
function onCancel()
|
||||
{
|
||||
// onunload will clear out the folder attributes we changed
|
||||
}
|
||||
|
||||
function addFolderToSearchListString(aFolder, aCurrentSearchURIString)
|
||||
{
|
||||
if (aCurrentSearchURIString)
|
||||
aCurrentSearchURIString += '|';
|
||||
aCurrentSearchURIString += aFolder.URI;
|
||||
|
||||
return aCurrentSearchURIString;
|
||||
}
|
||||
|
||||
function processSearchSettingForFolder(aFolder, aCurrentSearchURIString)
|
||||
{
|
||||
if (aFolder.inVFEditSearchScope)
|
||||
aCurrentSearchURIString = addFolderToSearchListString(aFolder, aCurrentSearchURIString);
|
||||
|
||||
aFolder.setInVFEditSearchScope(false, false);
|
||||
return aCurrentSearchURIString;
|
||||
}
|
||||
|
||||
// warning: this routine also clears out the search property list from all of the msg folders
|
||||
function generateFoldersToSearchList()
|
||||
{
|
||||
let uriSearchString = "";
|
||||
let allFolders = MailServices.accounts.allFolders;
|
||||
for (let folder in fixIterator(allFolders, Components.interfaces.nsIMsgFolder))
|
||||
uriSearchString = processSearchSettingForFolder(folder, uriSearchString);
|
||||
|
||||
return uriSearchString;
|
||||
}
|
||||
|
||||
function resetFolderToSearchAttribute()
|
||||
{
|
||||
// iterates over all accounts and all folders, clearing out the inVFEditScope property in case
|
||||
// we set it.
|
||||
let allFolders = MailServices.accounts.allFolders;
|
||||
for (let folder in fixIterator(allFolders, Components.interfaces.nsIMsgFolder))
|
||||
folder.setInVFEditSearchScope(false, false);
|
||||
}
|
||||
|
||||
function ReverseStateFromNode(row)
|
||||
{
|
||||
var folder = GetFolderResource(row).QueryInterface(Components.interfaces.nsIMsgFolder);
|
||||
var currentState = folder.inVFEditSearchScope;
|
||||
|
||||
folder.setInVFEditSearchScope(!currentState, false);
|
||||
}
|
||||
|
||||
function GetFolderResource(rowIndex)
|
||||
{
|
||||
return gFolderPickerTree.builder.QueryInterface(Components.interfaces.nsIXULTreeBuilder).getResourceAtIndex(rowIndex);
|
||||
}
|
||||
|
||||
function selectFolderTreeOnClick(event)
|
||||
{
|
||||
// we only care about button 0 (left click) events
|
||||
if (event.button != 0 || event.originalTarget.localName != "treechildren")
|
||||
return;
|
||||
|
||||
var row = {}, col = {}, obj = {};
|
||||
gFolderPickerTree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, obj);
|
||||
if (row.value == -1 || row.value > (gFolderPickerTree.view.rowCount - 1))
|
||||
return;
|
||||
|
||||
if (event.detail == 2) {
|
||||
// only toggle the search folder state when double clicking something
|
||||
// that isn't a container
|
||||
if (!gFolderPickerTree.view.isContainer(row.value)) {
|
||||
ReverseStateFromNode(row.value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (event.detail == 1)
|
||||
{
|
||||
if (obj.value != "twisty" && col.value.id == "selectedColumn")
|
||||
ReverseStateFromNode(row.value)
|
||||
}
|
||||
}
|
||||
|
||||
function onSelectFolderTreeKeyPress(event)
|
||||
{
|
||||
// for now, only do something on space key
|
||||
if (event.charCode != KeyEvent.DOM_VK_SPACE)
|
||||
return;
|
||||
|
||||
var treeSelection = gFolderPickerTree.view.selection;
|
||||
for (var i=0;i<treeSelection.getRangeCount();i++) {
|
||||
var start = {}, end = {};
|
||||
treeSelection.getRangeAt(i,start,end);
|
||||
for (var k=start.value;k<=end.value;k++)
|
||||
ReverseStateFromNode(k);
|
||||
}
|
||||
}
|
||||
91
mailnews/base/content/virtualFolderListDialog.xul
Normal file
91
mailnews/base/content/virtualFolderListDialog.xul
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- 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/.
|
||||
-->
|
||||
|
||||
<?xml-stylesheet href="chrome://messenger/skin/virtualFolderListDialog.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window SYSTEM "chrome://messenger/locale/virtualFolderListDialog.dtd">
|
||||
|
||||
<dialog id="searchFolderWindow"
|
||||
xmlns:NC="http://home.netscape.com/NC-rdf#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="&virtualFolderListTitle.title;"
|
||||
style="width: 27em; height: 25em;"
|
||||
persist="width height screenX screenY"
|
||||
onload="onLoad();"
|
||||
onunload="onUnLoad();"
|
||||
ondialogaccept="return onOK();"
|
||||
ondialogcancel="return onCancel();">
|
||||
|
||||
<script type="application/javascript" src="chrome://messenger/content/virtualFolderListDialog.js"/>
|
||||
|
||||
<label control="folderPickerTree">&virtualFolderDesc.label;</label>
|
||||
|
||||
<tree id="folderPickerTree"
|
||||
treelines="true"
|
||||
flex="1"
|
||||
hidecolumnpicker="true"
|
||||
seltype="multiple"
|
||||
disableKeyNavigation="true"
|
||||
datasources="rdf:msgaccountmanager rdf:mailnewsfolders"
|
||||
ref="msgaccounts:/"
|
||||
flags="dont-build-content"
|
||||
onkeypress="onSelectFolderTreeKeyPress(event);"
|
||||
onclick="selectFolderTreeOnClick(event);">
|
||||
<template>
|
||||
<rule>
|
||||
<conditions>
|
||||
<content uri="?container"/>
|
||||
<member container="?container" child="?member"/>
|
||||
<triple subject="?member"
|
||||
predicate="http://home.netscape.com/NC-rdf#Virtual"
|
||||
object="false"/>
|
||||
<triple subject="?member"
|
||||
predicate="http://home.netscape.com/NC-rdf#IsDeferred"
|
||||
object="false"/>
|
||||
</conditions>
|
||||
|
||||
<bindings>
|
||||
<binding subject="?member"
|
||||
predicate="http://home.netscape.com/NC-rdf#FolderTreeName"
|
||||
object="?folderTreeName"/>
|
||||
<binding subject="?member"
|
||||
predicate="http://home.netscape.com/NC-rdf#FolderTreeName?sort=true"
|
||||
object="?folderTreeNameSort"/>
|
||||
<binding subject="?member"
|
||||
predicate="http://home.netscape.com/NC-rdf#ServerType"
|
||||
object="?serverType"/>
|
||||
<binding subject="?member"
|
||||
predicate="http://home.netscape.com/NC-rdf#SpecialFolder"
|
||||
object="?specialFolder"/>
|
||||
<binding subject="?member"
|
||||
predicate="http://home.netscape.com/NC-rdf#HasUnreadMessages"
|
||||
object="?hasUnreadMessages"/>
|
||||
<binding subject="?member"
|
||||
predicate="http://home.netscape.com/NC-rdf#InVFEditSearchScope"
|
||||
object="?inVFEditSearchScope"/>
|
||||
</bindings>
|
||||
|
||||
<action>
|
||||
<treechildren>
|
||||
<treeitem uri="?member">
|
||||
<treerow>
|
||||
<treecell label="?folderTreeName" properties="ServerType-?ServerType specialFolder-?specialFolder hasUnreadMessages-?hasUnreadMessages"/>
|
||||
<treecell properties="inVFEditSearchScope-?inVFEditSearchScope"/>/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</action>
|
||||
</rule>
|
||||
</template>
|
||||
|
||||
<treecols>
|
||||
<treecol id="folderNameCol" sort="?folderTreeNameSort" sortActive="true" sortDirection="ascending"
|
||||
flex="10" primary="true" hideheader="true" crop="center"/>
|
||||
<treecol id="selectedColumn" hideheader="true" flex="1"/>
|
||||
</treecols>
|
||||
</tree>
|
||||
</dialog>
|
||||
266
mailnews/base/content/virtualFolderProperties.js
Normal file
266
mailnews/base/content/virtualFolderProperties.js
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
|
||||
|
||||
var gPickedFolder;
|
||||
var gMailView = null;
|
||||
var msgWindow; // important, don't change the name of this variable. it's really a global used by commandglue.js
|
||||
var gSearchTermSession; // really an in memory temporary filter we use to read in and write out the search terms
|
||||
var gSearchFolderURIs = "";
|
||||
var gMessengerBundle = null;
|
||||
|
||||
var nsMsgSearchScope = Components.interfaces.nsMsgSearchScope;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/PluralForm.jsm");
|
||||
Components.utils.import("resource:///modules/mailServices.js");
|
||||
Components.utils.import("resource:///modules/virtualFolderWrapper.js");
|
||||
Components.utils.import("resource:///modules/iteratorUtils.jsm");
|
||||
Components.utils.import("resource:///modules/MailUtils.js");
|
||||
|
||||
function onLoad()
|
||||
{
|
||||
var windowArgs = window.arguments[0];
|
||||
var acceptButton = document.documentElement.getButton("accept");
|
||||
|
||||
gMessengerBundle = document.getElementById("bundle_messenger");
|
||||
|
||||
// call this when OK is pressed
|
||||
msgWindow = windowArgs.msgWindow;
|
||||
|
||||
initializeSearchWidgets();
|
||||
|
||||
setSearchScope(nsMsgSearchScope.offlineMail);
|
||||
if (windowArgs.editExistingFolder)
|
||||
{
|
||||
acceptButton.label =
|
||||
document.documentElement.getAttribute("editFolderAcceptButtonLabel");
|
||||
acceptButton.accesskey =
|
||||
document.documentElement.getAttribute("editFolderAcceptButtonAccessKey");
|
||||
InitDialogWithVirtualFolder(windowArgs.folder);
|
||||
}
|
||||
else // we are creating a new virtual folder
|
||||
{
|
||||
acceptButton.label =
|
||||
document.documentElement.getAttribute("newFolderAcceptButtonLabel");
|
||||
acceptButton.accesskey =
|
||||
document.documentElement.getAttribute("newFolderAcceptButtonAccessKey");
|
||||
// it is possible that we were given arguments to pre-fill the dialog with...
|
||||
gSearchTermSession = Components.classes["@mozilla.org/messenger/searchSession;1"]
|
||||
.createInstance(Components.interfaces.nsIMsgSearchSession);
|
||||
|
||||
if (windowArgs.searchTerms) // then add them to our search session
|
||||
{
|
||||
for (let searchTerm in fixIterator(windowArgs.searchTerms,
|
||||
Components.interfaces.nsIMsgSearchTerm))
|
||||
gSearchTermSession.appendTerm(searchTerm);
|
||||
}
|
||||
if (windowArgs.folder)
|
||||
{
|
||||
// pre select the folderPicker, based on what they selected in the folder pane
|
||||
gPickedFolder = windowArgs.folder;
|
||||
try {
|
||||
document.getElementById("msgNewFolderPopup").selectFolder(windowArgs.folder);
|
||||
} catch(ex) {
|
||||
document.getElementById("msgNewFolderPicker")
|
||||
.setAttribute("label", windowArgs.folder.prettyName);
|
||||
}
|
||||
|
||||
// if the passed in URI is not a server then pre-select it as the folder to search
|
||||
if (!windowArgs.folder.isServer)
|
||||
gSearchFolderURIs = windowArgs.folder.URI;
|
||||
}
|
||||
|
||||
let folderNameField = document.getElementById("name");
|
||||
folderNameField.hidden = false;
|
||||
folderNameField.focus();
|
||||
if (windowArgs.newFolderName)
|
||||
folderNameField.value = windowArgs.newFolderName;
|
||||
if (windowArgs.searchFolderURIs)
|
||||
gSearchFolderURIs = windowArgs.searchFolderURIs;
|
||||
|
||||
setupSearchRows(gSearchTermSession.searchTerms);
|
||||
doEnabling(); // we only need to disable/enable the OK button for new virtual folders
|
||||
}
|
||||
|
||||
if (typeof windowArgs.searchOnline != "undefined")
|
||||
document.getElementById('searchOnline').checked = windowArgs.searchOnline;
|
||||
updateOnlineSearchState();
|
||||
updateFoldersCount();
|
||||
}
|
||||
|
||||
function setupSearchRows(aSearchTerms)
|
||||
{
|
||||
if (aSearchTerms && aSearchTerms.Count() > 0)
|
||||
initializeSearchRows(nsMsgSearchScope.offlineMail, aSearchTerms); // load the search terms for the folder
|
||||
else
|
||||
onMore(null);
|
||||
}
|
||||
|
||||
function updateOnlineSearchState()
|
||||
{
|
||||
var enableCheckbox = false;
|
||||
var checkbox = document.getElementById('searchOnline');
|
||||
// only enable the checkbox for selection, for online servers
|
||||
var srchFolderUriArray = gSearchFolderURIs.split('|');
|
||||
if (srchFolderUriArray[0])
|
||||
{
|
||||
var realFolder = MailUtils.getFolderForURI(srchFolderUriArray[0]);
|
||||
enableCheckbox = realFolder.server.offlineSupportLevel; // anything greater than 0 is an online server like IMAP or news
|
||||
}
|
||||
|
||||
if (enableCheckbox)
|
||||
checkbox.removeAttribute('disabled');
|
||||
else
|
||||
{
|
||||
checkbox.setAttribute('disabled', true);
|
||||
checkbox.checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
function InitDialogWithVirtualFolder(aVirtualFolder)
|
||||
{
|
||||
let virtualFolderWrapper =
|
||||
VirtualFolderHelper.wrapVirtualFolder(window.arguments[0].folder);
|
||||
|
||||
// when editing an existing folder, hide the folder picker that stores the parent location of the folder
|
||||
document.getElementById("chooseFolderLocationRow").collapsed = true;
|
||||
let folderNameField = document.getElementById("existingName");
|
||||
folderNameField.hidden = false;
|
||||
|
||||
gSearchFolderURIs = virtualFolderWrapper.searchFolderURIs;
|
||||
updateFoldersCount();
|
||||
document.getElementById('searchOnline').checked = virtualFolderWrapper.onlineSearch;
|
||||
gSearchTermSession = virtualFolderWrapper.searchTermsSession;
|
||||
|
||||
setupSearchRows(gSearchTermSession.searchTerms);
|
||||
|
||||
// set the name of the folder
|
||||
let folderBundle = document.getElementById("bundle_folder");
|
||||
let name = folderBundle.getFormattedString("verboseFolderFormat",
|
||||
[aVirtualFolder.prettyName, aVirtualFolder.server.prettyName]);
|
||||
folderNameField.setAttribute("label", name);
|
||||
// update the window title based on the name of the saved search
|
||||
document.title = gMessengerBundle.getFormattedString("editVirtualFolderPropertiesTitle",
|
||||
[aVirtualFolder.prettyName]);
|
||||
}
|
||||
|
||||
function onFolderPick(aEvent) {
|
||||
gPickedFolder = aEvent.target._folder;
|
||||
document.getElementById("msgNewFolderPopup")
|
||||
.selectFolder(gPickedFolder);
|
||||
}
|
||||
|
||||
function onOK()
|
||||
{
|
||||
var name = document.getElementById("name").value;
|
||||
var searchOnline = document.getElementById('searchOnline').checked;
|
||||
|
||||
if (!gSearchFolderURIs)
|
||||
{
|
||||
Services.prompt.alert(window, null,
|
||||
gMessengerBundle.getString('alertNoSearchFoldersSelected'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (window.arguments[0].editExistingFolder)
|
||||
{
|
||||
// update the search terms
|
||||
saveSearchTerms(gSearchTermSession.searchTerms, gSearchTermSession);
|
||||
// save the settings
|
||||
let virtualFolderWrapper =
|
||||
VirtualFolderHelper.wrapVirtualFolder(window.arguments[0].folder);
|
||||
virtualFolderWrapper.searchTerms = gSearchTermSession.searchTerms;
|
||||
virtualFolderWrapper.searchFolders = gSearchFolderURIs;
|
||||
virtualFolderWrapper.onlineSearch = searchOnline;
|
||||
virtualFolderWrapper.cleanUpMessageDatabase();
|
||||
|
||||
MailServices.accounts.saveVirtualFolders();
|
||||
|
||||
if (window.arguments[0].onOKCallback)
|
||||
window.arguments[0].onOKCallback(virtualFolderWrapper.virtualFolder.URI);
|
||||
return true;
|
||||
}
|
||||
var uri = gPickedFolder.URI;
|
||||
if (name && uri) // create a new virtual folder
|
||||
{
|
||||
// check to see if we already have a folder with the same name and alert the user if so...
|
||||
var parentFolder = MailUtils.getFolderForURI(uri);
|
||||
|
||||
// sanity check the name based on the logic used by nsMsgBaseUtils.cpp. It can't start with a '.', it can't end with a '.', '~' or ' '.
|
||||
// it can't contain a ';' or '#'.
|
||||
if (/^\.|[\.\~ ]$|[\;\#]/.test(name))
|
||||
{
|
||||
Services.prompt.alert(window, null,
|
||||
gMessengerBundle.getString("folderCreationFailed"));
|
||||
return false;
|
||||
}
|
||||
else if (parentFolder.containsChildNamed(name))
|
||||
{
|
||||
Services.prompt.alert(window, null,
|
||||
gMessengerBundle.getString("folderExists"));
|
||||
return false;
|
||||
}
|
||||
|
||||
saveSearchTerms(gSearchTermSession.searchTerms, gSearchTermSession);
|
||||
VirtualFolderHelper.createNewVirtualFolder(name, parentFolder, gSearchFolderURIs,
|
||||
gSearchTermSession.searchTerms,
|
||||
searchOnline);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function doEnabling()
|
||||
{
|
||||
var acceptButton = document.documentElement.getButton("accept");
|
||||
acceptButton.disabled = !document.getElementById("name").value;
|
||||
}
|
||||
|
||||
function chooseFoldersToSearch()
|
||||
{
|
||||
// if we have some search folders already, then root the folder picker dialog off the account
|
||||
// for those folders. Otherwise fall back to the preselectedfolderURI which is the parent folder
|
||||
// for this new virtual folder.
|
||||
var dialog = window.openDialog("chrome://messenger/content/virtualFolderListDialog.xul", "",
|
||||
"chrome,titlebar,modal,centerscreen,resizable",
|
||||
{searchFolderURIs:gSearchFolderURIs,
|
||||
okCallback:onFolderListDialogCallback});
|
||||
}
|
||||
|
||||
// callback routine from chooseFoldersToSearch
|
||||
function onFolderListDialogCallback(searchFolderURIs)
|
||||
{
|
||||
gSearchFolderURIs = searchFolderURIs;
|
||||
updateFoldersCount();
|
||||
updateOnlineSearchState(); // we may have changed the server type we are searching...
|
||||
}
|
||||
|
||||
function updateFoldersCount()
|
||||
{
|
||||
let srchFolderUriArray = gSearchFolderURIs.split('|');
|
||||
let folderCount = gSearchFolderURIs ? srchFolderUriArray.length : 0;
|
||||
let foldersList = document.getElementById("chosenFoldersCount");
|
||||
foldersList.textContent =
|
||||
PluralForm.get(folderCount, gMessengerBundle.getString("virtualFolderSourcesChosen"))
|
||||
.replace("#1", folderCount);
|
||||
if (folderCount > 0) {
|
||||
let folderNames = [];
|
||||
for (let folderURI of srchFolderUriArray) {
|
||||
let folder = MailUtils.getFolderForURI(folderURI);
|
||||
let name = this.gMessengerBundle.getFormattedString("verboseFolderFormat",
|
||||
[folder.prettyName, folder.server.prettyName]);
|
||||
folderNames.push(name);
|
||||
}
|
||||
foldersList.setAttribute("tooltiptext", folderNames.join("\n"));
|
||||
} else {
|
||||
foldersList.removeAttribute("tooltiptext");
|
||||
}
|
||||
}
|
||||
|
||||
function onEnterInSearchTerm()
|
||||
{
|
||||
// stub function called by the core search widget code...
|
||||
// nothing for us to do here
|
||||
}
|
||||
103
mailnews/base/content/virtualFolderProperties.xul
Normal file
103
mailnews/base/content/virtualFolderProperties.xul
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- 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/.
|
||||
-->
|
||||
|
||||
<?xml-stylesheet href="chrome://messenger/skin/dialogs.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://messenger/skin/searchDialog.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://messenger/skin/folderMenus.css" type="text/css"?>
|
||||
|
||||
<?xul-overlay href="chrome://messenger/content/searchTermOverlay.xul"?>
|
||||
|
||||
<!DOCTYPE dialog [
|
||||
<!ENTITY % folderDTD SYSTEM "chrome://messenger/locale/virtualFolderProperties.dtd">
|
||||
%folderDTD;
|
||||
]>
|
||||
|
||||
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
id="virtualFolderPropertiesDialog"
|
||||
title="&virtualFolderProperties.title;"
|
||||
onload="onLoad();"
|
||||
buttons="accept,cancel"
|
||||
newFolderAcceptButtonLabel="&newFolderButton.label;"
|
||||
newFolderAcceptButtonAccessKey="&newFolderButton.accesskey;"
|
||||
editFolderAcceptButtonLabel="&editFolderButton.label;"
|
||||
editFolderAcceptButtonAccessKey="&editFolderButton.accesskey;"
|
||||
style="width: 50em; height: 28em;"
|
||||
windowtype="mailnews:virtualFolderProperties"
|
||||
ondialogaccept="return onOK();">
|
||||
|
||||
<stringbundleset id="stringbundleset">
|
||||
<stringbundle id="bundle_search" src="chrome://messenger/locale/search.properties"/>
|
||||
<stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
|
||||
<stringbundle id="bundle_folder" src="chrome://messenger/locale/folderWidgets.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<script type="application/javascript" src="chrome://messenger/content/mailCommands.js"/>
|
||||
<script type="application/javascript" src="chrome://messenger/content/commandglue.js"/>
|
||||
<script type="application/javascript" src="chrome://messenger/content/virtualFolderProperties.js"/>
|
||||
|
||||
<grid>
|
||||
<columns>
|
||||
<column/>
|
||||
<column flex="1"/>
|
||||
<column flex="2"/>
|
||||
</columns>
|
||||
|
||||
<rows>
|
||||
<row align="center">
|
||||
<label value="&name.label;" accesskey="&name.accesskey;" control="name"/>
|
||||
<textbox id="name" hidden="true"
|
||||
oninput="doEnabling();"/>
|
||||
<filefield id="existingName" class="folderMenuItem"
|
||||
hidden="true" tabindex="0"
|
||||
SpecialFolder="Virtual"/>
|
||||
<spring/>
|
||||
</row>
|
||||
|
||||
<row align="center" id="chooseFolderLocationRow">
|
||||
<label value="&description.label;" accesskey="&description.accesskey;"
|
||||
control="msgNewFolderPicker"/>
|
||||
<menulist id="msgNewFolderPicker" class="folderMenuItem" flex="1"
|
||||
displayformat="verbose">
|
||||
<menupopup id="msgNewFolderPopup"
|
||||
class="menulist-menupopup"
|
||||
type="folder"
|
||||
mode="newFolder"
|
||||
showFileHereLabel="true"
|
||||
oncommand="onFolderPick(event);"/>
|
||||
</menulist>
|
||||
<spring/>
|
||||
</row>
|
||||
|
||||
<row align="center">
|
||||
<label value="&folderSelectionCaption.label;"/>
|
||||
<hbox align="center">
|
||||
<label id="chosenFoldersCount"/>
|
||||
<spacer flex="1"/>
|
||||
<button label="&chooseFoldersButton.label;"
|
||||
accesskey="&chooseFoldersButton.accesskey;"
|
||||
oncommand="chooseFoldersToSearch();"/>
|
||||
</hbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
|
||||
<hbox flex="1">
|
||||
<checkbox id="searchOnline" label="&searchOnline.label;"
|
||||
accesskey="&searchOnline.accesskey;"/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<vbox flex="2">
|
||||
<label value="&searchTermCaption.label;"/>
|
||||
<hbox flex="1">
|
||||
<vbox id="searchTermListBox" flex="2"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
</dialog>
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue