summaryrefslogtreecommitdiffstats
path: root/mailnews/addrbook/content/abDragDrop.js
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/addrbook/content/abDragDrop.js')
-rw-r--r--mailnews/addrbook/content/abDragDrop.js424
1 files changed, 424 insertions, 0 deletions
diff --git a/mailnews/addrbook/content/abDragDrop.js b/mailnews/addrbook/content/abDragDrop.js
new file mode 100644
index 000000000..6160ec530
--- /dev/null
+++ b/mailnews/addrbook/content/abDragDrop.js
@@ -0,0 +1,424 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/PluralForm.jsm");
+
+// Returns the load context for the current window
+function getLoadContext() {
+ return window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIWebNavigation)
+ .QueryInterface(Components.interfaces.nsILoadContext);
+}
+
+var abFlavorDataProvider = {
+ QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIFlavorDataProvider]),
+
+ getFlavorData: function(aTransferable, aFlavor, aData, aDataLen)
+ {
+ if (aFlavor == "application/x-moz-file-promise")
+ {
+ var primitive = {};
+ aTransferable.getTransferData("text/vcard", primitive, {});
+ var vCard = primitive.value.QueryInterface(Components.interfaces.nsISupportsString).data;
+ aTransferable.getTransferData("application/x-moz-file-promise-dest-filename", primitive, {});
+ var leafName = primitive.value.QueryInterface(Components.interfaces.nsISupportsString).data;
+ aTransferable.getTransferData("application/x-moz-file-promise-dir", primitive, {});
+ var localFile = primitive.value.QueryInterface(Components.interfaces.nsIFile).clone();
+ localFile.append(leafName);
+
+ var ofStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
+ ofStream.init(localFile, -1, -1, 0);
+ var converter = Components.classes["@mozilla.org/intl/converter-output-stream;1"].createInstance(Components.interfaces.nsIConverterOutputStream);
+ converter.init(ofStream, null, 0, 0);
+ converter.writeString(vCard);
+ converter.close();
+
+ aData.value = localFile;
+ }
+ }
+};
+
+var abResultsPaneObserver = {
+ onDragStart: function (aEvent, aXferData, aDragAction)
+ {
+ var selectedRows = GetSelectedRows();
+
+ if (!selectedRows)
+ return;
+
+ var selectedAddresses = GetSelectedAddresses();
+
+ aXferData.data = new TransferData();
+ aXferData.data.addDataForFlavour("moz/abcard", selectedRows);
+ aXferData.data.addDataForFlavour("text/x-moz-address", selectedAddresses);
+ aXferData.data.addDataForFlavour("text/unicode", selectedAddresses);
+
+ let srcDirectory = getSelectedDirectory();
+ // The default allowable actions are copy, move and link, so we need
+ // to restrict them here.
+ if (!srcDirectory.readOnly)
+ // Only allow copy & move from read-write directories.
+ aDragAction.action = Components.interfaces.
+ nsIDragService.DRAGDROP_ACTION_COPY |
+ Components.interfaces.
+ nsIDragService.DRAGDROP_ACTION_MOVE;
+ else
+ // Only allow copy from read-only directories.
+ aDragAction.action = Components.interfaces.
+ nsIDragService.DRAGDROP_ACTION_COPY;
+
+ var card = GetSelectedCard();
+ if (card && card.displayName) {
+ let vCard = card.translateTo("vcard");
+ aXferData.data.addDataForFlavour("text/vcard", decodeURIComponent(vCard));
+ aXferData.data.addDataForFlavour("application/x-moz-file-promise-dest-filename", card.displayName + ".vcf");
+ aXferData.data.addDataForFlavour("application/x-moz-file-promise-url", "data:text/vcard," + vCard);
+ aXferData.data.addDataForFlavour("application/x-moz-file-promise", abFlavorDataProvider);
+ }
+ },
+
+ onDrop: function (aEvent, aXferData, aDragSession)
+ {
+ },
+
+ onDragExit: function (aEvent, aDragSession)
+ {
+ },
+
+ onDragOver: function (aEvent, aFlavour, aDragSession)
+ {
+ },
+
+ getSupportedFlavours: function ()
+ {
+ return null;
+ }
+};
+
+
+var dragService = Components.classes["@mozilla.org/widget/dragservice;1"]
+ .getService(Components.interfaces.nsIDragService);
+
+var abDirTreeObserver = {
+ /**
+ * canDrop - determine if the tree will accept the dropping of a item
+ * onto it.
+ *
+ * Note 1: We don't allow duplicate mailing list names, therefore copy
+ * is not allowed for mailing lists.
+ * Note 2: Mailing lists currently really need a card in the parent
+ * address book, therefore only moving to an address book is allowed.
+ *
+ * The possibilities:
+ *
+ * anything -> same place = Not allowed
+ * anything -> read only directory = Not allowed
+ * mailing list -> mailing list = Not allowed
+ * (we currently do not support recursive lists)
+ * address book card -> different address book = MOVE or COPY
+ * address book card -> mailing list = COPY only
+ * (cards currently have to exist outside list for list to work correctly)
+ * mailing list -> different address book = MOVE only
+ * (lists currently need to have unique names)
+ * card in mailing list -> parent mailing list = Not allowed
+ * card in mailing list -> other mailing list = MOVE or COPY
+ * card in mailing list -> other address book = MOVE or COPY
+ * read only directory item -> anywhere = COPY only
+ */
+ canDrop: function(index, orientation, dataTransfer)
+ {
+ if (orientation != Components.interfaces.nsITreeView.DROP_ON)
+ return false;
+ if (!dataTransfer.types.includes("moz/abcard")) {
+ return false;
+ }
+
+ let targetURI = gDirectoryTreeView.getDirectoryAtIndex(index).URI;
+
+ let srcURI = getSelectedDirectoryURI();
+
+ // We cannot allow copy/move to "All Address Books".
+ if (targetURI == kAllDirectoryRoot + "?")
+ return false;
+
+ // The same place case
+ if (targetURI == srcURI)
+ return false;
+
+ // determine if we dragging from a mailing list on a directory x to the parent (directory x).
+ // if so, don't allow the drop
+ if (srcURI.startsWith(targetURI))
+ return false;
+
+ // check if we can write to the target directory
+ // e.g. LDAP is readonly currently
+ var targetDirectory = GetDirectoryFromURI(targetURI);
+
+ if (targetDirectory.readOnly)
+ return false;
+
+ var dragSession = dragService.getCurrentSession();
+ if (!dragSession)
+ return false;
+
+ // XXX Due to bug 373125/bug 349044 we can't specify a default action,
+ // so we default to move and this means that the user would have to press
+ // ctrl to copy which most users don't realise.
+ //
+ // If target directory is a mailing list, then only allow copies.
+ // if (targetDirectory.isMailList &&
+ // dragSession.dragAction != Components.interfaces.
+ // nsIDragService.DRAGDROP_ACTION_COPY)
+ //return false;
+
+ var srcDirectory = GetDirectoryFromURI(srcURI);
+
+ // Only allow copy from read-only directories.
+ if (srcDirectory.readOnly &&
+ dragSession.dragAction != Components.interfaces.
+ nsIDragService.DRAGDROP_ACTION_COPY)
+ return false;
+
+ // Go through the cards checking to see if one of them is a mailing list
+ // (if we are attempting a copy) - we can't copy mailing lists as
+ // that would give us duplicate names which isn't allowed at the
+ // moment.
+ var draggingMailList = false;
+
+ // The data contains the a string of "selected rows", eg.: "1,2".
+ var rows = dataTransfer.getData("moz/abcard").split(",").map(j => parseInt(j, 10));
+
+ for (var j = 0; j < rows.length; j++)
+ {
+ if (gAbView.getCardFromRow(rows[j]).isMailList)
+ {
+ draggingMailList = true;
+ break;
+ }
+ }
+
+ // The rest of the cases - allow cards for copy or move, but only allow
+ // move of mailing lists if we're not going into another mailing list.
+ if (draggingMailList &&
+ (targetDirectory.isMailList ||
+ dragSession.dragAction == Components.interfaces.
+ nsIDragService.DRAGDROP_ACTION_COPY))
+ {
+ return false;
+ }
+
+ dragSession.canDrop = true;
+ return true;
+ },
+
+ /**
+ * onDrop - we don't need to check again for correctness as the
+ * tree view calls canDrop just before calling onDrop.
+ *
+ */
+ onDrop: function(index, orientation, dataTransfer)
+ {
+ var dragSession = dragService.getCurrentSession();
+ if (!dragSession)
+ return;
+ if (!dataTransfer.types.includes("moz/abcard")) {
+ return;
+ }
+
+ let targetURI = gDirectoryTreeView.getDirectoryAtIndex(index).URI;
+ let srcURI = getSelectedDirectoryURI();
+
+ // The data contains the a string of "selected rows", eg.: "1,2".
+ var rows = dataTransfer.getData("moz/abcard").split(",").map(j => parseInt(j, 10));
+ var numrows = rows.length;
+
+ var result;
+ // needToCopyCard is used for whether or not we should be creating
+ // copies of the cards in a mailing list in a different address book
+ // - it's not for if we are moving or not.
+ var needToCopyCard = true;
+ if (srcURI.length > targetURI.length) {
+ result = srcURI.split(targetURI);
+ if (result[0] != srcURI) {
+ // src directory is a mailing list on target directory, no need to copy card
+ needToCopyCard = false;
+ }
+ }
+ else {
+ result = targetURI.split(srcURI);
+ if (result[0] != targetURI) {
+ // target directory is a mailing list on src directory, no need to copy card
+ needToCopyCard = false;
+ }
+ }
+
+ // if we still think we have to copy the card,
+ // check if srcURI and targetURI are mailing lists on same directory
+ // if so, we don't have to copy the card
+ if (needToCopyCard) {
+ var targetParentURI = GetParentDirectoryFromMailingListURI(targetURI);
+ if (targetParentURI && (targetParentURI == GetParentDirectoryFromMailingListURI(srcURI)))
+ needToCopyCard = false;
+ }
+
+ var directory = GetDirectoryFromURI(targetURI);
+
+ // Only move if we are not transferring to a mail list
+ var actionIsMoving = (dragSession.dragAction & dragSession.DRAGDROP_ACTION_MOVE) && !directory.isMailList;
+
+ let cardsToCopy = [];
+ for (let j = 0; j < numrows; j++) {
+ cardsToCopy.push(gAbView.getCardFromRow(rows[j]));
+ }
+ for (let card of cardsToCopy) {
+ if (card.isMailList) {
+ // This check ensures we haven't slipped through by mistake
+ if (needToCopyCard && actionIsMoving) {
+ directory.addMailList(GetDirectoryFromURI(card.mailListURI));
+ }
+ } else {
+ let srcDirectory = null;
+ if (srcURI == (kAllDirectoryRoot + "?") && actionIsMoving) {
+ let dirId = card.directoryId.substring(0, card.directoryId.indexOf("&"));
+ srcDirectory = MailServices.ab.getDirectoryFromId(dirId);
+ }
+
+ directory.dropCard(card, needToCopyCard);
+
+ // This is true only if srcURI is "All ABs" and action is moving.
+ if (srcDirectory) {
+ let cardArray =
+ Components.classes["@mozilla.org/array;1"]
+ .createInstance(Components.interfaces.nsIMutableArray);
+ cardArray.appendElement(card, false);
+ srcDirectory.deleteCards(cardArray);
+ }
+ }
+ }
+
+ var cardsTransferredText;
+
+ // If we are moving, but not moving to a directory, then delete the
+ // selected cards and display the appropriate text
+ if (actionIsMoving && srcURI != (kAllDirectoryRoot + "?")) {
+ // If we have moved the cards, then delete them as well.
+ gAbView.deleteSelectedCards();
+ }
+
+ if (actionIsMoving) {
+ cardsTransferredText = PluralForm.get(numrows,
+ gAddressBookBundle.getFormattedString("contactsMoved", [numrows]));
+ } else {
+ cardsTransferredText = PluralForm.get(numrows,
+ gAddressBookBundle.getFormattedString("contactsCopied", [numrows]));
+ }
+
+ if (srcURI == kAllDirectoryRoot + "?") {
+ SetAbView(srcURI);
+ }
+
+ document.getElementById("statusText").label = cardsTransferredText;
+ },
+
+ onToggleOpenState: function()
+ {
+ },
+
+ onCycleHeader: function(colID, elt)
+ {
+ },
+
+ onCycleCell: function(row, colID)
+ {
+ },
+
+ onSelectionChanged: function()
+ {
+ },
+
+ onPerformAction: function(action)
+ {
+ },
+
+ onPerformActionOnRow: function(action, row)
+ {
+ },
+
+ onPerformActionOnCell: function(action, row, colID)
+ {
+ }
+}
+
+function DragAddressOverTargetControl(event)
+{
+ var dragSession = gDragService.getCurrentSession();
+
+ if (!dragSession.isDataFlavorSupported("text/x-moz-address"))
+ return;
+
+ var trans = Components.classes["@mozilla.org/widget/transferable;1"]
+ .createInstance(Components.interfaces.nsITransferable);
+ trans.init(getLoadContext());
+ trans.addDataFlavor("text/x-moz-address");
+
+ var canDrop = true;
+
+ for ( var i = 0; i < dragSession.numDropItems; ++i )
+ {
+ dragSession.getData ( trans, i );
+ var dataObj = new Object();
+ var bestFlavor = new Object();
+ var len = new Object();
+ try
+ {
+ trans.getAnyTransferData ( bestFlavor, dataObj, len );
+ }
+ catch (ex)
+ {
+ canDrop = false;
+ break;
+ }
+ }
+ dragSession.canDrop = canDrop;
+}
+
+function DropAddressOverTargetControl(event)
+{
+ var dragSession = gDragService.getCurrentSession();
+
+ var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
+ trans.addDataFlavor("text/x-moz-address");
+
+ for ( var i = 0; i < dragSession.numDropItems; ++i )
+ {
+ dragSession.getData ( trans, i );
+ var dataObj = new Object();
+ var bestFlavor = new Object();
+ var len = new Object();
+
+ // Ensure we catch any empty data that may have slipped through
+ try
+ {
+ trans.getAnyTransferData ( bestFlavor, dataObj, len);
+ }
+ catch (ex)
+ {
+ continue;
+ }
+
+ if ( dataObj )
+ dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString);
+ if ( !dataObj )
+ continue;
+
+ // pull the address out of the data object
+ var address = dataObj.data.substring(0, len.value);
+ if (!address)
+ continue;
+
+ DropRecipient(address);
+ }
+}