Bug 131571 - [RFE] when clicking on a mail adress that is already in the adressbook the option should be "edit address book entry", not "add to address book" r=mnyromyr

This commit is contained in:
Ian Neal 2012-06-09 23:40:07 +01:00
Родитель e431698ec8
Коммит 3fcd7dcd81
5 изменённых файлов: 245 добавлений и 42 удалений

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

@ -5,6 +5,10 @@
<!-- Message Header View Popup -->
<!ENTITY AddToAddressBook.label "Add To Address Book…">
<!ENTITY AddToAddressBook.accesskey "B">
<!ENTITY EditContact.label "Edit Contact…">
<!ENTITY EditContact.accesskey "E">
<!ENTITY ViewContact.label "View Contact">
<!ENTITY ViewContact.accesskey "V">
<!ENTITY SendMailTo.label "Compose Mail To…">
<!ENTITY SendMailTo.accesskey "s">
<!ENTITY CopyEmailAddress.label "Copy Email Address">

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

@ -415,11 +415,11 @@ function ShowSeparator(aSeparatorID)
}
// message pane context menu helper methods
function AddNodeToAddressBook(emailAddressNode)
function AddContact(aEmailAddressNode)
{
if (emailAddressNode)
AddEmailToAddressBook(emailAddressNode.getAttribute("emailAddress"),
emailAddressNode.getAttribute("displayName"));
if (aEmailAddressNode)
AddEmailToAddressBook(aEmailAddressNode.getAttribute("emailAddress"),
aEmailAddressNode.getAttribute("displayName"));
}
function AddEmailToAddressBook(primaryEmail, displayName)
@ -429,6 +429,17 @@ function AddEmailToAddressBook(primaryEmail, displayName)
{primaryEmail:primaryEmail, displayName:displayName});
}
function EditContact(aEmailAddressNode)
{
if (aEmailAddressNode.cardDetails.card)
{
window.openDialog("chrome://messenger/content/addressbook/abEditCardDialog.xul",
"", "chrome,resizable=no,modal,titlebar,centerscreen",
{ abURI: aEmailAddressNode.cardDetails.book.URI,
card: aEmailAddressNode.cardDetails.card });
}
}
// SendMailToNode takes the email address title button, extracts
// the email address we stored in there and opens a compose window
// with that address

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

@ -312,12 +312,12 @@
try
{
if ("AddExtraAddressProcessing" in top)
AddExtraAddressProcessing(aAddress.emailAddress, aEmailNode);
if ("UpdateEmailNodeDetails" in top)
UpdateEmailNodeDetails(aAddress.emailAddress, aEmailNode);
}
catch(ex)
{
dump("AddExtraAddressProcessing failed: " + ex + "\n");
dump("UpdateEmailNodeDetails failed: " + ex + "\n");
}
]]>
</body>
@ -389,6 +389,11 @@
while (index < numAddresses && index < aNumAddressesToShow)
{
var newAddressNode = document.createElement("mail-emailaddress");
// Stash the headerName somewhere that UpdateEmailNodeDetails
// will be able to find it.
newAddressNode.setAttribute("headerName", this.headerName);
if (index)
{
var textNode = document.createElement("text");

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

@ -91,6 +91,10 @@ var gExpandedHeaderList = [ {name:"subject"},
{name:"content-base"},
{name:"tags"} ];
// These are all the items that use a mail-multi-emailHeaderField widget and
// therefore may require updating if the address book changes.
const gEmailAddressHeaderNames = ["from", "reply-to", "to", "cc", "bcc"];
// Now, for each view the message pane can generate, we need a global table of headerEntries. These
// header entry objects are generated dynamically based on the static data in the header lists (see above)
// and elements we find in the DOM based on properties in the header lists.
@ -113,6 +117,10 @@ var currentHeaderData = {};
// isExternalAttachment --> boolean flag stating whether the attachment is external or not.
var currentAttachments = new Array();
const nsIAbDirectory = Components.interfaces.nsIAbDirectory;
const nsIAbListener = Components.interfaces.nsIAbListener;
const nsIAbCard = Components.interfaces.nsIAbCard;
// createHeaderEntry --> our constructor method which creates a header Entry
// based on an entry in one of the header lists. A header entry is different from a header list.
// a header list just describes how you want a particular header to be presented. The header entry
@ -157,6 +165,12 @@ function createHeaderEntry(prefix, headerListInfo)
this.outputFunction = headerListInfo.outputFunction;
else
this.outputFunction = updateHeaderValue;
// Stash this so that the <mail-multi-emailheaderfield/> binding can
// later attach it to any <mail-emailaddress> tags it creates for later
// extraction and use by UpdateEmailNodeDetails.
this.enclosingBox.headerName = headerListInfo.name;
}
function initializeHeaderViewTables()
@ -225,6 +239,12 @@ function OnLoadMsgHeaderPane()
initializeHeaderViewTables();
// Add an address book listener so we can update the header view when things
// change.
Components.classes["@mozilla.org/abmanager;1"]
.getService(Components.interfaces.nsIAbManager)
.addAddressBookListener(AddressBookListener, nsIAbListener.all);
var toggleHeaderView = GetHeaderPane();
var initialCollapsedSetting = toggleHeaderView.getAttribute("state");
if (initialCollapsedSetting == "true")
@ -240,6 +260,10 @@ function OnUnloadMsgHeaderPane()
{
pref.removeObserver("mail.showCondensedAddresses", MsgHdrViewObserver);
Components.classes["@mozilla.org/abmanager;1"]
.getService(Components.interfaces.nsIAbManager)
.removeAddressBookListener(AddressBookListener);
// dispatch an event letting any listeners know that we have unloaded the message pane
var event = document.createEvent('Events');
event.initEvent('messagepane-unloaded', false, true);
@ -262,6 +286,53 @@ const MsgHdrViewObserver =
}
};
var AddressBookListener =
{
onItemAdded: function(aParentDir, aItem) {
OnAddressBookDataChanged(nsIAbListener.itemAdded,
aParentDir, aItem);
},
onItemRemoved: function(aParentDir, aItem) {
OnAddressBookDataChanged(aItem instanceof nsIAbCard ?
nsIAbListener.directoryItemRemoved :
nsIAbListener.directoryRemoved,
aParentDir, aItem);
},
onItemPropertyChanged: function(aItem, aProperty, aOldValue, aNewValue) {
// We only need updates for card changes, address book and mailing list
// ones don't affect us here.
if (aItem instanceof nsIAbCard)
OnAddressBookDataChanged(nsIAbListener.itemChanged, null, aItem);
}
};
function OnAddressBookDataChanged(aAction, aParentDir, aItem)
{
gEmailAddressHeaderNames.forEach(function (aHeaderName)
{
var headerEntry = null;
// Ensure both collapsed and expanded are updated in case we toggle
// between the two.
if (aHeaderName in gCollapsedHeaderView)
{
headerEntry = gCollapsedHeaderView[aHeaderName];
if (headerEntry)
headerEntry.enclosingBox.updateExtraAddressProcessing(aAction,
aParentDir,
aItem);
}
if (aHeaderName in gExpandedHeaderView)
{
headerEntry = gExpandedHeaderView[aHeaderName];
if (headerEntry)
headerEntry.enclosingBox.updateExtraAddressProcessing(aAction,
aParentDir,
aItem);
}
});
}
// The messageHeaderSink is the class that gets notified of a message's headers as we display the message
// through our mime converter.
@ -1076,69 +1147,167 @@ function setFromBuddyIcon(email)
function updateEmailAddressNode(emailAddressNode, address)
{
emailAddressNode.setAttribute("label", address.fullAddress || address.displayName);
emailAddressNode.setAttribute("emailAddress", address.emailAddress);
emailAddressNode.setAttribute("fullAddress", address.fullAddress);
emailAddressNode.setAttribute("displayName", address.displayName);
emailAddressNode.removeAttribute("tooltiptext");
AddExtraAddressProcessing(address.emailAddress, emailAddressNode);
UpdateEmailNodeDetails(address.emailAddress, emailAddressNode);
}
// If the email address is found in any of the address books,
// then consider this user a 'known' user and use the display name.
function AddExtraAddressProcessing(emailAddress, addressNode)
function UpdateEmailNodeDetails(aEmailAddress, aDocumentNode, aCardDetails)
{
if (!gShowCondensedEmailAddresses)
return;
// If we haven't been given specific details, search for a card.
var cardDetails = aCardDetails || GetCardForEmail(aEmailAddress);
aDocumentNode.cardDetails = cardDetails;
var condense = gShowCondensedEmailAddresses;
// Get the id of the mail-multi-emailHeaderField binding parent.
var parentElementId = addressNode.parentNode.parentNode.parentNode.id;
var parentElementId = aDocumentNode.parentNode.parentNode.parentNode.id;
// Don't condense the address for the from and reply-to fields.
// Ids: "collapsedfromValue", "expandedfromBox", "expandedreply-toBox".
if (/^(collapsedfromValue|expanded(from|reply-to)Box)$/.test(parentElementId))
return;
condense = false;
// TODO: Maybe do domain matches too (i.e. any email from someone in my
// company should use the friendly display name).
var displayName = "";
if (condense && cardDetails.card)
displayName = cardDetails.card.displayName;
var card = getCardForAddress(emailAddress);
if (!(card && card.displayName))
return;
if (displayName)
{
aDocumentNode.setAttribute("tooltiptext", aEmailAddress);
}
else
{
aDocumentNode.removeAttribute("tooltiptext");
displayName = aDocumentNode.getAttribute("fullAddress") ||
aDocumentNode.getAttribute("displayName");
}
addressNode.setAttribute("label", card.displayName);
addressNode.setAttribute("tooltiptext", emailAddress);
aDocumentNode.setAttribute("label", displayName);
}
function fillEmailAddressPopup(emailAddressNode)
function UpdateExtraAddressProcessing(aAddressData, aDocumentNode, aAction,
aParentDir, aItem)
{
switch (aAction)
{
case nsIAbListener.itemChanged:
if (aAddressData &&
aDocumentNode.cardDetails.card &&
aItem.hasEmailAddress(aAddressData.emailAddress)) {
aDocumentNode.cardDetails.card = aItem;
UpdateEmailNodeDetails(aAddressData.emailAddress, aDocumentNode,
aDocumentNode.cardDetails);
}
break;
case nsIAbListener.itemAdded:
// Is it a new address book?
if (aItem instanceof nsIAbDirectory)
{
// If we don't have a match, search again for updates (e.g. a interface
// to an existing book may just have been added).
if (!aDocumentNode.cardDetails.card)
UpdateEmailNodeDetails(aAddressData.emailAddress, aDocumentNode);
}
else if (aItem instanceof nsIAbCard)
{
// If we don't have a card, does this new one match?
if (!aDocumentNode.cardDetails.card &&
aItem.hasEmailAddress(aAddressData.emailAddress))
{
// Just in case we have a bogus parent directory.
if (aParentDir instanceof nsIAbDirectory)
{
let cardDetails = { book: aParentDir, card: aItem };
UpdateEmailNodeDetails(aAddressData.emailAddress, aDocumentNode,
cardDetails);
}
else
{
UpdateEmailNodeDetails(aAddressData.emailAddress, aDocumentNode);
}
}
}
break;
case nsIAbListener.directoryItemRemoved:
// Unfortunately we don't necessarily get the same card object back.
if (aAddressData &&
aDocumentNode.cardDetails.card &&
aDocumentNode.cardDetails.book == aParentDir &&
aItem.hasEmailAddress(aAddressData.emailAddress))
{
UpdateEmailNodeDetails(aAddressData.emailAddress, aDocumentNode);
}
break;
case nsIAbListener.directoryRemoved:
if (aDocumentNode.cardDetails.book == aItem)
UpdateEmailNodeDetails(aAddressData.emailAddress, aDocumentNode);
break;
}
}
function SetupEmailAddressPopup(aAddressNode)
{
document.getElementById("emailAddressPlaceHolder")
.setAttribute("label", emailAddressNode.getAttribute("emailAddress"));
.setAttribute("label", aAddressNode.getAttribute("emailAddress"));
var addItem = document.getElementById("addToAddressBookItem");
var editItem = document.getElementById("editContactItem");
var viewItem = document.getElementById("viewContactItem");
if (aAddressNode.cardDetails.card)
{
addItem.setAttribute("hidden", true);
if (!aAddressNode.cardDetails.book.readOnly)
{
editItem.removeAttribute("hidden");
viewItem.setAttribute("hidden", true);
}
else
{
editItem.setAttribute("hidden", true);
viewItem.removeAttribute("hidden");
}
}
else
{
addItem.removeAttribute("hidden");
editItem.setAttribute("hidden", true);
viewItem.setAttribute("hidden", true);
}
}
/**
* Returns a card matching the given address, or |null|.
* Searches all (searchable) address books, until a (first) card is found.
* Returns an object with two properties, book and card. If the email address
* is found in the address books, then book will contain an nsIAbDirectory,
* and card will contain an nsIAbCard. If the email address is not found, both
* properties will be null.
*
* @param emailAddress The email address to find.
* @return A card, or |null|.
* @return An object with two properties, book and card.
* @see nsIAbDirectory.cardForEmailAddress()
*/
function getCardForAddress(emailAddress)
function GetCardForEmail(aEmailAddress)
{
var books = Components.classes["@mozilla.org/abmanager;1"]
.getService(Components.interfaces.nsIAbManager)
.directories;
while (books.hasMoreElements())
var result = { book: null, card: null};
while (!result.card && books.hasMoreElements())
{
var ab = books.getNext();
if (ab instanceof Components.interfaces.nsIAbDirectory)
if (ab instanceof nsIAbDirectory)
{
try
{
var card = ab.cardForEmailAddress(emailAddress);
var card = ab.cardForEmailAddress(aEmailAddress);
if (card)
return card;
{
result.book = ab;
result.card = card;
}
}
catch (ex)
{
@ -1147,7 +1316,7 @@ function getCardForAddress(emailAddress)
}
}
return null;
return result;
}
/**

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

@ -50,20 +50,34 @@
</menupopup>
<menupopup id="emailAddressPopup" popupanchor="bottomleft"
onpopupshowing="fillEmailAddressPopup(document.popupNode);
goUpdateCommand('cmd_createFilterFromPopup');">
onpopupshowing="SetupEmailAddressPopup(document.popupNode);
goUpdateCommand('cmd_createFilterFromPopup');">
<menuitem id="emailAddressPlaceHolder" label="" disabled="true"/>
<menuseparator/>
<menuitem label="&SendMailTo.label;"
<menuitem id="sendMailToItem"
label="&SendMailTo.label;"
accesskey="&SendMailTo.accesskey;"
oncommand="SendMailToNode(document.popupNode)"/>
<menuitem label="&CreateFilterFrom.label;"
<menuitem id="createFilterFromItem"
label="&CreateFilterFrom.label;"
accesskey="&CreateFilterFrom.accesskey;"
command="cmd_createFilterFromPopup"/>
<menuitem label="&AddToAddressBook.label;"
<menuitem id="addToAddressBookItem"
label="&AddToAddressBook.label;"
accesskey="&AddToAddressBook.accesskey;"
oncommand="AddNodeToAddressBook(document.popupNode)"/>
<menuitem label="&CopyEmailAddress.label;"
oncommand="AddContact(document.popupNode);"/>
<menuitem id="editContactItem"
label="&EditContact.label;"
accesskey="&EditContact.accesskey;"
hidden="true"
oncommand="EditContact(document.popupNode);"/>
<menuitem id="viewContactItem"
label="&ViewContact.label;"
accesskey="&ViewContact.accesskey;"
hidden="true"
oncommand="EditContact(document.popupNode);"/>
<menuitem id="copyEmailAddressItem"
label="&CopyEmailAddress.label;"
accesskey="&CopyEmailAddress.accesskey;"
oncommand="CopyEmailAddress(document.popupNode)"/>
</menupopup>