зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1761265, don't show the downloads panel when a download was started by user action that they expect will save the file, r=mhowell,necko-reviewers,kershaw
The download panel should still appear when clicking on download links or those with content-disposition: attachment Differential Revision: https://phabricator.services.mozilla.com/D147875
This commit is contained in:
Родитель
d4ff2f21bf
Коммит
a49aa34d6d
|
@ -45,6 +45,7 @@ skip-if =
|
|||
support-files =
|
||||
foo.txt
|
||||
foo.txt^headers^
|
||||
[browser_downloads_panel_dontshow.js]
|
||||
[browser_downloads_panel_height.js]
|
||||
[browser_downloads_panel_opens.js]
|
||||
[browser_downloads_autohide.js]
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
// This test verifies that the download panel opens when a
|
||||
// download occurs but not when a user manually saves a page.
|
||||
|
||||
let MockFilePicker = SpecialPowers.MockFilePicker;
|
||||
MockFilePicker.init(window);
|
||||
|
||||
async function promiseDownloadFinished(list) {
|
||||
return new Promise(resolve => {
|
||||
list.addView({
|
||||
onDownloadChanged(download) {
|
||||
download.launchWhenSucceeded = false;
|
||||
if (download.succeeded || download.error) {
|
||||
list.removeView(this);
|
||||
resolve(download);
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function openTestPage() {
|
||||
return BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
`https://www.example.com/document-builder.sjs?html=
|
||||
<html><body>
|
||||
<a id='normallink' href='https://www.example.com'>Link1</a>
|
||||
<a id='downloadlink' href='https://www.example.com' download='file.txt'>Link2</a>
|
||||
</body</html>
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function download_saveas_file() {
|
||||
let tab = await openTestPage();
|
||||
|
||||
for (let testname of ["save link", "save page"]) {
|
||||
if (testname == "save link") {
|
||||
let menu = document.getElementById("contentAreaContextMenu");
|
||||
let popupShown = BrowserTestUtils.waitForEvent(menu, "popupshown");
|
||||
BrowserTestUtils.synthesizeMouse(
|
||||
"#normallink",
|
||||
5,
|
||||
5,
|
||||
{ type: "contextmenu", button: 2 },
|
||||
gBrowser.selectedBrowser
|
||||
);
|
||||
await popupShown;
|
||||
}
|
||||
|
||||
let list = await Downloads.getList(Downloads.PUBLIC);
|
||||
let downloadFinishedPromise = promiseDownloadFinished(list);
|
||||
|
||||
let saveFile = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
saveFile.append("testsavedir");
|
||||
if (!saveFile.exists()) {
|
||||
saveFile.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
|
||||
}
|
||||
|
||||
await new Promise(resolve => {
|
||||
MockFilePicker.showCallback = function(fp) {
|
||||
saveFile.append("sample");
|
||||
MockFilePicker.setFiles([saveFile]);
|
||||
setTimeout(() => {
|
||||
resolve(fp.defaultString);
|
||||
}, 0);
|
||||
return Ci.nsIFilePicker.returnOK;
|
||||
};
|
||||
|
||||
if (testname == "save link") {
|
||||
let menu = document.getElementById("contentAreaContextMenu");
|
||||
let menuitem = document.getElementById("context-savelink");
|
||||
menu.activateItem(menuitem);
|
||||
} else if (testname == "save page") {
|
||||
document.getElementById("Browser:SavePage").doCommand();
|
||||
}
|
||||
});
|
||||
|
||||
await downloadFinishedPromise;
|
||||
is(
|
||||
DownloadsPanel.panel.state,
|
||||
"closed",
|
||||
"downloads panel closed after download link after " + testname
|
||||
);
|
||||
}
|
||||
|
||||
await task_resetState();
|
||||
|
||||
MockFilePicker.cleanup();
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(async function download_link() {
|
||||
let tab = await openTestPage();
|
||||
|
||||
let list = await Downloads.getList(Downloads.PUBLIC);
|
||||
let downloadFinishedPromise = promiseDownloadFinished(list);
|
||||
|
||||
let panelOpenedPromise = promisePanelOpened();
|
||||
|
||||
BrowserTestUtils.synthesizeMouse(
|
||||
"#downloadlink",
|
||||
5,
|
||||
5,
|
||||
{},
|
||||
gBrowser.selectedBrowser
|
||||
);
|
||||
|
||||
let download = await downloadFinishedPromise;
|
||||
await panelOpenedPromise;
|
||||
|
||||
is(
|
||||
DownloadsPanel.panel.state,
|
||||
"open",
|
||||
"downloads panel open after download link clicked"
|
||||
);
|
||||
|
||||
DownloadsPanel.hidePanel();
|
||||
|
||||
await task_resetState();
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
try {
|
||||
await IOUtils.remove(download.target.path);
|
||||
} catch (ex) {}
|
||||
});
|
|
@ -1377,6 +1377,9 @@ nsresult nsWebBrowserPersist::SaveURIInternal(
|
|||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = inputChannel->LoadInfo();
|
||||
loadInfo->SetIsUserTriggeredSave(true);
|
||||
|
||||
// Set the referrer, post data and headers if any
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(inputChannel));
|
||||
if (httpChannel) {
|
||||
|
|
|
@ -1800,6 +1800,20 @@ LoadInfo::SetAllowDeprecatedSystemRequests(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetIsUserTriggeredSave(bool* aIsUserTriggeredSave) {
|
||||
*aIsUserTriggeredSave =
|
||||
mIsUserTriggeredSave ||
|
||||
mInternalContentPolicyType == nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::SetIsUserTriggeredSave(bool aIsUserTriggeredSave) {
|
||||
mIsUserTriggeredSave = aIsUserTriggeredSave;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetIsInDevToolsContext(bool* aIsInDevToolsContext) {
|
||||
*aIsInDevToolsContext = mIsInDevToolsContext;
|
||||
|
|
|
@ -330,6 +330,7 @@ class LoadInfo final : public nsILoadInfo {
|
|||
uint32_t mHttpsOnlyStatus = nsILoadInfo::HTTPS_ONLY_UNINITIALIZED;
|
||||
bool mHasValidUserGestureActivation = false;
|
||||
bool mAllowDeprecatedSystemRequests = false;
|
||||
bool mIsUserTriggeredSave = false;
|
||||
bool mIsInDevToolsContext = false;
|
||||
bool mParserCreatedScript = false;
|
||||
nsILoadInfo::StoragePermissionState mStoragePermission =
|
||||
|
|
|
@ -698,6 +698,16 @@ TRRLoadInfo::SetAllowDeprecatedSystemRequests(
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TRRLoadInfo::GetIsUserTriggeredSave(bool* aIsUserTriggeredSave) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TRRLoadInfo::SetIsUserTriggeredSave(bool aIsUserTriggeredSave) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TRRLoadInfo::GetIsInDevToolsContext(bool* aIsInDevToolsContext) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
|
|
@ -510,6 +510,12 @@ interface nsILoadInfo : nsISupports
|
|||
*/
|
||||
[infallible] attribute boolean parserCreatedScript;
|
||||
|
||||
/**
|
||||
* True if this request is known to have been triggered by a user
|
||||
* manually requesting the URI to be saved.
|
||||
*/
|
||||
[infallible] attribute boolean isUserTriggeredSave;
|
||||
|
||||
/**
|
||||
* True if this request is from DevTools.
|
||||
*/
|
||||
|
|
|
@ -2867,6 +2867,15 @@ DownloadLegacySaver.prototype = {
|
|||
this.download.source.referrerInfo = aRequest.referrerInfo;
|
||||
}
|
||||
|
||||
// Don't open the download panel when the user initiated to save a
|
||||
// link or document.
|
||||
if (
|
||||
aRequest instanceof Ci.nsIChannel &&
|
||||
aRequest.loadInfo.isUserTriggeredSave
|
||||
) {
|
||||
this.download.openDownloadsListOnStart = false;
|
||||
}
|
||||
|
||||
this.addToHistory();
|
||||
},
|
||||
|
||||
|
|
|
@ -12,6 +12,20 @@ MockFilePicker.returnValue = MockFilePicker.returnOK;
|
|||
|
||||
var tempDir;
|
||||
|
||||
async function promiseDownloadFinished(list) {
|
||||
return new Promise(resolve => {
|
||||
list.addView({
|
||||
onDownloadChanged(download) {
|
||||
download.launchWhenSucceeded = false;
|
||||
if (download.succeeded || download.error) {
|
||||
list.removeView(this);
|
||||
resolve(download);
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createPromiseForFilePicker() {
|
||||
return new Promise(resolve => {
|
||||
MockFilePicker.showCallback = fp => {
|
||||
|
@ -77,10 +91,7 @@ add_task(async function test_downloading_pdf_nonprivate_window() {
|
|||
|
||||
let filePickerShown = createPromiseForFilePicker();
|
||||
|
||||
let downloadsPanelPromise = BrowserTestUtils.waitForEvent(
|
||||
DownloadsPanel.panel,
|
||||
"popupshown"
|
||||
);
|
||||
let downloadFinishedPromise = promiseDownloadFinished(downloadList);
|
||||
|
||||
info("Clicking on the download button...");
|
||||
await SpecialPowers.spawn(browser, [], () => {
|
||||
|
@ -89,14 +100,13 @@ add_task(async function test_downloading_pdf_nonprivate_window() {
|
|||
info("Waiting for a filename to be picked from the file picker");
|
||||
await filePickerShown;
|
||||
|
||||
// check that resulted in a download being added to the list
|
||||
// and the dl panel opened
|
||||
info("Waiting for download panel to open when the download is complete");
|
||||
await downloadsPanelPromise;
|
||||
// check that resulted in a download being added to the list. The
|
||||
// download panel should not open.
|
||||
await downloadFinishedPromise;
|
||||
is(
|
||||
DownloadsPanel.panel.state,
|
||||
"open",
|
||||
"Check the download panel state is 'open'"
|
||||
"closed",
|
||||
"Check the download panel state is 'closed'"
|
||||
);
|
||||
downloadList = await Downloads.getList(Downloads.PUBLIC);
|
||||
const allDownloads = await downloadList.getAll();
|
||||
|
@ -120,7 +130,6 @@ add_task(async function test_downloading_pdf_nonprivate_window() {
|
|||
tabCount,
|
||||
"No new tab was opened to view the downloaded PDF"
|
||||
);
|
||||
await closeDownloadsPanel();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче