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