Bug 1458056 - Implement ability to move a selection of tabs into another window through drag and drop. r=jaws

MozReview-Commit-ID: LFFoE6HsBp8

Differential Revision: https://phabricator.services.mozilla.com/D2986

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Abdoulaye O. Ly 2018-08-09 18:45:52 +00:00
parent 584157b2d3
commit 19bf2f8d32
6 changed files with 105 additions and 10 deletions

View File

@ -3487,6 +3487,12 @@ window._gBrowser = {
if (activeTabNewIndex > -1) {
win.gBrowser.adoptTab(activeTab, activeTabNewIndex, true /* aSelectTab */);
}
// Restore tab selection
let winVisibleTabs = win.gBrowser.visibleTabs;
let winTabLength = winVisibleTabs.length;
win.gBrowser.addRangeToMultiSelectedTabs(winVisibleTabs[0],
winVisibleTabs[winTabLength - 1]);
}, { once: true });
win = this.replaceTabWithWindow(firstInactiveTab);

View File

@ -1479,7 +1479,14 @@
}
} else if (draggedTab) {
let newIndex = this._getDropIndex(event, false);
gBrowser.adoptTab(draggedTab, newIndex, true);
let newTabs = [];
for (let tab of movingTabs) {
let newTab = gBrowser.adoptTab(tab, newIndex++, tab == draggedTab);
newTabs.push(newTab);
}
// Restore tab selection
gBrowser.addRangeToMultiSelectedTabs(newTabs[0], newTabs[newTabs.length - 1]);
} else {
// Pass true to disallow dropping javascript: or data: urls
let links;
@ -1606,7 +1613,7 @@
props.outerWidth = winWidth;
props.outerHeight = winHeight;
}
gBrowser.replaceTabWithWindow(draggedTab, props);
gBrowser.replaceTabsWithWindow(draggedTab, props);
}
event.stopPropagation();
]]></handler>

View File

@ -28,6 +28,7 @@ support-files =
[browser_multiselect_tabs_close.js]
[browser_multiselect_tabs_copy_through_drag_and_drop.js]
[browser_multiselect_tabs_event.js]
[browser_multiselect_tabs_move_to_another_window_drag.js]
[browser_multiselect_tabs_move_to_new_window_contextmenu.js]
[browser_multiselect_tabs_mute_unmute.js]
[browser_multiselect_tabs_pin_unpin.js]

View File

@ -1,7 +1,4 @@
const PREF_MULTISELECT_TABS = "browser.tabs.multiselect";
function url(tab) {
return tab.linkedBrowser.currentURI.spec;
}
add_task(async function setPref() {
await SpecialPowers.pushPrefEnv({
@ -48,8 +45,8 @@ add_task(async function test() {
ok(!tabs[i].multiselected, "Tab" + i + " is not multiselected");
}
await BrowserTestUtils.waitForCondition(() => url(tab4) == url(tab1));
await BrowserTestUtils.waitForCondition(() => url(tab5) == url(tab2));
await BrowserTestUtils.waitForCondition(() => getUrl(tab4) == getUrl(tab1));
await BrowserTestUtils.waitForCondition(() => getUrl(tab5) == getUrl(tab2));
ok(true, "Tab1 and tab2 are duplicated succesfully");

View File

@ -0,0 +1,71 @@
const PREF_MULTISELECT_TABS = "browser.tabs.multiselect";
const PREF_ANIMATIONS_ENABLED = "toolkit.cosmeticAnimations.enabled";
add_task(async function setPref() {
await SpecialPowers.pushPrefEnv({
set: [
[PREF_MULTISELECT_TABS, true],
[PREF_ANIMATIONS_ENABLED, false]
]
});
});
add_task(async function test() {
let tab1 = await addTab();
let tab2 = await addTab();
let tab3 = await addTab("http://mochi.test:8888/3");
let tab4 = await addTab();
let tab5 = await addTab("http://mochi.test:8888/5");
is(gBrowser.multiSelectedTabsCount, 0, "Zero multiselected tabs");
await BrowserTestUtils.switchTab(gBrowser, tab2);
await triggerClickOn(tab1, { ctrlKey: true });
ok(tab1.multiselected, "Tab1 is multiselected");
ok(tab2.multiselected, "Tab2 is multiselected");
ok(!tab3.multiselected, "Tab3 is not multiselected");
ok(!tab4.multiselected, "Tab4 is not multiselected");
ok(!tab5.multiselected, "Tab5 is not multiselected");
is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs");
let newWindow = gBrowser.replaceTabsWithWindow(tab1);
// waiting for tab2 to close ensure that the newWindow is created,
// thus newWindow.gBrowser used in the second waitForCondition
// will not be undefined.
await TestUtils.waitForCondition(() => tab2.closing, "Wait for tab2 to close");
await TestUtils.waitForCondition(() => newWindow.gBrowser.visibleTabs.length == 2,
"Wait for all two tabs to get moved to the new window");
let gBrowser2 = newWindow.gBrowser;
tab1 = gBrowser2.visibleTabs[0];
tab2 = gBrowser2.visibleTabs[1];
if (gBrowser.selectedTab != tab3)
await BrowserTestUtils.switchTab(gBrowser, tab3);
await triggerClickOn(tab5, { ctrlKey: true });
ok(tab1.multiselected, "Tab1 is multiselected");
ok(tab2.multiselected, "Tab2 is multiselected");
ok(tab3.multiselected, "Tab3 is multiselected");
ok(!tab4.multiselected, "Tab4 is not multiselected");
ok(tab5.multiselected, "Tab5 is multiselected");
await dragAndDrop(tab3, tab1, false, newWindow);
await TestUtils.waitForCondition(() => gBrowser2.visibleTabs.length == 4,
"Moved tab3 and tab5 to second window");
tab3 = gBrowser2.visibleTabs[1];
tab5 = gBrowser2.visibleTabs[2];
await BrowserTestUtils.waitForCondition(() => getUrl(tab3) == "http://mochi.test:8888/3");
await BrowserTestUtils.waitForCondition(() => getUrl(tab5) == "http://mochi.test:8888/5");
ok(true, "Tab3 and tab5 are duplicated succesfully");
BrowserTestUtils.closeWindow(newWindow);
BrowserTestUtils.removeTab(tab4);
});

View File

@ -157,7 +157,7 @@ async function test_mute_tab(tab, icon, expectMuted) {
return mutedPromise;
}
async function dragAndDrop(tab1, tab2, copy) {
async function dragAndDrop(tab1, tab2, copy, destWindow = window) {
let rect = tab2.getBoundingClientRect();
let event = {
ctrlKey: copy,
@ -166,10 +166,23 @@ async function dragAndDrop(tab1, tab2, copy) {
clientY: rect.top + rect.height / 2,
};
if (destWindow != window) {
// Make sure that both tab1 and tab2 are visible
window.focus();
window.moveTo(rect.left, rect.top + rect.height * 3);
}
let originalTPos = tab1._tPos;
EventUtils.synthesizeDrop(tab1, tab2, null, copy ? "copy" : "move", window, window, event);
if (!copy) {
EventUtils.synthesizeDrop(tab1, tab2, null, copy ? "copy" : "move", window, destWindow, event);
if (!copy && destWindow == window) {
await BrowserTestUtils.waitForCondition(() => tab1._tPos != originalTPos,
"Waiting for tab position to be updated");
} else if (destWindow != window) {
await BrowserTestUtils.waitForCondition(() => tab1.closing,
"Waiting for tab closing");
}
}
function getUrl(tab) {
return tab.linkedBrowser.currentURI.spec;
}