summaryrefslogtreecommitdiffstats
path: root/remote/shared/listeners/LoadListener.sys.mjs
blob: ed7ba3f6d496e8d5c258edb22960d8b384f7ed65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/* 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",
});

/**
 * The LoadListener can be used to listen for load events.
 *
 * Example:
 * ```
 * const listener = new LoadListener();
 * listener.on("DOMContentLoaded", onDOMContentLoaded);
 * listener.startListening();
 *
 * const onDOMContentLoaded = (eventName, data = {}) => {
 *   const { target } = data;
 *   ...
 * };
 * ```
 *
 * @emits message
 *    The LoadListener emits "DOMContentLoaded" and "load" events,
 *    with the following object as payload:
 *      - {Document} target
 *            The target document.
 */
export class LoadListener {
  #abortController;
  #window;

  /**
   * Create a new LoadListener instance.
   */
  constructor(win) {
    lazy.EventEmitter.decorate(this);

    // Use an abort controller instead of removeEventListener because destroy
    // might be called close to the window global destruction.
    this.#abortController = null;

    this.#window = win;
  }

  destroy() {
    this.stopListening();
  }

  startListening() {
    if (this.#abortController) {
      return;
    }

    this.#abortController = new AbortController();
    this.#window.addEventListener(
      "DOMContentLoaded",
      this.#onDOMContentLoaded,
      {
        mozSystemGroup: true,
        signal: this.#abortController.signal,
      }
    );

    this.#window.addEventListener("load", this.#onLoad, {
      mozSystemGroup: true,
      signal: this.#abortController.signal,
    });
  }

  stopListening() {
    if (!this.#abortController) {
      return;
    }

    this.#abortController.abort();
    this.#abortController = null;
  }

  #onDOMContentLoaded = event => {
    this.emit("DOMContentLoaded", { target: event.target });
  };

  #onLoad = event => {
    this.emit("load", { target: event.target });
  };
}