Dactyloidae/mailnews/addrbook/content/abMailListDialog.js

613 lines
17 KiB
JavaScript

/* 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/. */
top.MAX_RECIPIENTS = 1;
var inputElementType = "";
var gListCard;
var gEditList;
var oldListName = "";
var gLoadListeners = [];
var gSaveListeners = [];
try
{
var gDragService = Components.classes["@mozilla.org/widget/dragservice;1"]
.getService(Components.interfaces.nsIDragService);
}
catch (e)
{
}
// Returns the load context for the current window
function getLoadContext() {
return window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsILoadContext);
}
function awHandleKeyPress(element, event)
{
// allow dialog to close on enter if focused textbox has no value
if (element.value != "" && event.keyCode == KeyEvent.DOM_VK_RETURN) {
event.stopPropagation();
event.preventDefault();
}
}
function mailingListExists(listname)
{
if (MailServices.ab.mailListNameExists(listname))
{
Services.prompt.alert(window,
gAddressBookBundle.getString("mailListNameExistsTitle"),
gAddressBookBundle.getString("mailListNameExistsMessage"));
return true;
}
return false;
}
function GetListValue(mailList, doAdd)
{
var listname = document.getElementById("ListName").value.trim();
if (listname.length == 0)
{
var alertText = gAddressBookBundle.getString("emptyListName");
alert(alertText);
return false;
}
else
{
var canonicalNewListName = listname.toLowerCase();
var canonicalOldListName = oldListName.toLowerCase();
if (doAdd)
{
if (mailingListExists(canonicalNewListName))
return false;
}
else if (canonicalOldListName != canonicalNewListName)
{
if (mailingListExists(canonicalNewListName))
return false;
}
}
mailList.isMailList = true;
mailList.dirName = listname;
mailList.listNickName = document.getElementById('ListNickName').value;
mailList.description = document.getElementById('ListDescription').value;
var oldTotal = mailList.addressLists.length;
var i = 1;
var pos = 0;
var inputField, fieldValue, cardproperty;
while ((inputField = awGetInputElement(i)))
{
fieldValue = inputField.value;
if (doAdd || (!doAdd && pos >= oldTotal))
cardproperty = Components.classes["@mozilla.org/addressbook/cardproperty;1"].createInstance();
else
cardproperty = mailList.addressLists.queryElementAt(pos, Components.interfaces.nsIAbCard);
if (fieldValue == "")
{
if (!doAdd && cardproperty)
try
{
mailList.addressLists.removeElementAt(pos);
--oldTotal;
}
catch(ex)
{
// Ignore attempting to remove an item
// at a position greater than the number
// of elements in the addressLists attribute
}
}
else if (cardproperty)
{
cardproperty = cardproperty.QueryInterface(Components.interfaces.nsIAbCard);
if (cardproperty)
{
let addrObjects = MailServices.headerParser
.makeFromDisplayAddress(fieldValue, {});
for (let j = 0; j < addrObjects.length; j++)
{
if (j > 0)
{
cardproperty = Components.classes["@mozilla.org/addressbook/cardproperty;1"].createInstance();
cardproperty = cardproperty.QueryInterface(Components.interfaces.nsIAbCard);
}
cardproperty.primaryEmail = addrObjects[j].email;
cardproperty.displayName = addrObjects[j].name || addrObjects[j].email;
if (doAdd || (doAdd == false && pos >= oldTotal))
mailList.addressLists.appendElement(cardproperty, false);
}
pos++;
}
}
i++;
}
--i;
if (doAdd == false && i < oldTotal)
{
for (var j = i; j < oldTotal; j++)
mailList.addressLists.removeElementAt(j);
}
return true;
}
function MailListOKButton()
{
var popup = document.getElementById('abPopup');
if (popup)
{
var uri = popup.getAttribute('value');
// FIX ME - hack to avoid crashing if no ab selected because of blank option bug from template
// should be able to just remove this if we are not seeing blank lines in the ab popup
if (!uri)
return false; // don't close window
// -----
//Add mailing list to database
var mailList = Components.classes["@mozilla.org/addressbook/directoryproperty;1"].createInstance();
mailList = mailList.QueryInterface(Components.interfaces.nsIAbDirectory);
if (GetListValue(mailList, true))
{
var parentDirectory = GetDirectoryFromURI(uri);
mailList = parentDirectory.addMailList(mailList);
NotifySaveListeners(mailList);
}
else
return false;
}
return true; // close the window
}
function OnLoadNewMailList()
{
var selectedAB = null;
InitCommonJS();
if ("arguments" in window && window.arguments[0])
{
var abURI = window.arguments[0].selectedAB;
if (abURI && abURI != kAllDirectoryRoot + "?") {
var directory = GetDirectoryFromURI(abURI);
if (directory.isMailList) {
var parentURI = GetParentDirectoryFromMailingListURI(abURI);
if (parentURI) {
selectedAB = parentURI;
}
}
else if (directory.readOnly) {
selectedAB = kPersonalAddressbookURI;
}
else {
selectedAB = abURI;
}
}
}
if (!selectedAB)
selectedAB = kPersonalAddressbookURI;
// set popup with address book names
var abPopup = document.getElementById('abPopup');
abPopup.value = selectedAB;
AppendNewRowAndSetFocus();
awFitDummyRows(1);
document.addEventListener("keypress", awDocumentKeyPress, true);
// focus on first name
var listName = document.getElementById('ListName');
if (listName)
setTimeout( function(firstTextBox) { firstTextBox.focus(); }, 0, listName );
NotifyLoadListeners(directory);
}
function EditListOKButton()
{
//edit mailing list in database
if (GetListValue(gEditList, false))
{
if (gListCard) {
// modify the list card (for the results pane) from the mailing list
gListCard.displayName = gEditList.dirName;
gListCard.lastName = gEditList.dirName;
gListCard.setProperty("NickName", gEditList.listNickName);
gListCard.setProperty("Notes", gEditList.description);
}
NotifySaveListeners(gEditList);
gEditList.editMailListToDatabase(gListCard);
window.arguments[0].refresh = true;
return true; // close the window
}
return false;
}
function OnLoadEditList()
{
InitCommonJS();
gListCard = window.arguments[0].abCard;
var listUri = window.arguments[0].listURI;
gEditList = GetDirectoryFromURI(listUri);
document.getElementById('ListName').value = gEditList.dirName;
document.getElementById('ListNickName').value = gEditList.listNickName;
document.getElementById('ListDescription').value = gEditList.description;
oldListName = gEditList.dirName;
document.title = gAddressBookBundle.getFormattedString("mailingListTitleEdit", [oldListName]);
if (gEditList.addressLists)
{
let total = gEditList.addressLists.length;
if (total)
{
let listbox = document.getElementById('addressingWidget');
let newListBoxNode = listbox.cloneNode(false);
let templateNode = listbox.querySelector("listitem");
top.MAX_RECIPIENTS = 0;
for (let i = 0; i < total; i++)
{
let card = gEditList.addressLists.queryElementAt(i, Components.interfaces.nsIAbCard);
let address = MailServices.headerParser.makeMailboxObject(
card.displayName, card.primaryEmail).toString();
SetInputValue(address, newListBoxNode, templateNode);
}
listbox.parentNode.replaceChild(newListBoxNode, listbox);
}
}
// Is this directory read-only? If so, we now need to set all the fields to
// read-only.
if (gEditList.readOnly) {
const kMailListFields = [ 'ListName', 'ListNickName', 'ListDescription' ];
for (let i = 0; i < kMailListFields.length; ++i)
document.getElementById(kMailListFields[i]).readOnly = true;
document.documentElement.buttons = "accept";
document.documentElement.removeAttribute("ondialogaccept");
// Getting a sane read-only implementation for the addressing widget would
// basically need a separate dialog. Given I'm not sure about the future of
// the mailing list dialog in its current state, let's just disable it
// completely.
document.getElementById("addressingWidget").disabled = true;
}
document.addEventListener("keypress", awDocumentKeyPress, true);
// workaround for bug 118337 - for mailing lists that have more rows than fits inside
// the display, the value of the textbox inside the new row isn't inherited into the input -
// the first row then appears to be duplicated at the end although it is actually empty.
// see awAppendNewRow which copies first row and clears it
setTimeout(AppendLastRow, 0);
NotifyLoadListeners(gEditList);
}
function AppendLastRow()
{
AppendNewRowAndSetFocus();
awFitDummyRows(1);
// focus on first name
var listName = document.getElementById('ListName');
if (listName)
listName.focus();
}
function AppendNewRowAndSetFocus()
{
var lastInput = awGetInputElement(top.MAX_RECIPIENTS);
if (lastInput && lastInput.value)
awAppendNewRow(true);
else
awSetFocus(top.MAX_RECIPIENTS, lastInput);
}
function SetInputValue(inputValue, parentNode, templateNode)
{
top.MAX_RECIPIENTS++;
var newNode = templateNode.cloneNode(true);
parentNode.appendChild(newNode); // we need to insert the new node before we set the value of the select element!
var input = newNode.getElementsByTagName(awInputElementName());
if (input && input.length == 1)
{
//We need to set the value using both setAttribute and .value else we will
// lose the content when the field is not visible. See bug 37435
input[0].setAttribute("value", inputValue);
input[0].value = inputValue;
input[0].setAttribute("id", "addressCol1#" + top.MAX_RECIPIENTS);
}
}
function awNotAnEmptyArea(event)
{
//This is temporary until i figure out how to ensure to always having an empty space after the last row
var lastInput = awGetInputElement(top.MAX_RECIPIENTS);
if (lastInput && lastInput.value)
awAppendNewRow(false);
event.stopPropagation();
}
function awClickEmptySpace(target, setFocus)
{
if (target == null ||
(target.localName != "listboxbody" &&
target.localName != "listcell" &&
target.localName != "listitem"))
return;
var lastInput = awGetInputElement(top.MAX_RECIPIENTS);
if (lastInput && lastInput.value)
awAppendNewRow(setFocus);
else
if (setFocus)
awSetFocus(top.MAX_RECIPIENTS, lastInput);
}
function awReturnHit(inputElement)
{
var row = awGetRowByInputElement(inputElement);
if (inputElement.value)
{
var nextInput = awGetInputElement(row+1);
if (!nextInput)
awAppendNewRow(true);
else
awSetFocus(row+1, nextInput);
}
}
function awDeleteRow(rowToDelete)
{
/* When we delete a row, we must reset the id of others row in order to not break the sequence */
var maxRecipients = top.MAX_RECIPIENTS;
awRemoveRow(rowToDelete);
var numberOfCols = awGetNumberOfCols();
for (var row = rowToDelete + 1; row <= maxRecipients; row ++)
for (var col = 1; col <= numberOfCols; col++)
awGetElementByCol(row, col).setAttribute("id", "addressCol" + (col) + "#" + (row-1));
awTestRowSequence();
}
function awInputChanged(inputElement)
{
// AutoCompleteAddress(inputElement);
//Do we need to add a new row?
var lastInput = awGetInputElement(top.MAX_RECIPIENTS);
if (lastInput && lastInput.value && !top.doNotCreateANewRow)
awAppendNewRow(false);
top.doNotCreateANewRow = false;
}
function awInputElementName()
{
if (inputElementType == "")
inputElementType = document.getElementById("addressCol1#1").localName;
return inputElementType;
}
function awAppendNewRow(setFocus)
{
var body = document.getElementById("addressingWidget");
var listitem1 = awGetListItem(1);
if (body && listitem1)
{
var nextDummy = awGetNextDummyRow();
var newNode = listitem1.cloneNode(true);
if (nextDummy)
body.replaceChild(newNode, nextDummy);
else
body.appendChild(newNode);
top.MAX_RECIPIENTS++;
var input = newNode.getElementsByTagName(awInputElementName());
if (input && input.length == 1)
{
input[0].setAttribute("value", "");
input[0].setAttribute("id", "addressCol1#" + top.MAX_RECIPIENTS);
if (input[0].getAttribute('focused') != '')
input[0].removeAttribute('focused');
}
// focus on new input widget
if (setFocus && input )
awSetFocus(top.MAX_RECIPIENTS, input[0]);
}
}
// functions for accessing the elements in the addressing widget
function awGetInputElement(row)
{
return document.getElementById("addressCol1#" + row);
}
function _awSetFocus()
{
var listbox = document.getElementById('addressingWidget');
try
{
var theNewRow = awGetListItem(top.awRow);
listbox.ensureElementIsVisible(theNewRow);
top.awInputElement.focus();
}
catch(ex)
{
top.awFocusRetry ++;
if (top.awFocusRetry < 8)
{
dump("_awSetFocus failed, try it again...\n");
setTimeout(_awSetFocus, 0);
}
else
dump("_awSetFocus failed, forget about it!\n");
}
}
function awTabFromRecipient(element, event)
{
//If we are the last element in the listbox, we don't want to create a new row.
if (element == awGetInputElement(top.MAX_RECIPIENTS))
top.doNotCreateANewRow = true;
}
function DragOverAddressListTree(event)
{
var validFlavor = false;
var dragSession = gDragService.getCurrentSession();
// XXX add support for other flavors here
if (dragSession.isDataFlavorSupported("text/x-moz-address")) {
dragSession.canDrop = true;
}
}
function DropOnAddressListTree(event)
{
let dragSession = gDragService.getCurrentSession();
let trans;
try {
trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
trans.init(getLoadContext());
trans.addDataFlavor("text/x-moz-address");
}
catch (ex) {
return;
}
for (let i = 0; i < dragSession.numDropItems; ++i)
{
dragSession.getData(trans, i);
let dataObj = new Object();
let bestFlavor = new Object();
let len = new Object();
trans.getAnyTransferData(bestFlavor, dataObj, len);
if (dataObj)
dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString);
if (!dataObj)
continue;
// pull the URL out of the data object
let address = dataObj.data.substring(0, len.value);
if (!address)
continue;
DropListAddress(event.target, address);
}
}
function DropListAddress(target, address)
{
// Set focus on a new available, visible row.
awClickEmptySpace(target, true);
if (top.MAX_RECIPIENTS == 0)
top.MAX_RECIPIENTS = 1;
// Break apart the MIME-ready header address into individual addressees to
// add to the dialog.
let addresses = {}, names = {}, fullNames = {};
MailServices.headerParser.parseHeadersWithArray(address, addresses, names,
fullNames);
for (let full of fullNames.value)
{
let lastInput = awGetInputElement(top.MAX_RECIPIENTS);
lastInput.value = full;
awAppendNewRow(true);
}
}
/* Allows extensions to register a listener function for
* when a mailing list is loaded. The listener function
* should take two parameters - the first being the
* mailing list being loaded, the second one being the
* current window document.
*/
function RegisterLoadListener(aListener)
{
gLoadListeners.push(aListener);
}
/* Allows extensions to unload a load listener function.
*/
function UnregisterLoadListener(aListener)
{
var fIndex = gLoadListeners.indexOf(aListener);
if (fIndex != -1)
gLoadListeners.splice(fIndex, 1);
}
/* Allows extensions to register a listener function for
* when a mailing list is saved. Like a load listener,
* the save listener should take two parameters: the first
* being a copy of the mailing list that is being saved,
* and the second being the current window document.
*/
function RegisterSaveListener(aListener)
{
gSaveListeners.push(aListener);
}
/* Allows extensions to unload a save listener function.
*/
function UnregisterSaveListener(aListener)
{
var fIndex = gSaveListeners.indexOf(aListener);
if (fIndex != -1)
gSaveListeners.splice(fIndex, 1);
}
/* Notifies all load listeners.
*/
function NotifyLoadListeners(aMailingList)
{
for (let i = 0; i < gLoadListeners.length; i++)
gLoadListeners[i](aMailingList, document);
}
/* Notifies all save listeners.
*/
function NotifySaveListeners(aMailingList)
{
for (let i = 0; i < gSaveListeners.length; i++)
gSaveListeners[i](aMailingList, document);
}