Bug 92737 - Part 4: Open multiple tabs when multiple items are dropped on tab. r=enndeakin
authorTooru Fujisawa <arai_a@mac.com>
Sat, 15 Aug 2015 07:20:22 +0900
changeset 314593 40e1dbd5409b5d7f54eb39c787d643af5139265f
parent 314592 978a6615d7cce1d5970fd014c72ec474dfa02629
child 314594 9b53031d587cb51af43095f7f86e5137a524470d
push id30732
push usercbook@mozilla.com
push dateWed, 21 Sep 2016 10:04:03 +0000
treeherdermozilla-central@560b2c805bf7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersenndeakin
bugs92737
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 92737 - Part 4: Open multiple tabs when multiple items are dropped on tab. r=enndeakin
browser/base/content/tabbrowser.xml
browser/base/content/test/general/browser_tabDrop.js
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -6253,51 +6253,42 @@
               newIndex--;
             this.tabbrowser.moveTabTo(draggedTab, newIndex);
           }
         } else if (draggedTab) {
           let newIndex = this._getDropIndex(event, false);
           this.tabbrowser.adoptTab(draggedTab, newIndex, true);
         } else {
           // Pass true to disallow dropping javascript: or data: urls
-          let url;
+          let links;
           try {
-            url = browserDragAndDrop.drop(event, { }, true);
+            links = browserDragAndDrop.dropLinks(event, true);
           } catch (ex) {}
 
-          if (!url)
+          if (!links || links.length === 0)
             return;
 
-          let bgLoad = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
+          let inBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
 
           if (event.shiftKey)
-            bgLoad = !bgLoad;
-
-          let tab = this._getDragTargetTab(event, true);
-          if (!tab) {
-            // We're adding a new tab.
-            let userContextId = this.selectedItem.getAttribute("usercontextid");
-            let newIndex = this._getDropIndex(event, true);
-            let newTab = this.tabbrowser.loadOneTab(url, {inBackground: bgLoad,
-                                                          allowThirdPartyFixup: true,
-                                                          userContextId});
-            this.tabbrowser.moveTabTo(newTab, newIndex);
-          } else {
-            // Load in an existing tab.
-            try {
-              let webNav = Ci.nsIWebNavigation;
-              let flags = webNav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
-                          webNav.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
-              this.tabbrowser.getBrowserForTab(tab).loadURIWithFlags(url, flags);
-              if (!bgLoad)
-                this.selectedItem = tab;
-            } catch (ex) {
-              // Just ignore invalid urls
-            }
-          }
+            inBackground = !inBackground;
+
+          let targetTab = this._getDragTargetTab(event, true);
+          let userContextId = this.selectedItem.getAttribute("usercontextid");
+          let replace = !!targetTab;
+          let newIndex = this._getDropIndex(event, true);
+          let urls = links.map(link => link.url);
+          this.tabbrowser.loadTabs(urls, {
+            inBackground,
+            replace,
+            allowThirdPartyFixup: true,
+            targetTab,
+            newIndex,
+            userContextId,
+          });
         }
 
         if (draggedTab) {
           delete draggedTab._dragData;
         }
       ]]></handler>
 
       <handler event="dragend"><![CDATA[
--- a/browser/base/content/test/general/browser_tabDrop.js
+++ b/browser/base/content/test/general/browser_tabDrop.js
@@ -12,50 +12,93 @@ add_task(function* test_setup() {
   // Stop search-engine loads from hitting the network
   Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET",
                                        "http://example.com/?q={searchTerms}");
   let engine = Services.search.getEngineByName("MozSearch");
   originalEngine = Services.search.currentEngine;
   Services.search.currentEngine = engine;
 });
 
-add_task(function*() { yield drop("mochi.test/first", true); });
-add_task(function*() { yield drop("javascript:'bad'"); });
-add_task(function*() { yield drop("jAvascript:'bad'"); });
-add_task(function*() { yield drop("search this", true); });
-add_task(function*() { yield drop("mochi.test/second", true); });
-add_task(function*() { yield drop("data:text/html,bad"); });
-add_task(function*() { yield drop("mochi.test/third", true); });
+add_task(function*() { yield dropText("mochi.test/first", 1); });
+add_task(function*() { yield dropText("javascript:'bad'"); });
+add_task(function*() { yield dropText("jAvascript:'bad'"); });
+add_task(function*() { yield dropText("search this", 1); });
+add_task(function*() { yield dropText("mochi.test/second", 1); });
+add_task(function*() { yield dropText("data:text/html,bad"); });
+add_task(function*() { yield dropText("mochi.test/third", 1); });
+
+// Single text/plain item, with multiple links.
+add_task(function*() { yield dropText("mochi.test/1\nmochi.test/2", 2); });
+add_task(function*() { yield dropText("javascript:'bad1'\nmochi.test/3", 0); });
+add_task(function*() { yield dropText("mochi.test/4\ndata:text/html,bad1", 0); });
+
+// Multiple text/plain items, with single and multiple links.
+add_task(function*() {
+  yield drop([[{type: "text/plain",
+                data: "mochi.test/5"}],
+              [{type: "text/plain",
+                data: "mochi.test/6\nmochi.test/7"}]], 3);
+});
 
-function* drop(text, valid = false) {
-  info(`Starting test for text:${text}; valid:${valid}`);
+// Single text/x-moz-url item, with multiple links.
+// "text/x-moz-url" has titles in even-numbered lines.
+add_task(function*() {
+  yield drop([[{type: "text/x-moz-url",
+                data: "mochi.test/8\nTITLE8\nmochi.test/9\nTITLE9"}]], 2);
+});
+
+// Single item with multiple types.
+add_task(function*() {
+  yield drop([[{type: "text/plain",
+                data: "mochi.test/10"},
+               {type: "text/x-moz-url",
+                data: "mochi.test/11\nTITLE11"}]], 1);
+});
+
+function dropText(text, expectedTabOpenCount=0) {
+  return drop([[{type: "text/plain", data: text}]], expectedTabOpenCount);
+}
+
+function* drop(dragData, expectedTabOpenCount=0) {
+  let dragDataString = JSON.stringify(dragData);
+  info(`Starting test for datagData:${dragDataString}; expectedTabOpenCount:${expectedTabOpenCount}`);
   let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
                      getService(Ci.mozIJSSubScriptLoader);
   let EventUtils = {};
   scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
 
   let awaitDrop = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "drop");
-  let awaitTabOpen = valid && BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
+  let actualTabOpenCount = 0;
+  let openedTabs = [];
+  let checkCount = function(event) {
+    openedTabs.push(event.target);
+    actualTabOpenCount++;
+    return actualTabOpenCount == expectedTabOpenCount;
+  };
+  let awaitTabOpen = expectedTabOpenCount && BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen", false, checkCount);
   // A drop type of "link" onto an existing tab would normally trigger a
   // load in that same tab, but tabbrowser code in _getDragTargetTab treats
   // drops on the outer edges of a tab differently (loading a new tab
   // instead). Make events created by synthesizeDrop have all of their
   // coordinates set to 0 (screenX/screenY), so they're treated as drops
   // on the outer edge of the tab, thus they open new tabs.
   var event = {
     clientX: 0,
     clientY: 0,
     screenX: 0,
     screenY: 0,
   };
-  EventUtils.synthesizeDrop(gBrowser.selectedTab, gBrowser.selectedTab, [[{type: "text/plain", data: text}]], "link", window, undefined, event);
+  EventUtils.synthesizeDrop(gBrowser.selectedTab, gBrowser.selectedTab, dragData, "link", window, undefined, event);
+  let tabsOpened = false;
   let tabOpened = false;
   if (awaitTabOpen) {
-    let tabOpenEvent = yield awaitTabOpen;
+    yield awaitTabOpen;
     info("Got TabOpen event");
-    tabOpened = true;
-    yield BrowserTestUtils.removeTab(tabOpenEvent.target);
+    tabsOpened = true;
+    for (let tab of openedTabs) {
+      yield BrowserTestUtils.removeTab(tab);
+    }
   }
-  is(tabOpened, valid, `Tab for ${text} should only open if valid`);
+  is(tabsOpened, !!expectedTabOpenCount, `Tabs for ${dragDataString} should only open if any of dropped items are valid`);
 
   yield awaitDrop;
   ok(true, "Got drop event");
 }