diff options
Diffstat (limited to 'mailnews/addrbook/content/abMailListDialog.js')
-rw-r--r-- | mailnews/addrbook/content/abMailListDialog.js | 613 |
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); +} + |