Bug 1435910 - Part 1: Warn when opening too many tabs by drag and drop. r=Gijs

This commit is contained in:
Tooru Fujisawa 2018-02-28 10:36:43 +09:00
parent 9a32a77bc1
commit 3546360add
7 changed files with 195 additions and 19 deletions

View File

@ -35,6 +35,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
Log: "resource://gre/modules/Log.jsm",
LoginManagerParent: "resource://gre/modules/LoginManagerParent.jsm",
NewTabUtils: "resource://gre/modules/NewTabUtils.jsm",
OpenInTabsUtils: "resource:///modules/OpenInTabsUtils.jsm",
PageActions: "resource:///modules/PageActions.jsm",
PageThumbs: "resource://gre/modules/PageThumbs.jsm",
PanelMultiView: "resource:///modules/PanelMultiView.jsm",
@ -3569,12 +3570,23 @@ var newTabButtonObserver = {
},
onDragExit(aEvent) {},
async onDrop(aEvent) {
let shiftKey = aEvent.shiftKey;
let links = browserDragAndDrop.dropLinks(aEvent);
if (links.length >= Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")) {
// Sync dialog cannot be used inside drop event handler.
let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(links.length,
window);
if (!answer) {
return;
}
}
for (let link of links) {
if (link.url) {
let data = await getShortcutOrURIAndPostData(link.url);
// Allow third-party services to fixup this URL.
openNewTabWith(data.url, null, data.postData, aEvent, true);
openNewTabWith(data.url, null, data.postData, shiftKey, true);
}
}
}
@ -3587,6 +3599,16 @@ var newWindowButtonObserver = {
onDragExit(aEvent) {},
async onDrop(aEvent) {
let links = browserDragAndDrop.dropLinks(aEvent);
if (links.length >= Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")) {
// Sync dialog cannot be used inside drop event handler.
let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(links.length,
window);
if (!answer) {
return;
}
}
for (let link of links) {
if (link.url) {
let data = await getShortcutOrURIAndPostData(link.url);
@ -6113,6 +6135,15 @@ function handleDroppedLink(event, urlOrLinks, nameOrTriggeringPrincipal, trigger
}
(async function() {
if (links.length >= Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")) {
// Sync dialog cannot be used inside drop event handler.
let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(links.length,
window);
if (!answer) {
return;
}
}
let urls = [];
let postDatas = [];
for (let link of links) {

View File

@ -7671,7 +7671,6 @@
return;
let inBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
if (event.shiftKey)
inBackground = !inBackground;
@ -7682,15 +7681,27 @@
let urls = links.map(link => link.url);
let triggeringPrincipal = browserDragAndDrop.getTriggeringPrincipal(event);
this.tabbrowser.loadTabs(urls, {
inBackground,
replace,
allowThirdPartyFixup: true,
targetTab,
newIndex,
userContextId,
triggeringPrincipal,
});
(async () => {
if (urls.length >= Services.prefs.getIntPref("browser.tabs.maxOpenBeforeWarn")) {
// Sync dialog cannot be used inside drop event handler.
let answer = await OpenInTabsUtils.promiseConfirmOpenInTabs(urls.length,
window);
if (!answer) {
return;
}
}
this.tabbrowser.loadTabs(urls, {
inBackground,
replace,
allowThirdPartyFixup: true,
targetTab,
newIndex,
userContextId,
triggeringPrincipal,
});
})();
}
if (draggedTab) {

View File

@ -53,6 +53,45 @@ add_task(async function() {
data: "mochi.test/11\nTITLE11"}]], 1);
});
// Warn when too many URLs are dropped.
add_task(async function multiple_tabs_under_max() {
let urls = [];
for (let i = 0; i < 5; i++) {
urls.push("mochi.test/multi" + i);
}
await dropText(urls.join("\n"), 5);
});
add_task(async function multiple_tabs_over_max_accept() {
await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]);
let confirmPromise = BrowserTestUtils.promiseAlertDialog("accept");
let urls = [];
for (let i = 0; i < 5; i++) {
urls.push("mochi.test/accept" + i);
}
await dropText(urls.join("\n"), 5);
await confirmPromise;
await popPrefs();
});
add_task(async function multiple_tabs_over_max_cancel() {
await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]);
let confirmPromise = BrowserTestUtils.promiseAlertDialog("cancel");
let urls = [];
for (let i = 0; i < 5; i++) {
urls.push("mochi.test/cancel" + i);
}
await dropText(urls.join("\n"), 0);
await confirmPromise;
await popPrefs();
});
function dropText(text, expectedTabOpenCount = 0) {
return drop([[{type: "text/plain", data: text}]], expectedTabOpenCount);
}

View File

@ -66,11 +66,53 @@ add_task(async function() {
data: "mochi.test/11\nTITLE11"}]], 1);
});
function dropText(text, expectedWindowOpenCount = 0) {
return drop([[{type: "text/plain", data: text}]], expectedWindowOpenCount);
// Warn when too many URLs are dropped.
add_task(async function multiple_tabs_under_max() {
let urls = [];
for (let i = 0; i < 5; i++) {
urls.push("mochi.test/multi" + i);
}
await dropText(urls.join("\n"), 5);
});
add_task(async function multiple_tabs_over_max_accept() {
await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]);
let confirmPromise = BrowserTestUtils.promiseAlertDialog("accept");
let urls = [];
for (let i = 0; i < 5; i++) {
urls.push("mochi.test/accept" + i);
}
await dropText(urls.join("\n"), 5, true);
await confirmPromise;
await popPrefs();
});
add_task(async function multiple_tabs_over_max_cancel() {
await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]);
let confirmPromise = BrowserTestUtils.promiseAlertDialog("cancel");
let urls = [];
for (let i = 0; i < 5; i++) {
urls.push("mochi.test/cancel" + i);
}
await dropText(urls.join("\n"), 0, true);
await confirmPromise;
await popPrefs();
});
function dropText(text, expectedWindowOpenCount = 0,
ignoreFirstWindow = false) {
return drop([[{type: "text/plain", data: text}]], expectedWindowOpenCount,
ignoreFirstWindow);
}
async function drop(dragData, expectedWindowOpenCount = 0) {
async function drop(dragData, expectedWindowOpenCount = 0,
ignoreFirstWindow = false) {
let dragDataString = JSON.stringify(dragData);
info(`Starting test for datagData:${dragDataString}; expectedWindowOpenCount:${expectedWindowOpenCount}`);
let EventUtils = {};
@ -89,6 +131,14 @@ async function drop(dragData, expectedWindowOpenCount = 0) {
let actualWindowOpenCount = 0;
let openedWindows = [];
let checkCount = function(window) {
if (ignoreFirstWindow) {
// When dropping too many dialog, the confirm dialog is opened and
// domwindowopened notification is dispatched for it, before opening
// windows for dropped items. Ignore it.
ignoreFirstWindow = false;
return false;
}
// Add observer as soon as domWindow is opened to avoid missing the topic.
let awaitStartup = tmp.TestUtils.topicObserved("browser-delayed-startup-finished",
subject => subject == window);

View File

@ -53,6 +53,45 @@ add_task(async function() {
data: "mochi.test/11\nTITLE11"}]], 1);
});
// Warn when too many URLs are dropped.
add_task(async function multiple_tabs_under_max() {
let urls = [];
for (let i = 0; i < 5; i++) {
urls.push("mochi.test/multi" + i);
}
await dropText(urls.join("\n"), 5);
});
add_task(async function multiple_tabs_over_max_accept() {
await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]);
let confirmPromise = BrowserTestUtils.promiseAlertDialog("accept");
let urls = [];
for (let i = 0; i < 5; i++) {
urls.push("mochi.test/accept" + i);
}
await dropText(urls.join("\n"), 5, true);
await confirmPromise;
await popPrefs();
});
add_task(async function multiple_tabs_over_max_cancel() {
await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]);
let confirmPromise = BrowserTestUtils.promiseAlertDialog("cancel");
let urls = [];
for (let i = 0; i < 5; i++) {
urls.push("mochi.test/cancel" + i);
}
await dropText(urls.join("\n"), 0, true);
await confirmPromise;
await popPrefs();
});
function dropText(text, expectedTabOpenCount = 0) {
return drop([[{type: "text/plain", data: text}]], expectedTabOpenCount);
}

View File

@ -169,6 +169,12 @@ function pushPrefs(...aPrefs) {
});
}
function popPrefs() {
return new Promise(resolve => {
SpecialPowers.popPrefEnv(resolve);
});
}
function updateBlocklist(aCallback) {
var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
.getService(Ci.nsITimerCallback);

View File

@ -860,9 +860,9 @@ function makeURLAbsolute(aBase, aUrl) {
* referrer header derived from aDocument (null case).
* @param aPostData
* Form POST data, or null.
* @param aEvent
* The triggering event (for the purpose of determining whether to open
* in the background), or null.
* @param aShiftKey
* True if shift key is held. This value is used for the purpose of
* determining whether to open in the background.
* @param aAllowThirdPartyFixup
* If true, then we allow the URL text to be sent to third party services
* (e.g., Google's I Feel Lucky) for interpretation. This parameter may
@ -872,7 +872,7 @@ function makeURLAbsolute(aBase, aUrl) {
* @param [optional] aReferrerPolicy
* Referrer policy - Ci.nsIHttpChannel.REFERRER_POLICY_*.
*/
function openNewTabWith(aURL, aDocument, aPostData, aEvent,
function openNewTabWith(aURL, aDocument, aPostData, aShiftKey,
aAllowThirdPartyFixup, aReferrer, aReferrerPolicy) {
// As in openNewWindowWith(), we want to pass the charset of the
@ -881,7 +881,7 @@ function openNewTabWith(aURL, aDocument, aPostData, aEvent,
if (document.documentElement.getAttribute("windowtype") == "navigator:browser")
originCharset = gBrowser.selectedBrowser.characterSet;
openLinkIn(aURL, aEvent && aEvent.shiftKey ? "tabshifted" : "tab",
openLinkIn(aURL, aShiftKey ? "tabshifted" : "tab",
{ charset: originCharset,
postData: aPostData,
allowThirdPartyFixup: aAllowThirdPartyFixup,