Bug 789781 - Switch to new drag and drop api in tabbrowser r=neil
authorIan Neal <iann_cvs@blueyonder.co.uk>
Mon, 17 Sep 2012 22:44:22 +0100
changeset 11075 ab06a84a717ac217ec77455d2bc52a92e92e7444
parent 11074 c05d43695bef401ffdf25ec0b16d29a811737013
child 11076 1f950704f3916d07b02d48599b8bdc3086bfeab2
push id8310
push useriann_cvs@blueyonder.co.uk
push dateMon, 17 Sep 2012 21:44:34 +0000
treeherdercomm-central@1f950704f391 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersneil
bugs789781
Bug 789781 - Switch to new drag and drop api in tabbrowser r=neil
suite/browser/navigator.xul
suite/browser/tabbrowser.xml
--- a/suite/browser/navigator.xul
+++ b/suite/browser/navigator.xul
@@ -35,17 +35,16 @@
         lightweightthemesfooter="status-bar"
         windowtype="navigator:browser"
         macanimationtype="document"
         persist="screenX screenY width height sizemode"> 
 
   <!-- Generic Utility -->
   <script type="application/javascript" src="chrome://global/content/nsUserSettings.js"/>
   <script type="application/javascript" src="chrome://global/content/nsClipboard.js"/>
-  <script type="application/javascript" src="chrome://global/content/nsDragAndDrop.js"/>
   <script type="application/javascript" src="chrome://global/content/viewSourceUtils.js"/>
 
   <!-- Content Area -->
   <script type="application/javascript" src="chrome://navigator/content/nsBrowserStatusHandler.js"/>
   <script type="application/javascript" src="chrome://navigator/content/nsBrowserContentListener.js"/>
   <script type="application/javascript" src="chrome://communicator/content/contentAreaClick.js"/>
   <script type="application/javascript" src="chrome://communicator/content/findUtils.js"/>
   <script type="application/javascript" src="chrome://global/content/printUtils.js"/>
--- a/suite/browser/tabbrowser.xml
+++ b/suite/browser/tabbrowser.xml
@@ -23,20 +23,20 @@
     <content>
       <xul:stringbundle anonid="tbstringbundle" src="chrome://navigator/locale/tabbrowser.properties"/>
       <xul:tabbox anonid="tabbox" flex="1" eventnode="document" xbl:inherits="handleCtrlPageUpDown">
         <xul:hbox class="tab-drop-indicator-bar" collapsed="true">
           <xul:image class="tab-drop-indicator" mousethrough="always"/>
         </xul:hbox>
         <xul:hbox class="tabbrowser-strip" collapsed="true" tooltip="_child" context="_child"
                   anonid="strip"
-                  ondraggesture="nsDragAndDrop.startDrag(event, this.parentNode.parentNode); event.stopPropagation();"
-                  ondragover="nsDragAndDrop.dragOver(event, this.parentNode.parentNode); event.stopPropagation();"
-                  ondragdrop="nsDragAndDrop.drop(event, this.parentNode.parentNode); event.stopPropagation();"
-                  ondragexit="nsDragAndDrop.dragExit(event, this.parentNode.parentNode); event.stopPropagation();">
+                  ondragstart="this.parentNode.parentNode._onDragStart(event);"
+                  ondragover="this.parentNode.parentNode._onDragOver(event);"
+                  ondrop="this.parentNode.parentNode._onDrop(event);"
+                  ondragleave="this.parentNode.parentNode._onDragLeave(event);">
           <xul:tooltip onpopupshowing="event.stopPropagation(); return this.parentNode.parentNode.parentNode.doPreview(this);"
                        onpopuphiding="this.parentNode.parentNode.parentNode.resetPreview(this);" orient="vertical">
             <xul:label class="tooltip-label" crop="right"/>
             <xul:label class="tooltip-label" hidden="true"><html:canvas class="tab-tooltip-canvas"/></xul:label>
           </xul:tooltip>
           <xul:menupopup anonid="tabContextMenu" onpopupshowing="return document.getBindingParent(this).updatePopupMenu(this);">
             <xul:menuitem label="&closeTab.label;" accesskey="&closeTab.accesskey;"
                           oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
@@ -1971,58 +1971,43 @@
           <![CDATA[
             return this._browsers ||
                    (this._browsers = Array.map(this.tabs, function (tab) tab.linkedBrowser));
           ]]>
         </getter>
       </property>
 
       <!-- Drag and drop observer API -->
-      <method name="onDragStart">
+      <method name="_onDragStart">
         <parameter name="aEvent"/>
-        <parameter name="aXferData"/>
-        <parameter name="aDragAction"/>
         <body>
           <![CDATA[
-            if (aEvent.target.localName == "tab") {
-              aXferData.data = new TransferData();
-
-              var URI = aEvent.target.linkedBrowser.currentURI;
-              var title = aEvent.target.linkedBrowser.contentTitle || URI.spec;
-              aXferData.data.addDataForFlavour("text/unicode", URI.spec);
-              aXferData.data.addDataForFlavour("text/x-moz-url", URI.spec + "\n" + title);
-              aXferData.data.addDataForFlavour("text/html", '<a href="' + URI.spec + '">' + title + '</a>');
+            var target = aEvent.target;
+            if (target.localName == "tab") {
+              var URI = target.linkedBrowser.currentURI;
+              var spec = URI.spec;
+              var title = target.linkedBrowser.contentTitle || spec;
+              var dt = aEvent.dataTransfer;
+              dt.mozSetDataAt("text/x-moz-url", spec + "\n" + title, 0);
+              dt.mozSetDataAt("text/uri-list", spec, 0);
+              dt.mozSetDataAt("text/plain", spec, 0);
+              dt.mozSetDataAt("text/html", '<a href="' + spec + '">' + title + '</a>', 0);
             }
+            aEvent.stopPropagation();
           ]]>
         </body>
       </method>
 
-      <method name="canDrop">
+      <method name="_onDragOver">
         <parameter name="aEvent"/>
-        <parameter name="aDragSession"/>
         <body>
           <![CDATA[
-            if (aDragSession.sourceNode &&
-                aDragSession.sourceNode.parentNode == this.tabContainer) {
-              var newIndex = this.getDropIndex(aEvent);
-              var tabIndex = this.getTabIndex(aDragSession.sourceNode);
-              if (newIndex == tabIndex || newIndex == tabIndex + 1)
-                return false;
-            }
-            return true;
-          ]]>
-        </body>
-      </method>
-
-      <method name="onDragOver">
-        <parameter name="aEvent"/>
-        <parameter name="aFlavour"/>
-        <parameter name="aDragSession"/>
-        <body>
-          <![CDATA[
+            aEvent.preventDefault();
+            aEvent.stopPropagation();
+
             var ib = document.getAnonymousElementByAttribute(this, "class", "tab-drop-indicator-bar");
 
             // autoscroll the tab strip if we drag over the scroll buttons,
             // even if we aren't dragging a tab
             var pixelsToScroll = 0;
             var tabStrip = this.mTabContainer.mTabstrip;
             var ltr = window.getComputedStyle(this, null).direction == "ltr";
             if (this.mTabContainer.getAttribute("overflow") == "true") {
@@ -2034,35 +2019,41 @@
                 case "scrollbutton-down":
                 case "alltabs-button":
                   pixelsToScroll = tabStrip.scrollIncrement;
                   break;
               }
               if (pixelsToScroll)
                 tabStrip.scrollByPixels((ltr ? 1 : -1) * pixelsToScroll);
             }
-            if (!aDragSession.canDrop) {
-              ib.collapsed = true;
-              return;
-            }
 
             var ind = document.getAnonymousElementByAttribute(this, "class", "tab-drop-indicator");
 
-            var newIndexOn = aDragSession.sourceNode &&
-                             aDragSession.sourceNode.parentNode == this.tabContainer ?
-                             -1 : this.getDropOnIndex(aEvent);
+            var draggedTab = aEvent.dataTransfer.mozSourceNode;
+            var within = draggedTab &&
+                         draggedTab.parentNode == this.tabContainer;
+            var newIndexOn = within ? -1 : this.getDropOnIndex(aEvent);
 
             var ltr = window.getComputedStyle(this, null).direction == "ltr";
             var arrowX, tabBoxObject;
             if (newIndexOn != -1) {
               tabBoxObject = this.tabs[newIndexOn].boxObject;
               arrowX = tabBoxObject.screenX + tabBoxObject.width / 2;
             }
             else {
               var newIndexBetween = this.getDropIndex(aEvent);
+              if (within) {
+                var tabIndex = this.getTabIndex(draggedTab);
+                if (newIndexBetween == tabIndex ||
+                    newIndexBetween == tabIndex + 1) {
+                  ib.collapsed = true;
+                  return;
+                }
+              }
+
               if (newIndexBetween == this.tabs.length) {
                 tabBoxObject = this.tabs[this.tabs.length - 1].boxObject;
                 arrowX = tabBoxObject.x;
                 arrowX = tabBoxObject.screenX;
                 if (ltr) // for LTR "after" is on the right-hand side of the tab
                   arrowX += tabBoxObject.width;
               }
               else {
@@ -2085,105 +2076,96 @@
             else
               ind.style.marginRight = (this.boxObject.screenX + this.boxObject.width - arrowX) + "px";
 
             ib.collapsed = false;
           ]]>
         </body>
       </method>
 
-      <method name="onDrop">
+      <method name="_onDrop">
         <parameter name="aEvent"/>
-        <parameter name="aXferData"/>
-        <parameter name="aDragSession"/>
         <body>
           <![CDATA[
             document.getAnonymousElementByAttribute(this, "class",
                                                     "tab-drop-indicator-bar")
                     .collapsed = true;
+            aEvent.stopPropagation();
+
             var newIndex = this.getDropIndex(aEvent);
             var tabIndex;
-            if (aDragSession.sourceNode &&
-                aDragSession.sourceNode.parentNode == this.tabContainer) {
-              tabIndex = this.getTabIndex(aDragSession.sourceNode);
+            var dt = aEvent.dataTransfer;
+            var draggedTab = dt.mozSourceNode;
+            if (draggedTab && draggedTab.parentNode == this.tabContainer) {
+              tabIndex = this.getTabIndex(draggedTab);
               if (newIndex > tabIndex)
                 newIndex--;
               this.moveTabTo(tabIndex, newIndex);
             } else {
-              var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType);
-
-              // valid urls don't contain spaces ' '; if we have a space it isn't a valid url.
-              // Also disallow dropping javascript: or data: urls--bail out
-              if (!url || !url.length || url.indexOf(" ", 0) != -1 ||
-                  /^\s*(javascript|data):/.test(url))
+              var url;
+              var linkHandler = Components.classes["@mozilla.org/content/dropped-link-handler;1"]
+                                          .getService(Components.interfaces.nsIDroppedLinkHandler);
+              try {
+                // Pass true to disallow dropping javascript: or data: urls.
+                url = linkHandler.dropLink(aEvent, {}, true);
+              } catch (ex) {}
+
+              // Valid urls don't contain spaces ' '; if we have a space
+              // it isn't a valid url.
+              if (!url || url.indexOf(" ") != -1)
                 return;
 
-              // Perform a security check before loading the URI
-              nsDragAndDrop.dragDropSecurityCheck(aEvent, aDragSession, url);
-
               var bgLoad = this.mPrefs.getBoolPref("browser.tabs.loadInBackground");
               if (aEvent.shiftKey)
                 bgLoad = !bgLoad;
 
               var tab = null;
               tabIndex = this.getDropOnIndex(aEvent);
               if (tabIndex != -1) {
-                // Load in an existing tab
+                // Load in an existing tab.
                 tab = this.tabs[tabIndex];
                 tab.linkedBrowser.loadURI(getShortcutOrURI(url));
                 if (this.mCurrentTab != tab && !bgLoad)
                   this.selectedTab = tab;
               }
-              else if (aDragSession.sourceDocument &&
-                       aDragSession.sourceDocument.defaultView.top == content) {
-                // We're adding a new tab, and we may want parent-tab tracking
+              else if (dt.mozSourceDocument &&
+                       dt.mozSourceDocument.defaultView.top == content) {
+                // We're adding a new tab, and we may want parent-tab tracking.
                 tab = this.loadOneTab(getShortcutOrURI(url), {inBackground: bgLoad});
                 if (newIndex != this.tabs.length - 1)
                   this.moveTabTo(this.tabs.length - 1, newIndex);
               }
               else {
-                // We're adding a new tab, but do not want parent-tab tracking
+                // We're adding a new tab, but do not want parent-tab tracking.
                 tab = this.addTab(getShortcutOrURI(url));
                 if (newIndex != this.tabs.length - 1)
                   this.moveTabTo(this.tabs.length - 1, newIndex);
                 if (this.mCurrentTab != tab && !bgLoad)
                   this.selectedTab = tab;
               }
             }
           ]]>
         </body>
       </method>
 
-      <method name="onDragExit">
+      <method name="_onDragLeave">
         <parameter name="aEvent"/>
-        <parameter name="aDragSession"/>
         <body>
           <![CDATA[
             var target = aEvent.relatedTarget;
             while (target && target != this.mStrip)
               target = target.parentNode;
 
             if (target)
               return;
 
             document.getAnonymousElementByAttribute(this, "class",
                                                     "tab-drop-indicator-bar")
                     .collapsed = true;
-          ]]>
-        </body>
-      </method>
-
-      <method name="getSupportedFlavours">
-        <body>
-          <![CDATA[
-            var flavourSet = new FlavourSet();
-            flavourSet.appendFlavour("text/x-moz-url");
-            flavourSet.appendFlavour("text/unicode");
-            flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
-            return flavourSet;
+            aEvent.stopPropagation();
           ]]>
         </body>
       </method>
 
       <method name="moveTabTo">
         <parameter name="aSrcIndex"/>
         <parameter name="aDestIndex"/>
         <body>