From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../cdp/domains/parent/page/DialogHandler.sys.mjs | 140 +++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 remote/cdp/domains/parent/page/DialogHandler.sys.mjs (limited to 'remote/cdp/domains/parent/page/DialogHandler.sys.mjs') 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 }); + } +} -- cgit v1.2.3