Bug 1655866: Part 1 - Add async version of beforeUnloadCheck prompt. r=geckoview-reviewers,Gijs,agi

Differential Revision: https://phabricator.services.mozilla.com/D88314
This commit is contained in:
Kris Maglione 2020-09-21 22:40:42 +00:00
Родитель 3e0a30ea57
Коммит 2d863e9e4c
6 изменённых файлов: 85 добавлений и 26 удалений

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

@ -71,7 +71,7 @@ class PromptCollection {
return buttonPressed === 0;
}
beforeUnloadCheck(browsingContext) {
beforeUnloadCheckInternal(browsingContext, sync) {
let title;
let message;
let leaveLabel;
@ -94,9 +94,17 @@ class PromptCollection {
}
let contentViewer = browsingContext?.docShell?.contentViewer;
let modalType = contentViewer?.isTabModalPromptAllowed
? Ci.nsIPromptService.MODAL_TYPE_CONTENT
: Ci.nsIPromptService.MODAL_TYPE_WINDOW;
// TODO: Do we really want to allow modal dialogs from inactive
// content viewers at all, particularly for permit unload prompts?
let modalAllowed = contentViewer
? contentViewer.isTabModalPromptAllowed
: browsingContext.ancestorsAreCurrent;
let modalType =
Ci.nsIPromptService[
modalAllowed ? "MODAL_TYPE_CONTENT" : "MODAL_TYPE_WINDOW"
];
let buttonFlags =
Ci.nsIPromptService.BUTTON_POS_0_DEFAULT |
@ -105,20 +113,55 @@ class PromptCollection {
(Ci.nsIPromptService.BUTTON_TITLE_IS_STRING *
Ci.nsIPromptService.BUTTON_POS_1);
let buttonPressed = Services.prompt.confirmExBC(
browsingContext,
modalType,
title,
message,
buttonFlags,
leaveLabel,
stayLabel,
null,
null,
{}
);
if (sync) {
let buttonNumClicked = Services.prompt.confirmExBC(
browsingContext,
modalType,
title,
message,
buttonFlags,
leaveLabel,
stayLabel,
null,
null,
{}
);
return buttonPressed === 0;
return buttonNumClicked === 0;
}
return Services.prompt
.asyncConfirmEx(
browsingContext,
modalType,
title,
message,
buttonFlags,
leaveLabel,
stayLabel,
null,
null,
false,
// Tell the prompt service that this is a permit unload prompt
// so that it can set the appropriate flag on the detail object
// of the events it dispatches. This happens automatically for
// the sync version of the prompt, which is always dispatched
// from the content process, where the flag comes from the
// content viewer which triggers the prompt.
{ inPermitUnload: true }
)
.then(
result =>
result.QueryInterface(Ci.nsIPropertyBag2).get("buttonNumClicked") == 0
);
}
beforeUnloadCheck(browsingContext) {
return this.beforeUnloadCheckInternal(browsingContext, /* sync */ true);
}
asyncBeforeUnloadCheck(browsingContext) {
return this.beforeUnloadCheckInternal(browsingContext, /* sync */ false);
}
}
@ -144,9 +187,6 @@ for (const [bundleName, bundleUrl] of Object.entries(BUNDLES)) {
);
}
PromptCollection.prototype.classID = Components.ID(
"{7913837c-9623-11ea-bb37-0242ac130002}"
);
PromptCollection.prototype.QueryInterface = ChromeUtils.generateQI([
"nsIPromptCollection",
]);

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

@ -68,6 +68,8 @@ interface BrowsingContext {
readonly attribute WindowContext? topWindowContext;
readonly attribute boolean ancestorsAreCurrent;
[SetterThrows] attribute [TreatNullAs=EmptyString] DOMString customPlatform;
[SetterThrows] attribute [TreatNullAs=EmptyString] DOMString customUserAgent;

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

@ -37,11 +37,17 @@ class PromptCollection {
const result = prompter.showPrompt(msg);
return !!result?.allow;
}
}
PromptCollection.prototype.classID = Components.ID(
"{3e30d2a0-9934-11ea-bb37-0242ac130002}"
);
asyncBeforeUnloadCheck(browsingContext) {
return new Promise(resolve => {
const msg = {
type: "beforeUnload",
};
const prompter = new GeckoViewPrompter(browsingContext);
prompter.asyncShowPrompt(msg, resolve);
}).then(result => !!result?.allow);
}
}
PromptCollection.prototype.QueryInterface = ChromeUtils.generateQI([
"nsIPromptCollection",

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

@ -346,6 +346,7 @@ Prompter.prototype = {
* @param {String} checkLabel - Text to appear with the checkbox.
* Null if no checkbox.
* @param {Boolean} checkValue - The initial checked state of the checkbox.
* @param {Object} [extraArgs] - Extra arguments for the prompt metadata.
* @returns {Promise<nsIPropertyBag<{ buttonNumClicked: Number, checked: Boolean }>>}
*/
asyncConfirmEx(browsingContext, modalType, ...promptArgs) {
@ -1400,7 +1401,8 @@ class ModalPrompter {
button1,
button2,
checkLabel,
checkValue
checkValue,
extraArgs = {}
) {
if (!title) {
title = PromptUtils.getLocalizedString("Confirm");
@ -1414,6 +1416,7 @@ class ModalPrompter {
checked: this.async ? checkValue : checkValue.value,
ok: false,
buttonNumClicked: 1,
...extraArgs,
};
let [

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

@ -23,6 +23,13 @@ interface nsIPromptCollection : nsISupports
*/
boolean beforeUnloadCheck(in BrowsingContext aBrowsingContext);
/**
* Like `beforeUnloadCheck`, but does not spin a nested event loop, and
* instead returns a promise which resolves to true if navigation should be
* allowed, and false if not.
*/
Promise asyncBeforeUnloadCheck(in BrowsingContext aBrowsingContext);
/**
* Puts up a dialog for the confirm repost prompt.
*

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

@ -364,7 +364,8 @@ interface nsIPromptService : nsISupports
in wstring aButton1Title,
in wstring aButton2Title,
in wstring aCheckMsg,
in boolean aCheckState);
in boolean aCheckState,
[optional] in jsval aExtraArgs);
/**
* Puts up a dialog with an edit field and an optional, labeled checkbox.
*