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:
Jim Porter 2014-05-25 18:51:59 -05:00
Родитель 51792b22f3
Коммит 9b8912dd85
5 изменённых файлов: 143 добавлений и 92 удалений

Просмотреть файл

@ -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