summaryrefslogtreecommitdiffstats
path: root/remote/cdp/domains/parent/page/DialogHandler.sys.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'remote/cdp/domains/parent/page/DialogHandler.sys.mjs')
-rw-r--r--remote/cdp/domains/parent/page/DialogHandler.sys.mjs140
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 });
+ }
+}