Bug 1171979 - Thunderbird: Change usage of draggesture to dragstart, dragdrop to drop. r=bwinton, Fallen
authorMagnus Melin <mkmelin+mozilla@iki.fi>
Thu, 19 Nov 2015 23:04:54 +0200
changeset 22678 8af06972e2134db19475f9fbb5e767039ca1eebb
parent 22677 79b18e6b5e34a2bf02985999a8304cef675c74ba
child 22679 7c24277d79ad70104a09d8869a900424f2e407bf
push idunknown
push userunknown
push dateunknown
reviewersbwinton, Fallen
bugs1171979
Bug 1171979 - Thunderbird: Change usage of draggesture to dragstart, dragdrop to drop. r=bwinton, Fallen Mostly find ./mail ./mailnews ./calendar -type f -readable -writable -exec sed -i "s/draggesture/dragstart/g" {} \; find ./mail ./mailnews ./calendar -type f -readable -writable -exec sed -i "s/dragdrop/drop/g" {} \;
calendar/base/content/agenda-listbox.xml
calendar/base/content/calendar-task-tree.xml
calendar/base/content/calendar-view-core.xml
calendar/base/content/today-pane.xul
calendar/base/content/widgets/calendar-widgets.xml
calendar/resources/content/calendarCreation.xul
mail/base/content/ABSearchDialog.xul
mail/base/content/SearchDialog.xul
mail/base/content/messageWindow.xul
mail/base/content/messenger.xul
mail/base/content/msgHdrViewOverlay.xul
mail/base/content/nsDragAndDrop.js
mail/base/jar.mn
mail/components/addrbook/content/abContactsPanel.xul
mail/components/addrbook/content/abEditListDialog.xul
mail/components/addrbook/content/abMailListDialog.xul
mail/components/addrbook/content/addressbook.xul
mail/components/compose/content/messengercompose.xul
mail/components/im/content/imAccounts.xul
mailnews/addrbook/content/abResultsPaneOverlay.xul
--- a/calendar/base/content/agenda-listbox.xml
+++ b/calendar/base/content/agenda-listbox.xml
@@ -164,17 +164,17 @@
             addWrap.classList.add("wrap");
             addWrap = document.getAnonymousElementByAttribute(this.mAllDayItem, "anonid", "event-detail-box");
             addWrap.classList.add("wrap");
             allDayDateLabel.value = date;
         ]]></body>
       </method>
     </implementation>
     <handlers>
-      <handler event="draggesture" phase="capturing"><![CDATA[
+      <handler event="dragstart" phase="capturing"><![CDATA[
         invokeEventDragSession(this.mAllDayItem.occurrence.clone(), this);
         event.stopPropagation();
         event.preventDefault();
       ]]></handler>
     </handlers>
   </binding>
 
   <binding id="agenda-richlist-item"
@@ -276,14 +276,14 @@
                             "#a8c2e1");
   
             var imagebox = document.getAnonymousElementByAttribute(this, "anonid", "agenda-calendar-image");
             imagebox.setAttribute("style", "background-color: " + calcolor + ";");
         ]]></body>
       </method>
     </implementation>
     <handlers>
-      <handler event="draggesture"><![CDATA[
+      <handler event="dragstart"><![CDATA[
         invokeEventDragSession(this.mOccurrence.clone(), this);
       ]]></handler>
     </handlers>
   </binding>
 </bindings>
--- a/calendar/base/content/calendar-task-tree.xml
+++ b/calendar/base/content/calendar-task-tree.xml
@@ -672,17 +672,17 @@
           // IsSeparator is used to determine if the row at index is a separator.
           // A value of true will result in the tree drawing a horizontal separator.
           // The tree uses the ::moz-tree-separator pseudoclass to draw the separator.
           isSeparator: function mTV_isSeparator(aRow) {
               return false;
           },
 
           // Specifies if there is currently a sort on any column.
-          // Used mostly by dragdrop to affect drop feedback.
+          // Used mostly by drag'n'drop to affect drop feedback.
           isSorted: function mTV_isSorted(aRow) {
               return false;
           },
 
           canDrop: function mTV_canDrop() { return false; },
 
           drop: function mTV_drop(aRow, aOrientation) {},
 
@@ -1127,17 +1127,17 @@
         this.updateFocus();
       ]]></handler>
       <handler event="keypress"><![CDATA[
         this.mTreeView.onKeyPress(event);
       ]]></handler>
       <handler event="mousedown"><![CDATA[
         this.mTreeView.onMouseDown(event);
       ]]></handler>
-      <handler event="draggesture"><![CDATA[
+      <handler event="dragstart"><![CDATA[
         if (event.originalTarget.localName != "treechildren") {
             // We should only drag treechildren, not for example the scrollbar.
             return;
         }
         var item = this.mTreeView._getItemFromEvent(event);
         if (!item || item.calendar.readOnly) {
             return;
         }
--- a/calendar/base/content/calendar-view-core.xml
+++ b/calendar/base/content/calendar-view-core.xml
@@ -351,17 +351,17 @@
         }
       ]]></handler>
       <handler event="mouseover"><![CDATA[
         if (this.calendarView && this.calendarView.controller) {
             event.stopPropagation();
             onMouseOverItem(event);
         }
       ]]></handler>
-      <handler event="draggesture"><![CDATA[
+      <handler event="dragstart"><![CDATA[
         if( event.target.localName == "calendar-event-box") {
             return;
         }
         let item = this.occurrence;
         if (!isCalendarWritable(item.calendar)
             || !userCanModifyItem(item)
             || (item.calendar instanceof Components.interfaces.calISchedulingSupport && item.calendar.isInvitation(item))) {
             return;
--- a/calendar/base/content/today-pane.xul
+++ b/calendar/base/content/today-pane.xul
@@ -184,19 +184,19 @@
                                                checked="false"
                                                persist="checked"/>
               </vbox>
               <richlistbox id="agenda-listbox" flex="1" context="_child"
                            onblur="agendaListbox.onBlur();"
                            onfocus="agendaListbox.onFocus();"
                            onkeypress="agendaListbox.onKeyPress(event);"
                            ondblclick="agendaListbox.createNewEvent(event);"
-                           ondraggesture="nsDragAndDrop.startDrag(event, calendarCalendarButtonDNDObserver);"
+                           ondragstart="nsDragAndDrop.startDrag(event, calendarCalendarButtonDNDObserver);"
                            ondragover="nsDragAndDrop.dragOver(event, calendarCalendarButtonDNDObserver);"
-                           ondragdrop="nsDragAndDrop.drop(event, calendarCalendarButtonDNDObserver);">
+                           ondrop="nsDragAndDrop.drop(event, calendarCalendarButtonDNDObserver);">
                 <menupopup id="agenda-menupopup" onpopupshowing="return agendaListbox.setupContextMenu(event.target)">
                   <menuitem label="&calendar.context.modifyorviewitem.label;"
                            accesskey="&calendar.context.modifyorviewitem.accesskey;"
                            observes="agenda_edit_event_command"/>
                   <menu id="agenda-context-menu-convert-menu"
                        label="&calendar.context.convertmenu.label;"
                        accesskey="&calendar.context.convertmenu.accesskey.calendar;">
                    <menupopup id="agenda-context-menu-convert-menupopup">
@@ -277,18 +277,18 @@
               </richlistbox>
             </vbox>
         </modevbox>
         <splitter id="today-pane-splitter" persist="hidden"/>
         <modevbox id="todo-tab-panel" flex="1" mode="mail,calendar"
                   collapsedinmodes="mail,task"
                   broadcaster="modeBroadcaster"
                   persist="height collapsedinmodes"
-                  ondraggesture="nsDragAndDrop.startDrag(event, calendarTaskButtonDNDObserver);"
+                  ondragstart="nsDragAndDrop.startDrag(event, calendarTaskButtonDNDObserver);"
                   ondragover="nsDragAndDrop.dragOver(event, calendarTaskButtonDNDObserver);"
-                  ondragdrop="nsDragAndDrop.drop(event, calendarTaskButtonDNDObserver);"/>
+                  ondrop="nsDragAndDrop.drop(event, calendarTaskButtonDNDObserver);"/>
     </vbox>
   </modevbox>
 
   <commandset id="calendar_commands">
     <command id="calendar_toggle_todaypane_command" oncommand="TodayPane.toggleVisibility(event)"/>
   </commandset>
 </overlay>
--- a/calendar/base/content/widgets/calendar-widgets.xml
+++ b/calendar/base/content/widgets/calendar-widgets.xml
@@ -654,17 +654,17 @@
                    // the today-pane.
                    currentView().removeDropShadows();
                }
                this.setAttribute("dropbox", "true");
            }
        }
       ]]></handler>
 
-      <handler event="dragdrop"><![CDATA[
+      <handler event="drop"><![CDATA[
          let session = cal.getDragService().getCurrentSession();
          if (!session || !session.sourceNode || !session.sourceNode.sourceObject) {
             // No source node? Not our drag.
             return;
          }
          let item = session.sourceNode.sourceObject.clone();
          this.setAttribute("dropbox", "false");
          let transfer = Components.classes["@mozilla.org/widget/transferable;1"].
--- a/calendar/resources/content/calendarCreation.xul
+++ b/calendar/resources/content/calendarCreation.xul
@@ -56,17 +56,17 @@
                         <radio id="wcap-radio" value="wcap" label="&calendarproperties.wcap.label;"/>
                     </radiogroup>
                 </row>
                 <row align="center">
                     <label value="&calendarproperties.location.label;" control="calendar-uri"/>
                     <!--  Due to bug 128066, dropping urls here doesn't trigger
                           events. To work around, we use the dragexit handler,
                           which is triggered. Unfortunately, the more logical
-                          choice of dragdrop doesn't work here either.-->
+                          choice of drag'n'drop doesn't work here either.-->
                     <textbox id="calendar-uri"
                              required="true"
                              type="search"
                              oncommand="checkRequired();"
                              ondragexit="checkRequired();"/>
                 </row>
                 <row>
                      <label/>
--- a/mail/base/content/ABSearchDialog.xul
+++ b/mail/base/content/ABSearchDialog.xul
@@ -158,17 +158,17 @@
             <treecol id="_PhoneticName"
                      persist="hidden ordinal width sortDirection"
                      hidden="true"
                      flex="1" label="&_PhoneticName.label;"/>
             <splitter class="tree-splitter"/>
            -->
 
           </treecols>
-          <treechildren ondraggesture="nsDragAndDrop.startDrag(event, abResultsPaneObserver);"/>
+          <treechildren ondragstart="nsDragAndDrop.startDrag(event, abResultsPaneObserver);"/>
         </tree>
       </vbox>
       <hbox align="start">
         <button label="&propertiesButton.label;"
                 accesskey="&propertiesButton.accesskey;"
                 command="cmd_properties"/>
         <button label="&composeButton.label;"
                 accesskey="&composeButton.accesskey;"
--- a/mail/base/content/SearchDialog.xul
+++ b/mail/base/content/SearchDialog.xul
@@ -173,17 +173,17 @@
                      label="&totalColumn.label;" tooltiptext="&totalColumn2.tooltip;"/>
             <splitter class="tree-splitter"/>
             <treecol id="locationCol" persist="width" flex="1" hidden="true" ignoreincolumnpicker="true"
                      label="&locationColumn.label;" tooltiptext="&locationColumn2.tooltip;"/>
             <splitter class="tree-splitter"/>
             <treecol id="idCol" persist="hidden ordinal width" flex="1" hidden="true"
                      label="&idColumn.label;" tooltiptext="&idColumn2.tooltip;"/>
           </treecols>
-          <treechildren ondraggesture="ThreadPaneOnDragStart(event);"/>
+          <treechildren ondragstart="ThreadPaneOnDragStart(event);"/>
         </tree>
       </vbox>
       <hbox align="start">
         <button label="&openButton.label;" id="openButton" command="cmd_open" accesskey="&openButton.accesskey;"/>
         <button id="fileMessageButton" type="menu" label="&moveButton.label;"
                 accesskey="&moveButton.accesskey;"
                 observes="file_message_button">
           <menupopup type="folder" showFileHereLabel="true" mode="filing"
--- a/mail/base/content/messageWindow.xul
+++ b/mail/base/content/messageWindow.xul
@@ -135,17 +135,17 @@
 
   <tooltip id="aHTMLTooltip" page="true"/>
 
  <!-- msg header view -->
   <!-- a convenience box for ease of extension overlaying -->
   <hbox id="messagepaneboxwrapper" flex="1">
     <vbox id="messagepanebox" flex="3"
           ondragover="nsDragAndDrop.dragOver(event, messagepaneObserver);"
-          ondragdrop="nsDragAndDrop.drop(event, messagepaneObserver);"
+          ondrop="nsDragAndDrop.drop(event, messagepaneObserver);"
           ondragexit="nsDragAndDrop.dragExit(event, messagepaneObserver);">
 
       <hbox id="msgHeaderView"/>
       <!-- The msgNotificationBar appears on top of the message and displays
            information like: junk, mdn, remote content and phishing warnings -->
       <notificationbox id="msgNotificationBar" notificationside="top"/>
 
       <!-- message view -->
--- a/mail/base/content/messenger.xul
+++ b/mail/base/content/messenger.xul
@@ -331,17 +331,17 @@
                                onclick="gFolderTreeView.cycleMode(true);"/>
               </sidebarheader>
 
               <tree id="folderTree" class="plain" flex="1"
                     hidecolumnpicker="true" persist="mode" mode="all"
                     keepcurrentinview="true"
                     context="folderPaneContext"
                     disableKeyNavigation="true"
-                    ondraggesture="gFolderTreeView._onDragStart(event);"
+                    ondragstart="gFolderTreeView._onDragStart(event);"
                     ondragover="gFolderTreeView._onDragOver(event);"
                     ondblclick="gFolderTreeView.onDoubleClick(event);"
                     onselect="FolderPaneSelectionChange();">
                 <treecols id="folderPaneCols">
                   <treecol id="folderNameCol"
                            label2="&folderNameColumn.label;"
                            flex="5"
                            crop="center"
@@ -488,17 +488,17 @@
                                  label="&totalColumn.label;" tooltiptext="&totalColumn2.tooltip;"/>
                         <splitter class="tree-splitter"/>
                         <treecol id="locationCol" persist="width" flex="1" hidden="true"
                                  label="&locationColumn.label;" tooltiptext="&locationColumn2.tooltip;"/>
                         <splitter class="tree-splitter"/>
                         <treecol id="idCol" persist="width" flex="1" hidden="true"
                                  label="&idColumn.label;" tooltiptext="&idColumn2.tooltip;"/>
                       </treecols>
-                    <treechildren ondraggesture="ThreadPaneOnDragStart(event);"
+                    <treechildren ondragstart="ThreadPaneOnDragStart(event);"
                                   ondragover="ThreadPaneOnDragOver(event);"
                                   ondrop="ThreadPaneOnDrop(event);"/>
                   </tree>
                  </vbox>
                 </hbox>
                 <!-- extensions may overlay in additional panels; don't assume that there are only 2! -->
                 </deck> <!-- displayDeck -->
 
--- a/mail/base/content/msgHdrViewOverlay.xul
+++ b/mail/base/content/msgHdrViewOverlay.xul
@@ -569,17 +569,17 @@
             onclick="event.stopPropagation();"
             oncommand="toggleAttachmentList(this.checked, true);"/>
     <hbox align="center" id="attachmentInfo" flex="1">
       <image id="attachmentIcon"/>
       <label id="attachmentCount"/>
       <label id="attachmentName" crop="center" flex="1"
              tooltiptext="&openAttachment.tooltip;"
              onclick="OpenAttachmentFromBar(event);"
-             ondraggesture="nsDragAndDrop.startDrag(event,attachmentNameDNDObserver);"/>
+             ondragstart="nsDragAndDrop.startDrag(event,attachmentNameDNDObserver);"/>
       <label id="attachmentSize"/>
     </hbox>
     <!-- Use a very large flex value here so that attachmentCount doesn't take
          up more space than necessary, but still crops itself if there's not
          enough space. -->
     <spacer flex="9999"/>
 
     <toolbox id="attachment-view-toolbox"
@@ -654,13 +654,13 @@
                context="attachment-toolbar-context-menu"
                defaulticonsize="small" defaultmode="full"
                defaultset="attachmentSaveAll"/>
     </toolbox>
   </hbox>
   <attachmentlist orient="horizontal" id="attachmentList" flex="1"
                   seltype="multiple" context="attachmentListContext"
                   itemcontext="attachmentItemContext"
-                  ondraggesture="nsDragAndDrop.startDrag(event,attachmentListDNDObserver);"
+                  ondragstart="nsDragAndDrop.startDrag(event,attachmentListDNDObserver);"
                   ondragover="nsDragAndDrop.dragOver(event, attachmentListDNDObserver);"/>
 </vbox>
 
 </overlay>
new file mode 100644
--- /dev/null
+++ b/mail/base/content/nsDragAndDrop.js
@@ -0,0 +1,607 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 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/. */
+
+////////////////////////////////////////////////////////////////////////
+//
+// USE OF THIS API FOR DRAG AND DROP IS DEPRECATED!
+// Do not use this file for new code.
+// 
+// Toolkit dropped nsDragAndDrop.js in bug 1162050.
+// Mapped to content/global/nsDragAndDrop.js until we can remove this usage.
+//
+// For documentation about what to use instead, see:
+//   http://developer.mozilla.org/En/DragDrop/Drag_and_Drop
+//
+////////////////////////////////////////////////////////////////////////
+
+
+/** 
+ *  nsTransferable - a wrapper for nsITransferable that simplifies
+ *                   javascript clipboard and drag&drop. for use in
+ *                   these situations you should use the nsClipboard
+ *                   and nsDragAndDrop wrappers for more convenience
+ **/ 
+ 
+var nsTransferable = {
+  /**
+   * nsITransferable set (TransferData aTransferData) ;
+   *
+   * Creates a transferable with data for a list of supported types ("flavours")
+   * 
+   * @param TransferData aTransferData
+   *        a javascript object in the format described above 
+   **/ 
+  set: function (aTransferDataSet)
+    {
+      var trans = this.createTransferable();
+      for (var i = 0; i < aTransferDataSet.dataList.length; ++i) 
+        {
+          var currData = aTransferDataSet.dataList[i];
+          var currFlavour = currData.flavour.contentType;
+          trans.addDataFlavor(currFlavour);
+          var supports = null; // nsISupports data
+          var length = 0;
+          if (currData.flavour.dataIIDKey == "nsISupportsString")
+            {
+              supports = Components.classes["@mozilla.org/supports-string;1"]
+                                   .createInstance(Components.interfaces.nsISupportsString);
+
+              supports.data = currData.supports;
+              length = supports.data.length;
+            }
+          else 
+            {
+              // non-string data.
+              supports = currData.supports;
+              length = 0; // kFlavorHasDataProvider
+            }
+          trans.setTransferData(currFlavour, supports, length * 2);
+        }
+      return trans;
+    },
+  
+  /**
+   * TransferData/TransferDataSet get (FlavourSet aFlavourSet, 
+   *                                   Function aRetrievalFunc, Boolean aAnyFlag) ;
+   *
+   * Retrieves data from the transferable provided in aRetrievalFunc, formatted
+   * for more convenient access.
+   *
+   * @param FlavourSet aFlavourSet
+   *        a FlavourSet object that contains a list of supported flavours.
+   * @param Function aRetrievalFunc
+   *        a reference to a function that returns a nsISupportsArray of nsITransferables
+   *        for each item from the specified source (clipboard/drag&drop etc)
+   * @param Boolean aAnyFlag
+   *        a flag specifying whether or not a specific flavour is requested. If false,
+   *        data of the type of the first flavour in the flavourlist parameter is returned,
+   *        otherwise the best flavour supported will be returned.
+   **/
+  get: function (aFlavourSet, aRetrievalFunc, aAnyFlag)
+    {
+      if (!aRetrievalFunc) 
+        throw "No data retrieval handler provided!";
+      
+      var supportsArray = aRetrievalFunc(aFlavourSet);
+      var dataArray = [];
+      var count = supportsArray.Count();
+      
+      // Iterate over the number of items returned from aRetrievalFunc. For
+      // clipboard operations, this is 1, for drag and drop (where multiple
+      // items may have been dragged) this could be >1.
+      for (var i = 0; i < count; i++)
+        {
+          var trans = supportsArray.GetElementAt(i);
+          if (!trans) continue;
+          trans = trans.QueryInterface(Components.interfaces.nsITransferable);
+            
+          var data = { };
+          var length = { };
+          
+          var currData = null;
+          if (aAnyFlag)
+            { 
+              var flavour = { };
+              trans.getAnyTransferData(flavour, data, length);
+              if (data && flavour)
+                {
+                  var selectedFlavour = aFlavourSet.flavourTable[flavour.value];
+                  if (selectedFlavour) 
+                    dataArray[i] = FlavourToXfer(data.value, length.value, selectedFlavour);
+                }
+            }
+          else
+            {
+              var firstFlavour = aFlavourSet.flavours[0];
+              trans.getTransferData(firstFlavour, data, length);
+              if (data && firstFlavour)
+                dataArray[i] = FlavourToXfer(data.value, length.value, firstFlavour);
+            }
+        }
+      return new TransferDataSet(dataArray);
+    },
+
+  /** 
+   * nsITransferable createTransferable (void) ;
+   *
+   * Creates and returns a transferable object.
+   **/    
+  createTransferable: function ()
+    {
+      const kXferableContractID = "@mozilla.org/widget/transferable;1";
+      const kXferableIID = Components.interfaces.nsITransferable;
+      var trans = Components.classes[kXferableContractID].createInstance(kXferableIID);
+      trans.init(null);
+      return trans;
+    }
+};  
+
+/** 
+ * A FlavourSet is a simple type that represents a collection of Flavour objects.
+ * FlavourSet is constructed from an array of Flavours, and stores this list as
+ * an array and a hashtable. The rationale for the dual storage is as follows:
+ * 
+ * Array: Ordering is important when adding data flavours to a transferable. 
+ *        Flavours added first are deemed to be 'preferred' by the client. 
+ * Hash:  Convenient lookup of flavour data using the content type (MIME type)
+ *        of data as a key. 
+ */
+function FlavourSet(aFlavourList)
+{
+  this.flavours = aFlavourList || [];
+  this.flavourTable = { };
+
+  this._XferID = "FlavourSet";
+  
+  for (var i = 0; i < this.flavours.length; ++i)
+    this.flavourTable[this.flavours[i].contentType] = this.flavours[i];
+}
+
+FlavourSet.prototype = {
+  appendFlavour: function (aFlavour, aFlavourIIDKey)
+  {
+    var flavour = new Flavour (aFlavour, aFlavourIIDKey);
+    this.flavours.push(flavour);
+    this.flavourTable[flavour.contentType] = flavour;
+  }
+};
+
+/** 
+ * A Flavour is a simple type that represents a data type that can be handled. 
+ * It takes a content type (MIME type) which is used when storing data on the
+ * system clipboard/drag and drop, and an IIDKey (string interface name
+ * which is used to QI data to an appropriate form. The default interface is
+ * assumed to be wide-string.
+ */ 
+function Flavour(aContentType, aDataIIDKey)
+{
+  this.contentType = aContentType;
+  this.dataIIDKey = aDataIIDKey || "nsISupportsString";
+
+  this._XferID = "Flavour";
+}
+
+function TransferDataBase() {}
+TransferDataBase.prototype = {
+  push: function (aItems)
+  {
+    this.dataList.push(aItems);
+  },
+
+  get first ()
+  {
+    return "dataList" in this && this.dataList.length ? this.dataList[0] : null;
+  }
+};
+
+/** 
+ * TransferDataSet is a list (array) of TransferData objects, which represents
+ * data dragged from one or more elements. 
+ */
+function TransferDataSet(aTransferDataList)
+{
+  this.dataList = aTransferDataList || [];
+
+  this._XferID = "TransferDataSet";
+}
+TransferDataSet.prototype = TransferDataBase.prototype;
+
+/** 
+ * TransferData is a list (array) of FlavourData for all the applicable content
+ * types associated with a drag from a single item. 
+ */
+function TransferData(aFlavourDataList)
+{
+  this.dataList = aFlavourDataList || [];
+
+  this._XferID = "TransferData";
+}
+TransferData.prototype = {
+  __proto__: TransferDataBase.prototype,
+  
+  addDataForFlavour: function (aFlavourString, aData, aLength, aDataIIDKey)
+  {
+    this.dataList.push(new FlavourData(aData, aLength, 
+                       new Flavour(aFlavourString, aDataIIDKey)));
+  }
+};
+
+/** 
+ * FlavourData is a type that represents data retrieved from the system 
+ * clipboard or drag and drop. It is constructed internally by the Transferable
+ * using the raw (nsISupports) data from the clipboard, the length of the data,
+ * and an object of type Flavour representing the type. Clients implementing
+ * IDragDropObserver receive an object of this type in their implementation of
+ * onDrop. They access the 'data' property to retrieve data, which is either data 
+ * QI'ed to a usable form, or unicode string. 
+ */
+function FlavourData(aData, aLength, aFlavour) 
+{
+  this.supports = aData;
+  this.contentLength = aLength;
+  this.flavour = aFlavour || null;
+  
+  this._XferID = "FlavourData";
+}
+
+FlavourData.prototype = {
+  get data ()
+  {
+    if (this.flavour &&
+        this.flavour.dataIIDKey != "nsISupportsString")
+      return this.supports.QueryInterface(Components.interfaces[this.flavour.dataIIDKey]); 
+
+    var supports = this.supports;
+    if (supports instanceof Components.interfaces.nsISupportsString)
+      return supports.data.substring(0, this.contentLength/2);
+     
+    return supports;
+  }
+}
+
+/** 
+ * Create a TransferData object with a single FlavourData entry. Used when 
+ * unwrapping data of a specific flavour from the drag service. 
+ */
+function FlavourToXfer(aData, aLength, aFlavour) 
+{
+  return new TransferData([new FlavourData(aData, aLength, aFlavour)]);
+}
+
+var transferUtils = {
+
+  retrieveURLFromData: function (aData, flavour)
+  {
+    switch (flavour) {
+      case "text/unicode":
+      case "text/plain":
+      case "text/x-moz-text-internal":
+        return aData.replace(/^\s+|\s+$/g, "");
+      case "text/x-moz-url":
+        return ((aData instanceof Components.interfaces.nsISupportsString) ? aData.toString() : aData).split("\n")[0];
+      case "application/x-moz-file":
+        var ioService = Components.classes["@mozilla.org/network/io-service;1"]
+                                  .getService(Components.interfaces.nsIIOService);
+        var fileHandler = ioService.getProtocolHandler("file")
+                                   .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
+        return fileHandler.getURLSpecFromFile(aData);
+    }
+    return null;                                                   
+  }
+
+}
+
+/**
+ * nsDragAndDrop - a convenience wrapper for nsTransferable, nsITransferable
+ *                 and nsIDragService/nsIDragSession. 
+ *
+ * Use: map the handler functions to the 'ondraggesture', 'ondragover' and
+ *   'ondragdrop' event handlers on your XML element, e.g.                   
+ *   <xmlelement ondraggesture="nsDragAndDrop.startDrag(event, observer);"   
+ *               ondragover="nsDragAndDrop.dragOver(event, observer);"      
+ *               ondragdrop="nsDragAndDrop.drop(event, observer);"/>         
+ *                                                                           
+ *   You need to create an observer js object with the following member      
+ *   functions:                                                              
+ *     Object onDragStart (event)        // called when drag initiated,      
+ *                                       // returns flavour list with data   
+ *                                       // to stuff into transferable      
+ *     void onDragOver (Object flavour)  // called when element is dragged   
+ *                                       // over, so that it can perform     
+ *                                       // any drag-over feedback for provided
+ *                                       // flavour                          
+ *     void onDrop (Object data)         // formatted data object dropped.   
+ *     Object getSupportedFlavours ()    // returns a flavour list so that   
+ *                                       // nsTransferable can determine
+ *                                       // whether or not to accept drop. 
+ **/   
+
+var nsDragAndDrop = {
+  
+  _mDS: null,
+  get mDragService()
+    {
+      if (!this._mDS) 
+        {
+          const kDSContractID = "@mozilla.org/widget/dragservice;1";
+          const kDSIID = Components.interfaces.nsIDragService;
+          this._mDS = Components.classes[kDSContractID].getService(kDSIID);
+        }
+      return this._mDS;
+    },
+
+  /**
+   * void startDrag (DOMEvent aEvent, Object aDragDropObserver) ;
+   *
+   * called when a drag on an element is started.
+   *
+   * @param DOMEvent aEvent
+   *        the DOM event fired by the drag init
+   * @param Object aDragDropObserver
+   *        javascript object of format described above that specifies
+   *        the way in which the element responds to drag events.
+   **/  
+  startDrag: function (aEvent, aDragDropObserver)
+    {
+      if (!("onDragStart" in aDragDropObserver))
+        return;
+
+      const kDSIID = Components.interfaces.nsIDragService;
+      var dragAction = { action: kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_MOVE + kDSIID.DRAGDROP_ACTION_LINK };
+
+      var transferData = { data: null };
+      try 
+        {
+          aDragDropObserver.onDragStart(aEvent, transferData, dragAction);
+        }
+      catch (e) 
+        {
+          return;  // not a draggable item, bail!
+        }
+
+      if (!transferData.data) return;
+      transferData = transferData.data;
+
+      var dt = aEvent.dataTransfer;
+      var count = 0;
+      do {
+        var tds = transferData._XferID == "TransferData" 
+                                         ? transferData 
+                                         : transferData.dataList[count]
+        for (var i = 0; i < tds.dataList.length; ++i) 
+        {
+          var currData = tds.dataList[i];
+          var currFlavour = currData.flavour.contentType;
+          var value = currData.supports;
+          if (value instanceof Components.interfaces.nsISupportsString)
+            value = value.toString();
+          dt.mozSetDataAt(currFlavour, value, count);
+        }
+
+        count++;
+      }
+      while (transferData._XferID == "TransferDataSet" && 
+             count < transferData.dataList.length);
+
+      dt.effectAllowed = "all";
+      // a drag targeted at a tree should instead use the treechildren so that
+      // the current selection is used as the drag feedback
+      dt.addElement(aEvent.originalTarget.localName == "treechildren" ?
+                    aEvent.originalTarget : aEvent.target);
+      aEvent.stopPropagation();
+    },
+
+  /** 
+   * void dragOver (DOMEvent aEvent, Object aDragDropObserver) ;
+   *
+   * called when a drag passes over this element
+   *
+   * @param DOMEvent aEvent
+   *        the DOM event fired by passing over the element
+   * @param Object aDragDropObserver
+   *        javascript object of format described above that specifies
+   *        the way in which the element responds to drag events.
+   **/
+  dragOver: function (aEvent, aDragDropObserver)
+    { 
+      if (!("onDragOver" in aDragDropObserver)) 
+        return;
+      if (!this.checkCanDrop(aEvent, aDragDropObserver))
+        return;
+      var flavourSet = aDragDropObserver.getSupportedFlavours();
+      for (var flavour in flavourSet.flavourTable)
+        {
+          if (this.mDragSession.isDataFlavorSupported(flavour))
+            {
+              aDragDropObserver.onDragOver(aEvent, 
+                                           flavourSet.flavourTable[flavour], 
+                                           this.mDragSession);
+              aEvent.stopPropagation();
+              aEvent.preventDefault();
+              break;
+            }
+        }
+    },
+
+  mDragSession: null,
+
+  /** 
+   * void drop (DOMEvent aEvent, Object aDragDropObserver) ;
+   *
+   * called when the user drops on the element
+   *
+   * @param DOMEvent aEvent
+   *        the DOM event fired by the drop
+   * @param Object aDragDropObserver
+   *        javascript object of format described above that specifies
+   *        the way in which the element responds to drag events.
+   **/
+  drop: function (aEvent, aDragDropObserver)
+    {
+      if (!("onDrop" in aDragDropObserver))
+        return;
+      if (!this.checkCanDrop(aEvent, aDragDropObserver))
+        return;  
+
+      var flavourSet = aDragDropObserver.getSupportedFlavours();
+
+      var dt = aEvent.dataTransfer;
+      var dataArray = [];
+      var count = dt.mozItemCount;
+      for (var i = 0; i < count; ++i) {
+        var types = dt.mozTypesAt(i);
+        for (var j = 0; j < flavourSet.flavours.length; j++) {
+          var type = flavourSet.flavours[j].contentType;
+          // dataTransfer uses text/plain but older code used text/unicode, so
+          // switch this for compatibility
+          var modtype = (type == "text/unicode") ? "text/plain" : type;
+          if (Array.indexOf(types, modtype) >= 0) {
+            var data = dt.mozGetDataAt(modtype, i);
+            if (data) {
+              // Non-strings need some non-zero value used for their data length.
+              const kNonStringDataLength = 4;
+
+              var length = (typeof data == "string") ? data.length : kNonStringDataLength;
+              dataArray[i] = FlavourToXfer(data, length, flavourSet.flavourTable[type]);
+              break;
+            }
+          }
+        }
+      }
+
+      var transferData = new TransferDataSet(dataArray)
+
+      // hand over to the client to respond to dropped data
+      var multiple = "canHandleMultipleItems" in aDragDropObserver && aDragDropObserver.canHandleMultipleItems;
+      var dropData = multiple ? transferData : transferData.first.first;
+      aDragDropObserver.onDrop(aEvent, dropData, this.mDragSession);
+      aEvent.stopPropagation();
+    },
+
+  /** 
+   * void dragExit (DOMEvent aEvent, Object aDragDropObserver) ;
+   *
+   * called when a drag leaves this element
+   *
+   * @param DOMEvent aEvent
+   *        the DOM event fired by leaving the element
+   * @param Object aDragDropObserver
+   *        javascript object of format described above that specifies
+   *        the way in which the element responds to drag events.
+   **/
+  dragExit: function (aEvent, aDragDropObserver)
+    {
+      if (!this.checkCanDrop(aEvent, aDragDropObserver))
+        return;
+      if ("onDragExit" in aDragDropObserver)
+        aDragDropObserver.onDragExit(aEvent, this.mDragSession);
+    },  
+    
+  /** 
+   * void dragEnter (DOMEvent aEvent, Object aDragDropObserver) ;
+   *
+   * called when a drag enters in this element
+   *
+   * @param DOMEvent aEvent
+   *        the DOM event fired by entering in the element
+   * @param Object aDragDropObserver
+   *        javascript object of format described above that specifies
+   *        the way in which the element responds to drag events.
+   **/
+  dragEnter: function (aEvent, aDragDropObserver)
+    {
+      if (!this.checkCanDrop(aEvent, aDragDropObserver))
+        return;
+      if ("onDragEnter" in aDragDropObserver)
+        aDragDropObserver.onDragEnter(aEvent, this.mDragSession);
+    },  
+
+  /** 
+   * Boolean checkCanDrop (DOMEvent aEvent, Object aDragDropObserver) ;
+   *
+   * Sets the canDrop attribute for the drag session.
+   * returns false if there is no current drag session.
+   *
+   * @param DOMEvent aEvent
+   *        the DOM event fired by the drop
+   * @param Object aDragDropObserver
+   *        javascript object of format described above that specifies
+   *        the way in which the element responds to drag events.
+   **/
+  checkCanDrop: function (aEvent, aDragDropObserver)
+    {
+      if (!this.mDragSession) 
+        this.mDragSession = this.mDragService.getCurrentSession();
+      if (!this.mDragSession) 
+        return false;
+      this.mDragSession.canDrop = this.mDragSession.sourceNode != aEvent.target;
+      if ("canDrop" in aDragDropObserver)
+        this.mDragSession.canDrop &= aDragDropObserver.canDrop(aEvent, this.mDragSession);
+      return true;
+    },
+
+  /**
+   * Do a security check for drag n' drop. Make sure the source document
+   * can load the dragged link.
+   *
+   * @param DOMEvent aEvent
+   *        the DOM event fired by leaving the element
+   * @param Object aDragDropObserver
+   *        javascript object of format described above that specifies
+   *        the way in which the element responds to drag events.
+   * @param String aDraggedText
+   *        the text being dragged
+   **/
+  dragDropSecurityCheck: function (aEvent, aDragSession, aDraggedText)
+    {
+      // Strip leading and trailing whitespace, then try to create a
+      // URI from the dropped string. If that succeeds, we're
+      // dropping a URI and we need to do a security check to make
+      // sure the source document can load the dropped URI. We don't
+      // so much care about creating the real URI here
+      // (i.e. encoding differences etc don't matter), we just want
+      // to know if aDraggedText really is a URI.
+
+      aDraggedText = aDraggedText.replace(/^\s*|\s*$/g, '');
+
+      var uri;
+      var ioService = Components.classes["@mozilla.org/network/io-service;1"]
+                                .getService(Components.interfaces.nsIIOService);
+      try {
+        uri = ioService.newURI(aDraggedText, null, null);
+      } catch (e) {
+      }
+
+      if (!uri)
+        return;
+
+      // aDraggedText is a URI, do the security check.
+      const nsIScriptSecurityManager = Components.interfaces
+                                                 .nsIScriptSecurityManager;
+      var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
+                             .getService(nsIScriptSecurityManager);
+
+      if (!aDragSession)
+        aDragSession = this.mDragService.getCurrentSession();
+
+      var sourceDoc = aDragSession.sourceDocument;
+      // Use "file:///" as the default sourceURI so that drops of file:// URIs
+      // are always allowed.
+      var principal = sourceDoc ? sourceDoc.nodePrincipal
+                                : secMan.getSimpleCodebasePrincipal(ioService.newURI("file:///", null, null));
+
+      try {
+        secMan.checkLoadURIStrWithPrincipal(principal, aDraggedText,
+                                            nsIScriptSecurityManager.STANDARD);
+      } catch (e) {
+        // Stop event propagation right here.
+        aEvent.stopPropagation();
+
+        throw "Drop of " + aDraggedText + " denied.";
+      }
+    }
+};
+
--- a/mail/base/jar.mn
+++ b/mail/base/jar.mn
@@ -117,10 +117,12 @@ comm.jar:
 % content communicator %content/communicator/
    content/communicator/charsetOverlay.xul          (content/charsetOverlay.xul)
    content/communicator/contentAreaClick.js         (content/contentAreaClick.js)
    content/communicator/labelsencodings.properties  (/mozilla/dom/encoding/labelsencodings.properties)
 *  content/communicator/utilityOverlay.xul          (content/utilityOverlay.xul)
    content/communicator/utilityOverlay.js           (content/utilityOverlay.js)
 
 toolkit.jar:
+# toolkit dropped nsDragAndDrop.js in bug 1162050. ship a copy until we can remove it.
+ content/global/nsDragAndDrop.js                    (content/nsDragAndDrop.js)
 % overlay chrome://global/content/customizeToolbar.xul chrome://messenger/content/customizeToolbarOverlay.xul
 % overlay chrome://mozapps/content/downloads/downloads.xul chrome://messenger/content/downloadsOverlay.xul
--- a/mail/components/addrbook/content/abContactsPanel.xul
+++ b/mail/components/addrbook/content/abContactsPanel.xul
@@ -101,17 +101,17 @@
         <treecol id="addrbook"
                  persist="hidden ordinal width sortDirection" hidden="true"
                  flex="1" label="&Addrbook.label;"/>
         <splitter class="tree-splitter"/>
         <treecol id="PrimaryEmail"
                  persist="hidden ordinal width sortDirection" hidden="true"
                  flex="1" label="&PrimaryEmail.label;"/>
       </treecols>
-      <treechildren ondraggesture="nsDragAndDrop.startDrag(event, abResultsPaneObserver);"/>
+      <treechildren ondragstart="nsDragAndDrop.startDrag(event, abResultsPaneObserver);"/>
     </tree>
 
     <separator class="thin"/>
 
     <hbox>
       <spring flex="1"/>
       <grid>
         <columns>
--- a/mail/components/addrbook/content/abEditListDialog.xul
+++ b/mail/components/addrbook/content/abEditListDialog.xul
@@ -9,17 +9,17 @@
 <!DOCTYPE dialog SYSTEM "chrome://messenger/locale/addressbook/abMailListDialog.dtd">
 
 <dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         id="ablistWindow"
         title="&mailListWindow.title;"
         onload="OnLoadEditList();"
         ondialogaccept="return EditListOKButton();"
         ondragover="DragOverAddressListTree(event);"
-        ondragdrop="DropOnAddressListTree(event);">
+        ondrop="DropOnAddressListTree(event);">
 
   <stringbundleset id="stringbundleset">
     <stringbundle id="bundle_addressBook" src="chrome://messenger/locale/addressbook/addressBook.properties"/>
   </stringbundleset>
 
   <!-- move needed functions into a single js file -->
   <script type="application/javascript" src="chrome://messenger/content/messengercompose/addressingWidgetOverlay.js"/>
   <script type="application/javascript" src="chrome://messenger/content/addressbook/abCommon.js"/>
--- a/mail/components/addrbook/content/abMailListDialog.xul
+++ b/mail/components/addrbook/content/abMailListDialog.xul
@@ -9,17 +9,17 @@
 <!DOCTYPE dialog SYSTEM "chrome://messenger/locale/addressbook/abMailListDialog.dtd">
 
 <dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         id="ablistWindow"
         title="&mailListWindow.title;"
         ondialogaccept="return MailListOKButton();"
         onload="OnLoadNewMailList();"
         ondragover="DragOverAddressListTree(event);"
-        ondragdrop="DropOnAddressListTree(event);">
+        ondrop="DropOnAddressListTree(event);">
 
   <stringbundleset id="stringbundleset">
     <stringbundle id="bundle_addressBook" src="chrome://messenger/locale/addressbook/addressBook.properties"/>
   </stringbundleset>
 
   <!-- move needed functions into a single js file -->
   <script type="application/javascript" src="chrome://messenger/content/messengercompose/addressingWidgetOverlay.js"/>
   <script type="application/javascript" src="chrome://messenger/content/addressbook/abCommon.js"/>
--- a/mail/components/addrbook/content/addressbook.xul
+++ b/mail/components/addrbook/content/addressbook.xul
@@ -724,17 +724,17 @@
           <!--
           <treecol id="_PhoneticName"
                    persist="hidden ordinal width sortDirection" flex="1"
                    label="&_PhoneticName.label;" hiddenbydefault="true"/>
           <splitter class="tree-splitter"/>
           -->
         </treecols>
 
-        <treechildren ondraggesture="nsDragAndDrop.startDrag(event, abResultsPaneObserver);"/>
+        <treechildren ondragstart="nsDragAndDrop.startDrag(event, abResultsPaneObserver);"/>
       </tree>
 
       <splitter id="results-splitter" collapse="after" persist="state"/>
 
       <!-- card view -->
       <hbox id="CardViewOuterBox" flex="1" minheight="100" height="200" persist="height">
         <vbox id="CardViewBox" flex="1">
           <vbox id="CardViewInnerBox" collapsed="true" flex="1">
--- a/mail/components/compose/content/messengercompose.xul
+++ b/mail/components/compose/content/messengercompose.xul
@@ -744,17 +744,17 @@
                tooltiptext="&addressButton.tooltip;"
                observes="viewAddressPicker"/>
 
     <toolbarbutton class="toolbarbutton-1" type="menu-button"
                id="button-attach" label="&attachButton.label;"
                tooltiptext="&attachButton.tooltip;"
                command="cmd_attachFile"
                ondragover="nsDragAndDrop.dragOver(event, envelopeDragObserver);"
-               ondragdrop="nsDragAndDrop.drop(event, envelopeDragObserver);"
+               ondrop="nsDragAndDrop.drop(event, envelopeDragObserver);"
                ondragexit="nsDragAndDrop.dragExit(event, envelopeDragObserver);">
       <menupopup id="button-attachPopup" onpopupshowing="updateAttachmentItems();">
         <menuitem id="button-attachPopup_attachFileItem"
                   label="&attachFileCmd.label;"
                   accesskey="&attachFileCmd.accesskey;"
                   command="cmd_attachFile"/>
         <menu id="button-attachPopup_attachCloudMenu"
               label="&attachCloudCmd.label;"
@@ -900,17 +900,17 @@
 
     <splitter id="sidebar-splitter" hidden="true"/>
 
     <vbox id="headers-parent" flex="1">
     <toolbox id="headers-box" class="toolbox-top" mode="icons">
     <toolbar id="MsgHeadersToolbar" persist="collapsed" flex="1"
              customizable="true" nowindowdrag="true"
              ondragover="nsDragAndDrop.dragOver(event, envelopeDragObserver);"
-             ondragdrop="nsDragAndDrop.drop(event, envelopeDragObserver);"
+             ondrop="nsDragAndDrop.drop(event, envelopeDragObserver);"
              ondragexit="nsDragAndDrop.dragExit(event, envelopeDragObserver);">
       <hbox id="msgheaderstoolbar-box" flex="1">
         <vbox flex="1" id="addresses-box">
           <hbox id="top-gradient-box">
             <hbox align="center" pack="end" style="&headersSpace.style;">
               <label id="identityLabel" value="&fromAddr.label;"
                      accesskey="&fromAddr.accesskey;" control="msgIdentity"/>
             </hbox>
@@ -980,17 +980,17 @@
           </hbox>
           <attachmentlist orient="vertical" id="attachmentBucket"
                           disableonsend="true"
                           seltype="multiple" flex="1" height="0"
                           context="msgComposeAttachmentListContext"
                           itemcontext="msgComposeAttachmentItemContext"
                           onclick="AttachmentBucketClicked(event);"
                           onselect="updateAttachmentItems();"
-                          ondraggesture="nsDragAndDrop.startDrag(event, attachmentBucketDNDObserver);"/>
+                          ondragstart="nsDragAndDrop.startDrag(event, attachmentBucketDNDObserver);"/>
         </vbox>
       </hbox>
     </toolbar>
 
     <!-- These toolbar items get filled out from the editorOverlay -->
     <toolbox id="FormatToolbox" mode="icons">
       <toolbar class="chromeclass-toolbar" id="FormatToolbar" persist="collapsed"
                customizable="true" nowindowdrag="true">
--- a/mail/components/im/content/imAccounts.xul
+++ b/mail/components/im/content/imAccounts.xul
@@ -140,17 +140,17 @@
      </hbox>
    </vbox>
    <notificationbox id="accountsNotificationBox" flex="1">
      <richlistbox id="accountlist" flex="1" context="accountsContextMenu"
                   onselect="gAccountManager.onAccountSelect();"
                   ondragstart="nsDragAndDrop.startDrag(event, gAMDragAndDrop);"
                   ondragover="nsDragAndDrop.dragOver(event, gAMDragAndDrop);"
                   ondragend="gAMDragAndDrop.cleanBorders(true);"
-                  ondragdrop="nsDragAndDrop.drop(event, gAMDragAndDrop);"/>
+                  ondrop="nsDragAndDrop.drop(event, gAMDragAndDrop);"/>
    </notificationbox>
  </deck>
  <windowdragbox id="bottombuttons" align="center">
   <button id="newaccount" command="cmd_new"/>
   <spacer flex="1"/>
   <button id="close" command="cmd_close"/>
  </windowdragbox>
 </window>
--- a/mailnews/addrbook/content/abResultsPaneOverlay.xul
+++ b/mailnews/addrbook/content/abResultsPaneOverlay.xul
@@ -80,13 +80,13 @@
     <!--
     <splitter class="tree-splitter"/>
     <treecol id="_PhoneticName"
              persist="hidden ordinal width sortDirection" flex="1"
              label="&_PhoneticName.label;" hidden="true"/>
      -->
 
   </treecols>
-  <treechildren ondraggesture="nsDragAndDrop.startDrag(event, abResultsPaneObserver);"/>
+  <treechildren ondragstart="nsDragAndDrop.startDrag(event, abResultsPaneObserver);"/>
 </tree>
 
 </overlay>