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:
pbz 2020-10-29 13:43:54 +00:00
Родитель 84589d971b
Коммит 24d9b9243c
13 изменённых файлов: 479 добавлений и 253 удалений

Просмотреть файл

@ -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 %Ss 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 = Youll 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;