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
7var EXPORTED_SYMBOLS = ["GeckoViewModule"];
8
9const { GeckoViewUtils } = ChromeUtils.import(
10  "resource://gre/modules/GeckoViewUtils.jsm"
11);
12
13const { debug, warn } = GeckoViewUtils.initLogging("Module");
14
15class GeckoViewModule {
16  static initLogging(aModuleName) {
17    const tag = aModuleName.replace("GeckoView", "");
18    return GeckoViewUtils.initLogging(tag);
19  }
20
21  constructor(aModuleInfo) {
22    this._info = aModuleInfo;
23
24    this._isContentLoaded = false;
25    this._eventProxy = new EventProxy(this, this.eventDispatcher);
26
27    this.onInitBrowser();
28  }
29
30  get name() {
31    return this._info.name;
32  }
33
34  get enabled() {
35    return this._info.enabled;
36  }
37
38  get window() {
39    return this.moduleManager.window;
40  }
41
42  getActor(aActorName) {
43    return this.moduleManager.getActor(aActorName);
44  }
45
46  get browser() {
47    return this.moduleManager.browser;
48  }
49
50  get messageManager() {
51    return this.moduleManager.messageManager;
52  }
53
54  get eventDispatcher() {
55    return this.moduleManager.eventDispatcher;
56  }
57
58  get settings() {
59    return this.moduleManager.settings;
60  }
61
62  get moduleManager() {
63    return this._info.manager;
64  }
65
66  // Override to initialize the browser before it is bound to the window.
67  onInitBrowser() {}
68
69  // Override to initialize module.
70  onInit() {}
71
72  // Override to cleanup when the window is closed
73  onDestroy() {}
74
75  // Override to detect settings change. Access settings via this.settings.
76  onSettingsUpdate() {}
77
78  // Override to enable module after setting a Java delegate.
79  onEnable() {}
80
81  // Override to disable module after clearing the Java delegate.
82  onDisable() {}
83
84  // Override to perform actions when content module has started loading;
85  // by default, pause events so events that depend on content modules can work.
86  onLoadContentModule() {
87    this._eventProxy.enableQueuing(true);
88  }
89
90  // Override to perform actions when content module has finished loading;
91  // by default, un-pause events and flush queued events.
92  onContentModuleLoaded() {
93    this._eventProxy.enableQueuing(false);
94    this._eventProxy.dispatchQueuedEvents();
95  }
96
97  registerListener(aEventList) {
98    this._eventProxy.registerListener(aEventList);
99  }
100
101  unregisterListener() {
102    this._eventProxy.unregisterListener();
103  }
104}
105
106class EventProxy {
107  constructor(aListener, aEventDispatcher) {
108    this.listener = aListener;
109    this.eventDispatcher = aEventDispatcher;
110    this._eventQueue = [];
111    this._registeredEvents = [];
112    this._enableQueuing = false;
113  }
114
115  registerListener(aEventList) {
116    debug`registerListener ${aEventList}`;
117    this.eventDispatcher.registerListener(this, aEventList);
118    this._registeredEvents = this._registeredEvents.concat(aEventList);
119  }
120
121  unregisterListener() {
122    debug`unregisterListener`;
123    if (this._registeredEvents.length === 0) {
124      return;
125    }
126    this.eventDispatcher.unregisterListener(this, this._registeredEvents);
127    this._registeredEvents = [];
128  }
129
130  onEvent(aEvent, aData, aCallback) {
131    if (this._enableQueuing) {
132      debug`queue ${aEvent}, data=${aData}`;
133      this._eventQueue.unshift(arguments);
134    } else {
135      this._dispatch(...arguments);
136    }
137  }
138
139  enableQueuing(aEnable) {
140    debug`enableQueuing ${aEnable}`;
141    this._enableQueuing = aEnable;
142  }
143
144  _dispatch(aEvent, aData, aCallback) {
145    debug`dispatch ${aEvent}, data=${aData}`;
146    if (this.listener.onEvent) {
147      this.listener.onEvent(...arguments);
148    } else {
149      this.listener(...arguments);
150    }
151  }
152
153  dispatchQueuedEvents() {
154    debug`dispatchQueued`;
155    while (this._eventQueue.length) {
156      const args = this._eventQueue.pop();
157      this._dispatch(...args);
158    }
159  }
160}
161