diff options
Diffstat (limited to 'remote/webdriver-bidi/modules/windowglobal/input.sys.mjs')
-rw-r--r-- | remote/webdriver-bidi/modules/windowglobal/input.sys.mjs | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/remote/webdriver-bidi/modules/windowglobal/input.sys.mjs b/remote/webdriver-bidi/modules/windowglobal/input.sys.mjs new file mode 100644 index 0000000000..24259151ee --- /dev/null +++ b/remote/webdriver-bidi/modules/windowglobal/input.sys.mjs @@ -0,0 +1,103 @@ +/* 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/. */ + +import { WindowGlobalBiDiModule } from "chrome://remote/content/webdriver-bidi/modules/WindowGlobalBiDiModule.sys.mjs"; + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + action: "chrome://remote/content/shared/webdriver/Actions.sys.mjs", + deserialize: "chrome://remote/content/webdriver-bidi/RemoteValue.sys.mjs", + element: "chrome://remote/content/marionette/element.sys.mjs", + error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs", +}); + +class InputModule extends WindowGlobalBiDiModule { + #actionState; + + constructor(messageHandler) { + super(messageHandler); + + this.#actionState = null; + } + + destroy() {} + + async performActions(options) { + const { actions } = options; + if (this.#actionState === null) { + this.#actionState = new lazy.action.State({ + specCompatPointerOrigin: true, + }); + } + + await this.#deserializeActionOrigins(actions); + const actionChain = lazy.action.Chain.fromJSON(this.#actionState, actions); + await actionChain.dispatch(this.#actionState, this.messageHandler.window); + } + + async releaseActions() { + if (this.#actionState === null) { + return; + } + await this.#actionState.release(this.messageHandler.window); + this.#actionState = null; + } + + /** + * In the provided array of input.SourceActions, replace all origins matching + * the input.ElementOrigin production with the Element corresponding to this + * origin. + * + * Note that this method replaces the content of the `actions` in place, and + * does not return a new array. + * + * @param {Array<input.SourceActions>} actions + * The array of SourceActions to deserialize. + * @returns {Promise} + * A promise which resolves when all ElementOrigin origins have been + * deserialized. + */ + async #deserializeActionOrigins(actions) { + const promises = []; + for (const actionsByTick of actions) { + for (const action of actionsByTick.actions) { + if (action.origin?.type === "element") { + promises.push( + (async () => { + action.origin = await this.#getElementFromElementOrigin( + action.origin + ); + })() + ); + } + } + } + return Promise.all(promises); + } + + async #getElementFromElementOrigin(origin) { + const sharedReference = origin.element; + if (typeof sharedReference?.sharedId !== "string") { + throw new lazy.error.InvalidArgumentError( + `Expected "origin.element" to be a SharedReference, got: ${sharedReference}` + ); + } + + const realm = this.messageHandler.getRealm(); + + const element = lazy.deserialize(realm, sharedReference, { + nodeCache: this.nodeCache, + }); + if (!lazy.element.isElement(element)) { + throw new lazy.error.NoSuchElementError( + `No element found for shared id: ${sharedReference.sharedId}` + ); + } + + return element; + } +} + +export const input = InputModule; |