Bug 1479257 - Implement ability to duplicate a selection of tabs through drag and drop. r?jaws
MozReview-Commit-ID: FSttZ0ytxX0
--- 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");