summaryrefslogtreecommitdiffstats
path: root/mailnews/addrbook/content/abMailListDialog.js
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/addrbook/content/abMailListDialog.js')
-rw-r--r--mailnews/addrbook/content/abMailListDialog.js613
1 files changed, 613 insertions, 0 deletions
diff --git a/mailnews/addrbook/content/abMailListDialog.js b/mailnews/addrbook/content/abMailListDialog.js
new file mode 100644
index 000000000..ee94d39b7
--- /dev/null
+++ b/mailnews/addrbook/content/abMailListDialog.js
@@ -0,0 +1,613 @@
+/* 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);
+}
+