Bug 498519 - "make attachment reminder an inline notification bar" [r=mkmelin,ui-r=clarkbw]
This commit is contained in:
Родитель
8d65b52a84
Коммит
3973860a10
|
@ -46,6 +46,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||||
EXTRA_JS_MODULES = \
|
EXTRA_JS_MODULES = \
|
||||||
MailConsts.js \
|
MailConsts.js \
|
||||||
MailUtils.js \
|
MailUtils.js \
|
||||||
|
attachmentChecker.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Mozilla Messaging, Inc.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Blake Winton <bwinton@latte.ca>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
const EXPORTED_SYMBOLS = ["GetAttachmentKeywords"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the (possibly-empty) list of attachment keywords in this message.
|
||||||
|
*
|
||||||
|
* @return the (possibly-empty) list of attachment keywords in this message
|
||||||
|
**/
|
||||||
|
function GetAttachmentKeywords(mailData,keywordsInCsv)
|
||||||
|
{
|
||||||
|
// The empty string would get split to an array of size 1. Avoid that...
|
||||||
|
var keywordsArray = (keywordsInCsv) ? keywordsInCsv.split(",") : [];
|
||||||
|
|
||||||
|
function escapeRegxpSpecials(inputString)
|
||||||
|
{
|
||||||
|
const specials = [".", "\\", "^", "$", "*", "+", "?", "|",
|
||||||
|
"(", ")" , "[", "]", "{", "}"];
|
||||||
|
var re = new RegExp("(\\"+specials.join("|\\")+")", "g");
|
||||||
|
inputString = inputString.replace(re, "\\$1");
|
||||||
|
return inputString.replace(" ", "\\s+");
|
||||||
|
}
|
||||||
|
|
||||||
|
var keywordsFound = [];
|
||||||
|
for (var i = 0; i < keywordsArray.length; i++) {
|
||||||
|
var kw = escapeRegxpSpecials(keywordsArray[i]);
|
||||||
|
var re = new RegExp("(([^\\s]*)\\b|\\s*)" + kw + "\\b", "i");
|
||||||
|
var matching = re.exec(mailData);
|
||||||
|
// Ignore the match if it was a URL.
|
||||||
|
if (matching && !(/^http|^ftp/i.test(matching[0])))
|
||||||
|
keywordsFound.push(keywordsArray[i]);
|
||||||
|
}
|
||||||
|
return keywordsFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onmessage(event)
|
||||||
|
{
|
||||||
|
var keywordsFound = GetAttachmentKeywords(event.data[0], event.data[1]);
|
||||||
|
postMessage(keywordsFound);
|
||||||
|
};
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
|
|
||||||
// Ensure the activity modules are loaded for this window.
|
// Ensure the activity modules are loaded for this window.
|
||||||
Components.utils.import("resource://app/modules/activity/activityModules.js");
|
Components.utils.import("resource://app/modules/activity/activityModules.js");
|
||||||
|
Components.utils.import("resource://gre/modules/PluralForm.jsm");
|
||||||
|
Components.utils.import("resource://app/modules/attachmentChecker.js");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* interfaces
|
* interfaces
|
||||||
|
@ -92,6 +94,7 @@ var gMsgAddressingWidgetTreeElement;
|
||||||
var gMsgSubjectElement;
|
var gMsgSubjectElement;
|
||||||
var gMsgAttachmentElement;
|
var gMsgAttachmentElement;
|
||||||
var gMsgHeadersToolbarElement;
|
var gMsgHeadersToolbarElement;
|
||||||
|
var gRemindLater;
|
||||||
|
|
||||||
// i18n globals
|
// i18n globals
|
||||||
var gSendDefaultCharset;
|
var gSendDefaultCharset;
|
||||||
|
@ -137,6 +140,7 @@ function InitializeGlobalVariables()
|
||||||
gCharsetConvertManager = Components.classes['@mozilla.org/charset-converter-manager;1'].getService(Components.interfaces.nsICharsetConverterManager);
|
gCharsetConvertManager = Components.classes['@mozilla.org/charset-converter-manager;1'].getService(Components.interfaces.nsICharsetConverterManager);
|
||||||
gMailSession = Components.classes["@mozilla.org/messenger/services/session;1"].getService(Components.interfaces.nsIMsgMailSession);
|
gMailSession = Components.classes["@mozilla.org/messenger/services/session;1"].getService(Components.interfaces.nsIMsgMailSession);
|
||||||
gHideMenus = false;
|
gHideMenus = false;
|
||||||
|
gRemindLater = false;
|
||||||
|
|
||||||
gLastWindowToHaveFocus = null;
|
gLastWindowToHaveFocus = null;
|
||||||
gReceiptOptionChanged = false;
|
gReceiptOptionChanged = false;
|
||||||
|
@ -1166,6 +1170,181 @@ function handleMailtoArgs(mailtoUrl)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var attachmentWorker = new Worker("resource://app/modules/attachmentChecker.js");
|
||||||
|
|
||||||
|
attachmentWorker.lastMessage = null;
|
||||||
|
|
||||||
|
attachmentWorker.onerror = function(error)
|
||||||
|
{
|
||||||
|
dump("Attachment Notification Worker error!!! " + error.message + "\n");
|
||||||
|
throw error;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
attachmentWorker.onmessage = function(event)
|
||||||
|
{
|
||||||
|
let keywordsFound = event.data;
|
||||||
|
let bundle = document.getElementById("bundle_composeMsgs");
|
||||||
|
let msg = null;
|
||||||
|
let nBox = document.getElementById("attachmentNotificationBox");
|
||||||
|
let notification = nBox.getNotificationWithValue("1");
|
||||||
|
let removeNotification = false;
|
||||||
|
|
||||||
|
if (keywordsFound.length > 0) {
|
||||||
|
msg = document.createElement("hbox");
|
||||||
|
msg.setAttribute("flex", "100");
|
||||||
|
|
||||||
|
msg.onclick = function(event)
|
||||||
|
{
|
||||||
|
openOptionsDialog("paneCompose");
|
||||||
|
};
|
||||||
|
|
||||||
|
let msgText = document.createElement("label");
|
||||||
|
msg.appendChild(msgText);
|
||||||
|
msgText.id = "attachmentReminderText";
|
||||||
|
msgText.setAttribute("crop", "end");
|
||||||
|
msgText.setAttribute("flex", "1");
|
||||||
|
msgText.setAttribute("value", PluralForm.get(keywordsFound.length,
|
||||||
|
bundle.getString("attachmentReminderKeywordsMsg")));
|
||||||
|
|
||||||
|
let keywords = keywordsFound.join(", ");
|
||||||
|
let msgKeywords = document.createElement("label");
|
||||||
|
msg.appendChild(msgKeywords);
|
||||||
|
msgKeywords.id = "attachmentKeywords";
|
||||||
|
msgKeywords.setAttribute("crop", "end");
|
||||||
|
msgKeywords.setAttribute("flex", "1000");
|
||||||
|
msgKeywords.setAttribute("value", keywords);
|
||||||
|
|
||||||
|
if (notification) {
|
||||||
|
let description = notification.querySelector("#attachmentReminderText");
|
||||||
|
description.setAttribute("value", msgText.getAttribute("value"));
|
||||||
|
description = notification.querySelector("#attachmentKeywords")
|
||||||
|
description.setAttribute("value", keywords);
|
||||||
|
msg = null;
|
||||||
|
}
|
||||||
|
if (keywords == this.lastMessage) {
|
||||||
|
// The user closed the notification, and we have nothing new to say.
|
||||||
|
msg = null;
|
||||||
|
}
|
||||||
|
this.lastMessage = keywords;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
removeNotification = true;
|
||||||
|
this.lastMessage = null;
|
||||||
|
}
|
||||||
|
if (notification && removeNotification)
|
||||||
|
nBox.removeNotification(notification);
|
||||||
|
if (msg) {
|
||||||
|
var addButton = {
|
||||||
|
accessKey : bundle.getString("addAttachmentButton.accessskey"),
|
||||||
|
label: bundle.getString("addAttachmentButton"),
|
||||||
|
callback: function (aNotificationBar, aButton)
|
||||||
|
{
|
||||||
|
goDoCommand("cmd_attachFile");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var remindButton = {
|
||||||
|
accessKey : bundle.getString("remindLaterButton.accessskey"),
|
||||||
|
label: bundle.getString("remindLaterButton"),
|
||||||
|
callback: function (aNotificationBar, aButton)
|
||||||
|
{
|
||||||
|
gRemindLater = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
notification = nBox.appendNotification("", "1",
|
||||||
|
/* fake out the image so we can do it in CSS */
|
||||||
|
"null",
|
||||||
|
nBox.PRIORITY_WARNING_MEDIUM,
|
||||||
|
[addButton, remindButton]);
|
||||||
|
let buttons = notification.childNodes[0];
|
||||||
|
notification.insertBefore(msg, buttons);
|
||||||
|
}
|
||||||
|
CheckForAttachmentNotification.shouldFire = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether we should show the attachment notification or not.
|
||||||
|
*
|
||||||
|
* @param async Whether we should run the regex checker asynchronously or not.
|
||||||
|
* @return true if we should show the attachment notification
|
||||||
|
*/
|
||||||
|
function ShouldShowAttachmentNotification(async)
|
||||||
|
{
|
||||||
|
let bucket = document.getElementById("attachmentBucket");
|
||||||
|
let warn = getPref("mail.compose.attachment_reminder");
|
||||||
|
if (warn && !bucket.itemCount) {
|
||||||
|
let prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIPrefBranch);
|
||||||
|
let keywordsInCsv = prefs.getComplexValue(
|
||||||
|
"mail.compose.attachment_reminder_keywords",
|
||||||
|
Components.interfaces.nsIPrefLocalizedString).data;
|
||||||
|
let mailBody = document.getElementById("content-frame")
|
||||||
|
.contentDocument.getElementsByTagName("body")[0];
|
||||||
|
let mailBodyNode = mailBody.cloneNode(true);
|
||||||
|
|
||||||
|
// Don't check quoted text from reply.
|
||||||
|
let blockquotes = mailBodyNode.getElementsByTagName("blockquote");
|
||||||
|
for (let i = 0; i < blockquotes.length; i++) {
|
||||||
|
blockquotes[i].parentNode.removeChild(blockquotes[i]);
|
||||||
|
}
|
||||||
|
// For plaintext composition the quotes we need to find and exclude are
|
||||||
|
// normally <span _moz_quote="true">. If editor.quotesPreformatted is
|
||||||
|
// set we should exclude <pre _moz_quote="true"> nodes instead.
|
||||||
|
if (!getPref("editor.quotesPreformatted")) {
|
||||||
|
let spans = mailBodyNode.getElementsByTagName("span");
|
||||||
|
for (let i = 0; i < spans.length; i++) {
|
||||||
|
if (spans[i].hasAttribute("_moz_quote"))
|
||||||
|
spans[i].parentNode.removeChild(spans[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let pres = mailBodyNode.getElementsByTagName("pre");
|
||||||
|
for (let i = 0; i < pres.length; i++) {
|
||||||
|
if (pres[i].hasAttribute("_moz_quote"))
|
||||||
|
pres[i].parentNode.removeChild(pres[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let brs = mailBodyNode.getElementsByTagName("br");
|
||||||
|
for (let i = 0; i < brs.length; i++) {
|
||||||
|
brs[i].parentNode.replaceChild(document.createTextNode("\n"), brs[i]);
|
||||||
|
}
|
||||||
|
let mailData = mailBodyNode.textContent;
|
||||||
|
if (!async)
|
||||||
|
return GetAttachmentKeywords(mailData, keywordsInCsv).length != 0;
|
||||||
|
attachmentWorker.postMessage([mailData, keywordsInCsv]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for attachment keywords, and display a notification if it's
|
||||||
|
* appropriate.
|
||||||
|
*/
|
||||||
|
function CheckForAttachmentNotification(event)
|
||||||
|
{
|
||||||
|
if (!CheckForAttachmentNotification.shouldFire || gRemindLater)
|
||||||
|
return;
|
||||||
|
if (!event)
|
||||||
|
attachmentWorker.lastMessage = null;
|
||||||
|
CheckForAttachmentNotification.shouldFire = false;
|
||||||
|
let nBox = document.getElementById("attachmentNotificationBox");
|
||||||
|
let notification = nBox.getNotificationWithValue("1");
|
||||||
|
let removeNotification = false;
|
||||||
|
|
||||||
|
if (!ShouldShowAttachmentNotification(true)) {
|
||||||
|
removeNotification = true;
|
||||||
|
CheckForAttachmentNotification.shouldFire = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notification && removeNotification)
|
||||||
|
nBox.removeNotification(notification);
|
||||||
|
};
|
||||||
|
|
||||||
|
CheckForAttachmentNotification.shouldFire = true;
|
||||||
|
|
||||||
function ComposeStartup(recycled, aParams)
|
function ComposeStartup(recycled, aParams)
|
||||||
{
|
{
|
||||||
var params = null; // New way to pass parameters to the compose window as a nsIMsgComposeParameters object
|
var params = null; // New way to pass parameters to the compose window as a nsIMsgComposeParameters object
|
||||||
|
@ -1212,6 +1391,8 @@ function ComposeStartup(recycled, aParams)
|
||||||
var identityList = document.getElementById("msgIdentity");
|
var identityList = document.getElementById("msgIdentity");
|
||||||
|
|
||||||
document.addEventListener("keypress", awDocumentKeyPress, true);
|
document.addEventListener("keypress", awDocumentKeyPress, true);
|
||||||
|
var contentFrame = document.getElementById("content-frame");
|
||||||
|
contentFrame.addEventListener("click", CheckForAttachmentNotification, true);
|
||||||
|
|
||||||
if (identityList)
|
if (identityList)
|
||||||
FillIdentityList(identityList);
|
FillIdentityList(identityList);
|
||||||
|
@ -1706,85 +1887,20 @@ function GenericSendMessage( msgType )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attachment Reminder stuff...
|
if (gRemindLater && ShouldShowAttachmentNotification(false)) {
|
||||||
var bucket = document.getElementById("attachmentBucket");
|
var bundle = document.getElementById("bundle_composeMsgs");
|
||||||
var warn = getPref("mail.compose.attachment_reminder");
|
var flags = gPromptService.BUTTON_POS_0 * gPromptService.BUTTON_TITLE_IS_STRING +
|
||||||
if (warn && !bucket.itemCount)
|
gPromptService.BUTTON_POS_1 * gPromptService.BUTTON_TITLE_IS_STRING;
|
||||||
{
|
var hadForgotten = gPromptService.confirmEx(window,
|
||||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
bundle.getString("attachmentReminderTitle"),
|
||||||
.getService(Components.interfaces.nsIPrefBranch);
|
bundle.getString("attachmentReminderMsg"),
|
||||||
var keywordsInCsv = prefs.getComplexValue("mail.compose.attachment_reminder_keywords",
|
flags,
|
||||||
Components.interfaces.nsIPrefLocalizedString).data;
|
bundle.getString("attachmentReminderFalseAlarm"),
|
||||||
// And empty string pref is still going to get split to an array of
|
bundle.getString("attachmentReminderYesIForgot"),
|
||||||
// size 1. Avoid that...
|
null, null, {value:0});
|
||||||
var keywordsArray = (keywordsInCsv) ? keywordsInCsv.split(",") : [];
|
if (hadForgotten)
|
||||||
|
return;
|
||||||
var mailBody = document.getElementById("content-frame")
|
}
|
||||||
.contentDocument.getElementsByTagName("body")[0];
|
|
||||||
var mailBodyNode = mailBody.cloneNode(true);
|
|
||||||
|
|
||||||
// Don't check quoted text from reply.
|
|
||||||
var blockquotes = mailBodyNode.getElementsByTagName("blockquote");
|
|
||||||
for (let i = 0; i < blockquotes.length; i++)
|
|
||||||
{
|
|
||||||
blockquotes[i].parentNode.removeChild(blockquotes[i]);
|
|
||||||
}
|
|
||||||
// For plaintext composition the quotes we need to find and exclude are
|
|
||||||
// normally <span _moz_quote="true">. If editor.quotesPreformatted is
|
|
||||||
// set we should exclude <pre _moz_quote="true"> nodes instead.
|
|
||||||
if (!getPref("editor.quotesPreformatted"))
|
|
||||||
{
|
|
||||||
let spans = mailBodyNode.getElementsByTagName("span");
|
|
||||||
for (let i = 0; i < spans.length; i++)
|
|
||||||
{
|
|
||||||
if (spans[i].hasAttribute("_moz_quote"))
|
|
||||||
spans[i].parentNode.removeChild(spans[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
let pres = mailBodyNode.getElementsByTagName("pre");
|
|
||||||
for (let i = 0; i < pres.length; i++)
|
|
||||||
{
|
|
||||||
if (pres[i].hasAttribute("_moz_quote"))
|
|
||||||
pres[i].parentNode.removeChild(pres[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var mailData = mailBodyNode.textContent;
|
|
||||||
|
|
||||||
function escapeRegxpSpecials(inputString) {
|
|
||||||
const specials = [ ".", "\\", "^", "$", "*", "+", "?", , "|",
|
|
||||||
"(", ")" , "[", "]", "{", "}" ];
|
|
||||||
var re = new RegExp("(\\"+specials.join("|\\")+")", "g");
|
|
||||||
return inputString.replace(re, "\\$1");
|
|
||||||
}
|
|
||||||
|
|
||||||
var keywordFound;
|
|
||||||
for (let i = 0; i < keywordsArray.length && !keywordFound; i++)
|
|
||||||
{
|
|
||||||
let kw = escapeRegxpSpecials(keywordsArray[i]);
|
|
||||||
let re = new RegExp("(([^\\s]*)\\b|\\s*)" + kw + "\\b", "i");
|
|
||||||
let matching = re.exec(mailData);
|
|
||||||
// Ignore the match if it was a URL.
|
|
||||||
keywordFound = matching && !(/^http|^ftp/i.test(matching[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keywordFound)
|
|
||||||
{
|
|
||||||
var bundle = document.getElementById("bundle_composeMsgs");
|
|
||||||
var flags = gPromptService.BUTTON_POS_0 * gPromptService.BUTTON_TITLE_IS_STRING +
|
|
||||||
gPromptService.BUTTON_POS_1 * gPromptService.BUTTON_TITLE_IS_STRING;
|
|
||||||
var hadForgotten = gPromptService.confirmEx(window,
|
|
||||||
bundle.getString("attachmentReminderTitle"),
|
|
||||||
bundle.getString("attachmentReminderMsg"),
|
|
||||||
flags,
|
|
||||||
bundle.getString("attachmentReminderFalseAlarm"),
|
|
||||||
bundle.getString("attachmentReminderYesIForgot"),
|
|
||||||
null, null, {value:0});
|
|
||||||
if (hadForgotten)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} // End of Attachment Reminder.
|
|
||||||
|
|
||||||
// check if the user tries to send a message to a newsgroup through a mail account
|
// check if the user tries to send a message to a newsgroup through a mail account
|
||||||
var currentAccountKey = getCurrentAccountKey();
|
var currentAccountKey = getCurrentAccountKey();
|
||||||
|
@ -2713,6 +2829,7 @@ function AddUrlAttachment(attachment)
|
||||||
|
|
||||||
ChangeAttachmentBucketVisibility(false);
|
ChangeAttachmentBucketVisibility(false);
|
||||||
gContentChanged = true;
|
gContentChanged = true;
|
||||||
|
CheckForAttachmentNotification(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SelectAllAttachments()
|
function SelectAllAttachments()
|
||||||
|
@ -2804,6 +2921,7 @@ function RemoveAllAttachments()
|
||||||
}
|
}
|
||||||
|
|
||||||
ChangeAttachmentBucketVisibility(true);
|
ChangeAttachmentBucketVisibility(true);
|
||||||
|
CheckForAttachmentNotification(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ChangeAttachmentBucketVisibility(aHideBucket)
|
function ChangeAttachmentBucketVisibility(aHideBucket)
|
||||||
|
@ -2825,6 +2943,7 @@ function RemoveSelectedAttachment()
|
||||||
}
|
}
|
||||||
gContentChanged = true;
|
gContentChanged = true;
|
||||||
}
|
}
|
||||||
|
CheckForAttachmentNotification(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function RenameSelectedAttachment()
|
function RenameSelectedAttachment()
|
||||||
|
@ -3620,6 +3739,26 @@ function AutoSave()
|
||||||
gAutoSaveTimeout = setTimeout(AutoSave, gAutoSaveInterval);
|
gAutoSaveTimeout = setTimeout(AutoSave, gAutoSaveInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const gAttachmentNotifier =
|
||||||
|
{
|
||||||
|
event: {
|
||||||
|
notify: function(timer)
|
||||||
|
{
|
||||||
|
CheckForAttachmentNotification(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
timer: Components.classes["@mozilla.org/timer;1"]
|
||||||
|
.createInstance(Components.interfaces.nsITimer),
|
||||||
|
|
||||||
|
EditAction: function EditAction()
|
||||||
|
{
|
||||||
|
this.timer.cancel();
|
||||||
|
this.timer.initWithCallback(this.event, 500,
|
||||||
|
Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function InitEditor()
|
function InitEditor()
|
||||||
{
|
{
|
||||||
var editor = GetCurrentEditor();
|
var editor = GetCurrentEditor();
|
||||||
|
@ -3635,6 +3774,7 @@ function InitEditor()
|
||||||
InlineSpellCheckerUI.init(editor);
|
InlineSpellCheckerUI.init(editor);
|
||||||
enableInlineSpellCheck(getPref("mail.spellcheck.inline"));
|
enableInlineSpellCheck(getPref("mail.spellcheck.inline"));
|
||||||
document.getElementById('menu_inlineSpellCheck').setAttribute('disabled', !InlineSpellCheckerUI.canSpellCheck);
|
document.getElementById('menu_inlineSpellCheck').setAttribute('disabled', !InlineSpellCheckerUI.canSpellCheck);
|
||||||
|
editor.addEditorObserver(gAttachmentNotifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
function enableInlineSpellCheck(aEnableInlineSpellCheck)
|
function enableInlineSpellCheck(aEnableInlineSpellCheck)
|
||||||
|
|
|
@ -794,6 +794,10 @@
|
||||||
hidden="true"/>
|
hidden="true"/>
|
||||||
</panel>
|
</panel>
|
||||||
|
|
||||||
|
<hbox>
|
||||||
|
<notificationbox id="attachmentNotificationBox" flex="1" />
|
||||||
|
</hbox>
|
||||||
|
|
||||||
<statusbar id="status-bar" class="chromeclass-status">
|
<statusbar id="status-bar" class="chromeclass-status">
|
||||||
<statusbarpanel id="statusText" flex="1"/>
|
<statusbarpanel id="statusText" flex="1"/>
|
||||||
<statusbarpanel class="statusbarpanel-progress" id="statusbar-progresspanel">
|
<statusbarpanel class="statusbarpanel-progress" id="statusbar-progresspanel">
|
||||||
|
|
|
@ -337,8 +337,16 @@ renameAttachmentMessage=New attachment name:
|
||||||
## LOCALIZATION NOTE (mail.compose.attachment_reminder_keywords): comma separated
|
## LOCALIZATION NOTE (mail.compose.attachment_reminder_keywords): comma separated
|
||||||
## words that that should trigger an attachment reminder.
|
## words that that should trigger an attachment reminder.
|
||||||
mail.compose.attachment_reminder_keywords=.doc,.pdf,attachment,attach,attached,attaching,enclosed,CV,cover letter
|
mail.compose.attachment_reminder_keywords=.doc,.pdf,attachment,attach,attached,attaching,enclosed,CV,cover letter
|
||||||
|
|
||||||
|
addAttachmentButton=Add Attachment…
|
||||||
|
addAttachmentButton.accessskey=A
|
||||||
|
remindLaterButton=Remind Me Later
|
||||||
|
remindLaterButton.accessskey=R
|
||||||
|
|
||||||
attachmentReminderTitle=Attachment Reminder
|
attachmentReminderTitle=Attachment Reminder
|
||||||
attachmentReminderMsg=Did you forget to add an attachment?
|
attachmentReminderMsg=Did you forget to add an attachment?
|
||||||
|
attachmentReminderKeywordsMsg=Found an attachment keyword: ;Found some attachment keywords:
|
||||||
|
attachmentReminderOptionsMsg=Attachment reminder words can be configured in your preferences
|
||||||
attachmentReminderYesIForgot=Oh, I did!
|
attachmentReminderYesIForgot=Oh, I did!
|
||||||
attachmentReminderFalseAlarm=No, Send Now
|
attachmentReminderFalseAlarm=No, Send Now
|
||||||
|
|
||||||
|
|
|
@ -224,6 +224,27 @@ toolbar[iconsize="small"] #paste-button[disabled="true"] {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ::::: attachment reminder ::::: */
|
||||||
|
|
||||||
|
#attachmentNotificationBox > notification .messageImage {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
background-image: url(chrome://messenger/skin/messengercompose/compose-toolbar.png);
|
||||||
|
background-position: left -66px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachmentReminderText {
|
||||||
|
-moz-margin-start: 0px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachmentKeywords {
|
||||||
|
font-weight: bold;
|
||||||
|
-moz-margin-start: 0px;
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX I should really have a selector rule here to select just .listcell-icon objects underneath the attachmentList listbox */
|
/* XXX I should really have a selector rule here to select just .listcell-icon objects underneath the attachmentList listbox */
|
||||||
|
|
||||||
.listcell-icon
|
.listcell-icon
|
||||||
|
|
|
@ -346,6 +346,27 @@ toolbar[iconsize="small"] #paste-button[disabled="true"] {
|
||||||
height: 7px;
|
height: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ::::: attachment reminder ::::: */
|
||||||
|
|
||||||
|
#attachmentNotificationBox > notification .messageImage {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background-image: url(chrome://messenger/skin/messengercompose/compose-toolbar.png);
|
||||||
|
background-position: -96px top;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachmentReminderText {
|
||||||
|
-moz-margin-start: 0px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachmentKeywords {
|
||||||
|
font-weight: bold;
|
||||||
|
-moz-margin-start: 0px;
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX I should really have a selector rule here to select just .listcell-icon objects underneath the attachmentList listbox */
|
/* XXX I should really have a selector rule here to select just .listcell-icon objects underneath the attachmentList listbox */
|
||||||
|
|
||||||
.listcell-icon
|
.listcell-icon
|
||||||
|
|
|
@ -307,6 +307,27 @@ toolbar[iconsize="small"] #paste-button[disabled="true"] {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ::::: attachment reminder ::::: */
|
||||||
|
|
||||||
|
#attachmentNotificationBox > notification .messageImage {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
background-image: url(chrome://messenger/skin/messengercompose/compose-toolbar.png);
|
||||||
|
background-position: -72px top;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachmentReminderText {
|
||||||
|
-moz-margin-start: 0px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachmentKeywords {
|
||||||
|
font-weight: bold;
|
||||||
|
-moz-margin-start: 0px;
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX I should really have a selector rule here to select just .listcell-icon objects underneath the attachmentList listbox */
|
/* XXX I should really have a selector rule here to select just .listcell-icon objects underneath the attachmentList listbox */
|
||||||
|
|
||||||
.listcell-icon
|
.listcell-icon
|
||||||
|
|
Загрузка…
Ссылка в новой задаче