Bug 942638 - Clean up the multi-message summary code, part 7: Move FormatDisplayName and friends to a JS module (to help Mail Summaries); r=mconley
This commit is contained in:
Родитель
51792b22f3
Коммит
9b8912dd85
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||||
|
Components.utils.import("resource:///modules/displayNameUtils.js");
|
||||||
Components.utils.import("resource:///modules/mailServices.js");
|
Components.utils.import("resource:///modules/mailServices.js");
|
||||||
Components.utils.import("resource:///modules/gloda/utils.js");
|
Components.utils.import("resource:///modules/gloda/utils.js");
|
||||||
let {Status: statusUtils} =
|
let {Status: statusUtils} =
|
||||||
|
@ -1249,59 +1250,9 @@ function updateEmailAddressNode(emailAddressNode, address)
|
||||||
UpdateEmailNodeDetails(address.emailAddress, emailAddressNode);
|
UpdateEmailNodeDetails(address.emailAddress, emailAddressNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Take an email address and compose a sensible display name based on the
|
|
||||||
* header display name and/or the display name from the address book. If no
|
|
||||||
* appropriate name can be made (e.g. there is no card for this address),
|
|
||||||
* returns |null|.
|
|
||||||
*
|
|
||||||
* @param aEmailAddress the email address to format
|
|
||||||
* @param aHeaderDisplayName the display name from the header, if any
|
|
||||||
* @param aContext the field being formatted (e.g. "to", "from")
|
|
||||||
* @param aCard the address book card, if any
|
|
||||||
* @return The formatted display name, or null
|
|
||||||
*/
|
|
||||||
function FormatDisplayName(aEmailAddress, aHeaderDisplayName, aContext, aCard)
|
|
||||||
{
|
|
||||||
var displayName = null;
|
|
||||||
var identity = getBestIdentity(accountManager.allIdentities, aEmailAddress);
|
|
||||||
var card = aCard || getCardForEmail(aEmailAddress).card;
|
|
||||||
|
|
||||||
// If this address is one of the user's identities...
|
|
||||||
if (aEmailAddress == identity.email) {
|
|
||||||
var bundle = document.getElementById("bundle_messenger");
|
|
||||||
// ...pick a localized version of the word "Me" appropriate to this
|
|
||||||
// specific header; fall back to the version used by the "to" header
|
|
||||||
// if nothing else is available.
|
|
||||||
try {
|
|
||||||
displayName = bundle.getString("header" + aContext + "FieldMe");
|
|
||||||
} catch (ex) {
|
|
||||||
displayName = bundle.getString("headertoFieldMe");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we have an unambiguous name if there are multiple identities
|
|
||||||
if (accountManager.allIdentities.length > 1)
|
|
||||||
displayName += " <"+identity.email+">";
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we don't have a card, refuse to generate a display name. Places calling
|
|
||||||
// this are then responsible for falling back to something else (e.g. the
|
|
||||||
// value from the message header).
|
|
||||||
if (card) {
|
|
||||||
if (!displayName && aHeaderDisplayName)
|
|
||||||
displayName = aHeaderDisplayName;
|
|
||||||
|
|
||||||
// getProperty may return a "1" or "0" string, we want a boolean
|
|
||||||
if (!displayName || card.getProperty("PreferDisplayName", true) != false)
|
|
||||||
displayName = card.displayName || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return displayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
function UpdateEmailNodeDetails(aEmailAddress, aDocumentNode, aCardDetails) {
|
function UpdateEmailNodeDetails(aEmailAddress, aDocumentNode, aCardDetails) {
|
||||||
// If we haven't been given specific details, search for a card.
|
// If we haven't been given specific details, search for a card.
|
||||||
var cardDetails = aCardDetails || getCardForEmail(aEmailAddress);
|
var cardDetails = aCardDetails || GetCardForEmail(aEmailAddress);
|
||||||
aDocumentNode.cardDetails = cardDetails;
|
aDocumentNode.cardDetails = cardDetails;
|
||||||
|
|
||||||
if (!cardDetails.card) {
|
if (!cardDetails.card) {
|
||||||
|
|
|
@ -6,13 +6,10 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
Components.utils.import("resource:///modules/gloda/gloda.js");
|
Components.utils.import("resource:///modules/gloda/gloda.js");
|
||||||
Components.utils.import("resource:///modules/gloda/connotent.js");
|
Components.utils.import("resource:///modules/gloda/connotent.js");
|
||||||
Components.utils.import("resource:///modules/gloda/mimemsg.js");
|
Components.utils.import("resource:///modules/gloda/mimemsg.js");
|
||||||
|
Components.utils.import("resource:///modules/displayNameUtils.js");
|
||||||
Components.utils.import("resource:///modules/mailServices.js");
|
Components.utils.import("resource:///modules/mailServices.js");
|
||||||
Components.utils.import("resource:///modules/templateUtils.js");
|
Components.utils.import("resource:///modules/templateUtils.js");
|
||||||
|
|
||||||
// This is executed in the context of the message summary page, not main chrome,
|
|
||||||
// but we need to access a few things from the main window.
|
|
||||||
var global = window.top;
|
|
||||||
|
|
||||||
var gMessenger = Components.classes["@mozilla.org/messenger;1"]
|
var gMessenger = Components.classes["@mozilla.org/messenger;1"]
|
||||||
.createInstance(Components.interfaces.nsIMessenger);
|
.createInstance(Components.interfaces.nsIMessenger);
|
||||||
|
|
||||||
|
@ -26,34 +23,6 @@ XPCOMUtils.defineLazyGetter(this, "formatString", function() {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Format the display name for the multi-message/thread summaries. First, try
|
|
||||||
* using FormatDisplayName, then fall back to the header's display name or the
|
|
||||||
* address.
|
|
||||||
*
|
|
||||||
* @param aHeaderParser An instance of |nsIMsgHeaderParser|.
|
|
||||||
* @param aHeaderValue The raw header value.
|
|
||||||
* @param aContext The context of the header field (e.g. "to", "from").
|
|
||||||
* @return The formatted display name.
|
|
||||||
*/
|
|
||||||
function _mm_FormatDisplayName(aHeaderParser, aHeaderValue, aContext) {
|
|
||||||
let addresses = {};
|
|
||||||
let fullNames = {};
|
|
||||||
let names = {};
|
|
||||||
let numAddresses = aHeaderParser.parseHeadersWithArray(aHeaderValue,
|
|
||||||
addresses, names, fullNames);
|
|
||||||
|
|
||||||
if (numAddresses > 0) {
|
|
||||||
return global.FormatDisplayName(
|
|
||||||
addresses.value[0], names.value[0], aContext
|
|
||||||
) || names.value[0] || addresses.value[0];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Something strange happened, just return the raw header value.
|
|
||||||
return aHeaderValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The MultiMessageSummary class is responsible for populating the message pane
|
* The MultiMessageSummary class is responsible for populating the message pane
|
||||||
* with a reasonable summary of a set of messages.
|
* with a reasonable summary of a set of messages.
|
||||||
|
@ -124,7 +93,8 @@ MultiMessageSummary.prototype = {
|
||||||
|
|
||||||
// Enable/disable the archive button as appropriate.
|
// Enable/disable the archive button as appropriate.
|
||||||
let archiveBtn = document.getElementById("hdrArchiveButton");
|
let archiveBtn = document.getElementById("hdrArchiveButton");
|
||||||
archiveBtn.collapsed = !global.gFolderDisplay.canArchiveSelectedMessages;
|
archiveBtn.collapsed = !window.top.gFolderDisplay
|
||||||
|
.canArchiveSelectedMessages;
|
||||||
|
|
||||||
let summarizer = this._summarizers[aType];
|
let summarizer = this._summarizers[aType];
|
||||||
if (!summarizer)
|
if (!summarizer)
|
||||||
|
@ -205,8 +175,8 @@ MultiMessageSummary.prototype = {
|
||||||
|
|
||||||
let authorNode = document.createElement("span");
|
let authorNode = document.createElement("span");
|
||||||
authorNode.classList.add("author");
|
authorNode.classList.add("author");
|
||||||
authorNode.textContent = _mm_FormatDisplayName(
|
authorNode.textContent = FormatDisplayNameList(
|
||||||
MailServices.headerParser, message.mime2DecodedAuthor, "from"
|
message.mime2DecodedAuthor, "from"
|
||||||
);
|
);
|
||||||
|
|
||||||
if (aOptions && aOptions.showSubject) {
|
if (aOptions && aOptions.showSubject) {
|
||||||
|
@ -218,7 +188,7 @@ MultiMessageSummary.prototype = {
|
||||||
subjectNode.textContent = message.mime2DecodedSubject ||
|
subjectNode.textContent = message.mime2DecodedSubject ||
|
||||||
formatString("noSubject");
|
formatString("noSubject");
|
||||||
subjectNode.addEventListener("click", function() {
|
subjectNode.addEventListener("click", function() {
|
||||||
global.gFolderDisplay.selectMessages(thread);
|
window.top.gFolderDisplay.selectMessages(thread);
|
||||||
}, false);
|
}, false);
|
||||||
itemHeaderNode.appendChild(subjectNode);
|
itemHeaderNode.appendChild(subjectNode);
|
||||||
|
|
||||||
|
@ -246,8 +216,8 @@ MultiMessageSummary.prototype = {
|
||||||
|
|
||||||
authorNode.classList.add("primary_header", "link");
|
authorNode.classList.add("primary_header", "link");
|
||||||
authorNode.addEventListener("click", function() {
|
authorNode.addEventListener("click", function() {
|
||||||
global.gFolderDisplay.selectMessage(message);
|
window.top.gFolderDisplay.selectMessage(message);
|
||||||
global.document.getElementById("messagepane").focus();
|
window.top.document.getElementById("messagepane").focus();
|
||||||
}, false);
|
}, false);
|
||||||
itemHeaderNode.appendChild(authorNode);
|
itemHeaderNode.appendChild(authorNode);
|
||||||
}
|
}
|
||||||
|
@ -569,9 +539,9 @@ MultipleSelectionSummarizer.prototype = {
|
||||||
let threads = {};
|
let threads = {};
|
||||||
let numThreads = 0;
|
let numThreads = 0;
|
||||||
for (let [,msgHdr] in Iterator(aMessages)) {
|
for (let [,msgHdr] in Iterator(aMessages)) {
|
||||||
let viewThreadId = global.gFolderDisplay.view.dbView
|
let viewThreadId = window.top.gFolderDisplay.view.dbView
|
||||||
.getThreadContainingMsgHdr(msgHdr)
|
.getThreadContainingMsgHdr(msgHdr)
|
||||||
.threadKey;
|
.threadKey;
|
||||||
if (!(viewThreadId in threads)) {
|
if (!(viewThreadId in threads)) {
|
||||||
threads[viewThreadId] = [msgHdr];
|
threads[viewThreadId] = [msgHdr];
|
||||||
numThreads++;
|
numThreads++;
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
/* 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/iteratorUtils.jsm");
|
||||||
|
Components.utils.import("resource:///modules/mailServices.js");
|
||||||
|
Components.utils.import("resource:///modules/StringBundle.js");
|
||||||
|
|
||||||
|
var EXPORTED_SYMBOLS = [
|
||||||
|
"GetCardForEmail", "FormatDisplayName", "FormatDisplayNameList",
|
||||||
|
];
|
||||||
|
|
||||||
|
// XXX: Maybe the strings for this file should go in a separate bundle?
|
||||||
|
var gMessengerBundle = new StringBundle(
|
||||||
|
"chrome://messenger/locale/messenger.properties"
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an object with two properties, .book and .card. If the email address
|
||||||
|
* is found in the address books, then the book will contain an nsIAbDirectory,
|
||||||
|
* and card will contain an nsIAbCard. If the email address is not found, both
|
||||||
|
* items will contain null.
|
||||||
|
*
|
||||||
|
* @param aEmailAddress The address to look for.
|
||||||
|
* @return An object with two properties, .book and .card.
|
||||||
|
*/
|
||||||
|
function GetCardForEmail(aEmailAddress) {
|
||||||
|
// Email address is searched for in any of the address books that support
|
||||||
|
// the cardForEmailAddress function.
|
||||||
|
// Future expansion could be to domain matches
|
||||||
|
let books = MailServices.ab.directories;
|
||||||
|
for (let book in fixIterator(books, Components.interfaces.nsIAbDirectory)) {
|
||||||
|
try {
|
||||||
|
let card = book.cardForEmailAddress(aEmailAddress);
|
||||||
|
if (card)
|
||||||
|
return { book: book, card: card };
|
||||||
|
}
|
||||||
|
catch (ex) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { book: null, card: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getIdentityForAddress(aEmailAddress) {
|
||||||
|
let emailAddress = aEmailAddress.toLowerCase();
|
||||||
|
for (let identity in fixIterator(MailServices.accounts.allIdentities,
|
||||||
|
Components.interfaces.nsIMsgIdentity)) {
|
||||||
|
if (!identity.email)
|
||||||
|
continue;
|
||||||
|
if (emailAddress == identity.email.toLowerCase())
|
||||||
|
return identity;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take an email address and compose a sensible display name based on the
|
||||||
|
* header display name and/or the display name from the address book. If no
|
||||||
|
* appropriate name can be made (e.g. there is no card for this address),
|
||||||
|
* returns |null|.
|
||||||
|
*
|
||||||
|
* @param aEmailAddress The email address to format.
|
||||||
|
* @param aHeaderDisplayName The display name from the header, if any.
|
||||||
|
* @param aContext The field being formatted (e.g. "to", "from").
|
||||||
|
* @param aCard The address book card, if any.
|
||||||
|
* @return The formatted display name, or null.
|
||||||
|
*/
|
||||||
|
function FormatDisplayName(aEmailAddress, aHeaderDisplayName, aContext, aCard)
|
||||||
|
{
|
||||||
|
var displayName = null;
|
||||||
|
var identity = _getIdentityForAddress(aEmailAddress);
|
||||||
|
var card = aCard || GetCardForEmail(aEmailAddress).card;
|
||||||
|
|
||||||
|
// If this address is one of the user's identities...
|
||||||
|
if (identity) {
|
||||||
|
// ...pick a localized version of the word "Me" appropriate to this
|
||||||
|
// specific header; fall back to the version used by the "to" header
|
||||||
|
// if nothing else is available.
|
||||||
|
try {
|
||||||
|
displayName = gMessengerBundle.getString("header" + aContext + "FieldMe");
|
||||||
|
} catch (e) {
|
||||||
|
displayName = gMessenberBundle.getString("headertoFieldMe");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we have an unambiguous name if there are multiple identities
|
||||||
|
if (MailServices.accounts.allIdentities.length > 1)
|
||||||
|
displayName += " <" + identity.email + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we don't have a card, refuse to generate a display name. Places calling
|
||||||
|
// this are then responsible for falling back to something else (e.g. the
|
||||||
|
// value from the message header).
|
||||||
|
if (card) {
|
||||||
|
if (!displayName && aHeaderDisplayName)
|
||||||
|
displayName = aHeaderDisplayName;
|
||||||
|
|
||||||
|
// getProperty may return a "1" or "0" string, we want a boolean
|
||||||
|
if (!displayName || card.getProperty("PreferDisplayName", true) != false)
|
||||||
|
displayName = card.displayName || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format the display name from a list of addresses. First, try using
|
||||||
|
* FormatDisplayName, then fall back to the header's display name or the
|
||||||
|
* address.
|
||||||
|
*
|
||||||
|
* @param aHeaderValue The raw header value.
|
||||||
|
* @param aContext The context of the header field (e.g. "to", "from").
|
||||||
|
* @return The formatted display name.
|
||||||
|
*/
|
||||||
|
function FormatDisplayNameList(aHeaderValue, aContext) {
|
||||||
|
let addresses = {}, fullNames = {}, names = {};
|
||||||
|
let numAddresses = MailServices.headerParser.parseHeadersWithArray(
|
||||||
|
aHeaderValue, addresses, names, fullNames
|
||||||
|
);
|
||||||
|
|
||||||
|
if (numAddresses > 0) {
|
||||||
|
return FormatDisplayName(addresses.value[0], names.value[0], aContext) ||
|
||||||
|
names.value[0] || addresses.value[0];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Something strange happened, just return the raw header value.
|
||||||
|
return aHeaderValue;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
EXTRA_JS_MODULES += [
|
EXTRA_JS_MODULES += [
|
||||||
'attachmentChecker.js',
|
'attachmentChecker.js',
|
||||||
'dbViewWrapper.js',
|
'dbViewWrapper.js',
|
||||||
|
'displayNameUtils.js',
|
||||||
'distribution.js',
|
'distribution.js',
|
||||||
'glodaWebSearch.js',
|
'glodaWebSearch.js',
|
||||||
'MailConsts.js',
|
'MailConsts.js',
|
||||||
|
|
|
@ -577,6 +577,7 @@ regxpcom.exe
|
||||||
modules/attachmentChecker.js
|
modules/attachmentChecker.js
|
||||||
modules/ctypes.jsm
|
modules/ctypes.jsm
|
||||||
modules/dbViewWrapper.js
|
modules/dbViewWrapper.js
|
||||||
|
modules/displayNameutils.js
|
||||||
modules/debug.js
|
modules/debug.js
|
||||||
modules/errUtils.js
|
modules/errUtils.js
|
||||||
modules/folderUtils.jsm
|
modules/folderUtils.jsm
|
||||||
|
|
Загрузка…
Ссылка в новой задаче