diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /devtools/client/framework/toolbox-host-manager.js | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'devtools/client/framework/toolbox-host-manager.js')
-rw-r--r-- | devtools/client/framework/toolbox-host-manager.js | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/devtools/client/framework/toolbox-host-manager.js b/devtools/client/framework/toolbox-host-manager.js new file mode 100644 index 000000000..1638f3a9a --- /dev/null +++ b/devtools/client/framework/toolbox-host-manager.js @@ -0,0 +1,244 @@ +const Services = require("Services"); +const {Ci} = require("chrome"); +const {LocalizationHelper} = require("devtools/shared/l10n"); +const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties"); +const DevToolsUtils = require("devtools/shared/DevToolsUtils"); +const {Task} = require("devtools/shared/task"); + +loader.lazyRequireGetter(this, "Toolbox", "devtools/client/framework/toolbox", true); +loader.lazyRequireGetter(this, "Hosts", "devtools/client/framework/toolbox-hosts", true); + +/** + * Implement a wrapper on the chrome side to setup a Toolbox within Firefox UI. + * + * This component handles iframe creation within Firefox, in which we are loading + * the toolbox document. Then both the chrome and the toolbox document communicate + * via "message" events. + * + * Messages sent by the toolbox to the chrome: + * - switch-host: + * Order to display the toolbox in another host (side, bottom, window, or the + * previously used one) + * - toggle-minimize-mode: + * When using the bottom host, the toolbox can be miximized to only display + * the tool titles + * - maximize-host: + * When using the bottom host in minimized mode, revert back to regular mode + * in order to see tool titles and the tools + * - raise-host: + * Focus the tools + * - set-host-title: + * When using the window host, update the window title + * + * Messages sent by the chrome to the toolbox: + * - host-minimized: + * The bottom host is done minimizing (after animation end) + * - host-maximized: + * The bottom host is done switching back to regular mode (after animation + * end) + * - switched-host: + * The `switch-host` command sent by the toolbox is done + */ + +const LAST_HOST = "devtools.toolbox.host"; +const PREVIOUS_HOST = "devtools.toolbox.previousHost"; +let ID_COUNTER = 1; + +function ToolboxHostManager(target, hostType, hostOptions) { + this.target = target; + + this.frameId = ID_COUNTER++; + + if (!hostType) { + hostType = Services.prefs.getCharPref(LAST_HOST); + } + this.onHostMinimized = this.onHostMinimized.bind(this); + this.onHostMaximized = this.onHostMaximized.bind(this); + this.host = this.createHost(hostType, hostOptions); + this.hostType = hostType; +} + +ToolboxHostManager.prototype = { + create: Task.async(function* (toolId) { + yield this.host.create(); + + this.host.frame.setAttribute("aria-label", L10N.getStr("toolbox.label")); + this.host.frame.ownerDocument.defaultView.addEventListener("message", this); + // We have to listen on capture as no event fires on bubble + this.host.frame.addEventListener("unload", this, true); + + let toolbox = new Toolbox(this.target, toolId, this.host.type, this.host.frame.contentWindow, this.frameId); + + // Prevent reloading the toolbox when loading the tools in a tab (e.g. from about:debugging) + if (!this.host.frame.contentWindow.location.href.startsWith("about:devtools-toolbox")) { + this.host.frame.setAttribute("src", "about:devtools-toolbox"); + } + + return toolbox; + }), + + handleEvent(event) { + switch(event.type) { + case "message": + this.onMessage(event); + break; + case "unload": + // On unload, host iframe already lost its contentWindow attribute, so + // we can only compare against locations. Here we filter two very + // different cases: preliminary about:blank document as well as iframes + // like tool iframes. + if (!event.target.location.href.startsWith("about:devtools-toolbox")) { + break; + } + // Don't destroy the host during unload event (esp., don't remove the + // iframe from DOM!). Otherwise the unload event for the toolbox + // document doesn't fire within the toolbox *document*! This is + // the unload event that fires on the toolbox *iframe*. + DevToolsUtils.executeSoon(() => { + this.destroy(); + }); + break; + } + }, + + onMessage(event) { + if (!event.data) { + return; + } + // Toolbox document is still chrome and disallow identifying message + // origin via event.source as it is null. So use a custom id. + if (event.data.frameId != this.frameId) { + return; + } + switch (event.data.name) { + case "switch-host": + this.switchHost(event.data.hostType); + break; + case "maximize-host": + this.host.maximize(); + break; + case "raise-host": + this.host.raise(); + break; + case "toggle-minimize-mode": + this.host.toggleMinimizeMode(event.data.toolbarHeight); + break; + case "set-host-title": + this.host.setTitle(event.data.title); + break; + } + }, + + postMessage(data) { + let window = this.host.frame.contentWindow; + window.postMessage(data, "*"); + }, + + destroy() { + this.destroyHost(); + this.host = null; + this.hostType = null; + this.target = null; + }, + + /** + * Create a host object based on the given host type. + * + * Warning: bottom and sidebar hosts require that the toolbox target provides + * a reference to the attached tab. Not all Targets have a tab property - + * make sure you correctly mix and match hosts and targets. + * + * @param {string} hostType + * The host type of the new host object + * + * @return {Host} host + * The created host object + */ + createHost(hostType, options) { + if (!Hosts[hostType]) { + throw new Error("Unknown hostType: " + hostType); + } + + let newHost = new Hosts[hostType](this.target.tab, options); + // Update the label and icon when the state changes. + newHost.on("minimized", this.onHostMinimized); + newHost.on("maximized", this.onHostMaximized); + return newHost; + }, + + onHostMinimized() { + this.postMessage({ + name: "host-minimized" + }); + }, + + onHostMaximized() { + this.postMessage({ + name: "host-maximized" + }); + }, + + switchHost: Task.async(function* (hostType) { + if (hostType == "previous") { + // Switch to the last used host for the toolbox UI. + // This is determined by the devtools.toolbox.previousHost pref. + hostType = Services.prefs.getCharPref(PREVIOUS_HOST); + + // Handle the case where the previous host happens to match the current + // host. If so, switch to bottom if it's not already used, and side if not. + if (hostType === this.hostType) { + if (hostType === Toolbox.HostType.BOTTOM) { + hostType = Toolbox.HostType.SIDE; + } else { + hostType = Toolbox.HostType.BOTTOM; + } + } + } + let iframe = this.host.frame; + let newHost = this.createHost(hostType); + let newIframe = yield newHost.create(); + // change toolbox document's parent to the new host + newIframe.swapFrameLoaders(iframe); + + this.destroyHost(); + + if (this.hostType != Toolbox.HostType.CUSTOM) { + Services.prefs.setCharPref(PREVIOUS_HOST, this.hostType); + } + + this.host = newHost; + this.hostType = hostType; + this.host.setTitle(this.host.frame.contentWindow.document.title); + this.host.frame.ownerDocument.defaultView.addEventListener("message", this); + this.host.frame.addEventListener("unload", this, true); + + if (hostType != Toolbox.HostType.CUSTOM) { + Services.prefs.setCharPref(LAST_HOST, hostType); + } + + // Tell the toolbox the host changed + this.postMessage({ + name: "switched-host", + hostType + }); + }), + + /** + * Destroy the current host, and remove event listeners from its frame. + * + * @return {promise} to be resolved when the host is destroyed. + */ + destroyHost() { + // When Firefox toplevel is closed, the frame may already be detached and + // the top level document gone + if (this.host.frame.ownerDocument.defaultView) { + this.host.frame.ownerDocument.defaultView.removeEventListener("message", this); + } + this.host.frame.removeEventListener("unload", this, true); + + this.host.off("minimized", this.onHostMinimized); + this.host.off("maximized", this.onHostMaximized); + return this.host.destroy(); + } +}; +exports.ToolboxHostManager = ToolboxHostManager; |