diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index acfd3b339284..527542ba46cc 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1078,7 +1078,7 @@ pref("devtools.commands.dir", ""); // Enable the app manager pref("devtools.appmanager.enabled", true); -pref("devtools.appmanager.firstrun", true); +pref("devtools.appmanager.lastTab", "help"); pref("devtools.appmanager.manifestEditor.enabled", false); // Toolbox preferences diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index a08898dbd904..fb9a5241631b 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -986,16 +986,15 @@ nsContextMenu.prototype = { }, saveVideoFrameAsImage: function () { - urlSecurityCheck(this.mediaURL, - this._unremotePrincipal(this.browser.contentPrincipal), - Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); let name = ""; - try { - let uri = makeURI(this.mediaURL); - let url = uri.QueryInterface(Ci.nsIURL); - if (url.fileBaseName) - name = decodeURI(url.fileBaseName) + ".jpg"; - } catch (e) { } + if (this.mediaURL) { + try { + let uri = makeURI(this.mediaURL); + let url = uri.QueryInterface(Ci.nsIURL); + if (url.fileBaseName) + name = decodeURI(url.fileBaseName) + ".jpg"; + } catch (e) { } + } if (!name) name = "snapshot.jpg"; var video = this.target; diff --git a/browser/devtools/app-manager/content/device.js b/browser/devtools/app-manager/content/device.js index fb50073c7592..84f916c53405 100644 --- a/browser/devtools/app-manager/content/device.js +++ b/browser/devtools/app-manager/content/device.js @@ -162,16 +162,13 @@ let UI = { if (!this.connected) { return; } + + let app = this.store.object.apps.all.filter(a => a.manifestURL == manifest)[0]; getTargetForApp(this.connection.client, this.listTabsResponse.webappsActor, manifest).then((target) => { - gDevTools.showToolbox(target, - null, - devtools.Toolbox.HostType.WINDOW).then(toolbox => { - this.connection.once(Connection.Events.DISCONNECTED, () => { - toolbox.destroy(); - }); - }); + + top.UI.openAndShowToolboxForTarget(target, app.name, app.iconURL); }, console.error); }, diff --git a/browser/devtools/app-manager/content/index.js b/browser/devtools/app-manager/content/index.js index 8f21eeaf226d..aa0ee4d654dd 100644 --- a/browser/devtools/app-manager/content/index.js +++ b/browser/devtools/app-manager/content/index.js @@ -7,76 +7,176 @@ Cu.import("resource:///modules/devtools/gDevTools.jsm"); const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); const {require} = devtools; const {ConnectionManager, Connection} = require("devtools/client/connection-manager"); +const promise = require("sdk/core/promise"); const prefs = require('sdk/preferences/service'); -let connection; -window.addEventListener("message", function(event) { - try { - let json = JSON.parse(event.data); - switch (json.name) { - case "connection": - let cid = +json.cid; - for (let c of ConnectionManager.connections) { - if (c.uid == cid) { - connection = c; - onNewConnection(); - break; - } - } - break; - case "closeHelp": - selectTab("projects"); - break; - default: - Cu.reportError("Unknown message: " + json.name); +let UI = { + _toolboxTabCursor: 0, + _handledTargets: new Map(), + + connection: null, + + init: function() { + this.onLoad = this.onLoad.bind(this); + this.onUnload = this.onUnload.bind(this); + this.onMessage = this.onMessage.bind(this); + this.onConnected = this.onConnected.bind(this); + this.onDisconnected = this.onDisconnected.bind(this); + + window.addEventListener("load", this.onLoad); + window.addEventListener("unload", this.onUnload); + window.addEventListener("message", this.onMessage); + }, + + onLoad: function() { + window.removeEventListener("load", this.onLoad); + let defaultPanel = prefs.get("devtools.appmanager.lastTab"); + let panelExists = !!document.querySelector("." + defaultPanel + "-panel"); + this.selectTab(panelExists ? defaultPanel : "projects"); + }, + + onUnload: function() { + window.removeEventListener("unload", this.onUnload); + window.removeEventListener("message", this.onMessage); + if (this.connection) { + this.connection.off(Connection.Status.CONNECTED, this.onConnected); + this.connection.off(Connection.Status.DISCONNECTED, this.onDisconnected); } - } catch(e) { Cu.reportError(e); } + }, - // Forward message - let panels = document.querySelectorAll(".panel"); - for (let frame of panels) { - frame.contentWindow.postMessage(event.data, "*"); - } -}, false); + onMessage: function(event) { + try { + let json = JSON.parse(event.data); + switch (json.name) { + case "connection": + let cid = +json.cid; + for (let c of ConnectionManager.connections) { + if (c.uid == cid) { + this.onNewConnection(c); + break; + } + } + break; + case "closeHelp": + this.selectTab("projects"); + break; + case "toolbox-raise": + this.selectTab(json.uid); + break; + case "toolbox-close": + this.closeToolboxTab(json.uid); + break; + default: + Cu.reportError("Unknown message: " + json.name); + } + } catch(e) { Cu.reportError(e); } -window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - if (connection) { - connection.off(Connection.Status.CONNECTED, onConnected); - connection.off(Connection.Status.DISCONNECTED, onDisconnected); - } -}); + // Forward message + let panels = document.querySelectorAll(".panel"); + for (let frame of panels) { + frame.contentWindow.postMessage(event.data, "*"); + } + }, -function onNewConnection() { - connection.on(Connection.Status.CONNECTED, onConnected); - connection.on(Connection.Status.DISCONNECTED, onDisconnected); -} + selectTabFromButton: function(button) { + if (!button.hasAttribute("panel")) + return; + this.selectTab(button.getAttribute("panel")); + }, -function onConnected() { - document.querySelector("#content").classList.add("connected"); -} + selectTab: function(panel) { + let isToolboxTab = false; + for (let type of ["button", "panel"]) { + let oldSelection = document.querySelector("." + type + "[selected]"); + let newSelection = document.querySelector("." + panel + "-" + type); + if (oldSelection) oldSelection.removeAttribute("selected"); + if (newSelection) { + newSelection.scrollIntoView(false); + newSelection.setAttribute("selected", "true"); + if (newSelection.classList.contains("toolbox")) { + isToolboxTab = true; + } + } + } + if (!isToolboxTab) { + prefs.set("devtools.appmanager.lastTab", panel); + } + }, -function onDisconnected() { - document.querySelector("#content").classList.remove("connected"); -} + onNewConnection: function(connection) { + this.connection = connection; + this.connection.on(Connection.Status.CONNECTED, this.onConnected); + this.connection.on(Connection.Status.DISCONNECTED, this.onDisconnected); + }, -function selectTab(id) { - for (let type of ["button", "panel"]) { - let oldSelection = document.querySelector("." + type + "[selected]"); - let newSelection = document.querySelector("." + id + "-" + type); - if (oldSelection) oldSelection.removeAttribute("selected"); - if (newSelection) newSelection.setAttribute("selected", "true"); - } - if (id != "help") { - // Might be the first time the user is accessing the actual app manager - prefs.set("devtools.appmanager.firstrun", false); + onConnected: function() { + document.querySelector("#content").classList.add("connected"); + }, + + onDisconnected: function() { + for (let [,toolbox] of this._handledTargets) { + if (toolbox) { + toolbox.destroy(); + } + } + this._handledTargets.clear(); + document.querySelector("#content").classList.remove("connected"); + }, + + createToolboxTab: function(name, iconURL, uid) { + let button = document.createElement("button"); + button.className = "button toolbox " + uid + "-button"; + button.setAttribute("panel", uid); + button.textContent = name; + button.setAttribute("style", "background-image: url(" + iconURL + ")"); + let toolboxTabs = document.querySelector("#toolbox-tabs"); + toolboxTabs.appendChild(button); + let iframe = document.createElement("iframe"); + iframe.setAttribute("flex", "1"); + iframe.className = "panel toolbox " + uid + "-panel"; + let panels = document.querySelector("#tab-panels"); + panels.appendChild(iframe); + this.selectTab(uid); + return iframe; + }, + + closeToolboxTab: function(uid) { + let buttonToDestroy = document.querySelector("." + uid + "-button"); + let panelToDestroy = document.querySelector("." + uid + "-panel"); + + if (buttonToDestroy.hasAttribute("selected")) { + let lastTab = prefs.get("devtools.appmanager.lastTab"); + this.selectTab(lastTab); + } + + buttonToDestroy.remove(); + panelToDestroy.remove(); + }, + + openAndShowToolboxForTarget: function(target, name, icon) { + let host = devtools.Toolbox.HostType.CUSTOM; + if (!this._handledTargets.has(target)) { + let uid = "uid" + this._toolboxTabCursor++; + let iframe = this.createToolboxTab(name, icon, uid); + let options = { customIframe: iframe , uid: uid }; + this._handledTargets.set(target, null); + return gDevTools.showToolbox(target, null, host, options).then(toolbox => { + this._handledTargets.set(target, toolbox); + toolbox.once("destroyed", () => { + this._handledTargets.delete(target) + }); + }); + } else { + let toolbox = this._handledTargets.get(target); + if (!toolbox) { + // Target is handled, but toolbox is still being + // created. + return promise.resolve(null); + } + return gDevTools.showToolbox(target, null, host); + } } } -let firstRun = prefs.get("devtools.appmanager.firstrun"); -if (firstRun) { - selectTab("help"); -} else { - selectTab("projects"); -} +UI.init(); diff --git a/browser/devtools/app-manager/content/index.xul b/browser/devtools/app-manager/content/index.xul index ba27f097af83..82afbeb3c874 100644 --- a/browser/devtools/app-manager/content/index.xul +++ b/browser/devtools/app-manager/content/index.xul @@ -22,11 +22,11 @@ - - - - - + + + + +