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 file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 ChromeUtils.defineESModuleGetters(lazy, {
8 assert: "chrome://remote/content/shared/webdriver/Assert.sys.mjs",
9 dom: "chrome://remote/content/shared/DOM.sys.mjs",
10 error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs",
11 generateUUID: "chrome://remote/content/shared/UUID.sys.mjs",
12 pprint: "chrome://remote/content/shared/Format.sys.mjs",
16 * A web reference is an abstraction used to identify an element when
17 * it is transported via the protocol, between remote- and local ends.
19 * In Marionette this abstraction can represent DOM elements,
20 * WindowProxies, and XUL elements.
22 export class WebReference {
24 * @param {string} uuid
25 * Identifier that must be unique across all browsing contexts
26 * for the contract to be upheld.
29 this.uuid = lazy.assert.string(uuid);
33 * Performs an equality check between this web element and
36 * @param {WebReference} other
37 * Web element to compare with this.
40 * True if this and <var>other</var> are the same. False
44 return other instanceof WebReference && this.uuid === other.uuid;
48 return `[object ${this.constructor.name} uuid=${this.uuid}]`;
52 * Returns a new {@link WebReference} reference for a DOM or XUL element,
53 * <code>WindowProxy</code>, or <code>ShadowRoot</code>.
55 * @param {(Element|ShadowRoot|WindowProxy|MockXULElement)} node
56 * Node to construct a web element reference for.
57 * @param {string=} uuid
58 * Optional unique identifier of the WebReference if already known.
59 * If not defined a new unique identifier will be created.
61 * @returns {WebReference}
62 * Web reference for <var>node</var>.
64 * @throws {InvalidArgumentError}
65 * If <var>node</var> is neither a <code>WindowProxy</code>,
66 * DOM or XUL element, or <code>ShadowRoot</code>.
68 static from(node, uuid) {
69 if (uuid === undefined) {
70 uuid = lazy.generateUUID();
73 if (lazy.dom.isShadowRoot(node) && !lazy.dom.isInPrivilegedDocument(node)) {
74 // When we support Chrome Shadowroots we will need to
75 // do a check here of shadowroot.host being in a privileged document
77 return new ShadowRoot(uuid);
78 } else if (lazy.dom.isElement(node)) {
79 return new WebElement(uuid);
80 } else if (lazy.dom.isDOMWindow(node)) {
81 if (node.parent === node) {
82 return new WebWindow(uuid);
84 return new WebFrame(uuid);
87 throw new lazy.error.InvalidArgumentError(
88 "Expected DOM window/element " + lazy.pprint`or XUL element, got: ${node}`
93 * Unmarshals a JSON Object to one of {@link ShadowRoot}, {@link WebElement},
94 * {@link WebFrame}, or {@link WebWindow}.
96 * @param {Object<string, string>} json
97 * Web reference, which is supposed to be a JSON Object
98 * where the key is one of the {@link WebReference} concrete
99 * classes' UUID identifiers.
101 * @returns {WebReference}
102 * Web reference for the JSON object.
104 * @throws {InvalidArgumentError}
105 * If <var>json</var> is not a web reference.
107 static fromJSON(json) {
108 lazy.assert.object(json);
109 if (json instanceof WebReference) {
112 let keys = Object.keys(json);
114 for (let key of keys) {
116 case ShadowRoot.Identifier:
117 return ShadowRoot.fromJSON(json);
119 case WebElement.Identifier:
120 return WebElement.fromJSON(json);
122 case WebFrame.Identifier:
123 return WebFrame.fromJSON(json);
125 case WebWindow.Identifier:
126 return WebWindow.fromJSON(json);
130 throw new lazy.error.InvalidArgumentError(
131 lazy.pprint`Expected web reference, got: ${json}`
136 * Checks if <var>obj<var> is a {@link WebReference} reference.
138 * @param {Object<string, string>} obj
139 * Object that represents a {@link WebReference}.
142 * True if <var>obj</var> is a {@link WebReference}, false otherwise.
144 static isReference(obj) {
145 if (Object.prototype.toString.call(obj) != "[object Object]") {
150 ShadowRoot.Identifier in obj ||
151 WebElement.Identifier in obj ||
152 WebFrame.Identifier in obj ||
153 WebWindow.Identifier in obj
162 * Shadow Root elements are represented as shadow root references when they are
163 * transported over the wire protocol
165 export class ShadowRoot extends WebReference {
167 return { [ShadowRoot.Identifier]: this.uuid };
170 static fromJSON(json) {
171 const { Identifier } = ShadowRoot;
173 if (!(Identifier in json)) {
174 throw new lazy.error.InvalidArgumentError(
175 lazy.pprint`Expected shadow root reference, got: ${json}`
179 let uuid = json[Identifier];
180 return new ShadowRoot(uuid);
184 * Constructs a {@link ShadowRoot} from a string <var>uuid</var>.
186 * This whole function is a workaround for the fact that clients
187 * to Marionette occasionally pass <code>{id: <uuid>}</code> JSON
188 * Objects instead of shadow root representations.
190 * @param {string} uuid
191 * UUID to be associated with the web reference.
193 * @returns {ShadowRoot}
194 * The shadow root reference.
196 * @throws {InvalidArgumentError}
197 * If <var>uuid</var> is not a string.
199 static fromUUID(uuid) {
200 lazy.assert.string(uuid);
202 return new ShadowRoot(uuid);
206 ShadowRoot.Identifier = "shadow-6066-11e4-a52e-4f735466cecf";
209 * DOM elements are represented as web elements when they are
210 * transported over the wire protocol.
212 export class WebElement extends WebReference {
214 return { [WebElement.Identifier]: this.uuid };
217 static fromJSON(json) {
218 const { Identifier } = WebElement;
220 if (!(Identifier in json)) {
221 throw new lazy.error.InvalidArgumentError(
222 lazy.pprint`Expected web element reference, got: ${json}`
226 let uuid = json[Identifier];
227 return new WebElement(uuid);
231 * Constructs a {@link WebElement} from a string <var>uuid</var>.
233 * This whole function is a workaround for the fact that clients
234 * to Marionette occasionally pass <code>{id: <uuid>}</code> JSON
235 * Objects instead of web element representations.
237 * @param {string} uuid
238 * UUID to be associated with the web reference.
240 * @returns {WebElement}
241 * The web element reference.
243 * @throws {InvalidArgumentError}
244 * If <var>uuid</var> is not a string.
246 static fromUUID(uuid) {
247 return new WebElement(uuid);
251 WebElement.Identifier = "element-6066-11e4-a52e-4f735466cecf";
254 * Nested browsing contexts, such as the <code>WindowProxy</code>
255 * associated with <tt><frame></tt> and <tt><iframe></tt>,
256 * are represented as web frames over the wire protocol.
258 export class WebFrame extends WebReference {
260 return { [WebFrame.Identifier]: this.uuid };
263 static fromJSON(json) {
264 if (!(WebFrame.Identifier in json)) {
265 throw new lazy.error.InvalidArgumentError(
266 lazy.pprint`Expected web frame reference, got: ${json}`
269 let uuid = json[WebFrame.Identifier];
270 return new WebFrame(uuid);
274 WebFrame.Identifier = "frame-075b-4da1-b6ba-e579c2d3230a";
277 * Top-level browsing contexts, such as <code>WindowProxy</code>
278 * whose <code>opener</code> is null, are represented as web windows
279 * over the wire protocol.
281 export class WebWindow extends WebReference {
283 return { [WebWindow.Identifier]: this.uuid };
286 static fromJSON(json) {
287 if (!(WebWindow.Identifier in json)) {
288 throw new lazy.error.InvalidArgumentError(
289 lazy.pprint`Expected web window reference, got: ${json}`
292 let uuid = json[WebWindow.Identifier];
293 return new WebWindow(uuid);
297 WebWindow.Identifier = "window-fcc6-11e5-b4f8-330a88ab9d7f";