Bug 1479257 - Implement ability to duplicate a selection of tabs through drag and drop. r?jaws draft multiselect_copy_tabs_through_drag
authorAbdoulaye O. Ly <ablayelyfondou@gmail.com>
Sun, 05 Aug 2018 05:52:04 +0000
branchmultiselect_copy_tabs_through_drag
changeset 827384 62b1ca0f793a4050d4c6a143b4310b0b35504055
parent 827379 d9e6ce390607ad8c227adc2ad2ff3cac89a814bc
push id118525
push userbmo:ablayelyfondou@gmail.com
push dateTue, 07 Aug 2018 23:57:30 +0000
reviewersjaws
bugs1479257
milestone63.0a1
Bug 1479257 - Implement ability to duplicate a selection of tabs through drag and drop. r?jaws MozReview-Commit-ID: FSttZ0ytxX0
browser/base/content/tabbrowser.xml
browser/base/content/test/tabs/browser.ini
browser/base/content/test/tabs/browser_multiselect_tabs_copy_through_drag_and_drop.js
browser/base/content/test/tabs/head.js
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1397,20 +1397,25 @@
           movingTabs = draggedTab._dragData.movingTabs;
         }
 
         this._tabDropIndicator.collapsed = true;
         event.stopPropagation();
         if (draggedTab && dropEffect == "copy") {
           // copy the dropped tab (wherever it's from)
           let newIndex = this._getDropIndex(event, false);
-          let newTab = gBrowser.duplicateTab(draggedTab);
-          gBrowser.moveTabTo(newTab, newIndex);
+          let draggedTabCopy;
+          for (let tab of movingTabs) {
+            let newTab = gBrowser.duplicateTab(tab);
+            gBrowser.moveTabTo(newTab, newIndex++);
+            if (tab == draggedTab)
+              draggedTabCopy = newTab;
+          }
           if (draggedTab.parentNode != this || event.shiftKey) {
-            this.selectedItem = newTab;
+            this.selectedItem = draggedTabCopy;
           }
         } else if (draggedTab && draggedTab.parentNode == this) {
           let oldTranslateX = Math.round(draggedTab._dragData.translateX);
           let tabWidth = Math.round(draggedTab._dragData.tabWidth);
           let translateOffset = oldTranslateX % tabWidth;
           let newTranslateX = oldTranslateX - translateOffset;
           if (oldTranslateX > 0 && translateOffset > tabWidth / 2) {
             newTranslateX += tabWidth;
--- a/browser/base/content/test/tabs/browser.ini
+++ b/browser/base/content/test/tabs/browser.ini
@@ -21,16 +21,17 @@ support-files =
 [browser_isLocalAboutURI.js]
 [browser_multiselect_tabs_active_tab_selected_by_default.js]
 [browser_multiselect_tabs_bookmark.js]
 [browser_multiselect_tabs_clear_selection_when_tab_switch.js]
 [browser_multiselect_tabs_close_other_tabs.js]
 [browser_multiselect_tabs_close_tabs_to_the_right.js]
 [browser_multiselect_tabs_close_using_shortcuts.js]
 [browser_multiselect_tabs_close.js]
+[browser_multiselect_tabs_copy_through_drag_and_drop.js]
 [browser_multiselect_tabs_event.js]
 [browser_multiselect_tabs_move_to_new_window_contextmenu.js]
 [browser_multiselect_tabs_mute_unmute.js]
 [browser_multiselect_tabs_pin_unpin.js]
 [browser_multiselect_tabs_positional_attrs.js]
 [browser_multiselect_tabs_reload.js]
 [browser_multiselect_tabs_reorder.js]
 [browser_multiselect_tabs_using_Ctrl.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabs/browser_multiselect_tabs_copy_through_drag_and_drop.js
@@ -0,0 +1,59 @@
+const PREF_MULTISELECT_TABS = "browser.tabs.multiselect";
+function url(tab) {
+  return tab.linkedBrowser.currentURI.spec;
+}
+
+add_task(async function setPref() {
+  await SpecialPowers.pushPrefEnv({
+    set: [[PREF_MULTISELECT_TABS, true]]
+  });
+});
+
+add_task(async function test() {
+  let tab0 = gBrowser.selectedTab;
+  let tab1 = await addTab("http://example.com/1");
+  let tab2 = await addTab("http://example.com/2");
+  let tab3 = await addTab("http://example.com/3");
+  let tabs = [tab0, tab1, tab2, tab3];
+
+  await BrowserTestUtils.switchTab(gBrowser, tab1);
+  await triggerClickOn(tab2, { ctrlKey: true });
+
+  is(gBrowser.selectedTab, tab1, "Tab1 is active");
+  is(gBrowser.selectedTabs.length, 2, "Two selected tabs");
+  is(gBrowser.visibleTabs.length, 4, "Four tabs in window before copy");
+
+  for (let i of [1, 2]) {
+    ok(tabs[i].multiselected, "Tab" + i + " is multiselected");
+  }
+  for (let i of [0, 3]) {
+    ok(!tabs[i].multiselected, "Tab" + i + " is not multiselected");
+  }
+
+  await dragAndDrop(tab1, tab3, true);
+
+  is(gBrowser.selectedTab, tab1, "tab1 is still active");
+  is(gBrowser.selectedTabs.length, 2, "Two selected tabs");
+  is(gBrowser.visibleTabs.length, 6, "Six tabs in window after copy");
+
+  let tab4 = gBrowser.visibleTabs[4];
+  let tab5 = gBrowser.visibleTabs[5];
+  tabs.push(tab4);
+  tabs.push(tab5);
+
+  for (let i of [1, 2]) {
+    ok(tabs[i].multiselected, "Tab" + i + " is multiselected");
+  }
+  for (let i of [0, 3, 4, 5]) {
+    ok(!tabs[i].multiselected, "Tab" + i + " is not multiselected");
+  }
+
+  await BrowserTestUtils.waitForCondition(() => url(tab4) == url(tab1));
+  await BrowserTestUtils.waitForCondition(() => url(tab5) == url(tab2));
+
+  ok(true, "Tab1 and tab2 are duplicated succesfully");
+
+  for (let tab of tabs.filter(t => t != tab0))
+    BrowserTestUtils.removeTab(tab);
+});
+
--- a/browser/base/content/test/tabs/head.js
+++ b/browser/base/content/test/tabs/head.js
@@ -16,19 +16,18 @@ function triggerClickOn(target, options)
           metaKey: options.ctrlKey,
           shiftKey: options.shiftKey
       };
   }
   EventUtils.synthesizeMouseAtCenter(target, options);
   return promise;
 }
 
-async function addTab() {
-  const tab = BrowserTestUtils.addTab(gBrowser,
-      "http://mochi.test:8888/", { skipAnimation: true });
+async function addTab(url = "http://mochi.test:8888/") {
+  const tab = BrowserTestUtils.addTab(gBrowser, url, { skipAnimation: true });
   const browser = gBrowser.getBrowserForTab(tab);
   await BrowserTestUtils.browserLoaded(browser);
   return tab;
 }
 
 async function wait_for_tab_playing_event(tab, expectPlaying) {
   if (tab.soundPlaying == expectPlaying) {
     ok(true, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");