summaryrefslogtreecommitdiffstats
path: root/devtools/client/framework/toolbox-host-manager.js
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /devtools/client/framework/toolbox-host-manager.js
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-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.js244
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;