зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1565574
- Added protocol handler permission dialog and updated app chooser dialog. r=Gijs,fluent-reviewers
- Added a new permission dialog shown when the caller does not have permission to open a protocol - Updated the appChooser dialog for the new UX - Updated and moved l10n strings to fluent (fluent migration in the following patch) Differential Revision: https://phabricator.services.mozilla.com/D94149
This commit is contained in:
Родитель
84589d971b
Коммит
24d9b9243c
|
@ -1,10 +0,0 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!ENTITY window.emWidth "26em">
|
||||
<!ENTITY window.emHeight "26em">
|
||||
<!ENTITY ChooseOtherApp.description "Choose other Application">
|
||||
<!ENTITY ChooseApp.label "Choose…">
|
||||
<!ENTITY ChooseApp.accessKey "C">
|
||||
<!ENTITY accept "Open link">
|
|
@ -1,15 +0,0 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
protocol.title=Launch Application
|
||||
protocol.description=This link needs to be opened with an application.
|
||||
protocol.choices.label=Send to:
|
||||
protocol.checkbox.label=Remember my choice for %S links.
|
||||
protocol.checkbox.accesskey=R
|
||||
protocol.checkbox.extra=This can be changed in %S’s preferences.
|
||||
|
||||
# Displayed under the name of a protocol handler in the Launch Application dialog.
|
||||
privatebrowsing.disabled.label=Disabled in Private Windows
|
||||
|
||||
choose.application.title=Another Application…
|
|
@ -2,12 +2,73 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
## Permission Dialog
|
||||
## Variables:
|
||||
## $host - the hostname that is initiating the request
|
||||
## $scheme - the type of link that's being opened.
|
||||
## $appName - Name of the application that will be opened.
|
||||
|
||||
permission-dialog-description =
|
||||
Allow this site to open the { $scheme } link?
|
||||
|
||||
permission-dialog-description-host =
|
||||
Allow { $host } to open the { $scheme } link?
|
||||
|
||||
permission-dialog-description-app =
|
||||
Allow this site to open the { $scheme } link with { $appName }?
|
||||
|
||||
permission-dialog-description-host-app =
|
||||
Allow { $host } to open the { $scheme } link with { $appName }?
|
||||
|
||||
|
||||
# Please keep the emphasis around the hostname and scheme (ie the
|
||||
# `<strong>` HTML tags). Please also keep the hostname as close to the start
|
||||
# of the sentence as your language's grammar allows.
|
||||
#
|
||||
# Variables:
|
||||
# $host - the hostname that is initiating the request
|
||||
# $scheme - the type of link that's being opened.
|
||||
handler-dialog-host =
|
||||
<strong>{ $host }</strong> wants to open a <strong>{ $scheme }</strong> link.
|
||||
permission-dialog-remember =
|
||||
Always allow <strong>{ $host }</strong> to open <strong>{ $scheme }</strong> links
|
||||
|
||||
permission-dialog-btn-open-link =
|
||||
.label = Open Link
|
||||
.accessKey = O
|
||||
|
||||
permission-dialog-btn-choose-app =
|
||||
.label = Choose Application
|
||||
.accessKey = A
|
||||
|
||||
permission-dialog-unset-description = You’ll need to choose an application.
|
||||
|
||||
permission-dialog-set-change-app-link = Choose a different application.
|
||||
|
||||
|
||||
## Chooser dialog
|
||||
## Variables:
|
||||
## $scheme - the type of link that's being opened.
|
||||
|
||||
chooser-window =
|
||||
.title = Choose Application
|
||||
.style = min-width: 26em; min-height: 26em;
|
||||
|
||||
chooser-dialog =
|
||||
.buttonlabelaccept = Open Link
|
||||
.buttonaccesskeyaccept = O
|
||||
|
||||
chooser-dialog-description = Choose an application to open the { $scheme } link.
|
||||
|
||||
# Please keep the emphasis around the scheme (ie the `<strong>` HTML tags).
|
||||
chooser-dialog-remember =
|
||||
Always use this application to open <strong>{ $scheme }</strong> links
|
||||
|
||||
chooser-dialog-remember-extra = {
|
||||
PLATFORM() ->
|
||||
[windows] This can be changed in { -brand-short-name }’s options.
|
||||
*[other] This can be changed in { -brand-short-name }’s preferences.
|
||||
}
|
||||
|
||||
choose-other-app-description = Choose other Application
|
||||
choose-app-btn =
|
||||
.label = Choose…
|
||||
.accessKey = C
|
||||
choose-other-app-window-title = Another Application…
|
||||
|
||||
# Displayed under the name of a protocol handler in the Launch Application dialog.
|
||||
choose-dialog-privatebrowsing-disabled = Disabled in Private Windows
|
||||
|
|
|
@ -71,8 +71,6 @@
|
|||
#ifndef MOZ_FENNEC
|
||||
locale/@AB_CD@/mozapps/extensions/extensions.properties (%chrome/mozapps/extensions/extensions.properties)
|
||||
#endif
|
||||
locale/@AB_CD@/mozapps/handling/handling.dtd (%chrome/mozapps/handling/handling.dtd)
|
||||
locale/@AB_CD@/mozapps/handling/handling.properties (%chrome/mozapps/handling/handling.properties)
|
||||
locale/@AB_CD@/mozapps/profile/profileSelection.properties (%chrome/mozapps/profile/profileSelection.properties)
|
||||
#ifndef MOZ_FENNEC
|
||||
locale/@AB_CD@/mozapps/update/updates.properties (%chrome/mozapps/update/updates.properties)
|
||||
|
|
|
@ -2,41 +2,13 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* This dialog builds its content based on arguments passed into it.
|
||||
* window.arguments[0]:
|
||||
* The title of the dialog.
|
||||
* window.arguments[1]:
|
||||
* The url of the image that appears to the left of the description text
|
||||
* window.arguments[2]:
|
||||
* The text of the description that will appear above the choices the user
|
||||
* can choose from.
|
||||
* window.arguments[3]:
|
||||
* The text of the label directly above the choices the user can choose from.
|
||||
* window.arguments[4]:
|
||||
* This is the text to be placed in the label for the checkbox. If no text is
|
||||
* passed (ie, it's an empty string), the checkbox will be hidden.
|
||||
* window.arguments[5]:
|
||||
* The accesskey for the checkbox
|
||||
* window.arguments[6]:
|
||||
* This is the text that is displayed below the checkbox when it is checked.
|
||||
* window.arguments[7]:
|
||||
* This is the nsIHandlerInfo that gives us all our precious information.
|
||||
* window.arguments[8]:
|
||||
* This is the nsIURI that we are being brought up for in the first place.
|
||||
* window.arguments[9]:
|
||||
* This is the nsIPrincipal that has triggered the dialog; may be null.
|
||||
* window.arguments[10]:
|
||||
* The browsingContext from which the request originates; may be null.
|
||||
*/
|
||||
|
||||
const { EnableDelayHelper } = ChromeUtils.import(
|
||||
"resource://gre/modules/SharedPromptUtils.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { PrivateBrowsingUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm"
|
||||
);
|
||||
const { EnableDelayHelper } = ChromeUtils.import(
|
||||
"resource://gre/modules/SharedPromptUtils.jsm"
|
||||
);
|
||||
|
||||
class MozHandler extends window.MozElements.MozRichlistitem {
|
||||
static get markup() {
|
||||
|
@ -82,97 +54,62 @@ let loadPromise = new Promise(resolve => {
|
|||
window.addEventListener("load", resolve, { once: true });
|
||||
});
|
||||
|
||||
var dialog = {
|
||||
// Member Variables
|
||||
|
||||
_handlerInfo: null,
|
||||
_URI: null,
|
||||
_itemChoose: null,
|
||||
_okButton: null,
|
||||
_browsingContext: null,
|
||||
_buttonDisabled: true,
|
||||
|
||||
// Methods
|
||||
|
||||
let dialog = {
|
||||
/**
|
||||
* This function initializes the content of the dialog.
|
||||
*/
|
||||
initialize: function initialize() {
|
||||
this._handlerInfo = window.arguments[7].QueryInterface(Ci.nsIHandlerInfo);
|
||||
this._URI = window.arguments[8].QueryInterface(Ci.nsIURI);
|
||||
let principal = window.arguments[9]?.QueryInterface(Ci.nsIPrincipal);
|
||||
this._browsingContext = window.arguments[10];
|
||||
let usePrivateBrowsing = false;
|
||||
if (this._browsingContext) {
|
||||
usePrivateBrowsing = this._browsingContext.usePrivateBrowsing;
|
||||
}
|
||||
let args = window.arguments[0].wrappedJSObject || window.arguments[0];
|
||||
let { handler, outArgs, usePrivateBrowsing, enableButtonDelay } = args;
|
||||
|
||||
this._handlerInfo = handler.QueryInterface(Ci.nsIHandlerInfo);
|
||||
this._outArgs = outArgs;
|
||||
|
||||
this.isPrivate =
|
||||
usePrivateBrowsing ||
|
||||
(window.opener && PrivateBrowsingUtils.isWindowPrivate(window.opener));
|
||||
|
||||
this._dialog = document.querySelector("dialog");
|
||||
this._itemChoose = document.getElementById("item-choose");
|
||||
this._okButton = document.getElementById("handling").getButton("extra1");
|
||||
this._rememberCheck = document.getElementById("remember");
|
||||
|
||||
var description = {
|
||||
image: document.getElementById("description-image"),
|
||||
text: document.getElementById("description-text"),
|
||||
};
|
||||
var options = document.getElementById("item-action-text");
|
||||
var checkbox = {
|
||||
desc: document.getElementById("remember"),
|
||||
text: document.getElementById("remember-text"),
|
||||
};
|
||||
let rememberLabel = document.getElementById("remember-label");
|
||||
document.l10n.setAttributes(rememberLabel, "chooser-dialog-remember", {
|
||||
scheme: this._handlerInfo.type,
|
||||
});
|
||||
|
||||
// Setting values
|
||||
document.title = window.arguments[0];
|
||||
description.image.src = window.arguments[1];
|
||||
description.text.textContent = window.arguments[2];
|
||||
options.value = window.arguments[3];
|
||||
checkbox.desc.label = window.arguments[4];
|
||||
checkbox.desc.accessKey = window.arguments[5];
|
||||
checkbox.text.textContent = window.arguments[6];
|
||||
// Register event listener for the checkbox hint.
|
||||
this._rememberCheck.addEventListener("change", () => this.onCheck());
|
||||
|
||||
if (principal && principal.isContentPrincipal) {
|
||||
let hostContainer = document.getElementById("originating-host");
|
||||
document.l10n.pauseObserving();
|
||||
document.l10n.setAttributes(hostContainer, "handler-dialog-host", {
|
||||
host: principal.exposablePrePath,
|
||||
scheme: this._URI.scheme,
|
||||
});
|
||||
document.mozSubdialogReady = document.l10n
|
||||
.translateElements([hostContainer])
|
||||
.then(() => window.sizeToContent());
|
||||
document.l10n.resumeObserving();
|
||||
hostContainer.parentNode.removeAttribute("hidden");
|
||||
}
|
||||
let description = document.getElementById("description");
|
||||
document.l10n.setAttributes(description, "chooser-dialog-description", {
|
||||
scheme: this._handlerInfo.type,
|
||||
});
|
||||
|
||||
// Hide stuff that needs to be hidden
|
||||
if (!checkbox.desc.label) {
|
||||
checkbox.desc.hidden = true;
|
||||
}
|
||||
document.addEventListener("dialogaccept", () => {
|
||||
this.onAccept();
|
||||
});
|
||||
|
||||
// UI is ready, lets populate our list
|
||||
this.populateList();
|
||||
// Explicitly not an 'accept' button to avoid having `enter` accept the dialog.
|
||||
document.addEventListener("dialogextra1", () => {
|
||||
this.onOK();
|
||||
});
|
||||
document.addEventListener("dialogaccept", e => {
|
||||
e.preventDefault();
|
||||
|
||||
document.mozSubdialogReady = document.l10n.ready.then(() => {
|
||||
window.sizeToContent();
|
||||
});
|
||||
|
||||
this._delayHelper = new EnableDelayHelper({
|
||||
disableDialog: () => {
|
||||
this._buttonDisabled = true;
|
||||
this.updateOKButton();
|
||||
},
|
||||
enableDialog: () => {
|
||||
this._buttonDisabled = false;
|
||||
this.updateOKButton();
|
||||
},
|
||||
focusTarget: window,
|
||||
});
|
||||
if (enableButtonDelay) {
|
||||
this._delayHelper = new EnableDelayHelper({
|
||||
disableDialog: () => {
|
||||
this._acceptBtnDisabled = true;
|
||||
this.updateAcceptButton();
|
||||
},
|
||||
enableDialog: () => {
|
||||
this._acceptBtnDisabled = false;
|
||||
this.updateAcceptButton();
|
||||
},
|
||||
focusTarget: window,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -218,12 +155,10 @@ var dialog = {
|
|||
if (this.isPrivate) {
|
||||
let policy = WebExtensionPolicy.getByURI(uri);
|
||||
if (policy && !policy.privateBrowsingAllowed) {
|
||||
var bundle = document.getElementById("base-strings");
|
||||
var disabledLabel = bundle.getString(
|
||||
"privatebrowsing.disabled.label"
|
||||
);
|
||||
elm.setAttribute("disabled", true);
|
||||
elm.setAttribute("description", disabledLabel);
|
||||
this.getPrivateBrowsingDisabledLabel().then(label => {
|
||||
elm.setAttribute("description", label);
|
||||
});
|
||||
if (app == preferredHandler) {
|
||||
preferredHandler = null;
|
||||
}
|
||||
|
@ -262,7 +197,7 @@ var dialog = {
|
|||
let gIOSvc = Cc["@mozilla.org/gio-service;1"].getService(
|
||||
Ci.nsIGIOService
|
||||
);
|
||||
var gioApps = gIOSvc.getAppsForURIScheme(this._URI.scheme);
|
||||
var gioApps = gIOSvc.getAppsForURIScheme(this._handlerInfo.type);
|
||||
for (let handler of gioApps.enumerate(Ci.nsIHandlerApp)) {
|
||||
// OS handler share the same name, it's most likely the same app, skipping...
|
||||
if (handler.name == this._handlerInfo.defaultDescription) {
|
||||
|
@ -295,9 +230,8 @@ var dialog = {
|
|||
/**
|
||||
* Brings up a filepicker and allows a user to choose an application.
|
||||
*/
|
||||
chooseApplication: function chooseApplication() {
|
||||
var bundle = document.getElementById("base-strings");
|
||||
var title = bundle.getString("choose.application.title");
|
||||
async chooseApplication() {
|
||||
let title = await this.getChooseAppWindowTitle();
|
||||
|
||||
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
fp.init(window, title, Ci.nsIFilePicker.modeOpen);
|
||||
|
@ -342,43 +276,51 @@ var dialog = {
|
|||
/**
|
||||
* Function called when the OK button is pressed.
|
||||
*/
|
||||
onOK: function onOK() {
|
||||
if (this._buttonDisabled) {
|
||||
return;
|
||||
}
|
||||
var checkbox = document.getElementById("remember");
|
||||
if (!checkbox.hidden) {
|
||||
// We need to make sure that the default is properly set now
|
||||
if (this.selectedItem.obj) {
|
||||
// default OS handler doesn't have this property
|
||||
this._handlerInfo.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
|
||||
this._handlerInfo.preferredApplicationHandler = this.selectedItem.obj;
|
||||
} else {
|
||||
this._handlerInfo.preferredAction = Ci.nsIHandlerInfo.useSystemDefault;
|
||||
}
|
||||
}
|
||||
this._handlerInfo.alwaysAskBeforeHandling = !checkbox.checked;
|
||||
|
||||
var hs = Cc["@mozilla.org/uriloader/handler-service;1"].getService(
|
||||
Ci.nsIHandlerService
|
||||
);
|
||||
hs.store(this._handlerInfo);
|
||||
|
||||
this._handlerInfo.launchWithURI(this._URI, this._browsingContext);
|
||||
window.close();
|
||||
onAccept() {
|
||||
this.updateHandlerData(this._rememberCheck.checked);
|
||||
this._outArgs.setProperty("openHandler", true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if the OK button should be disabled or not
|
||||
* Determines if the accept button should be disabled or not
|
||||
*/
|
||||
updateOKButton: function updateOKButton() {
|
||||
this._okButton.disabled = this._itemChoose.selected || this._buttonDisabled;
|
||||
updateAcceptButton() {
|
||||
this._dialog.setAttribute(
|
||||
"buttondisabledaccept",
|
||||
this._acceptBtnDisabled || this._itemChoose.selected
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the handler info to reflect the user choice.
|
||||
* @param {boolean} skipAsk - Whether we should persist the application
|
||||
* choice and skip asking next time.
|
||||
*/
|
||||
updateHandlerData(skipAsk) {
|
||||
// We need to make sure that the default is properly set now
|
||||
if (this.selectedItem.obj) {
|
||||
// default OS handler doesn't have this property
|
||||
this._outArgs.setProperty(
|
||||
"preferredAction",
|
||||
Ci.nsIHandlerInfo.useHelperApp
|
||||
);
|
||||
this._outArgs.setProperty(
|
||||
"preferredApplicationHandler",
|
||||
this.selectedItem.obj
|
||||
);
|
||||
} else {
|
||||
this._outArgs.setProperty(
|
||||
"preferredAction",
|
||||
Ci.nsIHandlerInfo.useSystemDefault
|
||||
);
|
||||
}
|
||||
this._outArgs.setProperty("alwaysAskBeforeHandling", !skipAsk);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the UI based on the checkbox being checked or not.
|
||||
*/
|
||||
onCheck: function onCheck() {
|
||||
onCheck() {
|
||||
if (document.getElementById("remember").checked) {
|
||||
document.getElementById("remember-text").setAttribute("visible", "true");
|
||||
} else {
|
||||
|
@ -393,7 +335,7 @@ var dialog = {
|
|||
if (this.selectedItem == this._itemChoose) {
|
||||
this.chooseApplication();
|
||||
} else {
|
||||
this.onOK();
|
||||
this._dialog.acceptDialog();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -406,6 +348,31 @@ var dialog = {
|
|||
return document.getElementById("items").selectedItem;
|
||||
},
|
||||
set selectedItem(aItem) {
|
||||
return (document.getElementById("items").selectedItem = aItem);
|
||||
document.getElementById("items").selectedItem = aItem;
|
||||
},
|
||||
|
||||
/**
|
||||
* Lazy l10n getter for the title of the app chooser window
|
||||
*/
|
||||
async getChooseAppWindowTitle() {
|
||||
if (!this._chooseAppWindowTitle) {
|
||||
this._chooseAppWindowTitle = await document.l10n.formatValues([
|
||||
"choose-other-app-window-title",
|
||||
]);
|
||||
}
|
||||
return this._chooseAppWindowTitle;
|
||||
},
|
||||
|
||||
/**
|
||||
* Lazy l10n getter for handler menu items which are disabled due to private
|
||||
* browsing.
|
||||
*/
|
||||
async getPrivateBrowsingDisabledLabel() {
|
||||
if (!this._privateBrowsingDisabledLabel) {
|
||||
this._privateBrowsingDisabledLabel = await document.l10n.formatValues([
|
||||
"choose-dialog-privatebrowsing-disabled",
|
||||
]);
|
||||
}
|
||||
return this._privateBrowsingDisabledLabel;
|
||||
},
|
||||
};
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
<?xml-stylesheet href="chrome://mozapps/content/handling/handler.css"?>
|
||||
<?xml-stylesheet href="chrome://mozapps/skin/handling/handling.css"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!DOCTYPE window>
|
||||
|
||||
<window persist="width height screenX screenY"
|
||||
aria-describedby="description-text"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
data-l10n-id="chooser-window"
|
||||
data-l10n-attrs="style">
|
||||
<dialog id="handling"
|
||||
buttons="accept,cancel"
|
||||
defaultButton="none"
|
||||
data-l10n-id="chooser-dialog"
|
||||
data-l10n-attrs="buttonlabelaccept, buttonaccesskeyaccept">
|
||||
<linkset>
|
||||
<html:link rel="localization" href="branding/brand.ftl"/>
|
||||
<html:link rel="localization" href="toolkit/global/handlerDialog.ftl"/>
|
||||
</linkset>
|
||||
|
||||
<script src="chrome://mozapps/content/handling/appChooser.js"
|
||||
type="application/javascript"/>
|
||||
|
||||
<description id="description"/>
|
||||
|
||||
<vbox id="chooser" flex="1">
|
||||
<richlistbox id="items" flex="1"
|
||||
ondblclick="dialog.onDblClick();"
|
||||
onselect="dialog.updateAcceptButton();">
|
||||
<richlistitem id="item-choose" orient="horizontal" selected="true">
|
||||
<label data-l10n-id="choose-other-app-description" flex="1"/>
|
||||
<button oncommand="dialog.chooseApplication();"
|
||||
data-l10n-id="choose-app-btn"/>
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
</vbox>
|
||||
|
||||
<hbox id="rememberContainer">
|
||||
<html:input type="checkbox" id="remember"/>
|
||||
<html:label id="remember-label" for="remember"></html:label>
|
||||
<description id="remember-text" data-l10n-id="chooser-dialog-remember-extra"/>
|
||||
</hbox>
|
||||
</dialog>
|
||||
</window>
|
|
@ -1,65 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
<?xml-stylesheet href="chrome://mozapps/content/handling/handler.css"?>
|
||||
<?xml-stylesheet href="chrome://mozapps/skin/handling/handling.css"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!DOCTYPE window SYSTEM "chrome://mozapps/locale/handling/handling.dtd">
|
||||
|
||||
<window style="min-width: &window.emWidth;; min-height: &window.emHeight;;"
|
||||
persist="width height screenX screenY"
|
||||
aria-describedby="description-text"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
<dialog id="handling"
|
||||
buttons="cancel,extra1">
|
||||
<linkset>
|
||||
<html:link rel="localization" href="toolkit/global/handlerDialog.ftl"/>
|
||||
</linkset>
|
||||
|
||||
<script src="chrome://mozapps/content/handling/dialog.js" type="application/javascript"/>
|
||||
|
||||
<stringbundleset id="strings">
|
||||
<stringbundle id="base-strings"
|
||||
src="chrome://mozapps/locale/handling/handling.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<hbox hidden="true">
|
||||
<description id="originating-host"></description>
|
||||
</hbox>
|
||||
|
||||
<hbox>
|
||||
<image id="description-image"/>
|
||||
<description id="description-text"/>
|
||||
</hbox>
|
||||
|
||||
<vbox flex="1">
|
||||
<label id="item-action-text" control="items"/>
|
||||
<richlistbox id="items" flex="1"
|
||||
ondblclick="dialog.onDblClick();"
|
||||
onselect="dialog.updateOKButton();">
|
||||
<richlistitem id="item-choose" orient="horizontal" selected="true">
|
||||
<label value="&ChooseOtherApp.description;" flex="1"/>
|
||||
<button oncommand="dialog.chooseApplication();"
|
||||
label="&ChooseApp.label;" accesskey="&ChooseApp.accessKey;"/>
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
</vbox>
|
||||
|
||||
<checkbox id="remember" aria-describedby="remember-text" oncommand="dialog.onCheck();"/>
|
||||
<description id="remember-text"/>
|
||||
|
||||
<hbox class="dialog-button-box" pack="end">
|
||||
#ifdef XP_UNIX
|
||||
<button dlgtype="cancel" class="dialog-button"/>
|
||||
<button dlgtype="extra1" label="&accept;" class="dialog-button"/>
|
||||
#else
|
||||
<button dlgtype="extra1" label="&accept;" class="dialog-button"/>
|
||||
<button dlgtype="cancel" class="dialog-button"/>
|
||||
#endif
|
||||
</hbox>
|
||||
|
||||
</dialog>
|
||||
</window>
|
|
@ -2,6 +2,30 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#description {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#description-box, #chooser {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
#rememberContainer {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#remember-text:not([visible]) {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#remember-text {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
#remember {
|
||||
margin-inline-start: 6px;
|
||||
}
|
||||
|
||||
#remember-label, #remember {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { EnableDelayHelper } = ChromeUtils.import(
|
||||
"resource://gre/modules/SharedPromptUtils.jsm"
|
||||
);
|
||||
|
||||
let dialog = {
|
||||
/**
|
||||
* This function initializes the content of the dialog.
|
||||
*/
|
||||
initialize() {
|
||||
let args = window.arguments[0].wrappedJSObject || window.arguments[0];
|
||||
let {
|
||||
handler,
|
||||
principal,
|
||||
outArgs,
|
||||
canPersistPermission,
|
||||
preferredHandlerName,
|
||||
browsingContext,
|
||||
} = args;
|
||||
|
||||
this._handlerInfo = handler.QueryInterface(Ci.nsIHandlerInfo);
|
||||
this._principal = principal?.QueryInterface(Ci.nsIPrincipal);
|
||||
this._browsingContext = browsingContext;
|
||||
this._outArgs = outArgs.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
this._preferredHandlerName = preferredHandlerName;
|
||||
|
||||
this._dialog = document.querySelector("dialog");
|
||||
this._checkRemember = document.getElementById("remember");
|
||||
this._checkRememberContainer = document.getElementById("rememberContainer");
|
||||
|
||||
if (!canPersistPermission) {
|
||||
this._checkRememberContainer.hidden = true;
|
||||
}
|
||||
|
||||
let changeAppLink = document.getElementById("change-app");
|
||||
if (this._preferredHandlerName) {
|
||||
changeAppLink.hidden = false;
|
||||
|
||||
changeAppLink.addEventListener("click", () => this.onChangeApp());
|
||||
}
|
||||
|
||||
document.addEventListener("dialogaccept", () => this.onAccept());
|
||||
document.mozSubdialogReady = this.initL10n().then(() => {
|
||||
window.sizeToContent();
|
||||
});
|
||||
|
||||
this._delayHelper = new EnableDelayHelper({
|
||||
disableDialog: () => {
|
||||
this._dialog.setAttribute("buttondisabledaccept", true);
|
||||
},
|
||||
enableDialog: () => {
|
||||
this._dialog.setAttribute("buttondisabledaccept", false);
|
||||
},
|
||||
focusTarget: window,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks whether the principal that triggered this dialog is top level
|
||||
* (not embedded in a frame).
|
||||
* @returns {boolean} - true if principal is top level, false otherwise.
|
||||
* If the triggering principal is null this method always returns false.
|
||||
*/
|
||||
triggeringPrincipalIsTop() {
|
||||
let topContentPrincipal = this._browsingContext?.top.embedderElement
|
||||
?.contentPrincipal;
|
||||
if (!topContentPrincipal) {
|
||||
return false;
|
||||
}
|
||||
return this._principal.equals(topContentPrincipal);
|
||||
},
|
||||
|
||||
async initL10n() {
|
||||
// The UI labels depend on whether we will show the application chooser next
|
||||
// or directly open the assigned protocol handler.
|
||||
|
||||
// Fluent id for dialog accept button
|
||||
let idAcceptButton;
|
||||
if (this._preferredHandlerName) {
|
||||
idAcceptButton = "permission-dialog-btn-open-link";
|
||||
} else {
|
||||
idAcceptButton = "permission-dialog-btn-choose-app";
|
||||
|
||||
let descriptionExtra = document.getElementById("description-extra");
|
||||
descriptionExtra.hidden = false;
|
||||
}
|
||||
|
||||
// Set description depending on if we have a hostname and/or an already
|
||||
// assigned application.
|
||||
let host = this._principal?.exposablePrePath;
|
||||
let scheme = this._handlerInfo.type;
|
||||
let description = document.getElementById("description");
|
||||
|
||||
document.l10n.pauseObserving();
|
||||
let pendingElements = [description];
|
||||
|
||||
// We only show the website address if the request didn't come from the top
|
||||
// level frame.
|
||||
if (host && !this.triggeringPrincipalIsTop()) {
|
||||
if (this._preferredHandlerName) {
|
||||
document.l10n.setAttributes(
|
||||
description,
|
||||
"permission-dialog-description-host-app",
|
||||
{
|
||||
host,
|
||||
scheme,
|
||||
appName: this._preferredHandlerName,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
document.l10n.setAttributes(
|
||||
description,
|
||||
"permission-dialog-description-host",
|
||||
{
|
||||
host,
|
||||
scheme,
|
||||
}
|
||||
);
|
||||
}
|
||||
} else if (this._preferredHandlerName) {
|
||||
document.l10n.setAttributes(
|
||||
description,
|
||||
"permission-dialog-description-app",
|
||||
{ scheme, appName: this._preferredHandlerName }
|
||||
);
|
||||
} else {
|
||||
document.l10n.setAttributes(
|
||||
description,
|
||||
"permission-dialog-description",
|
||||
{ scheme }
|
||||
);
|
||||
}
|
||||
|
||||
if (!this._checkRememberContainer.hidden) {
|
||||
let checkboxLabel = document.getElementById("remember-label");
|
||||
document.l10n.setAttributes(checkboxLabel, "permission-dialog-remember", {
|
||||
host,
|
||||
scheme,
|
||||
});
|
||||
pendingElements.push(checkboxLabel);
|
||||
}
|
||||
|
||||
// Set the dialog button labels.
|
||||
// Ideally we would do this via attributes, however the <dialog> element
|
||||
// does not support changing l10n ids on the fly.
|
||||
let acceptButton = this._dialog.getButton("accept");
|
||||
let [result] = await document.l10n.formatMessages([{ id: idAcceptButton }]);
|
||||
result.attributes.forEach(attr => {
|
||||
if (attr.name == "label") {
|
||||
acceptButton.label = attr.value;
|
||||
} else {
|
||||
acceptButton.accessKey = attr.value;
|
||||
}
|
||||
});
|
||||
|
||||
await document.l10n.translateElements(pendingElements);
|
||||
document.l10n.resumeObserving();
|
||||
|
||||
return document.l10n.ready;
|
||||
},
|
||||
|
||||
onAccept() {
|
||||
this._outArgs.setProperty("remember", this._checkRemember.checked);
|
||||
this._outArgs.setProperty("granted", true);
|
||||
},
|
||||
|
||||
onChangeApp() {
|
||||
this._outArgs.setProperty("resetHandlerChoice", true);
|
||||
|
||||
// We can't call the dialogs accept handler here. If the accept button is
|
||||
// still disabled, it will prevent closing.
|
||||
this.onAccept();
|
||||
window.close();
|
||||
},
|
||||
};
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => dialog.initialize(), {
|
||||
once: true,
|
||||
});
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
<?xml-stylesheet href="chrome://mozapps/content/handling/handler.css"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!DOCTYPE window>
|
||||
|
||||
<window aria-describedby="description"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
<dialog buttons="accept,cancel"
|
||||
defaultButton="none"
|
||||
data-l10n-attrs="buttonlabelaccept, buttonaccesskeyaccept">
|
||||
<linkset>
|
||||
<html:link rel="localization" href="toolkit/global/handlerDialog.ftl"/>
|
||||
</linkset>
|
||||
|
||||
<script src="chrome://mozapps/content/handling/permissionDialog.js"
|
||||
type="application/javascript"/>
|
||||
|
||||
|
||||
<vbox id="description-box">
|
||||
<description id="description"></description>
|
||||
<label id="change-app"
|
||||
hidden="true"
|
||||
is="text-link"
|
||||
data-l10n-id="permission-dialog-set-change-app-link"></label>
|
||||
<description id="description-extra"
|
||||
hidden="true"
|
||||
data-l10n-id="permission-dialog-unset-description">
|
||||
</description>
|
||||
</vbox>
|
||||
|
||||
<hbox id="rememberContainer">
|
||||
<html:input type="checkbox" id="remember"/>
|
||||
<html:label id="remember-label" for="remember"></html:label>
|
||||
</hbox>
|
||||
</dialog>
|
||||
</window>
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
toolkit.jar:
|
||||
% content mozapps %content/mozapps/
|
||||
content/mozapps/handling/handler.css (content/handler.css)
|
||||
* content/mozapps/handling/dialog.xhtml (content/dialog.xhtml)
|
||||
content/mozapps/handling/dialog.js (content/dialog.js)
|
||||
content/mozapps/handling/handler.css (content/handler.css)
|
||||
content/mozapps/handling/appChooser.xhtml (content/appChooser.xhtml)
|
||||
content/mozapps/handling/appChooser.js (content/appChooser.js)
|
||||
content/mozapps/handling/permissionDialog.xhtml (content/permissionDialog.xhtml)
|
||||
content/mozapps/handling/permissionDialog.js (content/permissionDialog.js)
|
||||
|
|
|
@ -2,11 +2,6 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#description-image:not([src]) {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
richlistitem[type] {
|
||||
min-height: 36px; /* Don't forget to update the richlistbox height! */
|
||||
padding-inline-start: 2px;
|
||||
|
|
|
@ -2,11 +2,6 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#description-image:not([src]) {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
richlistitem[type] {
|
||||
min-height: 36px; /* Don't forget to update the richlistbox height! */
|
||||
padding-inline-start: 2px;
|
||||
|
|
Загрузка…
Ссылка в новой задаче