diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /remote/cdp/domains/parent/page/DialogHandler.sys.mjs | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'remote/cdp/domains/parent/page/DialogHandler.sys.mjs')
-rw-r--r-- | remote/cdp/domains/parent/page/DialogHandler.sys.mjs | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/remote/cdp/domains/parent/page/DialogHandler.sys.mjs b/remote/cdp/domains/parent/page/DialogHandler.sys.mjs new file mode 100644 index 0000000000..466511c762 --- /dev/null +++ b/remote/cdp/domains/parent/page/DialogHandler.sys.mjs @@ -0,0 +1,140 @@ +/* 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 lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + EventEmitter: "resource://gre/modules/EventEmitter.sys.mjs", +}); + +const DIALOG_TYPES = { + ALERT: "alert", + BEFOREUNLOAD: "beforeunload", + CONFIRM: "confirm", + PROMPT: "prompt", +}; + +/** + * Helper dedicated to detect and interact with browser dialogs such as `alert`, + * `confirm` etc. The current implementation only supports tabmodal dialogs, + * not full window dialogs. + * + * Emits "dialog-loaded" when a javascript dialog is opened for the current + * browser. + * + * @param {BrowserElement} browser + */ +export class DialogHandler { + constructor(browser) { + lazy.EventEmitter.decorate(this); + this._dialog = null; + this._browser = browser; + + this._onCommonDialogLoaded = this._onCommonDialogLoaded.bind(this); + this._onTabDialogLoaded = this._onTabDialogLoaded.bind(this); + + Services.obs.addObserver( + this._onCommonDialogLoaded, + "common-dialog-loaded" + ); + Services.obs.addObserver(this._onTabDialogLoaded, "tabmodal-dialog-loaded"); + } + + destructor() { + this._dialog = null; + this._pageTarget = null; + + Services.obs.removeObserver( + this._onCommonDialogLoaded, + "common-dialog-loaded" + ); + Services.obs.removeObserver( + this._onTabDialogLoaded, + "tabmodal-dialog-loaded" + ); + } + + async handleJavaScriptDialog({ accept, promptText }) { + if (!this._dialog) { + throw new Error("No dialog available for handleJavaScriptDialog"); + } + + const type = this._getDialogType(); + if (promptText && type === "prompt") { + this._dialog.ui.loginTextbox.value = promptText; + } + + const onDialogClosed = new Promise(r => { + this._browser.addEventListener("DOMModalDialogClosed", r, { + once: true, + }); + }); + + // 0 corresponds to the OK callback, 1 to the CANCEL callback. + if (accept) { + this._dialog.ui.button0.click(); + } else { + this._dialog.ui.button1.click(); + } + + await onDialogClosed; + + // Resetting dialog to null here might be racy and lead to errors if the + // content page is triggering several prompts in a row. + // See Bug 1569578. + this._dialog = null; + } + + _getDialogType() { + const { inPermitUnload, promptType } = this._dialog.args; + + if (inPermitUnload) { + return DIALOG_TYPES.BEFOREUNLOAD; + } + + switch (promptType) { + case "alert": + return DIALOG_TYPES.ALERT; + case "confirm": + return DIALOG_TYPES.CONFIRM; + case "prompt": + return DIALOG_TYPES.PROMPT; + default: + throw new Error("Unsupported dialog type: " + promptType); + } + } + + _onCommonDialogLoaded(dialogWindow) { + const dialogs = + this._browser.tabDialogBox.getContentDialogManager().dialogs; + const dialog = dialogs.find(d => d.frameContentWindow === dialogWindow); + + if (!dialog) { + // The dialog is not for the current tab. + return; + } + + this._dialog = dialogWindow.Dialog; + const message = this._dialog.args.text; + const type = this._getDialogType(); + + this.emit("dialog-loaded", { message, type }); + } + + _onTabDialogLoaded(promptContainer) { + const prompts = this._browser.tabModalPromptBox.listPrompts(); + const prompt = prompts.find(p => p.ui.promptContainer === promptContainer); + + if (!prompt) { + // The dialog is not for the current tab. + return; + } + + this._dialog = prompt; + const message = this._dialog.args.text; + const type = this._getDialogType(); + + this.emit("dialog-loaded", { message, type }); + } +} |