GeckoViewPrompterParent.sys.mjs (4787B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import { GeckoViewActorParent } from "resource://gre/modules/GeckoViewActorParent.sys.mjs"; 6 7 const DIALOGS = [ 8 "alert", 9 "alertCheck", 10 "confirm", 11 "confirmCheck", 12 "prompt", 13 "promptCheck", 14 ]; 15 16 export class GeckoViewPrompterParent extends GeckoViewActorParent { 17 constructor() { 18 super(); 19 this._prompts = new Map(); 20 } 21 22 get rootActor() { 23 return this.browsingContext.top.currentWindowGlobal.getActor( 24 "GeckoViewPrompter" 25 ); 26 } 27 28 registerPrompt(promptId, promptType, actor) { 29 return this._prompts.set( 30 promptId, 31 new RemotePrompt(promptId, promptType, actor) 32 ); 33 } 34 35 unregisterPrompt(promptId) { 36 this._prompts.delete(promptId); 37 } 38 39 notifyPromptShow(promptId) { 40 // ToDo: Bug 1761480 - GeckoView can send additional prompts to Marionette 41 if (this._prompts.get(promptId).isDialog) { 42 Services.obs.notifyObservers({ id: promptId }, "geckoview-prompt-show"); 43 } 44 } 45 46 getPrompts() { 47 const self = this; 48 const prompts = []; 49 // Marionette expects this event to be fired from the parent 50 const createDialogClosedEvent = detail => 51 new CustomEvent("DOMModalDialogClosed", { 52 cancelable: true, 53 bubbles: true, 54 detail, 55 }); 56 57 for (const [, prompt] of this._prompts) { 58 // Adding only WebDriver compliant dialogs to the window 59 if (prompt.isDialog) { 60 prompts.push({ 61 args: { 62 modalType: "GeckoViewPrompter", 63 promptType: prompt.type, 64 isDialog: prompt.isDialog, 65 }, 66 getPromptId() { 67 return prompt.id; 68 }, 69 setInputText(text) { 70 prompt.inputText = text; 71 prompt.setInputText(text); 72 }, 73 async getPromptText() { 74 return prompt.getPromptText(); 75 }, 76 async getInputText() { 77 return prompt.getInputText(); 78 }, 79 acceptPrompt() { 80 prompt.acceptPrompt(); 81 self.window.dispatchEvent( 82 createDialogClosedEvent({ 83 areLeaving: true, 84 promptType: prompt.type, 85 value: prompt.inputText, 86 }) 87 ); 88 }, 89 dismissPrompt() { 90 prompt.dismissPrompt(); 91 self.window.dispatchEvent( 92 createDialogClosedEvent({ 93 areLeaving: false, 94 promptType: prompt.type, 95 }) 96 ); 97 }, 98 }); 99 } 100 } 101 return prompts; 102 } 103 104 /** 105 * Handles the message coming from GeckoViewPrompterChild. 106 * 107 * @param {string} message.name The subject of the message. 108 * @param {object} message.data The data of the message. 109 */ 110 // eslint-disable-next-line consistent-return 111 async receiveMessage({ name, data }) { 112 switch (name) { 113 case "RegisterPrompt": { 114 this.rootActor.registerPrompt(data.id, data.promptType, this); 115 break; 116 } 117 case "UnregisterPrompt": { 118 this.rootActor.unregisterPrompt(data.id); 119 break; 120 } 121 case "NotifyPromptShow": { 122 this.rootActor.notifyPromptShow(data.id); 123 break; 124 } 125 case "GeckoView:Prompt:Dismiss": { 126 return this.eventDispatcher.sendRequest({ 127 ...data, 128 type: "GeckoView:Prompt:Dismiss", 129 }); 130 } 131 case "GeckoView:Prompt:Update": { 132 return this.eventDispatcher.sendRequest({ 133 ...data, 134 type: "GeckoView:Prompt:Update", 135 }); 136 } 137 case "GeckoView:Prompt": { 138 return this.eventDispatcher.sendRequestForResult({ 139 ...data, 140 type: "GeckoView:Prompt", 141 }); 142 } 143 default: { 144 return super.receiveMessage({ name, data }); 145 } 146 } 147 } 148 } 149 150 class RemotePrompt { 151 constructor(id, type, actor) { 152 this.id = id; 153 this.type = type; 154 this.actor = actor; 155 } 156 157 // Checks if the prompt conforms to a WebDriver simple dialog. 158 get isDialog() { 159 return DIALOGS.includes(this.type); 160 } 161 162 getPromptText() { 163 return this.actor.sendQuery("GetPromptText", { 164 id: this.id, 165 }); 166 } 167 168 getInputText() { 169 return this.actor.sendQuery("GetInputText", { 170 id: this.id, 171 }); 172 } 173 174 setInputText(inputText) { 175 this.actor.sendAsyncMessage("SetInputText", { 176 id: this.id, 177 text: inputText, 178 }); 179 } 180 181 acceptPrompt() { 182 this.actor.sendAsyncMessage("AcceptPrompt", { 183 id: this.id, 184 }); 185 } 186 187 dismissPrompt() { 188 this.actor.sendAsyncMessage("DismissPrompt", { 189 id: this.id, 190 }); 191 } 192 }