forked from mirrors/gecko-dev
Bug 1639069 - Add download context menu items to 'Use' and 'Always use' the system viewer to open the download. r=jaws
Differential Revision: https://phabricator.services.mozilla.com/D79396
This commit is contained in:
parent
1c447df70b
commit
394b51b9e3
13 changed files with 389 additions and 8 deletions
|
|
@ -359,6 +359,13 @@ pref("browser.download.animateNotifications", true);
|
||||||
// This records whether or not the panel has been shown at least once.
|
// This records whether or not the panel has been shown at least once.
|
||||||
pref("browser.download.panel.shown", false);
|
pref("browser.download.panel.shown", false);
|
||||||
|
|
||||||
|
// This records whether or not to show the 'Open in system viewer' context menu item when appropriate
|
||||||
|
pref("browser.download.openInSystemViewerContextMenuItem", true);
|
||||||
|
|
||||||
|
// This records whether or not to show the 'Always open...' context menu item when appropriate
|
||||||
|
pref("browser.download.alwaysOpenInSystemViewerContextMenuItem", true);
|
||||||
|
|
||||||
|
|
||||||
// This controls whether the button is automatically shown/hidden depending
|
// This controls whether the button is automatically shown/hidden depending
|
||||||
// on whether there are downloads to show.
|
// on whether there are downloads to show.
|
||||||
pref("browser.download.autohideButton", true);
|
pref("browser.download.autohideButton", true);
|
||||||
|
|
|
||||||
|
|
@ -229,6 +229,8 @@ var PrefObserver = {
|
||||||
PrefObserver.register({
|
PrefObserver.register({
|
||||||
// prefName: defaultValue
|
// prefName: defaultValue
|
||||||
animateNotifications: true,
|
animateNotifications: true,
|
||||||
|
openInSystemViewerContextMenuItem: true,
|
||||||
|
alwaysOpenInSystemViewerContextMenuItem: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// DownloadsCommon
|
// DownloadsCommon
|
||||||
|
|
@ -296,6 +298,20 @@ var DownloadsCommon = {
|
||||||
return PrefObserver.animateNotifications;
|
return PrefObserver.animateNotifications;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether or not to show the 'Open in system viewer' context menu item when appropriate
|
||||||
|
*/
|
||||||
|
get openInSystemViewerItemEnabled() {
|
||||||
|
return PrefObserver.openInSystemViewerContextMenuItem;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether or not to show the 'Always open...' context menu item when appropriate
|
||||||
|
*/
|
||||||
|
get alwaysOpenInSystemViewerItemEnabled() {
|
||||||
|
return PrefObserver.alwaysOpenInSystemViewerContextMenuItem;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get access to one of the DownloadsData, PrivateDownloadsData, or
|
* Get access to one of the DownloadsData, PrivateDownloadsData, or
|
||||||
* HistoryDownloadsData objects, depending on the privacy status of the
|
* HistoryDownloadsData objects, depending on the privacy status of the
|
||||||
|
|
@ -610,6 +626,9 @@ var DownloadsCommon = {
|
||||||
* @param options.openWhere
|
* @param options.openWhere
|
||||||
* Optional string indicating how to handle opening a download target file URI.
|
* Optional string indicating how to handle opening a download target file URI.
|
||||||
* One of "window", "tab", "tabshifted".
|
* One of "window", "tab", "tabshifted".
|
||||||
|
* @param options.useSystemDefault
|
||||||
|
* Optional value indicating how to handle launching this download,
|
||||||
|
* this call only. Will override the associated mimeInfo.preferredAction
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
* @resolves When the instruction to launch the file has been
|
* @resolves When the instruction to launch the file has been
|
||||||
* successfully given to the operating system or handled internally
|
* successfully given to the operating system or handled internally
|
||||||
|
|
|
||||||
|
|
@ -297,6 +297,11 @@ class DownloadsSubview extends DownloadsViewUI.BaseView {
|
||||||
while (!button._shell) {
|
while (!button._shell) {
|
||||||
button = button.parentNode;
|
button = button.parentNode;
|
||||||
}
|
}
|
||||||
|
let download = button._shell.download;
|
||||||
|
let { preferredAction, useSystemDefault } = DownloadsCommon.getMimeInfo(
|
||||||
|
download
|
||||||
|
);
|
||||||
|
|
||||||
menu.setAttribute("state", button.getAttribute("state"));
|
menu.setAttribute("state", button.getAttribute("state"));
|
||||||
if (button.hasAttribute("exists")) {
|
if (button.hasAttribute("exists")) {
|
||||||
menu.setAttribute("exists", button.getAttribute("exists"));
|
menu.setAttribute("exists", button.getAttribute("exists"));
|
||||||
|
|
@ -307,6 +312,37 @@ class DownloadsSubview extends DownloadsViewUI.BaseView {
|
||||||
"temporary-block",
|
"temporary-block",
|
||||||
button.classList.contains("temporary-block")
|
button.classList.contains("temporary-block")
|
||||||
);
|
);
|
||||||
|
// menu items are conditionally displayed via CSS based on an is-pdf attribute
|
||||||
|
DownloadsCommon.log(
|
||||||
|
"DownloadsSubview, updateContextMenu, download is pdf? ",
|
||||||
|
download.target.path,
|
||||||
|
button.hasAttribute("is-pdf")
|
||||||
|
);
|
||||||
|
if (button.hasAttribute("is-pdf")) {
|
||||||
|
menu.setAttribute("is-pdf", "true");
|
||||||
|
let alwaysUseSystemViewerItem = menu.querySelector(
|
||||||
|
".downloadAlwaysUseSystemDefaultMenuItem"
|
||||||
|
);
|
||||||
|
if (preferredAction === useSystemDefault) {
|
||||||
|
alwaysUseSystemViewerItem.setAttribute("checked", "true");
|
||||||
|
} else {
|
||||||
|
alwaysUseSystemViewerItem.removeAttribute("checked");
|
||||||
|
}
|
||||||
|
alwaysUseSystemViewerItem.toggleAttribute(
|
||||||
|
"enabled",
|
||||||
|
DownloadsCommon.alwaysOpenInSystemViewerItemEnabled
|
||||||
|
);
|
||||||
|
let useSystemViewerItem = menu.querySelector(
|
||||||
|
".downloadUseSystemDefaultMenuItem"
|
||||||
|
);
|
||||||
|
useSystemViewerItem.toggleAttribute(
|
||||||
|
"enabled",
|
||||||
|
DownloadsCommon.openInSystemViewerItemEnabled
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
menu.removeAttribute("is-pdf");
|
||||||
|
}
|
||||||
|
|
||||||
for (let menuitem of menu.getElementsByTagName("menuitem")) {
|
for (let menuitem of menu.getElementsByTagName("menuitem")) {
|
||||||
let command = menuitem.getAttribute("command");
|
let command = menuitem.getAttribute("command");
|
||||||
if (!command) {
|
if (!command) {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,13 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
OS: "resource://gre/modules/osfile.jsm",
|
OS: "resource://gre/modules/osfile.jsm",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyServiceGetter(
|
||||||
|
this,
|
||||||
|
"handlerSvc",
|
||||||
|
"@mozilla.org/uriloader/handler-service;1",
|
||||||
|
"nsIHandlerService"
|
||||||
|
);
|
||||||
|
|
||||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||||
|
|
||||||
var gDownloadElementButtons = {
|
var gDownloadElementButtons = {
|
||||||
|
|
@ -457,9 +464,21 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
||||||
// on other properties. The order in which we check the properties of the
|
// on other properties. The order in which we check the properties of the
|
||||||
// Download object is the same used by stateOfDownload.
|
// Download object is the same used by stateOfDownload.
|
||||||
if (this.download.succeeded) {
|
if (this.download.succeeded) {
|
||||||
|
DownloadsCommon.log(
|
||||||
|
"_updateStateInner, target exists? ",
|
||||||
|
this.download.target.path,
|
||||||
|
this.download.target.exists
|
||||||
|
);
|
||||||
if (this.download.target.exists) {
|
if (this.download.target.exists) {
|
||||||
// This is a completed download, and the target file still exists.
|
// This is a completed download, and the target file still exists.
|
||||||
this.element.setAttribute("exists", "true");
|
this.element.setAttribute("exists", "true");
|
||||||
|
|
||||||
|
const isPDF = DownloadsCommon.isFileOfType(
|
||||||
|
this.download,
|
||||||
|
"application/pdf"
|
||||||
|
);
|
||||||
|
this.element.toggleAttribute("is-pdf", isPDF);
|
||||||
|
|
||||||
let sizeWithUnits = DownloadsViewUI.getSizeWithUnits(this.download);
|
let sizeWithUnits = DownloadsViewUI.getSizeWithUnits(this.download);
|
||||||
if (this.isPanel) {
|
if (this.isPanel) {
|
||||||
// In the Downloads Panel, we show the file size after the state
|
// In the Downloads Panel, we show the file size after the state
|
||||||
|
|
@ -728,6 +747,9 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
||||||
case "cmd_delete":
|
case "cmd_delete":
|
||||||
// We don't want in-progress downloads to be removed accidentally.
|
// We don't want in-progress downloads to be removed accidentally.
|
||||||
return this.download.stopped;
|
return this.download.stopped;
|
||||||
|
case "downloadsCmd_openInSystemViewer":
|
||||||
|
case "downloadsCmd_alwaysOpenInSystemViewer":
|
||||||
|
return DownloadsCommon.isFileOfType(this.download, "application/pdf");
|
||||||
}
|
}
|
||||||
return DownloadsViewUI.isCommandName(aCommand) && !!this[aCommand];
|
return DownloadsViewUI.isCommandName(aCommand) && !!this[aCommand];
|
||||||
},
|
},
|
||||||
|
|
@ -807,4 +829,39 @@ DownloadsViewUI.DownloadElementShell.prototype = {
|
||||||
cmd_delete() {
|
cmd_delete() {
|
||||||
DownloadsCommon.deleteDownload(this.download).catch(Cu.reportError);
|
DownloadsCommon.deleteDownload(this.download).catch(Cu.reportError);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
downloadsCmd_openInSystemViewer() {
|
||||||
|
// For this interaction only, pass a flag to override the preferredAction for this
|
||||||
|
// mime-type and open using the system viewer
|
||||||
|
DownloadsCommon.openDownload(this.download, {
|
||||||
|
useSystemDefault: true,
|
||||||
|
}).catch(Cu.reportError);
|
||||||
|
},
|
||||||
|
|
||||||
|
downloadsCmd_alwaysOpenInSystemViewer() {
|
||||||
|
// this command toggles between setting preferredAction for this mime-type to open
|
||||||
|
// using the system viewer, or to open the file in browser.
|
||||||
|
const mimeInfo = DownloadsCommon.getMimeInfo(this.download);
|
||||||
|
if (mimeInfo.preferredAction !== mimeInfo.useSystemDefault) {
|
||||||
|
// User has selected to open this mime-type with the system viewer from now on
|
||||||
|
DownloadsCommon.log(
|
||||||
|
"downloadsCmd_alwaysOpenInSystemViewer command for download: ",
|
||||||
|
this.download,
|
||||||
|
"switching to use system default for " + mimeInfo.type
|
||||||
|
);
|
||||||
|
mimeInfo.preferredAction = mimeInfo.useSystemDefault;
|
||||||
|
mimeInfo.alwaysAskBeforeHandling = false;
|
||||||
|
} else {
|
||||||
|
DownloadsCommon.log(
|
||||||
|
"downloadsCmd_alwaysOpenInSystemViewer command for download: ",
|
||||||
|
this.download,
|
||||||
|
"currently uses system default, switching to handleInternally"
|
||||||
|
);
|
||||||
|
// User has selected to not open this mime-type with the system viewer
|
||||||
|
mimeInfo.preferredAction = mimeInfo.handleInternally;
|
||||||
|
mimeInfo.alwaysAskBeforeHandling = true;
|
||||||
|
}
|
||||||
|
handlerSvc.store(mimeInfo);
|
||||||
|
DownloadsCommon.openDownload(this.download).catch(Cu.reportError);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -705,6 +705,9 @@ DownloadsPlacesView.prototype = {
|
||||||
// Set the state attribute so that only the appropriate items are displayed.
|
// Set the state attribute so that only the appropriate items are displayed.
|
||||||
let contextMenu = document.getElementById("downloadsContextMenu");
|
let contextMenu = document.getElementById("downloadsContextMenu");
|
||||||
let download = element._shell.download;
|
let download = element._shell.download;
|
||||||
|
let { preferredAction, useSystemDefault } = DownloadsCommon.getMimeInfo(
|
||||||
|
download
|
||||||
|
);
|
||||||
contextMenu.setAttribute(
|
contextMenu.setAttribute(
|
||||||
"state",
|
"state",
|
||||||
DownloadsCommon.stateOfDownload(download)
|
DownloadsCommon.stateOfDownload(download)
|
||||||
|
|
@ -712,6 +715,31 @@ DownloadsPlacesView.prototype = {
|
||||||
contextMenu.setAttribute("exists", "true");
|
contextMenu.setAttribute("exists", "true");
|
||||||
contextMenu.classList.toggle("temporary-block", !!download.hasBlockedData);
|
contextMenu.classList.toggle("temporary-block", !!download.hasBlockedData);
|
||||||
|
|
||||||
|
if (element.hasAttribute("is-pdf")) {
|
||||||
|
contextMenu.setAttribute("is-pdf", "true");
|
||||||
|
let alwaysUseSystemViewerItem = contextMenu.querySelector(
|
||||||
|
".downloadAlwaysUseSystemDefaultMenuItem"
|
||||||
|
);
|
||||||
|
if (preferredAction === useSystemDefault) {
|
||||||
|
alwaysUseSystemViewerItem.setAttribute("checked", "true");
|
||||||
|
} else {
|
||||||
|
alwaysUseSystemViewerItem.removeAttribute("checked");
|
||||||
|
}
|
||||||
|
alwaysUseSystemViewerItem.toggleAttribute(
|
||||||
|
"enabled",
|
||||||
|
DownloadsCommon.alwaysOpenInSystemViewerItemEnabled
|
||||||
|
);
|
||||||
|
let useSystemViewerItem = contextMenu.querySelector(
|
||||||
|
".downloadUseSystemDefaultMenuItem"
|
||||||
|
);
|
||||||
|
useSystemViewerItem.toggleAttribute(
|
||||||
|
"enabled",
|
||||||
|
DownloadsCommon.openInSystemViewerItemEnabled
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
contextMenu.removeAttribute("is-pdf");
|
||||||
|
}
|
||||||
|
|
||||||
if (!download.stopped) {
|
if (!download.stopped) {
|
||||||
// The hasPartialData property of a download may change at any time after
|
// The hasPartialData property of a download may change at any time after
|
||||||
// it has started, so ensure we update the related command now.
|
// it has started, so ensure we update the related command now.
|
||||||
|
|
|
||||||
|
|
@ -95,8 +95,14 @@
|
||||||
.download-state[state="1"]:not([exists])
|
.download-state[state="1"]:not([exists])
|
||||||
.downloadCommandsSeparator,
|
.downloadCommandsSeparator,
|
||||||
.download-state[state="8"]:not(.temporary-block)
|
.download-state[state="8"]:not(.temporary-block)
|
||||||
.downloadCommandsSeparator
|
.downloadCommandsSeparator,
|
||||||
|
|
||||||
|
/* the system-viewer context menu items are only shown for certain mime-types
|
||||||
|
and can be individually enabled via prefs */
|
||||||
|
.download-state:not([is-pdf]) .downloadUseSystemDefaultMenuItem,
|
||||||
|
.download-state .downloadUseSystemDefaultMenuItem:not([enabled]),
|
||||||
|
.download-state .downloadAlwaysUseSystemDefaultMenuItem:not([enabled]),
|
||||||
|
.download-state:not([is-pdf]) .downloadAlwaysUseSystemDefaultMenuItem
|
||||||
{
|
{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -937,6 +937,11 @@ var DownloadsView = {
|
||||||
|
|
||||||
DownloadsViewController.updateCommands();
|
DownloadsViewController.updateCommands();
|
||||||
|
|
||||||
|
let download = element._shell.download;
|
||||||
|
let { preferredAction, useSystemDefault } = DownloadsCommon.getMimeInfo(
|
||||||
|
download
|
||||||
|
);
|
||||||
|
|
||||||
// Set the state attribute so that only the appropriate items are displayed.
|
// Set the state attribute so that only the appropriate items are displayed.
|
||||||
let contextMenu = document.getElementById("downloadsContextMenu");
|
let contextMenu = document.getElementById("downloadsContextMenu");
|
||||||
contextMenu.setAttribute("state", element.getAttribute("state"));
|
contextMenu.setAttribute("state", element.getAttribute("state"));
|
||||||
|
|
@ -949,6 +954,30 @@ var DownloadsView = {
|
||||||
"temporary-block",
|
"temporary-block",
|
||||||
element.classList.contains("temporary-block")
|
element.classList.contains("temporary-block")
|
||||||
);
|
);
|
||||||
|
if (element.hasAttribute("is-pdf")) {
|
||||||
|
contextMenu.setAttribute("is-pdf", "true");
|
||||||
|
let alwaysUseSystemViewerItem = contextMenu.querySelector(
|
||||||
|
".downloadAlwaysUseSystemDefaultMenuItem"
|
||||||
|
);
|
||||||
|
if (preferredAction === useSystemDefault) {
|
||||||
|
alwaysUseSystemViewerItem.setAttribute("checked", "true");
|
||||||
|
} else {
|
||||||
|
alwaysUseSystemViewerItem.removeAttribute("checked");
|
||||||
|
}
|
||||||
|
alwaysUseSystemViewerItem.toggleAttribute(
|
||||||
|
"enabled",
|
||||||
|
DownloadsCommon.alwaysOpenInSystemViewerItemEnabled
|
||||||
|
);
|
||||||
|
let useSystemViewerItem = contextMenu.querySelector(
|
||||||
|
".downloadUseSystemDefaultMenuItem"
|
||||||
|
);
|
||||||
|
useSystemViewerItem.toggleAttribute(
|
||||||
|
"enabled",
|
||||||
|
DownloadsCommon.openInSystemViewerItemEnabled
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
contextMenu.removeAttribute("is-pdf");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onDownloadDragStart(aEvent) {
|
onDownloadDragStart(aEvent) {
|
||||||
|
|
@ -1093,6 +1122,22 @@ class DownloadsViewItem extends DownloadsViewUI.DownloadElementShell {
|
||||||
DownloadsPanel.hidePanel();
|
DownloadsPanel.hidePanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
downloadsCmd_openInSystemViewer() {
|
||||||
|
super.downloadsCmd_openInSystemViewer();
|
||||||
|
|
||||||
|
// We explicitly close the panel here to give the user the feedback that
|
||||||
|
// their click has been received, and we're handling the action.
|
||||||
|
DownloadsPanel.hidePanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadsCmd_alwaysOpenInSystemViewer() {
|
||||||
|
super.downloadsCmd_alwaysOpenInSystemViewer();
|
||||||
|
|
||||||
|
// We explicitly close the panel here to give the user the feedback that
|
||||||
|
// their click has been received, and we're handling the action.
|
||||||
|
DownloadsPanel.hidePanel();
|
||||||
|
}
|
||||||
|
|
||||||
downloadsCmd_show() {
|
downloadsCmd_show() {
|
||||||
let file = new FileUtils.File(this.download.target.path);
|
let file = new FileUtils.File(this.download.target.path);
|
||||||
DownloadsCommon.showDownloadedFile(file);
|
DownloadsCommon.showDownloadedFile(file);
|
||||||
|
|
|
||||||
|
|
@ -22,4 +22,6 @@
|
||||||
<command id="downloadsCmd_retry"/>
|
<command id="downloadsCmd_retry"/>
|
||||||
<command id="downloadsCmd_openReferrer"/>
|
<command id="downloadsCmd_openReferrer"/>
|
||||||
<command id="downloadsCmd_clearDownloads"/>
|
<command id="downloadsCmd_clearDownloads"/>
|
||||||
|
<command id="downloadsCmd_openInSystemViewer"/>
|
||||||
|
<command id="downloadsCmd_alwaysOpenInSystemViewer"/>
|
||||||
</commandset>
|
</commandset>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,13 @@
|
||||||
<menuitem command="downloadsCmd_unblock"
|
<menuitem command="downloadsCmd_unblock"
|
||||||
class="downloadUnblockMenuItem"
|
class="downloadUnblockMenuItem"
|
||||||
data-l10n-id="downloads-cmd-unblock"/>
|
data-l10n-id="downloads-cmd-unblock"/>
|
||||||
|
<menuitem command="downloadsCmd_openInSystemViewer"
|
||||||
|
class="downloadUseSystemDefaultMenuItem"
|
||||||
|
data-l10n-id="downloads-cmd-use-system-default"/>
|
||||||
|
<menuitem command="downloadsCmd_alwaysOpenInSystemViewer"
|
||||||
|
type="checkbox"
|
||||||
|
class="downloadAlwaysUseSystemDefaultMenuItem"
|
||||||
|
data-l10n-id="downloads-cmd-always-use-system-default"/>
|
||||||
<menuitem command="downloadsCmd_show"
|
<menuitem command="downloadsCmd_show"
|
||||||
class="downloadShowMenuItem"
|
class="downloadShowMenuItem"
|
||||||
#ifdef XP_MACOSX
|
#ifdef XP_MACOSX
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,10 @@
|
||||||
oncommand="goDoCommand('downloadsCmd_copyLocation')"/>
|
oncommand="goDoCommand('downloadsCmd_copyLocation')"/>
|
||||||
<command id="downloadsCmd_clearList"
|
<command id="downloadsCmd_clearList"
|
||||||
oncommand="goDoCommand('downloadsCmd_clearList')"/>
|
oncommand="goDoCommand('downloadsCmd_clearList')"/>
|
||||||
|
<command id="downloadsCmd_openInSystemViewer"
|
||||||
|
oncommand="goDoCommand('downloadsCmd_openInSystemViewer')"/>
|
||||||
|
<command id="downloadsCmd_alwaysOpenInSystemViewer"
|
||||||
|
oncommand="goDoCommand('downloadsCmd_alwaysOpenInSystemViewer')"/>
|
||||||
</commandset>
|
</commandset>
|
||||||
|
|
||||||
<!-- The panel has level="top" to ensure that it is never hidden by the
|
<!-- The panel has level="top" to ensure that it is never hidden by the
|
||||||
|
|
@ -75,6 +79,13 @@
|
||||||
<menuitem command="downloadsCmd_unblock"
|
<menuitem command="downloadsCmd_unblock"
|
||||||
class="downloadUnblockMenuItem"
|
class="downloadUnblockMenuItem"
|
||||||
data-l10n-id="downloads-cmd-unblock"/>
|
data-l10n-id="downloads-cmd-unblock"/>
|
||||||
|
<menuitem command="downloadsCmd_openInSystemViewer"
|
||||||
|
class="downloadUseSystemDefaultMenuItem"
|
||||||
|
data-l10n-id="downloads-cmd-use-system-default"/>
|
||||||
|
<menuitem command="downloadsCmd_alwaysOpenInSystemViewer"
|
||||||
|
type="checkbox"
|
||||||
|
class="downloadAlwaysUseSystemDefaultMenuItem"
|
||||||
|
data-l10n-id="downloads-cmd-always-use-system-default"/>
|
||||||
<menuitem command="downloadsCmd_show"
|
<menuitem command="downloadsCmd_show"
|
||||||
class="downloadShowMenuItem"
|
class="downloadShowMenuItem"
|
||||||
#ifdef XP_MACOSX
|
#ifdef XP_MACOSX
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,26 @@ const TestCases = [
|
||||||
tabSelected: true,
|
tabSelected: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Download panel, system viewer menu items prefd off",
|
||||||
|
whichUI: "downloadPanel",
|
||||||
|
itemSelector: "#downloadsListBox richlistitem .downloadMainArea",
|
||||||
|
async userEvents(itemTarget, win) {
|
||||||
|
EventUtils.synthesizeMouseAtCenter(itemTarget, {}, win);
|
||||||
|
},
|
||||||
|
prefs: [
|
||||||
|
["browser.download.openInSystemViewerContextMenuItem", false],
|
||||||
|
["browser.download.alwaysOpenInSystemViewerContextMenuItem", false],
|
||||||
|
],
|
||||||
|
expected: {
|
||||||
|
downloadCount: 1,
|
||||||
|
newWindow: false,
|
||||||
|
opensTab: true,
|
||||||
|
tabSelected: true,
|
||||||
|
useSystemMenuItemDisabled: true,
|
||||||
|
alwaysMenuItemDisabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Download panel, open from keyboard",
|
name: "Download panel, open from keyboard",
|
||||||
whichUI: "downloadPanel",
|
whichUI: "downloadPanel",
|
||||||
|
|
@ -109,6 +129,26 @@ const TestCases = [
|
||||||
tabSelected: true,
|
tabSelected: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Library all downloads dialog, system viewer menu items prefd off",
|
||||||
|
whichUI: "allDownloads",
|
||||||
|
async userEvents(itemTarget, win) {
|
||||||
|
// double click
|
||||||
|
await triggerDblclickOn(itemTarget, {}, win);
|
||||||
|
},
|
||||||
|
prefs: [
|
||||||
|
["browser.download.openInSystemViewerContextMenuItem", false],
|
||||||
|
["browser.download.alwaysOpenInSystemViewerContextMenuItem", false],
|
||||||
|
],
|
||||||
|
expected: {
|
||||||
|
downloadCount: 1,
|
||||||
|
newWindow: false,
|
||||||
|
opensTab: true,
|
||||||
|
tabSelected: true,
|
||||||
|
useSystemMenuItemDisabled: true,
|
||||||
|
alwaysMenuItemDisabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Library all downloads dialog, open from keyboard",
|
name: "Library all downloads dialog, open from keyboard",
|
||||||
whichUI: "allDownloads",
|
whichUI: "allDownloads",
|
||||||
|
|
@ -189,6 +229,28 @@ const TestCases = [
|
||||||
tabSelected: true,
|
tabSelected: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "about:downloads, system viewer menu items prefd off",
|
||||||
|
whichUI: "aboutDownloads",
|
||||||
|
itemSelector: "#downloadsRichListBox richlistitem .downloadContainer",
|
||||||
|
async userEvents(itemSelector, win) {
|
||||||
|
let browser = win.gBrowser.selectedBrowser;
|
||||||
|
is(browser.currentURI.spec, "about:downloads");
|
||||||
|
await contentTriggerDblclickOn(itemSelector, {}, browser);
|
||||||
|
},
|
||||||
|
prefs: [
|
||||||
|
["browser.download.openInSystemViewerContextMenuItem", false],
|
||||||
|
["browser.download.alwaysOpenInSystemViewerContextMenuItem", false],
|
||||||
|
],
|
||||||
|
expected: {
|
||||||
|
downloadCount: 1,
|
||||||
|
newWindow: false,
|
||||||
|
opensTab: true,
|
||||||
|
tabSelected: true,
|
||||||
|
useSystemMenuItemDisabled: true,
|
||||||
|
alwaysMenuItemDisabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "about:downloads, open in new window",
|
name: "about:downloads, open in new window",
|
||||||
whichUI: "aboutDownloads",
|
whichUI: "aboutDownloads",
|
||||||
|
|
@ -306,6 +368,66 @@ function contentTriggerDblclickOn(selector, eventModifiers = {}, browser) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function openContextMenu(itemElement, win = window) {
|
||||||
|
let popupShownPromise = BrowserTestUtils.waitForEvent(
|
||||||
|
itemElement.ownerDocument,
|
||||||
|
"popupshown"
|
||||||
|
);
|
||||||
|
EventUtils.synthesizeMouseAtCenter(
|
||||||
|
itemElement,
|
||||||
|
{
|
||||||
|
type: "contextmenu",
|
||||||
|
button: 2,
|
||||||
|
},
|
||||||
|
win
|
||||||
|
);
|
||||||
|
let { target } = await popupShownPromise;
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verifyContextMenu(contextMenu, expected = {}) {
|
||||||
|
info("verifyContextMenu with expected: " + JSON.stringify(expected, null, 2));
|
||||||
|
let alwaysMenuItem = contextMenu.querySelector(
|
||||||
|
".downloadAlwaysUseSystemDefaultMenuItem"
|
||||||
|
);
|
||||||
|
let useSystemMenuItem = contextMenu.querySelector(
|
||||||
|
".downloadUseSystemDefaultMenuItem"
|
||||||
|
);
|
||||||
|
await TestUtils.waitForCondition(
|
||||||
|
() => BrowserTestUtils.is_visible(contextMenu),
|
||||||
|
"The context menu is visible"
|
||||||
|
);
|
||||||
|
await TestUtils.waitForTick();
|
||||||
|
|
||||||
|
is(
|
||||||
|
BrowserTestUtils.is_hidden(useSystemMenuItem),
|
||||||
|
expected.useSystemMenuItemDisabled,
|
||||||
|
`The 'Use system viewer' menu item was ${
|
||||||
|
expected.useSystemMenuItemDisabled ? "hidden" : "visible"
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
is(
|
||||||
|
BrowserTestUtils.is_hidden(alwaysMenuItem),
|
||||||
|
expected.alwaysMenuItemDisabled,
|
||||||
|
`The 'Use system viewer' menu item was ${
|
||||||
|
expected.alwaysMenuItemDisabled ? "hidden" : "visible"
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!expected.useSystemMenuItemDisabled && expected.alwaysChecked) {
|
||||||
|
is(
|
||||||
|
alwaysMenuItem.getAttribute("checked"),
|
||||||
|
"true",
|
||||||
|
"The 'Always...' menu item is checked"
|
||||||
|
);
|
||||||
|
} else if (!expected.useSystemMenuItemDisabled) {
|
||||||
|
ok(
|
||||||
|
!alwaysMenuItem.hasAttribute("checked"),
|
||||||
|
"The 'Always...' menu item not checked"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function createDownloadedFile(pathname, contents) {
|
async function createDownloadedFile(pathname, contents) {
|
||||||
let encoder = new TextEncoder();
|
let encoder = new TextEncoder();
|
||||||
let file = new FileUtils.File(pathname);
|
let file = new FileUtils.File(pathname);
|
||||||
|
|
@ -352,7 +474,7 @@ async function addPDFDownload(itemData) {
|
||||||
return download;
|
return download;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function testSetup(testData = {}) {
|
async function testSetup() {
|
||||||
// remove download files, empty out collections
|
// remove download files, empty out collections
|
||||||
let downloadList = await Downloads.getList(Downloads.ALL);
|
let downloadList = await Downloads.getList(Downloads.ALL);
|
||||||
let downloadCount = (await downloadList.getAll()).length;
|
let downloadCount = (await downloadList.getAll()).length;
|
||||||
|
|
@ -379,6 +501,7 @@ async function testOpenPDFPreview({
|
||||||
whichUI,
|
whichUI,
|
||||||
itemSelector,
|
itemSelector,
|
||||||
expected,
|
expected,
|
||||||
|
prefs = [],
|
||||||
userEvents,
|
userEvents,
|
||||||
isPrivate,
|
isPrivate,
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -386,6 +509,11 @@ async function testOpenPDFPreview({
|
||||||
// Wait for focus first
|
// Wait for focus first
|
||||||
await promiseFocus();
|
await promiseFocus();
|
||||||
await testSetup();
|
await testSetup();
|
||||||
|
if (prefs.length) {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: prefs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Populate downloads database with the data required by this test.
|
// Populate downloads database with the data required by this test.
|
||||||
info("Adding download objects");
|
info("Adding download objects");
|
||||||
|
|
@ -454,12 +582,16 @@ async function testOpenPDFPreview({
|
||||||
}
|
}
|
||||||
|
|
||||||
let itemTarget;
|
let itemTarget;
|
||||||
|
let contextMenu;
|
||||||
|
|
||||||
switch (whichUI) {
|
switch (whichUI) {
|
||||||
case "downloadPanel":
|
case "downloadPanel":
|
||||||
info("Opening download panel");
|
info("Opening download panel");
|
||||||
await openDownloadPanel(expected.downloadCount);
|
await openDownloadPanel(expected.downloadCount);
|
||||||
info("/Opening download panel");
|
info("/Opening download panel");
|
||||||
itemTarget = document.querySelector(itemSelector);
|
itemTarget = document.querySelector(itemSelector);
|
||||||
|
contextMenu = uiWindow.document.querySelector("#downloadsContextMenu");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "allDownloads":
|
case "allDownloads":
|
||||||
// we'll be interacting with the library dialog
|
// we'll be interacting with the library dialog
|
||||||
|
|
@ -467,11 +599,17 @@ async function testOpenPDFPreview({
|
||||||
|
|
||||||
let listbox = uiWindow.document.getElementById("downloadsRichListBox");
|
let listbox = uiWindow.document.getElementById("downloadsRichListBox");
|
||||||
ok(listbox, "download list box present");
|
ok(listbox, "download list box present");
|
||||||
// wait for the expected number of items in the view
|
// wait for the expected number of items in the view,
|
||||||
await TestUtils.waitForCondition(
|
// and for the first item to be visible && clickable
|
||||||
() => listbox.itemChildren.length == expected.downloadCount
|
await TestUtils.waitForCondition(() => {
|
||||||
);
|
return (
|
||||||
|
listbox.itemChildren.length == expected.downloadCount &&
|
||||||
|
BrowserTestUtils.is_visible(listbox.itemChildren[0])
|
||||||
|
);
|
||||||
|
});
|
||||||
itemTarget = listbox.itemChildren[0];
|
itemTarget = listbox.itemChildren[0];
|
||||||
|
contextMenu = uiWindow.document.querySelector("#downloadsContextMenu");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "aboutDownloads":
|
case "aboutDownloads":
|
||||||
info("Preparing about:downloads browser window");
|
info("Preparing about:downloads browser window");
|
||||||
|
|
@ -537,6 +675,21 @@ async function testOpenPDFPreview({
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (contextMenu) {
|
||||||
|
info("trigger the contextmenu");
|
||||||
|
await openContextMenu(itemTarget || itemSelector, uiWindow);
|
||||||
|
info("context menu should be open, verify its menu items");
|
||||||
|
let expectedValues = {
|
||||||
|
useSystemMenuItemDisabled: false,
|
||||||
|
alwaysMenuItemDisabled: false,
|
||||||
|
...expected,
|
||||||
|
};
|
||||||
|
await verifyContextMenu(contextMenu, expectedValues);
|
||||||
|
contextMenu.hidePopup();
|
||||||
|
} else {
|
||||||
|
todo(contextMenu, "No context menu checks for test: " + name);
|
||||||
|
}
|
||||||
|
|
||||||
info("Executing user events");
|
info("Executing user events");
|
||||||
await userEvents(itemTarget || itemSelector, uiWindow);
|
await userEvents(itemTarget || itemSelector, uiWindow);
|
||||||
|
|
||||||
|
|
@ -594,6 +747,9 @@ async function testOpenPDFPreview({
|
||||||
await lastPBContextExitedPromise;
|
await lastPBContextExitedPromise;
|
||||||
});
|
});
|
||||||
await downloadList.removeFinished();
|
await downloadList.removeFinished();
|
||||||
|
if (prefs.length) {
|
||||||
|
await SpecialPowers.popPrefEnv();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// register the tests
|
// register the tests
|
||||||
|
|
|
||||||
|
|
@ -726,6 +726,9 @@ Download.prototype = {
|
||||||
* @param options.openWhere Optional string indicating how to open when handling
|
* @param options.openWhere Optional string indicating how to open when handling
|
||||||
* download by opening the target file URI.
|
* download by opening the target file URI.
|
||||||
* One of "window", "tab", "tabshifted"
|
* One of "window", "tab", "tabshifted"
|
||||||
|
* @param options.useSystemDefault
|
||||||
|
* Optional value indicating how to handle launching this download,
|
||||||
|
* this time only. Will override the associated mimeInfo.preferredAction
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
* @resolves When the instruction to launch the file has been
|
* @resolves When the instruction to launch the file has been
|
||||||
* successfully given to the operating system. Note that
|
* successfully given to the operating system. Note that
|
||||||
|
|
|
||||||
|
|
@ -712,6 +712,9 @@ var DownloadIntegration = {
|
||||||
* @param options.openWhere Optional string indicating how to open when handling
|
* @param options.openWhere Optional string indicating how to open when handling
|
||||||
* download by opening the target file URI.
|
* download by opening the target file URI.
|
||||||
* One of "window", "tab", "tabshifted"
|
* One of "window", "tab", "tabshifted"
|
||||||
|
* @param options.useSystemDefault
|
||||||
|
* Optional value indicating how to handle launching this download,
|
||||||
|
* this time only. Will override the associated mimeInfo.preferredAction
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
* @resolves When the instruction to launch the file has been
|
* @resolves When the instruction to launch the file has been
|
||||||
|
|
@ -721,7 +724,7 @@ var DownloadIntegration = {
|
||||||
* @rejects JavaScript exception if there was an error trying to launch
|
* @rejects JavaScript exception if there was an error trying to launch
|
||||||
* the file.
|
* the file.
|
||||||
*/
|
*/
|
||||||
async launchDownload(aDownload, { openWhere }) {
|
async launchDownload(aDownload, { openWhere, useSystemDefault = null }) {
|
||||||
let file = new FileUtils.File(aDownload.target.path);
|
let file = new FileUtils.File(aDownload.target.path);
|
||||||
|
|
||||||
// In case of a double extension, like ".tar.gz", we only
|
// In case of a double extension, like ".tar.gz", we only
|
||||||
|
|
@ -794,7 +797,8 @@ var DownloadIntegration = {
|
||||||
const PDF_CONTENT_TYPE = "application/pdf";
|
const PDF_CONTENT_TYPE = "application/pdf";
|
||||||
if (
|
if (
|
||||||
aDownload.handleInternally ||
|
aDownload.handleInternally ||
|
||||||
(mimeInfo &&
|
(!useSystemDefault && // No explicit instruction was passed to launch this download using the default system viewer.
|
||||||
|
mimeInfo &&
|
||||||
(mimeInfo.type == PDF_CONTENT_TYPE ||
|
(mimeInfo.type == PDF_CONTENT_TYPE ||
|
||||||
fileExtension?.toLowerCase() == "pdf") &&
|
fileExtension?.toLowerCase() == "pdf") &&
|
||||||
!mimeInfo.alwaysAskBeforeHandling &&
|
!mimeInfo.alwaysAskBeforeHandling &&
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue