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("use strict");
6
7const EXPORTED_SYMBOLS = [
8  "EventDispatcher",
9  "MarionetteEventsParent",
10  "registerEventsActor",
11  "unregisterEventsActor",
12];
13
14const { XPCOMUtils } = ChromeUtils.import(
15  "resource://gre/modules/XPCOMUtils.jsm"
16);
17
18XPCOMUtils.defineLazyModuleGetters(this, {
19  EventEmitter: "resource://gre/modules/EventEmitter.jsm",
20  Log: "chrome://remote/content/shared/Log.jsm",
21});
22
23XPCOMUtils.defineLazyGetter(this, "logger", () =>
24  Log.get(Log.TYPES.MARIONETTE)
25);
26
27// Singleton to allow forwarding events to registered listeners.
28const EventDispatcher = {
29  init() {
30    EventEmitter.decorate(this);
31  },
32};
33EventDispatcher.init();
34
35class MarionetteEventsParent extends JSWindowActorParent {
36  async receiveMessage(msg) {
37    const { name, data } = msg;
38
39    let rv;
40    switch (name) {
41      case "MarionetteEventsChild:PageLoadEvent":
42        EventDispatcher.emit("page-load", data);
43        break;
44    }
45
46    return rv;
47  }
48}
49
50/**
51 * Register Events actors to listen for page load events via EventDispatcher.
52 */
53function registerEventsActor() {
54  try {
55    // Register the JSWindowActor pair for events as used by Marionette
56    ChromeUtils.registerWindowActor("MarionetteEvents", {
57      kind: "JSWindowActor",
58      parent: {
59        moduleURI:
60          "chrome://remote/content/marionette/actors/MarionetteEventsParent.jsm",
61      },
62      child: {
63        moduleURI:
64          "chrome://remote/content/marionette/actors/MarionetteEventsChild.jsm",
65        events: {
66          beforeunload: { capture: true },
67          DOMContentLoaded: { mozSystemGroup: true },
68          hashchange: { mozSystemGroup: true },
69          pagehide: { mozSystemGroup: true },
70          pageshow: { mozSystemGroup: true },
71          // popstate doesn't bubble, as such use capturing phase
72          popstate: { capture: true, mozSystemGroup: true },
73
74          click: {},
75          dblclick: {},
76          unload: { capture: true, createActor: false },
77        },
78      },
79
80      allFrames: true,
81      includeChrome: true,
82    });
83  } catch (e) {
84    if (e.name === "NotSupportedError") {
85      logger.warn(`MarionetteEvents actor is already registered!`);
86    } else {
87      throw e;
88    }
89  }
90}
91
92function unregisterEventsActor() {
93  ChromeUtils.unregisterWindowActor("MarionetteEvents");
94}
95