Bug 1007061 - Remove app-manager. r=jryans

This commit is contained in:
Alexandre Poirot 2015-10-26 10:35:35 -07:00
parent 97e65e8041
commit 48802de620
53 changed files with 1 additions and 5346 deletions

View File

@ -543,9 +543,6 @@
<menuitem id="menu_devToolbar"
observes="devtoolsMenuBroadcaster_DevToolbar"
accesskey="&devToolbarMenu.accesskey;"/>
<menuitem id="menu_devAppMgr"
observes="devtoolsMenuBroadcaster_DevAppMgr"
accesskey="&devAppMgrMenu.accesskey;"/>
<menuitem id="menu_webide"
observes="devtoolsMenuBroadcaster_webide"
accesskey="&webide.accesskey;"/>

View File

@ -99,7 +99,6 @@
<command id="Tools:DevToolbox" oncommand="gDevToolsBrowser.toggleToolboxCommand(gBrowser);"/>
<command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true" hidden="true"/>
<command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focusToggle();" disabled="true"/>
<command id="Tools:DevAppMgr" oncommand="gDevToolsBrowser.openAppManager(gBrowser);" disabled="true" hidden="true"/>
<command id="Tools:WebIDE" oncommand="gDevToolsBrowser.openWebIDE();" disabled="true" hidden="true"/>
<command id="Tools:BrowserToolbox" oncommand="BrowserToolboxProcess.init();" disabled="true" hidden="true"/>
<command id="Tools:BrowserContentToolbox" oncommand="gDevToolsBrowser.openContentProcessToolbox();" disabled="true" hidden="true"/>
@ -199,9 +198,6 @@
type="checkbox" autocheck="false"
command="Tools:DevToolbar"
key="key_devToolbar"/>
<broadcaster id="devtoolsMenuBroadcaster_DevAppMgr"
label="&devAppMgrMenu.label;"
command="Tools:DevAppMgr"/>
<broadcaster id="devtoolsMenuBroadcaster_webide"
label="&webide.label;"
command="Tools:WebIDE"

View File

@ -7085,7 +7085,7 @@ var gIdentityHandler = {
this._uriHasHost = false;
}
let whitelist = /^(?:accounts|addons|app-manager|cache|config|crashes|customizing|downloads|healthreport|home|license|newaddon|permissions|preferences|privatebrowsing|rights|sessionrestore|support|welcomeback)(?:[?#]|$)/i;
let whitelist = /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|home|license|newaddon|permissions|preferences|privatebrowsing|rights|sessionrestore|support|welcomeback)(?:[?#]|$)/i;
this._isSecureInternalUI = uri.schemeIs("about") && whitelist.test(uri.path);
this._sslStatus = gBrowser.securityUI

View File

@ -105,8 +105,6 @@ static RedirEntry kRedirMap[] = {
#endif
{ "accounts", "chrome://browser/content/aboutaccounts/aboutaccounts.xhtml",
nsIAboutModule::ALLOW_SCRIPT },
{ "app-manager", "chrome://devtools/content/app-manager/content/index.xul",
nsIAboutModule::ALLOW_SCRIPT },
{ "customizing", "chrome://browser/content/customizableui/aboutCustomizing.xul",
nsIAboutModule::ALLOW_SCRIPT },
{

View File

@ -115,7 +115,6 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
#ifdef MOZ_SERVICES_HEALTHREPORT
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
#endif
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "app-manager", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "customizing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "debugging", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "looppanel", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },

View File

@ -318,8 +318,6 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
<!ENTITY devToolbarMenu.label "Developer Toolbar">
<!ENTITY devToolbarMenu.accesskey "v">
<!ENTITY devAppMgrMenu.label "App Manager">
<!ENTITY devAppMgrMenu.accesskey "A">
<!ENTITY webide.label "WebIDE">
<!ENTITY webide.accesskey "W">
<!ENTITY webide.keycode "VK_F8">

View File

@ -1,103 +0,0 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!ENTITY index.title "App Manager">
<!ENTITY index.projects2 "Apps">
<!ENTITY index.device2 "Device">
<!ENTITY index.help "Help">
<!ENTITY device.debugMainProcess "Debug main process">
<!ENTITY device.debugMainProcessTooltip "Open the Developer Tools connected to the main process on the device">
<!ENTITY device.screenshot "Screenshot">
<!ENTITY device.screenshotTooltip "Open a screenshot of the current state of the device in a new tab">
<!ENTITY device.title "Device Control Center">
<!ENTITY device.notConnected "Not connected. Please connect your device below.">
<!ENTITY device.startApp "Start">
<!ENTITY device.startAppTooltip "Start this app on the device">
<!ENTITY device.stopApp "Stop">
<!ENTITY device.stopAppTooltip "Stop this app on the device">
<!ENTITY device.debugApp "Debug">
<!ENTITY device.debugAppTooltip "Open the Developer Tools connected to this app on the device">
<!ENTITY device.name "Name">
<!ENTITY device.plain "Plain (default)">
<!ENTITY device.privileged "Privileged">
<!ENTITY device.certified "Certified">
<!ENTITY device.allow "Allow">
<!ENTITY device.allowTooltip "This permission is allowed for apps of this type">
<!ENTITY device.prompt "Prompt">
<!ENTITY device.promptTooltip "This permission requires a user prompt for apps of this type">
<!ENTITY device.deny "Deny">
<!ENTITY device.denyTooltip "This permission is denied for apps of this type">
<!ENTITY device.installedApps "Installed Apps">
<!ENTITY device.installedAppsTooltip "View a list of apps installed on the device. Some apps, such as certified apps, may be excluded from this view.">
<!ENTITY device.permissions "Permissions">
<!ENTITY device.permissionsTooltip "View a table of the permissions accessible to the different types of apps">
<!ENTITY device.permissionsHelpLink "https://developer.mozilla.org/docs/Web/Apps/App_permissions">
<!ENTITY device.browserTabs "Browser Tabs">
<!ENTITY device.browserTabsTooltip "View a list of tabs in the browser of the connected device">
<!ENTITY device.debugBrowserTab "Debug">
<!ENTITY device.debugBrowserTabTooltip "Open the Developer Tools connected to this browser tab on the device">
<!ENTITY device.help "Help">
<!ENTITY connection.connectTooltip "Connect to the device">
<!ENTITY connection.disconnect "Disconnect">
<!ENTITY connection.disconnectTooltip "Disconnect from the current device or simulator">
<!ENTITY connection.notConnected2 "Not Connected.">
<!ENTITY connection.connectTo "Connect to:">
<!ENTITY connection.noDeviceFound "No device found. Plug a device">
<!ENTITY connection.changeHostAndPort "Change">
<!ENTITY connection.changeHostAndPortTooltip "Change the host and port used to connect to the device (defaults to localhost:6000)">
<!ENTITY connection.startSimulator "Start Simulator">
<!ENTITY connection.startSimulatorTooltip "Start an instance of the Simulator and connect to it">
<!ENTITY connection.saveConnectionInfo "Save">
<!ENTITY connection.saveConnectionInfoTooltip "Save the host and port">
<!ENTITY connection.connecting "Connecting…">
<!ENTITY connection.disconnecting "Disconnecting…">
<!ENTITY connection.cancel "Cancel">
<!ENTITY connection.cancelConnectTooltip "Cancel the connection in progress">
<!ENTITY connection.cancelShowSimulatorTooltip "Exit the Simulator connection mode and return to the initial prompt">
<!ENTITY connection.or "or">
<!ENTITY connection.noSimulatorInstalled "No simulator installed.">
<!ENTITY connection.installOneSimulator "Install Simulator">
<!ENTITY connection.installOneSimulatorTooltip "Install a version of the Simulator by downloading the relevant add-on">
<!ENTITY connection.installAnotherSimulator "Add">
<!ENTITY connection.installAnotherSimulatorTooltip "Install an additional version of the Simulator by downloading the relevant add-on">
<!ENTITY connection.startRegisteredSimulator "Start:">
<!ENTITY projects.localApps "Local Apps">
<!ENTITY projects.addApp "Add">
<!ENTITY projects.addPackaged "Add Packaged App">
<!ENTITY projects.addPackagedTooltip "Add a new packaged app (a directory) from your computer">
<!ENTITY projects.addHosted "Add Hosted App">
<!ENTITY projects.addHostedTooltip "Add a new hosted app (link to a manifest.webapp file) from a remote website">
<!ENTITY projects.title "Local Apps">
<!ENTITY projects.appDetails "App Details">
<!ENTITY projects.removeAppFromList "Remove this app from the list of apps you are working on. This will not remove it from a device or a simulator.">
<!ENTITY projects.updateApp "Update">
<!ENTITY projects.updateAppTooltip "Execute validation checks and update the app to the connected device">
<!ENTITY projects.debugApp "Debug">
<!ENTITY projects.debugAppTooltip "Open Developer Tools connected to this app">
<!ENTITY projects.saveManifest "Save">
<!ENTITY projects.saveManifestTooltip "Save the contents of the Manifest Editor below">
<!ENTITY projects.hostedManifestPlaceHolder2 "http://example.com/app/manifest.webapp">
<!ENTITY projects.noProjects "No projects. Add a new packaged app below (local directory) or a hosted app (link to a manifest file).">
<!ENTITY projects.manifestEditor "Manifest Editor">
<!ENTITY projects.manifestEditorTooltip "Edit your app's manifest in the panel below. The Update button will save your changes and update the app.">
<!ENTITY projects.manifestViewer "Manifest Viewer">
<!ENTITY projects.manifestViewerTooltip "Examine your app's manifest in the panel below">
<!ENTITY projects.valid "Valid">
<!ENTITY projects.error "Error">
<!ENTITY projects.warning "Warning">
<!ENTITY projects.hosted "Hosted">
<!ENTITY projects.packaged "Packaged">
<!ENTITY help.title "App Manager">
<!ENTITY help.close "Close">
<!ENTITY help.intro "This tool will help you build and install web apps on compatible devices (i.e. Firefox OS). The <strong>Apps</strong> tab will assist you in the validation and installation process of your app. The <strong>Device</strong> tab will give you information about the connected device. Use the bottom toolbar to connect to a device or start the simulator.">
<!ENTITY help.usefullLinks "Useful links:">
<!ENTITY help.appMgrDoc "Documentation: Using the App Manager">
<!ENTITY help.configuringDevice "How to setup your Firefox OS device">
<!ENTITY help.troubleShooting "Troubleshooting">
<!ENTITY help.simulatorAddon "Install Simulator Add-on">
<!ENTITY help.adbHelperAddon "Install Adb Helper Add-on">

View File

@ -2,20 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
index.deprecationNotice=The App Manager will be removed in a future release. Your projects have been migrated to WebIDE.
index.launchWebIDE=Launch WebIDE
index.readMoreAboutWebIDE=Read More
# LOCALIZATION NOTE (device.deviceSize): %1$S is the device's width, %2$S is
# the device's height, %3$S is the device's pixel density.
# Example: 800x480 (86 DPI).
device.deviceSize=Device size: %1$Sx%2$S (%3$S DPI)
# LOCALIZATION NOTE (connection.connectedToDevice, connection.connectTo):
# %1$S is the host name, %2$S is the port number.
connection.connectedToDevice=Connected to %1$S
connection.connectTo=Connect to %1$S:%2$S
project.filePickerTitle=Select a webapp folder
project.installing=Installing…
project.installed=Installed!
validator.nonExistingFolder=The project folder doesn't exists
validator.expectProjectFolder=The project folder ends up being a file
validator.noManifestFile=A manifest file is required at project root folder, named either 'manifest.webapp' for packaged apps or 'manifest.json' for add-ons.

View File

@ -78,7 +78,6 @@
locale/browser/devtools/connection-screen.properties (%chrome/browser/devtools/connection-screen.properties)
locale/browser/devtools/font-inspector.dtd (%chrome/browser/devtools/font-inspector.dtd)
locale/browser/devtools/har.properties (%chrome/browser/devtools/har.properties)
locale/browser/devtools/app-manager.dtd (%chrome/browser/devtools/app-manager.dtd)
locale/browser/devtools/app-manager.properties (%chrome/browser/devtools/app-manager.properties)
locale/browser/devtools/webide.dtd (%chrome/browser/devtools/webide.dtd)
locale/browser/devtools/webide.properties (%chrome/browser/devtools/webide.properties)

View File

@ -1,24 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const {Cu} = require("chrome");
const ObservableObject = require("devtools/client/shared/observable-object");
const {Devices} = Cu.import("resource://devtools/shared/apps/Devices.jsm");
var store = new ObservableObject({versions:[]});
function feedStore() {
store.object.available = Devices.helperAddonInstalled;
store.object.devices = Devices.available().map(n => {
return {name:n}
});
}
Devices.on("register", feedStore);
Devices.on("unregister", feedStore);
Devices.on("addon-status-updated", feedStore);
feedStore();
module.exports = store;

View File

@ -1,54 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const ObservableObject = require("devtools/client/shared/observable-object");
const {Connection} = require("devtools/shared/client/connection-manager");
const _knownConnectionStores = new WeakMap();
var ConnectionStore;
module.exports = ConnectionStore = function(connection) {
// If we already know about this connection,
// let's re-use the existing store.
if (_knownConnectionStores.has(connection)) {
return _knownConnectionStores.get(connection);
}
_knownConnectionStores.set(connection, this);
ObservableObject.call(this, {status:null,host:null,port:null});
this.destroy = this.destroy.bind(this);
this._feedStore = this._feedStore.bind(this);
this._connection = connection;
this._connection.once(Connection.Events.DESTROYED, this.destroy);
this._connection.on(Connection.Events.STATUS_CHANGED, this._feedStore);
this._connection.on(Connection.Events.PORT_CHANGED, this._feedStore);
this._connection.on(Connection.Events.HOST_CHANGED, this._feedStore);
this._feedStore();
return this;
}
ConnectionStore.prototype = {
destroy: function() {
if (this._connection) {
// While this.destroy is bound using .once() above, that event may not
// have occurred when the ConnectionStore client calls destroy, so we
// manually remove it here.
this._connection.off(Connection.Events.DESTROYED, this.destroy);
this._connection.off(Connection.Events.STATUS_CHANGED, this._feedStore);
this._connection.off(Connection.Events.PORT_CHANGED, this._feedStore);
this._connection.off(Connection.Events.HOST_CHANGED, this._feedStore);
_knownConnectionStores.delete(this._connection);
this._connection = null;
}
},
_feedStore: function() {
this.object.status = this._connection.status;
this.object.host = this._connection.host;
this.object.port = this._connection.port;
}
}

View File

@ -1,208 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var Cu = Components.utils;
var Ci = Components.interfaces;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://devtools/client/framework/gDevTools.jsm");
const {Simulator} = Cu.import("resource://devtools/shared/apps/Simulator.jsm")
const {Devices} = Cu.import("resource://devtools/shared/apps/Devices.jsm");
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
const {ConnectionManager, Connection} = require("devtools/shared/client/connection-manager");
const {getDeviceFront} = require("devtools/server/actors/device");
const ConnectionStore = require("devtools/client/app-manager/connection-store");
const DeviceStore = require("devtools/client/app-manager/device-store");
const simulatorsStore = require("devtools/client/app-manager/simulators-store");
const adbStore = require("devtools/client/app-manager/builtin-adb-store");
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
UI.destroy();
});
var UI = {
init: function() {
this.useFloatingScrollbarsIfNeeded();
let connections = ConnectionManager.connections;
if (connections.length > 0) {
let hash = window.location.hash;
if (hash) {
let res = (/cid=([^&]+)/).exec(hash)
if (res) {
let [,cid] = res;
this.connection = connections.filter((({uid}) => uid == cid))[0];
}
}
if (!this.connection) {
// We take the first connection available.
this.connection = connections[0];
}
} else {
let host = Services.prefs.getCharPref("devtools.debugger.remote-host");
let port = Services.prefs.getIntPref("devtools.debugger.remote-port");
this.connection = ConnectionManager.createConnection(host, port);
}
window.location.hash = "cid=" + this.connection.uid;
window.parent.postMessage(JSON.stringify({name:"connection",cid:this.connection.uid}), "*");
this.store = Utils.mergeStores({
"device": new DeviceStore(this.connection),
"connection": new ConnectionStore(this.connection),
"simulators": simulatorsStore,
"adb": adbStore
});
let pre = document.querySelector("#logs > pre");
pre.textContent = this.connection.logs;
pre.scrollTop = pre.scrollTopMax;
this.connection.on(Connection.Events.NEW_LOG, this._onNewLog);
this.template = new Template(document.body, this.store, Utils.l10n);
this.template.start();
this._onSimulatorConnected = this._onSimulatorConnected.bind(this);
this._onSimulatorDisconnected = this._onSimulatorDisconnected.bind(this);
},
destroy: function() {
this.store.destroy();
this.connection.off(Connection.Events.NEW_LOG, this._onNewLog);
this.template.destroy();
},
_onNewLog: function(event, str) {
let pre = document.querySelector("#logs > pre");
pre.textContent += "\n" + str;
pre.scrollTop = pre.scrollTopMax;
},
useFloatingScrollbarsIfNeeded: function() {
if (Services.appinfo.OS == "Darwin") {
return;
}
let scrollbarsUrl = Services.io.newURI("chrome://devtools/skin/themes/floating-scrollbars-light.css", null, null);
let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
winUtils.loadSheet(scrollbarsUrl, winUtils.AGENT_SHEET);
let computedStyle = window.getComputedStyle(document.documentElement);
if (computedStyle) { // Force a reflow to take the new css into account
let display = computedStyle.display; // Save display value
document.documentElement.style.display = "none";
window.getComputedStyle(document.documentElement).display; // Flush
document.documentElement.style.display = display; // Restore
}
},
disconnect: function() {
this.connection.disconnect();
},
connect: function() {
this.connection.connect();
},
editConnectionParameters: function() {
document.body.classList.add("edit-connection");
document.querySelector("input.host").focus();
},
saveConnectionInfo: function() {
document.body.classList.remove("edit-connection");
document.querySelector("#connect-button").focus();
let host = document.querySelector("input.host").value;
let port = document.querySelector("input.port").value;
this.connection.port = port;
this.connection.host = host;
Services.prefs.setCharPref("devtools.debugger.remote-host", host);
Services.prefs.setIntPref("devtools.debugger.remote-port", port);
},
showSimulatorList: function() {
document.body.classList.add("show-simulators");
},
cancelShowSimulatorList: function() {
document.body.classList.remove("show-simulators");
},
installSimulator: function() {
let url = "https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager#Simulator";
window.open(url);
},
startSimulator: function(version) {
this._portBeforeSimulatorStarted = this.connection.port;
let port = ConnectionManager.getFreeTCPPort();
let simulator = Simulator.getByName(version);
if (!simulator) {
this.connection.log("Error: can't find simulator: " + version);
return;
}
if (!simulator.launch) {
this.connection.log("Error: invalid simulator: " + version);
return;
}
this.connection.log("Found simulator: " + version);
this.connection.log("Starting simulator...");
this.simulator = simulator;
this.simulator.launch({ port: port })
.then(() => {
this.connection.log("Simulator ready. Connecting.");
this.connection.port = port;
this.connection.host = "localhost";
this.connection.once("connected",
this._onSimulatorConnected);
this.connection.once("disconnected",
this._onSimulatorDisconnected);
this.connection.keepConnecting = true;
this.connection.connect();
});
document.body.classList.remove("show-simulators");
},
_onSimulatorConnected: function() {
this.connection.log("Connected to simulator.");
this.connection.keepConnecting = false;
// This doesn't change the current (successful) connection,
// but makes sure that when the simulator is disconnected, the
// connection doesn't end up with a random port number (from
// getFreeTCPPort).
this.connection.port = this._portBeforeSimulatorStarted;
},
_onSimulatorDisconnected: function() {
this.connection.off("connected", this._onSimulatorConnected);
},
connectToAdbDevice: function(name) {
let device = Devices.getByName(name);
device.connect().then((port) => {
this.connection.host = "localhost";
this.connection.port = port;
this.connect();
});
},
screenshot: function() {
this.connection.client.listTabs(
response => {
let front = getDeviceFront(this.connection.client, response);
front.screenshotToBlob().then(blob => {
let topWindow = Services.wm.getMostRecentWindow("navigator:browser");
let gBrowser = topWindow.gBrowser;
let url = topWindow.URL.createObjectURL(blob);
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
tab.addEventListener("TabClose", function onTabClose() {
tab.removeEventListener("TabClose", onTabClose, false);
topWindow.URL.revokeObjectURL(url);
}, false);
}).then(null, console.error);
}
);
},
}

View File

@ -1,146 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html [
<!ENTITY % appMgrDTD SYSTEM "chrome://browser/locale/devtools/app-manager.dtd" >
%appMgrDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf8"/>
<link rel="stylesheet" href="chrome://devtools/skin/themes/app-manager/connection-footer.css" type="text/css"/>
</head>
<body onload="UI.init()">
<div id="connection-footer" template='{"type":"attribute","path":"connection.status","name":"status"}'>
<div id="banners-and-logs">
<!-- Connected -->
<div id="banner-connected" class="banner">
<div class="connected-indicator"></div>
<div id="status" class="banner-box">
<div class="banner-content">
<span template='{"type":"localizedContent","property":"connection.connectedToDevice","paths":["device.description.name"]}'></span>
<button class="action-cancel" onclick="UI.disconnect()" title="&connection.disconnectTooltip;">&connection.disconnect;</button>
<button class="action-primary" onclick="UI.screenshot()" title="&device.screenshotTooltip;">&device.screenshot;</button>
</div>
</div>
</div>
<!-- Disconnected -->
<div id="banner-disconnected" class="banner">
<div class="connected-indicator"></div>
<div class="banner-box">
<div class="banner-content" template='{"type":"attribute","path":"adb.available","name":"adb-available"}'>
<span>&connection.notConnected2;</span>
<div id="connection-manual">
<button class="action-primary left" onclick="UI.connect()" id="connect-button" template='{"type":"localizedContent","property":"connection.connectTo","paths":["connection.host","connection.port"]}' title="&connection.connectTooltip;"></button>
<button class="right" onclick="UI.editConnectionParameters()" title="&connection.changeHostAndPortTooltip;">&connection.changeHostAndPort;</button>
</div>
<div id="connection-assisted" template='{"type":"attribute","path":"adb.devices.length","name":"device-count"}'>
<div id="connection-found-device">
<span>&connection.connectTo;</span>
<span template-loop='{"arrayPath":"adb.devices","childSelector":"#adb-devices-template"}'></span>
</div>
<div id="connection-no-device">
<span>&connection.noDeviceFound;</span>
</div>
</div>
<div id="start-simulator-box">
<span>&connection.or;</span>
<button id="start-simulator-button" class="action-primary" onclick="UI.showSimulatorList()" title="&connection.startSimulatorTooltip;">&connection.startSimulator;</button>
</div>
</div>
</div>
</div>
<!-- Connecting -->
<div id="banner-connecting" class="banner">
<div class="connected-indicator"></div>
<div id="status" class="banner-box">
<div class="banner-content">
<span>&connection.connecting;</span>
<button class="action-cancel" onclick="UI.disconnect()" title="&connection.cancelConnectTooltip;">&connection.cancel;</button>
</div>
</div>
</div>
<!-- Disconnecting -->
<div id="banner-disconnecting" class="banner">
<div class="connected-indicator"></div>
<div id="status" class="banner-box">
<div class="banner-content">
<span>&connection.disconnecting;</span>
</div>
</div>
</div>
<!-- Editing -->
<div id="banner-editing" class="banner">
<div class="connected-indicator"></div>
<div class="banner-box">
<div class="banner-content">
<form onsubmit="UI.saveConnectionInfo()">
<input class="host" template='{"type":"attribute","path":"connection.host","name":"value"}'></input>
<input class="port" pattern="\d+" template='{"type":"attribute","path":"connection.port","name":"value"}' type="number"></input>
<button type="submit" title="&connection.saveConnectionInfoTooltip;">&connection.saveConnectionInfo;</button>
</form>
</div>
</div>
</div>
<!-- Simulator -->
<div id="banner-simulators" class="banner" template='{"type":"attribute","path":"simulators.versions.length","name":"simulator-count"}'>
<div class="connected-indicator"></div>
<div class="banner-box">
<div class="banner-content">
<div class="no-simulator">
<span>&connection.noSimulatorInstalled;</span>
<button class="action-primary" onclick="UI.installSimulator()" title="&connection.installOneSimulatorTooltip;">&connection.installOneSimulator;</button>
</div>
<div class="found-simulator">
<span>&connection.startRegisteredSimulator;</span>
<span template-loop='{"arrayPath":"simulators.versions","childSelector":"#simulator-item-template"}'></span>
<button class="action-primary" onclick="UI.installSimulator()" title="&connection.installAnotherSimulatorTooltip;">&connection.installAnotherSimulator;</button>
</div>
<button class="action-cancel" onclick="UI.cancelShowSimulatorList()" title="&connection.cancelShowSimulatorTooltip;">&connection.cancel;</button>
</div>
</div>
</div>
<!-- Logs -->
<div id="banner-logs">
<div id="logs" class="banner-box">
<pre></pre>
</div>
</div>
</div>
</div>
</body>
<template id="simulator-item-template">
<span>
<button class="simulator-item action-primary" onclick="UI.startSimulator(this.dataset.version)" template='{"type":"attribute","path":"version","name":"data-version"}' title="&connection.startSimulatorTooltip;">
<span template='{"type":"textContent", "path":"label"}'></span>
</button>
</span>
</template>
<template id="adb-devices-template">
<span>
<button class="adb-device action-primary" onclick="UI.connectToAdbDevice(this.dataset.name)" template='{"type":"attribute","path":"name","name":"data-name"}'>
<span template='{"type":"textContent", "path":"name"}'></span>
</button>
</span>
</template>
<script type="application/javascript;version=1.8" src="utils.js"></script>
<script type="application/javascript;version=1.8" src="template.js"></script>
<script type="application/javascript;version=1.8" src="connection-footer.js"></script>
</html>

View File

@ -1,234 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
const {gDevTools} = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
const {TargetFactory} = require("devtools/client/framework/target");
const {ConnectionManager, Connection}
= require("devtools/shared/client/connection-manager");
const {getDeviceFront} = require("devtools/server/actors/device");
const {getTargetForApp, launchApp, closeApp}
= require("devtools/shared/apps/app-actor-front");
const DeviceStore = require("devtools/client/app-manager/device-store");
const WebappsStore = require("devtools/client/app-manager/webapps-store");
const promise = require("devtools/shared/deprecated-sync-thenables");
const DEFAULT_APP_ICON = "chrome://devtools/skin/themes/app-manager/images/default-app-icon.png";
window.addEventListener("message", function(event) {
try {
let message = JSON.parse(event.data);
if (message.name == "connection") {
let cid = parseInt(message.cid);
for (let c of ConnectionManager.connections) {
if (c.uid == cid) {
UI.connection = c;
UI.onNewConnection();
break;
}
}
}
} catch(e) {
Cu.reportError(e);
}
});
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
UI.destroy();
});
var UI = {
init: function() {
this.showFooterIfNeeded();
this.setTab("apps");
if (this.connection) {
this.onNewConnection();
} else {
this.hide();
}
},
destroy: function() {
if (this.connection) {
this.connection.off(Connection.Events.STATUS_CHANGED, this._onConnectionStatusChange);
}
if (this.store) {
this.store.destroy();
}
if (this.template) {
this.template.destroy();
}
},
showFooterIfNeeded: function() {
let footer = document.querySelector("#connection-footer");
if (window.parent == window) {
// We're alone. Let's add a footer.
footer.removeAttribute("hidden");
footer.src = "chrome://devtools/content/app-manager/content/connection-footer.xhtml";
} else {
footer.setAttribute("hidden", "true");
}
},
hide: function() {
document.body.classList.add("notconnected");
},
show: function() {
document.body.classList.remove("notconnected");
},
onNewConnection: function() {
this.connection.on(Connection.Events.STATUS_CHANGED, this._onConnectionStatusChange);
this.store = Utils.mergeStores({
"device": new DeviceStore(this.connection),
"apps": new WebappsStore(this.connection),
});
if (this.template) {
this.template.destroy();
}
this.template = new Template(document.body, this.store, Utils.l10n);
this.template.start();
this._onConnectionStatusChange();
},
setWallpaper: function(dataurl) {
document.getElementById("meta").style.backgroundImage = "url(" + dataurl + ")";
},
_onConnectionStatusChange: function() {
if (this.connection.status != Connection.Status.CONNECTED) {
this.hide();
this.listTabsResponse = null;
} else {
this.show();
this.connection.client.listTabs(
response => {
this.listTabsResponse = response;
let front = getDeviceFront(this.connection.client, this.listTabsResponse);
front.getWallpaper().then(longstr => {
longstr.string().then(dataURL => {
longstr.release().then(null, Cu.reportError);
this.setWallpaper(dataURL);
});
});
if (Services.prefs.getBoolPref("devtools.chrome.enabled")) {
let rootButton = document.getElementById("root-actor-debug");
if (response.consoleActor) {
rootButton.removeAttribute("hidden");
} else {
rootButton.setAttribute("hidden", "true");
}
}
let tabsButton = document.querySelector(".tab.browser-tabs");
if (response.tabs.length > 0) {
tabsButton.classList.remove("hidden");
} else {
tabsButton.classList.add("hidden");
}
}
);
}
},
get connected() { return !!this.listTabsResponse; },
setTab: function(name) {
var tab = document.querySelector(".tab.selected");
var panel = document.querySelector(".tabpanel.selected");
if (tab) tab.classList.remove("selected");
if (panel) panel.classList.remove("selected");
var tab = document.querySelector(".tab." + name);
var panel = document.querySelector(".tabpanel." + name);
if (tab) tab.classList.add("selected");
if (panel) panel.classList.add("selected");
},
openToolboxForRootActor: function() {
if (!this.connected) {
return;
}
let options = {
form: this.listTabsResponse,
client: this.connection.client,
chrome: true
};
TargetFactory.forRemoteTab(options).then((target) => {
top.UI.openAndShowToolboxForTarget(target, "Main process", null);
});
},
openToolboxForApp: function(manifest) {
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) => {
top.UI.openAndShowToolboxForTarget(target, app.name, app.iconURL);
}, console.error);
},
_getTargetForTab: function (form) {
let options = {
form: form,
client: this.connection.client,
chrome: false
};
let deferred = promise.defer();
return TargetFactory.forRemoteTab(options);
},
openToolboxForTab: function (aNode) {
let index = Array.prototype.indexOf.apply(
aNode.parentNode.parentNode.parentNode.children,
[aNode.parentNode.parentNode]);
this.connection.client.listTabs(
response => {
let tab = response.tabs[index];
this._getTargetForTab(tab).then(target => {
top.UI.openAndShowToolboxForTarget(
target, tab.title, DEFAULT_APP_ICON);
}, console.error);
}
);
},
startApp: function(manifest) {
if (!this.connected) {
return promise.reject();
}
return launchApp(this.connection.client,
this.listTabsResponse.webappsActor,
manifest);
},
stopApp: function(manifest) {
if (!this.connected) {
return promise.reject();
}
return closeApp(this.connection.client,
this.listTabsResponse.webappsActor,
manifest);
},
}
// This must be bound immediately, as it might be used via the message listener
// before UI.init() has been called.
UI._onConnectionStatusChange = UI._onConnectionStatusChange.bind(UI);

View File

@ -1,118 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html [
<!ENTITY % appMgrDTD SYSTEM "chrome://browser/locale/devtools/app-manager.dtd" >
%appMgrDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf8"/>
<title>&device.title;</title>
<link rel="stylesheet" href="chrome://devtools/skin/themes/app-manager/device.css" type="text/css"/>
</head>
<body onload="UI.init()">
<div id="notConnectedMessage"><span>&device.notConnected;</span></div>
<section id="content">
<aside id="sidebar">
<div id="meta">
<header>
<h1>
<span template='{"type":"textContent","path":"device.description.name"}'></span>
<span template='{"type":"textContent","path":"device.description.version"}'></span>
<span template='{"type":"textContent","path":"device.description.channel"}'></span>
</h1>
<h3>
<span>Gecko </span>
<span template='{"type":"textContent","path":"device.description.geckoversion"}'></span>
</h3>
<p template='{"type":"localizedContent","property":"device.deviceSize", "paths":["device.description.width","device.description.height","device.description.dpi"]}'></p>
<button id="root-actor-debug" hidden="true" onclick="UI.openToolboxForRootActor()" title="&device.debugMainProcessTooltip;">&device.debugMainProcess;</button>
</header>
<div id="tabs-headers">
<div onclick="UI.setTab('apps')" class="tab sidebar-item apps" title="&device.installedAppsTooltip;">&device.installedApps;</div>
<div onclick="UI.setTab('permissions')" class="tab sidebar-item permissions" title="&device.permissionsTooltip;">
&device.permissions;
<a target="_blank" href="&device.permissionsHelpLink;">
<button class="help">&device.help;</button>
</a>
</div>
<div onclick="UI.setTab('browser-tabs')" class="tab sidebar-item browser-tabs" hidden="true" title="&device.browserTabsTooltip;">&device.browserTabs;</div>
</div>
</div>
</aside>
<section id="detail">
<div id="tabs">
<div class="tabpanel apps">
<div class="app-list" template-loop='{"arrayPath":"apps.all","childSelector":"#app-template"}'></div>
</div>
<div class="tabpanel permissions permission-table">
<div class="permission-table-header">
<div>&device.name;</div>
<div title="type:'web'">&device.plain;</div>
<div title="type:'privileged'">&device.privileged;</div>
<div title="type:'certified'">&device.certified;</div>
</div>
<div class="permission-table-body" >
<section template-loop='{"arrayPath":"device.permissions","childSelector":"#permission-template"}'></section>
</div>
<div class="permission-table-footer">
<div class="allow-label" title="&device.allowTooltip;">&device.allow;</div>
<div class="prompt-label" title="&device.promptTooltip;">&device.prompt;</div>
<div class="deny-label" title="&device.denyTooltip;">&device.deny;</div>
</div>
</div>
<div class="tabpanel browser-tabs">
<section template-loop='{"arrayPath":"device.tabs","childSelector":"#browser-tab-template"}'></section>
</div>
</div>
</section>
</section>
<iframe id="connection-footer" hidden="true"></iframe>
</body>
<template id="permission-template">
<div class="permission">
<div template='{"type":"textContent","path":"name"}'></div>
<div template='{"type":"attribute", "name":"permission", "path":"app"}'></div>
<div template='{"type":"attribute", "name":"permission", "path":"privileged"}'></div>
<div template='{"type":"attribute", "name":"permission", "path":"certified"}'></div>
</div>
</template>
<template id="browser-tab-template">
<div class="browser-tab">
<div class="browser-tab-details">
<p template='{"type":"textContent","path":"title"}'></p>
<p class="browser-tab-url-subheading" template='{"type":"textContent","path":"url"}'></p>
</div>
<div class="browser-tab-buttons">
<button class="button-debug" template='{"type":"attribute","path":"actor","name":"data-actor"}' onclick="UI.openToolboxForTab(this)" style="display: inline-block;" title="&device.debugBrowserTabTooltip;">&device.debugBrowserTab;</button>
</div>
</div>
</template>
<template id="app-template">
<div class="app" template='{"type":"attribute","path":"running","name":"running"}'>
<img class="app-icon" template='{"type":"attribute","path":"iconURL","name":"src"}'></img>
<span class="app-name" template='{"type":"textContent","path":"name"}'></span>
<div class="app-buttons">
<button class="button-debug" template='{"type":"attribute","path":"manifestURL","name":"data-manifest"}' onclick="UI.openToolboxForApp(this.dataset.manifest)" title="&device.debugAppTooltip;">&device.debugApp;</button>
<button class="button-start" template='{"type":"attribute","path":"manifestURL","name":"data-manifest"}' onclick="UI.startApp(this.dataset.manifest)" title="&device.startAppTooltip;">&device.startApp;</button>
<button class="button-stop" template='{"type":"attribute","path":"manifestURL","name":"data-manifest"}' onclick="UI.stopApp(this.dataset.manifest)" title="&device.stopAppTooltip;">&device.stopApp;</button>
</div>
</div>
</template>
<script type="application/javascript;version=1.8" src="utils.js"></script>
<script type="application/javascript;version=1.8" src="template.js"></script>
<script type="application/javascript;version=1.8" src="device.js"></script>
</html>

View File

@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html [
<!ENTITY % appMgrDTD SYSTEM "chrome://browser/locale/devtools/app-manager.dtd" >
%appMgrDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf8"/>
<title>&help.title;</title>
<link rel="stylesheet" href="chrome://devtools/skin/themes/app-manager/help.css" type="text/css"/>
</head>
<body>
<h1>&help.title;</h1>
<p>&help.intro;</p>
<p>&help.usefullLinks;</p>
<ul>
<li><a target="mdn" href="https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager">&help.appMgrDoc;</a></li>
<li><a target="mdn" href="https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager#Configuring_device">&help.configuringDevice;</a></li>
<li><a target="mdn" href="https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager#Troubleshooting">&help.troubleShooting;</a></li>
<li><a target="mdn" href="https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager#Simulator">&help.simulatorAddon;</a></li>
<li><a target="mdn" href="https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager#Adb_Helper_Add-on">&help.adbHelperAddon;</a></li>
</ul>
<button id="close-button" onclick="closeHelp()">&help.close;</button>
</body>
<script type="application/javascript;version=1.8">
function closeHelp() {
window.parent.postMessage(JSON.stringify({name:"closeHelp"}), "*");
}
</script>
</html>

View File

@ -1,212 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var {utils: Cu, interfaces: Ci} = Components;
Cu.import("resource://devtools/client/framework/gDevTools.jsm");
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
const {Toolbox} = require("devtools/client/framework/toolbox");
const {ConnectionManager, Connection} = require("devtools/shared/client/connection-manager");
const promise = require("devtools/shared/deprecated-sync-thenables");
const prefs = require("sdk/preferences/service");
const Services = require("Services");
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/app-manager.properties");
var 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");
this.showDeprecationNotice();
},
onUnload: function() {
for (let [target, toolbox] of this._handledTargets) {
toolbox.destroy();
}
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);
}
},
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":
window.top.focus();
this.selectTab(json.uid);
break;
case "toolbox-close":
this.closeToolboxTab(json.uid);
break;
case "toolbox-title":
// Not implemented
break;
default:
Cu.reportError("Unknown message: " + json.name);
}
} catch(e) { Cu.reportError(e); }
// Forward message
let panels = document.querySelectorAll(".panel");
for (let frame of panels) {
frame.contentWindow.postMessage(event.data, "*");
}
},
selectTabFromButton: function(button) {
if (!button.hasAttribute("panel"))
return;
this.selectTab(button.getAttribute("panel"));
},
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.setAttribute("selected", "true");
if (newSelection.classList.contains("toolbox")) {
isToolboxTab = true;
}
}
}
if (!isToolboxTab) {
prefs.set("devtools.appmanager.lastTab", panel);
}
},
onNewConnection: function(connection) {
this.connection = connection;
this.connection.on(Connection.Status.CONNECTED, this.onConnected);
this.connection.on(Connection.Status.DISCONNECTED, this.onDisconnected);
},
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 = Toolbox.HostType.CUSTOM;
let toolbox = gDevTools.getToolbox(target);
if (!toolbox) {
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 {
return gDevTools.showToolbox(target, null, host);
}
},
showDeprecationNotice: function() {
let message = Strings.GetStringFromName("index.deprecationNotice");
let buttons = [
{
label: Strings.GetStringFromName("index.launchWebIDE"),
callback: gDevToolsBrowser.openWebIDE
},
{
label: Strings.GetStringFromName("index.readMoreAboutWebIDE"),
callback: () => {
window.open("https://developer.mozilla.org/docs/Tools/WebIDE");
}
}
];
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
let browser = docShell.chromeEventHandler;
let nbox = browser.ownerDocument.defaultView.gBrowser
.getNotificationBox(browser);
nbox.appendNotification(message, "app-manager-deprecation", null,
nbox.PRIORITY_WARNING_LOW, buttons);
}
};
UI.init();

View File

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE window [
<!ENTITY % appMgrDTD SYSTEM "chrome://browser/locale/devtools/app-manager.dtd" >
%appMgrDTD;
]>
<?xml-stylesheet href="chrome://global/skin/global.css"?>
<?xml-stylesheet href="chrome://devtools/skin/themes/app-manager/index.css"?>
<window id="app-manager-window"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&index.title;"
windowtype="devtools:app-manager"
macanimationtype="document"
fullscreenbutton="true"
screenX="4" screenY="4"
width="800" height="600"
persist="screenX screenY width height sizemode">
<vbox id="root" flex="1">
<hbox id="content" flex="1">
<vbox id="tabs" onclick="UI.selectTabFromButton(event.target)">
<button class="button projects-button" panel="projects">&index.projects2;</button>
<button class="button device-button" panel="device">&index.device2;</button>
<vbox id="toolbox-tabs" flex="1"/>
<button class="button help-button" panel="help">&index.help;</button>
</vbox>
<hbox id="tab-panels" flex="1">
<iframe flex="1" class="panel projects-panel" src="chrome://devtools/content/app-manager/content/projects.xhtml"/>
<iframe flex="1" class="panel device-panel" src="chrome://devtools/content/app-manager/content/device.xhtml"/>
<iframe flex="1" class="panel help-panel" src="chrome://devtools/content/app-manager/content/help.xhtml"></iframe>
</hbox>
</hbox>
<iframe id="connection-footer" src="chrome://devtools/content/app-manager/content/connection-footer.xhtml"></iframe>
</vbox>
<script type="application/javascript;version=1.8" src="chrome://devtools/content/app-manager/content/index.js"></script>
</window>

View File

@ -1,146 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
Cu.import("resource://gre/modules/osfile.jsm");
const {VariablesView} =
Cu.import("resource://devtools/client/shared/widgets/VariablesView.jsm", {});
const VARIABLES_VIEW_URL =
"chrome://devtools/content/shared/widgets/VariablesView.xul";
function ManifestEditor(project) {
this.project = project;
this._onContainerReady = this._onContainerReady.bind(this);
this._onEval = this._onEval.bind(this);
this._onSwitch = this._onSwitch.bind(this);
this._onDelete = this._onDelete.bind(this);
this._onNew = this._onNew.bind(this);
}
ManifestEditor.prototype = {
get manifest() { return this.project.manifest; },
get editable() { return this.project.type == "packaged"; },
show: function(containerElement) {
let deferred = promise.defer();
let iframe = this._iframe = document.createElement("iframe");
iframe.addEventListener("load", function onIframeLoad() {
iframe.removeEventListener("load", onIframeLoad, true);
deferred.resolve(iframe.contentWindow);
}, true);
iframe.setAttribute("src", VARIABLES_VIEW_URL);
iframe.classList.add("variables-view");
containerElement.appendChild(iframe);
return deferred.promise.then(this._onContainerReady);
},
_onContainerReady: function(varWindow) {
let variablesContainer = varWindow.document.querySelector("#variables");
variablesContainer.classList.add("manifest-editor");
let editor = this.editor = new VariablesView(variablesContainer);
editor.onlyEnumVisible = true;
editor.alignedValues = true;
editor.actionsFirst = true;
if (this.editable) {
editor.eval = this._onEval;
editor.switch = this._onSwitch;
editor.delete = this._onDelete;
editor.new = this._onNew;
}
return this.update();
},
_onEval: function(variable, value) {
let parent = this._descend(variable.ownerView.symbolicPath);
try {
parent[variable.name] = JSON.parse(value);
} catch(e) {
Cu.reportError(e);
}
this.update();
},
_onSwitch: function(variable, newName) {
if (variable.name == newName) {
return;
}
let parent = this._descend(variable.ownerView.symbolicPath);
parent[newName] = parent[variable.name];
delete parent[variable.name];
this.update();
},
_onDelete: function(variable) {
let parent = this._descend(variable.ownerView.symbolicPath);
delete parent[variable.name];
},
_onNew: function(variable, newName, newValue) {
let parent = this._descend(variable.symbolicPath);
try {
parent[newName] = JSON.parse(newValue);
} catch(e) {
Cu.reportError(e);
}
this.update();
},
/**
* Returns the value located at a given path in the manifest.
* @param path array
* A string for each path component: ["developer", "name"]
*/
_descend: function(path) {
let parent = this.manifest;
while (path.length) {
parent = parent[path.shift()];
}
return parent;
},
update: function() {
this.editor.rawObject = this.manifest;
this.editor.commitHierarchy();
// Wait until the animation from commitHierarchy has completed
let deferred = promise.defer();
setTimeout(deferred.resolve, this.editor.lazyEmptyDelay + 1);
return deferred.promise;
},
save: function() {
if (this.editable) {
let validator = new AppValidator(this.project);
let manifestFile = validator._getPackagedManifestFile();
let path = manifestFile.path;
let encoder = new TextEncoder();
let data = encoder.encode(JSON.stringify(this.manifest, null, 2));
return OS.File.writeAtomic(path, data, { tmpPath: path + ".tmp" });
}
return promise.resolve();
},
destroy: function() {
if (this._iframe) {
this._iframe.remove();
}
}
};

View File

@ -1,451 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
Cu.import("resource://devtools/client/framework/gDevTools.jsm");
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
const {ConnectionManager, Connection} = require("devtools/shared/client/connection-manager");
const {AppProjects} = require("devtools/client/app-manager/app-projects");
const {AppValidator} = require("devtools/client/app-manager/app-validator");
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
const {installHosted, installPackaged, getTargetForApp,
reloadApp, launchApp, closeApp} = require("devtools/shared/apps/app-actor-front");
const {EventEmitter} = Cu.import("resource://devtools/shared/event-emitter.js");
const promise = require("devtools/shared/deprecated-sync-thenables");
const MANIFEST_EDITOR_ENABLED = "devtools.appmanager.manifestEditor.enabled";
window.addEventListener("message", function(event) {
try {
let json = JSON.parse(event.data);
if (json.name == "connection") {
let cid = parseInt(json.cid);
for (let c of ConnectionManager.connections) {
if (c.uid == cid) {
UI.connection = c;
UI.onNewConnection();
break;
}
}
}
} catch(e) {}
});
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
UI.destroy();
});
var UI = {
isReady: false,
onload: function() {
if (Services.prefs.getBoolPref(MANIFEST_EDITOR_ENABLED)) {
document.querySelector("#lense").setAttribute("manifest-editable", "");
}
this.template = new Template(document.body, AppProjects.store, Utils.l10n);
this.template.start();
AppProjects.load().then(() => {
AppProjects.store.object.projects.forEach(UI.validate);
this.isReady = true;
this.emit("ready");
});
},
destroy: function() {
if (this.connection) {
this.connection.off(Connection.Events.STATUS_CHANGED, this._onConnectionStatusChange);
}
this.template.destroy();
},
onNewConnection: function() {
this.connection.on(Connection.Events.STATUS_CHANGED, this._onConnectionStatusChange);
this._onConnectionStatusChange();
},
_onConnectionStatusChange: function() {
if (this.connection.status != Connection.Status.CONNECTED) {
document.body.classList.remove("connected");
this.listTabsResponse = null;
} else {
document.body.classList.add("connected");
this.connection.client.listTabs(
response => {this.listTabsResponse = response}
);
}
},
get connected() { return !!this.listTabsResponse; },
_selectFolder: function() {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, Utils.l10n("project.filePickerTitle"), Ci.nsIFilePicker.modeGetFolder);
let res = fp.show();
if (res != Ci.nsIFilePicker.returnCancel)
return fp.file;
return null;
},
addPackaged: function(folder) {
if (!folder) {
folder = this._selectFolder();
}
if (!folder)
return;
return AppProjects.addPackaged(folder)
.then(function (project) {
UI.validate(project);
UI.selectProject(project.location);
});
},
addHosted: function() {
let form = document.querySelector("#new-hosted-project-wrapper");
if (!form.checkValidity())
return;
let urlInput = document.querySelector("#url-input");
let manifestURL = urlInput.value;
return AppProjects.addHosted(manifestURL)
.then(function (project) {
UI.validate(project);
UI.selectProject(project.location);
});
},
_getLocalIconURL: function(project, manifest) {
let icon;
if (manifest.icons) {
let size = Object.keys(manifest.icons).sort((a, b) => b - a)[0];
if (size) {
icon = manifest.icons[size];
}
}
if (!icon)
return "chrome://devtools/skin/themes/app-manager/images/default-app-icon.png";
if (project.type == "hosted") {
let manifestURL = Services.io.newURI(project.location, null, null);
let origin = Services.io.newURI(manifestURL.prePath, null, null);
return Services.io.newURI(icon, null, origin).spec;
} else if (project.type == "packaged") {
let projectFolder = FileUtils.File(project.location);
let folderURI = Services.io.newFileURI(projectFolder).spec;
return folderURI + icon.replace(/^\/|\\/, "");
}
},
validate: function(project) {
let validation = new AppValidator(project);
return validation.validate()
.then(function () {
if (validation.manifest) {
project.icon = UI._getLocalIconURL(project, validation.manifest);
project.manifest = validation.manifest;
}
project.validationStatus = "valid";
if (validation.warnings.length > 0) {
project.warningsCount = validation.warnings.length;
project.warnings = validation.warnings.join(",\n ");
project.validationStatus = "warning";
} else {
project.warnings = "";
project.warningsCount = 0;
}
if (validation.errors.length > 0) {
project.errorsCount = validation.errors.length;
project.errors = validation.errors.join(",\n ");
project.validationStatus = "error";
} else {
project.errors = "";
project.errorsCount = 0;
}
if (project.warningsCount && project.errorsCount) {
project.validationStatus = "error warning";
}
});
},
update: function(button, location) {
button.disabled = true;
let project = AppProjects.get(location);
// Update the manifest editor view, in case the manifest was modified
// outside of the app manager. This can happen in parallel with the other
// steps.
this._showManifestEditor(project);
this.validate(project)
.then(() => {
// Install the app to the device if we are connected,
// and there is no error
if (project.errorsCount == 0 && this.connected) {
return this.install(project);
}
})
.then(() => {
button.disabled = false;
// Finally try to reload the app if it is already opened
if (this.connected) {
this.reload(project);
}
},
(res) => {
button.disabled = false;
let message = res.error + ": " + res.message;
alert(message);
this.connection.log(message);
});
},
saveManifest: function(button) {
button.disabled = true;
this.manifestEditor.save().then(() => button.disabled = false);
},
reload: function (project) {
if (!this.connected) {
return promise.reject();
}
return reloadApp(this.connection.client,
this.listTabsResponse.webappsActor,
this._getProjectManifestURL(project)).
then(() => {
this.connection.log("App reloaded");
});
},
remove: function(location, event) {
if (event) {
// We don't want the "click" event to be propagated to the project item.
// That would trigger `selectProject()`.
event.stopPropagation();
}
let item = document.getElementById(location);
let toSelect = document.querySelector(".project-item.selected");
toSelect = toSelect ? toSelect.id : "";
if (toSelect == location) {
toSelect = null;
let sibling;
if (item.previousElementSibling) {
sibling = item.previousElementSibling;
} else {
sibling = item.nextElementSibling;
}
if (sibling && !!AppProjects.get(sibling.id)) {
toSelect = sibling.id;
}
}
AppProjects.remove(location).then(() => {
this.selectProject(toSelect);
});
},
_getProjectManifestURL: function (project) {
if (project.type == "packaged") {
return "app://" + project.packagedAppOrigin + "/manifest.webapp";
} else if (project.type == "hosted") {
return project.location;
}
},
install: function(project) {
if (!this.connected) {
return promise.reject();
}
this.connection.log("Installing the " + project.manifest.name + " app...");
let installPromise;
if (project.type == "packaged") {
installPromise = installPackaged(this.connection.client, this.listTabsResponse.webappsActor, project.location, project.packagedAppOrigin)
.then(({ appId }) => {
// If the packaged app specified a custom origin override,
// we need to update the local project origin
project.packagedAppOrigin = appId;
// And ensure the indexed db on disk is also updated
AppProjects.update(project);
});
} else {
let manifestURLObject = Services.io.newURI(project.location, null, null);
let origin = Services.io.newURI(manifestURLObject.prePath, null, null);
let appId = origin.host;
let metadata = {
origin: origin.spec,
manifestURL: project.location
};
installPromise = installHosted(this.connection.client, this.listTabsResponse.webappsActor, appId, metadata, project.manifest);
}
installPromise.then(() => {
this.connection.log("Install completed.");
}, () => {
this.connection.log("Install failed.");
});
return installPromise;
},
start: function(project) {
if (!this.connected) {
return promise.reject();
}
let manifestURL = this._getProjectManifestURL(project);
return launchApp(this.connection.client,
this.listTabsResponse.webappsActor,
manifestURL);
},
stop: function(location) {
if (!this.connected) {
return promise.reject();
}
let project = AppProjects.get(location);
let manifestURL = this._getProjectManifestURL(project);
return closeApp(this.connection.client,
this.listTabsResponse.webappsActor,
manifestURL);
},
debug: function(button, location) {
if (!this.connected) {
return promise.reject();
}
button.disabled = true;
let project = AppProjects.get(location);
let onFailedToStart = (error) => {
// If not installed, install and open it
if (error == "NO_SUCH_APP") {
return this.install(project);
} else {
throw error;
}
};
let onStarted = () => {
// Once we asked the app to launch, the app isn't necessary completely loaded.
// launch request only ask the app to launch and immediatly returns.
// We have to keep trying to get app tab actors required to create its target.
let deferred = promise.defer();
let loop = (count) => {
// Ensure not looping for ever
if (count >= 100) {
deferred.reject("Unable to connect to the app");
return;
}
// Also, in case the app wasn't installed yet, we also have to keep asking the
// app to launch, as launch request made right after install may race.
this.start(project);
getTargetForApp(
this.connection.client,
this.listTabsResponse.webappsActor,
this._getProjectManifestURL(project)).
then(deferred.resolve,
(err) => {
if (err == "appNotFound")
setTimeout(loop, 500, count + 1);
else
deferred.reject(err);
});
};
loop(0);
return deferred.promise;
};
// First try to open the app
this.start(project)
.then(null, onFailedToStart)
.then(onStarted)
.then((target) =>
top.UI.openAndShowToolboxForTarget(target,
project.manifest.name,
project.icon))
.then(() => {
// And only when the toolbox is opened, release the button
button.disabled = false;
},
(err) => {
button.disabled = false;
let message = err.error ? err.error + ": " + err.message : String(err);
alert(message);
this.connection.log(message);
});
},
reveal: function(location) {
let project = AppProjects.get(location);
if (project.type == "packaged") {
let projectFolder = FileUtils.File(project.location);
projectFolder.reveal();
} else {
// TODO: eventually open hosted apps in firefox
// when permissions are correctly supported by firefox
}
},
selectProject: function(location) {
let projects = AppProjects.store.object.projects;
let idx = 0;
for (; idx < projects.length; idx++) {
if (projects[idx].location == location) {
break;
}
}
let oldButton = document.querySelector(".project-item.selected");
if (oldButton) {
oldButton.classList.remove("selected");
}
if (idx == projects.length) {
// Not found. Empty lense.
let lense = document.querySelector("#lense");
lense.setAttribute("template-for", '{"path":"","childSelector":""}');
this.template._processFor(lense);
return;
}
let button = document.getElementById(location);
button.classList.add("selected");
let template = '{"path":"projects.' + idx + '","childSelector":"#lense-template"}';
let lense = document.querySelector("#lense");
lense.setAttribute("template-for", template);
this.template._processFor(lense);
let project = projects[idx];
this._showManifestEditor(project).then(() => this.emit("project-selected"));
},
_showManifestEditor: function(project) {
if (this.manifestEditor) {
this.manifestEditor.destroy();
}
let editorContainer = document.querySelector("#lense .manifest-editor");
this.manifestEditor = new ManifestEditor(project);
return this.manifestEditor.show(editorContainer);
}
};
// This must be bound immediately, as it might be used via the message listener
// before UI.onload() has been called.
UI._onConnectionStatusChange = UI._onConnectionStatusChange.bind(UI);
EventEmitter.decorate(UI);

View File

@ -1,96 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html [
<!ENTITY % appMgrDTD SYSTEM "chrome://browser/locale/devtools/app-manager.dtd" >
%appMgrDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf8"/>
<title>&projects.title;</title>
<link rel="stylesheet" href="chrome://devtools/skin/themes/app-manager/projects.css" type="text/css"/>
<script type="application/javascript;version=1.8" src="utils.js"></script>
<script type="application/javascript;version=1.8" src="projects.js"></script>
<script type="application/javascript;version=1.8" src="template.js"></script>
<script type="application/javascript;version=1.8" src="manifest-editor.js"></script>
</head>
<body onload="UI.onload()">
<aside id="sidebar">
<div id="project-list" template='{"type":"attribute","path":"projects.length","name":"projects-count"}'>
<div template-loop='{"arrayPath":"projects","childSelector":"#project-item-template"}'></div>
<div id="no-project">&projects.noProjects;</div>
</div>
<div id="new-packaged-project" onclick="UI.addPackaged()" title="&projects.addPackagedTooltip;">&projects.addPackaged;</div>
<div id="new-hosted-project">&projects.addHosted;
<form onsubmit="UI.addHosted(); return false;" id="new-hosted-project-wrapper">
<input value="" id="url-input" type="url" required="true" pattern="(https?|chrome)://.+" placeholder="&projects.hostedManifestPlaceHolder2;" size="50" />
<div onclick="UI.addHosted()" id="new-hosted-project-click" title="&projects.addHostedTooltip;"></div>
<input type="submit" hidden="true"></input>
</form>
</div>
</aside>
<section id="lense"></section>
</body>
<template id="project-item-template">
<div class="project-item" template='{"type":"attribute","path":"location","name":"id"}' onclick="UI.selectProject(this.id)">
<div class="project-item-status" template='{"type":"attribute","path":"validationStatus","name":"status"}'></div>
<img class="project-item-icon" template='{"type":"attribute","path":"icon","name":"src"}' />
<div class="project-item-meta">
<div class="button-remove" onclick="UI.remove(this.dataset.location, event)" template='{"type":"attribute","path":"location","name":"data-location"}' title="&projects.removeAppFromList;"></div>
<strong template='{"type":"textContent","path":"manifest.name"}'></strong>
<span class="project-item-type" template='{"type":"textContent","path":"type"}'></span>
<p class="project-item-description" template='{"type":"textContent","path":"manifest.description"}'></p>
<div template='{"type":"attribute","path":"validationStatus","name":"status"}'>
<div class="project-item-errors"><span template='{"type":"textContent","path":"errorsCount"}'></span></div>
<div class="project-item-warnings"><span template='{"type":"textContent","path":"warningsCount"}'></span></div>
</div>
</div>
</div>
</template>
<template id="lense-template">
<div>
<div class="project-details" template='{"type":"attribute","path":"validationStatus","name":"status"}'>
<div class="project-header">
<img class="project-icon" template='{"type":"attribute","path":"icon","name":"src"}'/>
<div class="project-metadata">
<div class="project-title">
<h1 template='{"type":"textContent","path":"manifest.name"}'></h1>
<div class="project-status" template='{"type":"attribute","path":"validationStatus","name":"status"}'>
<p class="project-validation valid">&projects.valid;</p>
<p class="project-validation warning">&projects.warning;</p>
<p class="project-validation error">&projects.error;</p>
</div>
<div class="project-status" template='{"type":"attribute","path":"type","name":"type"}'>
<p class="project-type hosted">&projects.hosted;</p>
<p class="project-type packaged">&projects.packaged;</p>
</div>
</div>
<span template='{"type":"textContent","path":"manifest.developer.name"}'></span>
<p class="project-location" template='{"type":"textContent","path":"location"}' onclick="UI.reveal(this.textContent)"></p>
<p class="project-description" template='{"type":"textContent","path":"manifest.description"}'></p>
</div>
</div>
<div class="project-buttons" template='{"type":"attribute","path":"type","name":"type"}'>
<button class="project-button-update" onclick="UI.update(this, this.dataset.location)" template='{"type":"attribute","path":"location","name":"data-location"}' title="&projects.updateAppTooltip;">&projects.updateApp;</button>
<button class="device-action project-button-debug" onclick="UI.debug(this, this.dataset.location)" template='{"type":"attribute","path":"location","name":"data-location"}' title="&projects.debugAppTooltip;">&projects.debugApp;</button>
</div>
<div class="project-errors" template='{"type":"textContent","path":"errors"}'></div>
<div class="project-warnings" template='{"type":"textContent","path":"warnings"}'></div>
</div>
<div class="manifest-editor">
<div class="manifest-header" template='{"type":"attribute","path":"type","name":"type"}'>
<h2 class="editable" title="&projects.manifestEditorTooltip;">&projects.manifestEditor;</h2>
<h2 class="viewable" title="&projects.manifestViewerTooltip;">&projects.manifestViewer;</h2>
<button class="editable manifest-button-save" onclick="UI.saveManifest(this, this.dataset.location)" template='{"type":"attribute","path":"location","name":"data-location"}' title="&projects.saveManifestTooltip;">&projects.saveManifest;</button>
</div>
</div>
</div>
</template>
</html>

View File

@ -1,406 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Template mechanism based on Object Emitters.
*
* The data used to expand the templates comes from
* a ObjectEmitter object. The templates are automatically
* updated as the ObjectEmitter is updated (via the "set"
* event). See documentation in observable-object.js.
*
* Templates are used this way:
*
* (See examples in devtools/client/app-manager/content/*.xhtml)
*
* <div template="{JSON Object}">
*
* {
* type: "attribute"
* name: name of the attribute
* path: location of the attribute value in the ObjectEmitter
* }
*
* {
* type: "textContent"
* path: location of the textContent value in the ObjectEmitter
* }
*
* {
* type: "localizedContent"
* paths: array of locations of the value of the arguments of the property
* property: l10n property
* }
*
* <div template-loop="{JSON Object}">
*
* {
* arrayPath: path of the array in the ObjectEmitter to loop from
* childSelector: selector of the element to duplicate in the loop
* }
*
*/
const NOT_FOUND_STRING = "n/a";
/**
* let t = new Template(root, store, l10nResolver);
* t.start();
*
* @param DOMNode root.
* Node from where templates are expanded.
* @param ObjectEmitter store.
* ObjectEmitter object.
* @param function (property, args). l10nResolver
* A function that returns localized content.
*/
function Template(root, store, l10nResolver) {
this._store = store;
this._rootResolver = new Resolver(this._store.object);
this._l10n = l10nResolver;
// Listeners are stored in Maps.
// path => Set(node1, node2, ..., nodeN)
// For example: "foo.bar.4.name" => Set(div1,div2)
this._nodeListeners = new Map();
this._loopListeners = new Map();
this._forListeners = new Map();
this._root = root;
this._doc = this._root.ownerDocument;
this._queuedNodeRegistrations = [];
this._storeChanged = this._storeChanged.bind(this);
this._store.on("set", this._storeChanged);
}
Template.prototype = {
start: function() {
this._processTree(this._root);
this._registerQueuedNodes();
},
destroy: function() {
this._store.off("set", this._storeChanged);
this._root = null;
this._doc = null;
},
_storeChanged: function(event, path, value) {
// The store has changed (a "set" event has been emitted).
// We need to invalidate and rebuild the affected elements.
let strpath = path.join(".");
this._invalidate(strpath);
for (let [registeredPath, set] of this._nodeListeners) {
if (strpath != registeredPath &&
registeredPath.indexOf(strpath) > -1) {
this._invalidate(registeredPath);
}
}
this._registerQueuedNodes();
},
_invalidate: function(path) {
// Loops:
let set = this._loopListeners.get(path);
if (set) {
for (let elt of set) {
this._processLoop(elt);
}
}
// For:
set = this._forListeners.get(path);
if (set) {
for (let elt of set) {
this._processFor(elt);
}
}
// Nodes:
set = this._nodeListeners.get(path);
if (set) {
for (let elt of set) {
this._processNode(elt);
}
}
},
// Delay node registration until the last step of starting / updating the UI.
// This allows us to avoid doing double work in _storeChanged where the first
// call to |_invalidate| registers new nodes, which would then be visited a
// second time when it iterates over node listeners.
_queueNodeRegistration: function(path, element) {
this._queuedNodeRegistrations.push([path, element]);
},
_registerQueuedNodes: function() {
for (let [path, element] of this._queuedNodeRegistrations) {
// We map a node to a path.
// If the value behind this path is updated,
// we get notified from the ObjectEmitter,
// and then we know which objects to update.
if (!this._nodeListeners.has(path)) {
this._nodeListeners.set(path, new Set());
}
let set = this._nodeListeners.get(path);
set.add(element);
}
this._queuedNodeRegistrations.length = 0;
},
_unregisterNodes: function(nodes) {
for (let e of nodes) {
for (let registeredPath of e.registeredPaths) {
let set = this._nodeListeners.get(registeredPath);
if (!set) {
continue;
}
set.delete(e);
if (set.size === 0) {
this._nodeListeners.delete(registeredPath);
}
}
e.registeredPaths = null;
}
},
_registerLoop: function(path, element) {
if (!this._loopListeners.has(path)) {
this._loopListeners.set(path, new Set());
}
let set = this._loopListeners.get(path);
set.add(element);
},
_registerFor: function(path, element) {
if (!this._forListeners.has(path)) {
this._forListeners.set(path, new Set());
}
let set = this._forListeners.get(path);
set.add(element);
},
_processNode: function(element, resolver=this._rootResolver) {
// The actual magic.
// The element has a template attribute.
// The value is supposed to be a JSON string.
// resolver is a helper object that is used to retrieve data
// from the template's data store, give the current path into
// the data store, or descend down another level of the store.
// See the Resolver object below.
let e = element;
let str = e.getAttribute("template");
try {
let json = JSON.parse(str);
// Sanity check
if (!("type" in json)) {
throw new Error("missing property");
}
if (json.rootPath) {
// If node has been generated through a loop, we stored
// previously its rootPath.
resolver = this._rootResolver.descend(json.rootPath);
}
// paths is an array that will store all the paths we needed
// to expand the node. We will then, via
// _registerQueuedNodes, link this element to these paths.
let paths = [];
switch (json.type) {
case "attribute": {
if (!("name" in json) ||
!("path" in json)) {
throw new Error("missing property");
}
e.setAttribute(json.name, resolver.get(json.path, NOT_FOUND_STRING));
paths.push(resolver.rootPathTo(json.path));
break;
}
case "textContent": {
if (!("path" in json)) {
throw new Error("missing property");
}
e.textContent = resolver.get(json.path, NOT_FOUND_STRING);
paths.push(resolver.rootPathTo(json.path));
break;
}
case "localizedContent": {
if (!("property" in json) ||
!("paths" in json)) {
throw new Error("missing property");
}
let params = json.paths.map((p) => {
paths.push(resolver.rootPathTo(p));
let str = resolver.get(p, NOT_FOUND_STRING);
return str;
});
e.textContent = this._l10n(json.property, params);
break;
}
}
if (resolver !== this._rootResolver) {
// We save the rootPath if any.
json.rootPath = resolver.path;
e.setAttribute("template", JSON.stringify(json));
}
if (paths.length > 0) {
for (let path of paths) {
this._queueNodeRegistration(path, e);
}
}
// Store all the paths on the node, to speed up unregistering later
e.registeredPaths = paths;
} catch(exception) {
console.error("Invalid template: " + e.outerHTML + " (" + exception + ")");
}
},
_processLoop: function(element, resolver=this._rootResolver) {
// The element has a template-loop attribute.
// The related path must be an array. We go
// through the array, and build one child per
// item. The template for this child is pointed
// by the childSelector property.
let e = element;
try {
let template, count;
let str = e.getAttribute("template-loop");
let json = JSON.parse(str);
if (!("arrayPath" in json) ||
!("childSelector" in json)) {
throw new Error("missing property");
}
let descendedResolver = resolver.descend(json.arrayPath);
let templateParent = this._doc.querySelector(json.childSelector);
if (!templateParent) {
throw new Error("can't find child");
}
template = this._doc.createElement("div");
template.innerHTML = templateParent.innerHTML;
template = template.firstElementChild;
let array = descendedResolver.get("", []);
if (!Array.isArray(array)) {
console.error("referenced array is not an array");
}
count = array.length;
let fragment = this._doc.createDocumentFragment();
for (let i = 0; i < count; i++) {
let node = template.cloneNode(true);
this._processTree(node, descendedResolver.descend(i));
fragment.appendChild(node);
}
this._registerLoop(descendedResolver.path, e);
this._registerLoop(descendedResolver.rootPathTo("length"), e);
this._unregisterNodes(e.querySelectorAll("[template]"));
e.innerHTML = "";
e.appendChild(fragment);
} catch(exception) {
console.error("Invalid template: " + e.outerHTML + " (" + exception + ")");
}
},
_processFor: function(element, resolver=this._rootResolver) {
let e = element;
try {
let template;
let str = e.getAttribute("template-for");
let json = JSON.parse(str);
if (!("path" in json) ||
!("childSelector" in json)) {
throw new Error("missing property");
}
if (!json.path) {
// Nothing to show.
this._unregisterNodes(e.querySelectorAll("[template]"));
e.innerHTML = "";
return;
}
let descendedResolver = resolver.descend(json.path);
let templateParent = this._doc.querySelector(json.childSelector);
if (!templateParent) {
throw new Error("can't find child");
}
let content = this._doc.createElement("div");
content.innerHTML = templateParent.innerHTML;
content = content.firstElementChild;
this._processTree(content, descendedResolver);
this._unregisterNodes(e.querySelectorAll("[template]"));
this._registerFor(descendedResolver.path, e);
e.innerHTML = "";
e.appendChild(content);
} catch(exception) {
console.error("Invalid template: " + e.outerHTML + " (" + exception + ")");
}
},
_processTree: function(parent, resolver=this._rootResolver) {
let loops = parent.querySelectorAll(":not(template) [template-loop]");
let fors = parent.querySelectorAll(":not(template) [template-for]");
let nodes = parent.querySelectorAll(":not(template) [template]");
for (let i = 0; i < loops.length; i++) {
this._processLoop(loops[i], resolver);
}
for (let i = 0; i < fors.length; i++) {
this._processFor(fors[i], resolver);
}
for (let i = 0; i < nodes.length; i++) {
this._processNode(nodes[i], resolver);
}
if (parent.hasAttribute("template")) {
this._processNode(parent, resolver);
}
},
};
function Resolver(object, path = "") {
this._object = object;
this.path = path;
}
Resolver.prototype = {
get: function(path, defaultValue = null) {
let obj = this._object;
if (path === "") {
return obj;
}
let chunks = path.toString().split(".");
for (let i = 0; i < chunks.length; i++) {
let word = chunks[i];
if ((typeof obj) == "object" &&
(word in obj)) {
obj = obj[word];
} else {
return defaultValue;
}
}
return obj;
},
rootPathTo: function(path) {
return this.path ? this.path + "." + path : path;
},
descend: function(path) {
return new Resolver(this.get(path), this.rootPathTo(path));
}
};

View File

@ -1,69 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
*
* Some helpers for common operations in the App Manager:
*
* . mergeStores: merge several store into one.
* . l10n: resolves strings from app-manager.properties.
*
*/
var Utils = (function() {
const Cu = Components.utils;
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
const EventEmitter = require("devtools/shared/event-emitter");
function _createSetEventForwarder(key, finalStore) {
return function(event, path, value) {
finalStore.emit("set", [key].concat(path), value);
};
}
function mergeStores(stores) {
let finalStore = {object:{}};
EventEmitter.decorate(finalStore);
let setEventForwarders = {};
for (let key in stores) {
let store = stores[key];
finalStore.object[key] = store.object;
setEventForwarders[key] = _createSetEventForwarder(key, finalStore);
store.on("set", setEventForwarders[key]);
}
finalStore.destroy = () => {
for (let key in stores) {
let store = stores[key];
store.off("set", setEventForwarders[key]);
if (store.destroy) {
store.destroy();
}
}
};
return finalStore;
}
let strings = Services.strings.createBundle("chrome://browser/locale/devtools/app-manager.properties");
function l10n (property, args = []) {
if (args && args.length > 0) {
return strings.formatStringFromName(property, args, args.length);
} else {
return strings.GetStringFromName(property);
}
}
return {
mergeStores: mergeStores,
l10n: l10n
}
})();

View File

@ -1,123 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const ObservableObject = require("devtools/client/shared/observable-object");
const {getDeviceFront} = require("devtools/server/actors/device");
const {Connection} = require("devtools/shared/client/connection-manager");
const {Cu} = require("chrome");
const _knownDeviceStores = new WeakMap();
var DeviceStore;
module.exports = DeviceStore = function(connection) {
// If we already know about this connection,
// let's re-use the existing store.
if (_knownDeviceStores.has(connection)) {
return _knownDeviceStores.get(connection);
}
_knownDeviceStores.set(connection, this);
ObservableObject.call(this, {});
this._resetStore();
this.destroy = this.destroy.bind(this);
this._onStatusChanged = this._onStatusChanged.bind(this);
this._connection = connection;
this._connection.once(Connection.Events.DESTROYED, this.destroy);
this._connection.on(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
this._onTabListChanged = this._onTabListChanged.bind(this);
this._onStatusChanged();
return this;
};
DeviceStore.prototype = {
destroy: function() {
if (this._connection) {
// While this.destroy is bound using .once() above, that event may not
// have occurred when the DeviceStore client calls destroy, so we
// manually remove it here.
this._connection.off(Connection.Events.DESTROYED, this.destroy);
this._connection.off(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
_knownDeviceStores.delete(this._connection);
this._connection = null;
}
},
_resetStore: function() {
this.object.description = {};
this.object.permissions = [];
this.object.tabs = [];
},
_onStatusChanged: function() {
if (this._connection.status == Connection.Status.CONNECTED) {
// Watch for changes to remote browser tabs
this._connection.client.addListener("tabListChanged",
this._onTabListChanged);
this._listTabs();
} else {
if (this._connection.client) {
this._connection.client.removeListener("tabListChanged",
this._onTabListChanged);
}
this._resetStore();
}
},
_onTabListChanged: function() {
this._listTabs();
},
_listTabs: function() {
if (!this._connection) {
return;
}
this._connection.client.listTabs((resp) => {
if (resp.error) {
this._connection.disconnect();
return;
}
this._deviceFront = getDeviceFront(this._connection.client, resp);
// Save remote browser's tabs
this.object.tabs = resp.tabs;
this._feedStore();
});
},
_feedStore: function() {
this._getDeviceDescription();
this._getDevicePermissionsTable();
},
_getDeviceDescription: function() {
return this._deviceFront.getDescription()
.then(json => {
json.dpi = Math.ceil(json.dpi);
this.object.description = json;
});
},
_getDevicePermissionsTable: function() {
return this._deviceFront.getRawPermissionsTable()
.then(json => {
let permissionsTable = json.rawPermissionsTable;
let permissionsArray = [];
for (let name in permissionsTable) {
permissionsArray.push({
name: name,
app: permissionsTable[name].app,
trusted: permissionsTable[name].trusted,
privileged: permissionsTable[name].privileged,
certified: permissionsTable[name].certified,
});
}
this.object.permissions = permissionsArray;
});
}
};

View File

@ -4,15 +4,9 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
DevToolsModules(
'app-projects.js',
'app-validator.js',
'builtin-adb-store.js',
'connection-store.js',
'device-store.js',
'simulators-store.js',
'webapps-store.js',
)

View File

@ -1,25 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const {Cu} = require("chrome");
const ObservableObject = require("devtools/client/shared/observable-object");
const {Simulator} = Cu.import("resource://devtools/shared/apps/Simulator.jsm");
var store = new ObservableObject({versions:[]});
function feedStore() {
store.object.versions = Simulator.availableNames().map(name => {
let simulator = Simulator.getByName(name);
return {
version: name,
label: simulator ? name : "Unknown"
}
});
}
Simulator.on("register", feedStore);
Simulator.on("unregister", feedStore);
feedStore();
module.exports = store;

View File

@ -1,11 +0,0 @@
[DEFAULT]
tags = devtools
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
subsuite = devtools
support-files =
head.js
hosted_app.manifest
manifest.webapp
[browser_manifest_editor.js]
skip-if = true # Bug 989169 - Very intermittent, but App Manager about to be removed

View File

@ -1,197 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
const MANIFEST_EDITOR_ENABLED = "devtools.appmanager.manifestEditor.enabled";
var gManifestWindow, gManifestEditor;
function test() {
waitForExplicitFinish();
Task.spawn(function*() {
Services.prefs.setBoolPref(MANIFEST_EDITOR_ENABLED, true);
let tab = yield openAppManager();
yield selectProjectsPanel();
yield addSamplePackagedApp();
yield showSampleProjectDetails();
gManifestWindow = getManifestWindow();
gManifestEditor = getProjectsWindow().UI.manifestEditor;
yield changeManifestValue("name", "the best app");
yield changeManifestValueBad("name", "the worst app");
yield addNewManifestProperty("developer", "foo", "bar");
// add duplicate property in the same parent doesn't create duplicates
yield addNewManifestProperty("developer", "foo", "bar2");
// add propery with same key in other parent is allowed
yield addNewManifestProperty("tester", "foo", "new");
yield addNewManifestPropertyBad("developer", "blob", "bob");
yield removeManifestProperty("developer", "foo");
gManifestWindow = null;
gManifestEditor = null;
yield removeSamplePackagedApp();
yield removeTab(tab);
Services.prefs.setBoolPref(MANIFEST_EDITOR_ENABLED, false);
finish();
});
}
// Wait until the animation from commitHierarchy has completed
function waitForUpdate() {
return waitForTime(gManifestEditor.editor.lazyEmptyDelay + 1);
}
function changeManifestValue(key, value) {
return Task.spawn(function*() {
let propElem = gManifestWindow.document
.querySelector("[id ^= '" + key + "']");
is(propElem.querySelector(".name").value, key,
"Key doesn't match expected value");
let valueElem = propElem.querySelector(".value");
EventUtils.sendMouseEvent({ type: "mousedown" }, valueElem, gManifestWindow);
let valueInput = propElem.querySelector(".element-value-input");
valueInput.value = '"' + value + '"';
EventUtils.sendKey("RETURN", gManifestWindow);
yield waitForUpdate();
// Elements have all been replaced, re-select them
propElem = gManifestWindow.document.querySelector("[id ^= '" + key + "']");
valueElem = propElem.querySelector(".value");
is(valueElem.value, '"' + value + '"',
"Value doesn't match expected value");
is(gManifestEditor.manifest[key], value,
"Manifest doesn't contain expected value");
});
}
function changeManifestValueBad(key, value) {
return Task.spawn(function*() {
let propElem = gManifestWindow.document
.querySelector("[id ^= '" + key + "']");
is(propElem.querySelector(".name").value, key,
"Key doesn't match expected value");
let valueElem = propElem.querySelector(".value");
EventUtils.sendMouseEvent({ type: "mousedown" }, valueElem, gManifestWindow);
let valueInput = propElem.querySelector(".element-value-input");
// Leaving out quotes will result in an error, so no change should be made.
valueInput.value = value;
EventUtils.sendKey("RETURN", gManifestWindow);
yield waitForUpdate();
// Elements have all been replaced, re-select them
propElem = gManifestWindow.document.querySelector("[id ^= '" + key + "']");
valueElem = propElem.querySelector(".value");
isnot(valueElem.value, '"' + value + '"',
"Value was changed, but it should not have been");
isnot(gManifestEditor.manifest[key], value,
"Manifest was changed, but it should not have been");
});
}
function addNewManifestProperty(parent, key, value) {
info("Adding new property - parent: " + parent + "; key: " + key + "; value: " + value + "\n\n");
return Task.spawn(function*() {
let parentElem = gManifestWindow.document
.querySelector("[id ^= '" + parent + "']");
ok(parentElem, "Found parent element: " + parentElem.id);
let addPropertyElem = parentElem.querySelector(".variables-view-add-property");
ok(addPropertyElem, "Found add-property button");
EventUtils.sendMouseEvent({ type: "mousedown" }, addPropertyElem, gManifestWindow);
let nameInput = parentElem.querySelector(".element-name-input");
nameInput.value = key;
EventUtils.sendKey("TAB", gManifestWindow);
let valueInput = parentElem.querySelector(".element-value-input");
valueInput.value = '"' + value + '"';
EventUtils.sendKey("RETURN", gManifestWindow);
yield waitForUpdate();
parentElem = gManifestWindow.document.querySelector("[id ^= '" + parent + "']");
let elems = parentElem.querySelectorAll("[id ^= '" + key + "']");
is(elems.length, 1, "No duplicate property is added");
let newElem = elems[0];
let nameElem = newElem.querySelector(".name");
is(nameElem.value, key, "Key doesn't match expected Key");
ok(key in gManifestEditor.manifest[parent],
"Manifest doesn't contain expected key");
let valueElem = newElem.querySelector(".value");
is(valueElem.value, '"' + value + '"',
"Value doesn't match expected value");
is(gManifestEditor.manifest[parent][key], value,
"Manifest doesn't contain expected value");
});
}
function addNewManifestPropertyBad(parent, key, value) {
return Task.spawn(function*() {
let parentElem = gManifestWindow.document
.querySelector("[id ^= '" + parent + "']");
ok(parentElem,
"Found parent element");
let addPropertyElem = parentElem
.querySelector(".variables-view-add-property");
ok(addPropertyElem,
"Found add-property button");
EventUtils.sendMouseEvent({ type: "mousedown" }, addPropertyElem, gManifestWindow);
let nameInput = parentElem.querySelector(".element-name-input");
nameInput.value = key;
EventUtils.sendKey("TAB", gManifestWindow);
let valueInput = parentElem.querySelector(".element-value-input");
// Leaving out quotes will result in an error, so no change should be made.
valueInput.value = value;
EventUtils.sendKey("RETURN", gManifestWindow);
yield waitForUpdate();
let newElem = gManifestWindow.document.querySelector("[id ^= '" + key + "']");
ok(!newElem, "Key was added, but it should not have been");
ok(!(key in gManifestEditor.manifest[parent]),
"Manifest contains key, but it should not");
});
}
function removeManifestProperty(parent, key) {
info("*** Remove property test ***");
return Task.spawn(function*() {
let parentElem = gManifestWindow.document
.querySelector("[id ^= '" + parent + "']");
ok(parentElem, "Found parent element");
let keyExists = key in gManifestEditor.manifest[parent];
ok(keyExists,
"The manifest contains the key under the expected parent");
let newElem = gManifestWindow.document.querySelector("[id ^= '" + key + "']");
let removePropertyButton = newElem.querySelector(".variables-view-delete");
ok(removePropertyButton, "The remove property button was found");
removePropertyButton.click();
yield waitForUpdate();
ok(!(key in gManifestEditor.manifest[parent]), "Property was successfully removed");
});
}

View File

@ -2,12 +2,6 @@
tags = devtools
skip-if = buildapp == 'b2g'
support-files =
hosted_app.manifest
validator/*
[test_connection_store.html]
[test_device_store.html]
[test_projects_store.html]
[test_remain_connected.html]
[test_template.html]
[test_app_validator.html]

View File

@ -1,175 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var {utils: Cu, classes: Cc, interfaces: Ci} = Components;
const {Promise: promise} =
Cu.import("resource://devtools/shared/deprecated-sync-thenables.js", {});
const {require} =
Cu.import("resource://devtools/shared/Loader.jsm", {});
const {AppProjects} = require("devtools/client/app-manager/app-projects");
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const APP_MANAGER_URL = "about:app-manager";
const TEST_BASE =
"chrome://mochitests/content/browser/devtools/client/app-manager/test/";
const HOSTED_APP_MANIFEST = TEST_BASE + "hosted_app.manifest";
const PACKAGED_APP_DIR_PATH = getTestFilePath(".");
DevToolsUtils.testing = true;
SimpleTest.registerCleanupFunction(() => {
DevToolsUtils.testing = false;
});
function addTab(url, targetWindow = window) {
info("Adding tab: " + url);
let deferred = promise.defer();
let targetBrowser = targetWindow.gBrowser;
targetWindow.focus();
let tab = targetBrowser.selectedTab = targetBrowser.addTab(url);
let linkedBrowser = tab.linkedBrowser;
linkedBrowser.addEventListener("load", function onLoad() {
linkedBrowser.removeEventListener("load", onLoad, true);
info("Tab added and finished loading: " + url);
deferred.resolve(tab);
}, true);
return deferred.promise;
}
function removeTab(tab, targetWindow = window) {
info("Removing tab.");
let deferred = promise.defer();
let targetBrowser = targetWindow.gBrowser;
let tabContainer = targetBrowser.tabContainer;
tabContainer.addEventListener("TabClose", function onClose(aEvent) {
tabContainer.removeEventListener("TabClose", onClose, false);
info("Tab removed and finished closing.");
deferred.resolve();
}, false);
targetBrowser.removeTab(tab);
return deferred.promise;
}
function openAppManager() {
return addTab(APP_MANAGER_URL);
}
function addSampleHostedApp() {
info("Adding sample hosted app");
let projectsWindow = getProjectsWindow();
let projectsDocument = projectsWindow.document;
let url = projectsDocument.querySelector("#url-input");
url.value = HOSTED_APP_MANIFEST;
return projectsWindow.UI.addHosted();
}
function removeSampleHostedApp() {
info("Removing sample hosted app");
return AppProjects.remove(HOSTED_APP_MANIFEST);
}
function addSamplePackagedApp() {
info("Adding sample packaged app");
let appDir = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
appDir.initWithPath(PACKAGED_APP_DIR_PATH);
return getProjectsWindow().UI.addPackaged(appDir);
}
function removeSamplePackagedApp() {
info("Removing sample packaged app");
return AppProjects.remove(PACKAGED_APP_DIR_PATH);
}
function getProjectsWindow() {
return content.document.querySelector(".projects-panel").contentWindow;
}
function getManifestWindow() {
return getProjectsWindow().document.querySelector(".variables-view")
.contentWindow;
}
function waitForProjectsPanel(deferred = promise.defer()) {
info("Wait for projects panel");
let projectsWindow = getProjectsWindow();
let projectsUI = projectsWindow.UI;
if (!projectsUI) {
info("projectsUI false");
projectsWindow.addEventListener("load", function onLoad() {
info("got load event");
projectsWindow.removeEventListener("load", onLoad);
waitForProjectsPanel(deferred);
});
return deferred.promise;
}
if (projectsUI.isReady) {
info("projectsUI ready");
deferred.resolve();
return deferred.promise;
}
info("projectsUI not ready");
projectsUI.once("ready", deferred.resolve);
return deferred.promise;
}
function selectProjectsPanel() {
return Task.spawn(function*() {
let projectsButton = content.document.querySelector(".projects-button");
EventUtils.sendMouseEvent({ type: "click" }, projectsButton, content);
yield waitForProjectsPanel();
});
}
function waitForProjectSelection() {
info("Wait for project selection");
let deferred = promise.defer();
getProjectsWindow().UI.once("project-selected", deferred.resolve);
return deferred.promise;
}
function selectFirstProject() {
return Task.spawn(function*() {
let projectsFrame = content.document.querySelector(".projects-panel");
let projectsWindow = projectsFrame.contentWindow;
let projectsDoc = projectsWindow.document;
let projectItem = projectsDoc.querySelector(".project-item");
EventUtils.sendMouseEvent({ type: "click" }, projectItem, projectsWindow);
yield waitForProjectSelection();
});
}
function showSampleProjectDetails() {
return Task.spawn(function*() {
yield selectProjectsPanel();
yield selectFirstProject();
});
}
function waitForTick() {
let deferred = promise.defer();
executeSoon(deferred.resolve);
return deferred.promise;
}
function waitForTime(aDelay) {
let deferred = promise.defer();
setTimeout(deferred.resolve, aDelay);
return deferred.promise;
}

View File

@ -1,3 +0,0 @@
{
"name": "My hosted app"
}

View File

@ -1,9 +0,0 @@
{
"name": "My packaged app",
"developer": {
"name": "Foo Bar"
},
"tester" : {
"who": "qa"
}
}

View File

@ -1,107 +0,0 @@
<!DOCTYPE html>
<!--
Bug 901519 - [app manager] data store for connections
-->
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
</head>
<body>
<div id="root">
<span id="status" template='{"type":"textContent","path":"status"}'></span>
<span id="host" template='{"type":"textContent","path":"host"}'></span>
<span id="port" template='{"type":"textContent","path":"port"}'></span>
</div>
<script type="application/javascript;version=1.8" src="chrome://devtools/content/app-manager/content/template.js"></script>
<script type="application/javascript;version=1.8">
const Cu = Components.utils;
const {require} = Cu.import("resource://devtools/shared/Loader.jsm");
const {DebuggerServer} = require("devtools/server/main");
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
window.onload = function() {
SimpleTest.waitForExplicitFinish();
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://devtools/client/framework/gDevTools.jsm");
const {ConnectionManager} = require("devtools/shared/client/connection-manager");
const ConnectionStore = require("devtools/client/app-manager/connection-store");
let connection = ConnectionManager.createConnection();
let store = new ConnectionStore(connection);
let root = document.querySelector("#root");
let status = root.querySelector("#status");
let host = root.querySelector("#host");
let port = root.querySelector("#port");
let template = new Template(root, store, () => {});
template.start();
connection.host = "foobar";
connection.port = 42;
is(host.textContent, "foobar", "host updated");
is(port.textContent, "42", "port updated");
let been_through_connecting = false;
let been_through_connected = false;
let been_through_disconnected = false;
is(status.textContent, "disconnected", "status updated (diconnected)");
connection.once("connecting", (e) => {
SimpleTest.executeSoon(() => {
been_through_connecting = true;
is(status.textContent, "connecting", "status updated (connecting)");
})
});
connection.once("connected", (e) => {
SimpleTest.executeSoon(() => {
been_through_connected = true;
is(status.textContent, "connected", "status updated (connected)");
connection.disconnect();
})
});
connection.once("disconnected", (e) => {
SimpleTest.executeSoon(() => {
been_through_disconnected = true;
is(status.textContent, "disconnected", "status updated (disconnected)");
connection.destroy();
finishup();
})
});
function finishup() {
ok(been_through_connecting &&
been_through_connected &&
been_through_disconnected, "All updates happened");
DebuggerServer.destroy();
SimpleTest.finish();
}
connection.host = null; // force pipe
connection.port = null;
connection.connect();
}
</script>
</body>
</html>

View File

@ -1,84 +0,0 @@
<!DOCTYPE html>
<!--
Bug 901520 - [app manager] data store for device
-->
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
</head>
<body>
<script type="application/javascript;version=1.8" src="chrome://devtools/content/app-manager/content/template.js"></script>
<script type="application/javascript;version=1.8">
const Cu = Components.utils;
const {require} = Cu.import("resource://devtools/shared/Loader.jsm");
const {DebuggerServer} = require("devtools/server/main");
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
function compare(o1, o2, msg) {
is(JSON.stringify(o1), JSON.stringify(o2), msg);
}
window.onload = function() {
SimpleTest.waitForExplicitFinish();
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://devtools/client/framework/gDevTools.jsm");
const {ConnectionManager} = require("devtools/shared/client/connection-manager");
const DeviceStore = require("devtools/client/app-manager/device-store");
let {getDeviceFront} = require("devtools/server/actors/device");
let connection = ConnectionManager.createConnection();
let store = new DeviceStore(connection);
connection.once("connected", function() {
store.on("set", function check(event, path, value) {
if (path.join(".") != "description") return;
store.off("set", check);
info("Connected");
connection.client.listTabs((resp) => {
info("List tabs response");
let deviceFront = getDeviceFront(connection.client, resp);
deviceFront.getDescription().then(json => {
info("getDescription response: " + JSON.stringify(json));
json.dpi = Math.ceil(json.dpi);
for (let key in json) {
compare(json[key], store.object.description[key], "description." + key + " is valid");
compare(json[key], value[key], "description." + key + " is valid");
}
connection.disconnect();
}).then(null, (error) => ok(false, "Error:" + error));
});
});
});
connection.once("disconnected", function() {
compare(store.object, {description:{},permissions:[],tabs:[]}, "empty store after disconnect")
connection.destroy();
DebuggerServer.destroy();
SimpleTest.finish();
});
compare(store.object, {description:{},permissions:[],tabs:[]}, "empty store before disconnect")
connection.connect();
}
</script>
</body>
</html>

View File

@ -1,59 +0,0 @@
<!DOCTYPE html>
<!--
Bug 907206 - data store for local apps
-->
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
</head>
<body>
<script type="application/javascript;version=1.8">
const Cu = Components.utils;
window.onload = function() {
SimpleTest.waitForExplicitFinish();
const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
const { AppProjects } = require("devtools/client/app-manager/app-projects");
function testHosted(projects) {
let manifestURL = document.location.href.replace("test_projects_store.html", "hosted_app/webapp.manifest");
AppProjects.addHosted(manifestURL)
.then(function (app) {
is(projects.length, 1,
"Hosted app has been added");
is(projects[0], app);
is(app.type, "hosted", "valid type");
is(app.location, manifestURL, "valid location");
is(AppProjects.get(manifestURL), app,
"get() returns the same app object");
AppProjects.remove(manifestURL)
.then(function () {
is(projects.length, 0,
"Hosted app has been removed");
SimpleTest.finish();
});
});
}
AppProjects.once("ready", function (event, projects) {
is(projects, AppProjects.store.object.projects,
"The ready event data is the store projects list");
testHosted(projects);
});
}
</script>
</body>
</html>

View File

@ -1,121 +0,0 @@
<!DOCTYPE html>
<!--
Bug 912646 - Closing app toolbox causes phone to disconnect
-->
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
</head>
<body>
<script type="application/javascript;version=1.8">
const Cu = Components.utils;
const {require} = Cu.import("resource://devtools/shared/Loader.jsm");
const {DebuggerServer} = require("devtools/server/main");
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
window.onload = function() {
SimpleTest.waitForExplicitFinish();
Cu.import("resource://devtools/client/framework/gDevTools.jsm");
const {TargetFactory} = require("devtools/client/framework/target");
const {Toolbox} = require("devtools/client/framework/toolbox");
const {Connection, ConnectionManager} =
require("devtools/shared/client/connection-manager");
const ConnectionStore =
require("devtools/client/app-manager/connection-store");
let connection = ConnectionManager.createConnection();
connection.host = null; // force pipe
connection.port = null;
let been_through_connecting = false;
let been_through_connected = false;
let been_through_disconnected = false;
is(connection.status, Connection.Status.DISCONNECTED,
"status updated (diconnected)");
connection.once("connecting", () => {
SimpleTest.executeSoon(() => {
been_through_connecting = true;
is(connection.status, Connection.Status.CONNECTING,
"status updated (connecting)");
})
});
connection.once("connected", () => {
SimpleTest.executeSoon(() => {
been_through_connected = true;
is(connection.status, Connection.Status.CONNECTED,
"status updated (connected)");
cycleToolbox();
})
});
function cycleToolbox() {
connection.client.listTabs(response => {
let options = {
form: response.tabs[0],
client: connection.client,
chrome: true
};
TargetFactory.forRemoteTab(options).then(target => {
let hostType = Toolbox.HostType.WINDOW;
gDevTools.showToolbox(target,
null,
hostType).then(toolbox => {
SimpleTest.executeSoon(() => {
toolbox.once("destroyed", onDestroyToolbox);
toolbox.destroy();
});
});
});
});
}
function onDestroyToolbox() {
is(connection.status, Connection.Status.CONNECTED,
"toolbox cycled, still connected");
connection.disconnect();
}
connection.once("disconnected", () => {
SimpleTest.executeSoon(() => {
been_through_disconnected = true;
is(connection.status, Connection.Status.DISCONNECTED,
"status updated (disconnected)");
connection.destroy();
finishUp();
})
});
function finishUp() {
ok(been_through_connecting &&
been_through_connected &&
been_through_disconnected, "All updates happened");
DebuggerServer.destroy();
SimpleTest.finish();
}
connection.connect();
}
</script>
</body>
</html>

View File

@ -1,255 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
</head>
<div id="root">
<span template='{"type":"textContent","path":"title"}'></span>
<span template='{"type":"attribute","name":"title","path":"title"}'></span>
<span template='{"type":"localizedContent","paths":["foo2.foo_l10n","foo2.bar_l10n"],"property":"foo2"}'></span>
<div template-for='{"path":"mop","childSelector":"#template-for"}'></div>
<div template-loop='{"arrayPath":"foo1.bar1","childSelector":"#template-loop"}'></div>
</div>
<div id="ref0">
<span template='{"type":"textContent","path":"title"}'>ttt</span>
<span title="ttt" template='{"type":"attribute","name":"title","path":"title"}'></span>
<span template='{"type":"localizedContent","paths":["foo2.foo_l10n","foo2.bar_l10n"],"property":"foo2"}'>foo2:foo_l10n/bar_l10n</span>
<div template-for='{"path":"mop","childSelector":"#template-for"}'><span template='{"type":"textContent","path":"name","rootPath":"mop"}'>meh</span></div>
<div template-loop='{"arrayPath":"foo1.bar1","childSelector":"#template-loop"}'>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.0"}'>xx0</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.0"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.0"}'>b</span>
</div>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.1"}'>xx1</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.1"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.1"}'>b</span>
</div>
</div>
</div>
<div id="ref1">
<span template='{"type":"textContent","path":"title"}'>xxx</span>
<span title="xxx" template='{"type":"attribute","name":"title","path":"title"}'></span>
<span template='{"type":"localizedContent","paths":["foo2.foo_l10n","foo2.bar_l10n"],"property":"foo2"}'>foo2:foo2_l10n/bar_l10n</span>
<div template-for='{"path":"mop","childSelector":"#template-for"}'><span template='{"type":"textContent","path":"name","rootPath":"mop"}'>meh2</span></div>
<div template-loop='{"arrayPath":"foo1.bar1","childSelector":"#template-loop"}'>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.0"}'>xx0</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.0"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.0"}'>b</span>
</div>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.1"}'>xx1</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.1"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.1"}'>b</span>
</div>
</div>
</div>
<div id="ref2">
<span template='{"type":"textContent","path":"title"}'>xxx</span>
<span title="xxx" template='{"type":"attribute","name":"title","path":"title"}'></span>
<span template='{"type":"localizedContent","paths":["foo2.foo_l10n","foo2.bar_l10n"],"property":"foo2"}'>foo2:yyy/zzz</span>
<div template-for='{"path":"","childSelector":"#template-for"}'></div>
<div template-loop='{"arrayPath":"foo1.bar1","childSelector":"#template-loop"}'>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.0"}'>xx0</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.0"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.0"}'>b</span>
</div>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.1"}'>xx1</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.1"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.1"}'>b</span>
</div>
</div>
</div>
<div id="ref3">
<span template='{"type":"textContent","path":"title"}'>xxx</span>
<span title="xxx" template='{"type":"attribute","name":"title","path":"title"}'></span>
<span template='{"type":"localizedContent","paths":["foo2.foo_l10n","foo2.bar_l10n"],"property":"foo2"}'>foo2:yyy/zzz</span>
<div template-for='{"path":"","childSelector":"#template-for"}'></div>
<div template-loop='{"arrayPath":"foo1.bar1","childSelector":"#template-loop"}'>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.0"}'>xx0</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.0"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.0"}'>b</span>
</div>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.1"}'>xx1</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.1"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.1"}'>b</span>
</div>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.2"}'>xx2</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.2"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.2"}'>b</span>
</div>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.3"}'>xx3</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.3"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.3"}'>b</span>
</div>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.4"}'>xx4</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.4"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.4"}'>b</span>
</div>
</div>
</div>
<div id="ref4">
<span template='{"type":"textContent","path":"title"}'>xxx</span>
<span title="xxx" template='{"type":"attribute","name":"title","path":"title"}'></span>
<span template='{"type":"localizedContent","paths":["foo2.foo_l10n","foo2.bar_l10n"],"property":"foo2"}'>foo2:yyy/zzz</span>
<div template-for='{"path":"","childSelector":"#template-for"}'></div>
<div template-loop='{"arrayPath":"foo1.bar1","childSelector":"#template-loop"}'>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.0"}'>xx0</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.0"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.0"}'>b</span>
</div>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.1"}'>xx1</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.1"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.1"}'>b</span>
</div>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.2"}'>xx2</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.2"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.2"}'>b</span>
</div>
<div>
<span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.3"}'>xx3</span>
<span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.3"}'>a</span>
<span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.3"}'>b</span>
</div>
</div>
</div>
<template id="template-loop">
<div>
<span template='{"type":"textContent","path":"idx"}'></span>
<span template='{"type":"textContent","path":"a"}'></span>
<span template='{"type":"textContent","path":"b"}'></span>
</div>
</template>
<template id="template-for">
<span template='{"type":"textContent","path":"name"}'></span>
</template>
<script type="application/javascript;version=1.8" src="chrome://devtools/content/app-manager/content/template.js"></script>
<script type="application/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
const Cu = Components.utils;
Cu.import("resource://devtools/client/framework/gDevTools.jsm");
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
const ObservableObject = require("devtools/client/shared/observable-object");
let data = {
title: "ttt",
mop: {
name: "meh",
},
foo1: {
bar1: [
{idx: "xx0", a: "a", b: "b"},
{idx: "xx1", a: "a", b: "b"},
],
},
foo2: {
foo_l10n: "foo_l10n",
bar_l10n: "bar_l10n"
},
};
let store = new ObservableObject(data);
let changes = [
{
exec: function() {},
reference: document.querySelector("#ref0")
},
{
exec: function() {
store.object.title = "xxx";
store.object.foo2.foo_l10n = "foo2_l10n";
store.object.mop.name = "meh2";
},
reference: document.querySelector("#ref1")
},
{
exec: function() {
store.object.foo2 = {
foo_l10n: "yyy",
bar_l10n: "zzz",
}
let forElt = document.querySelector("#root > [template-for]");
forElt.setAttribute("template-for", '{"path":"","childSelector":"#template-for"}');
t._processFor(forElt);
},
reference: document.querySelector("#ref2")
},
{
exec: function() {
let items = [];
for (let i = 2; i < 5; i++) {
items.push({idx: "xx" + i, a: "a", b: "b"});
}
store.object.foo1.bar1 = store.object.foo1.bar1.concat(items);
},
reference: document.querySelector("#ref3")
},
{
exec: function() {
store.object.foo1.bar1.pop();
},
reference: document.querySelector("#ref4")
},
];
function compare(node1, node2) {
let text1 = node1.innerHTML;
let text2 = node2.innerHTML;
text1 = text1.replace(/\n/g,"");
text2 = text2.replace(/\n/g,"");
text1 = text1.replace(/\s+/g,"");
text2 = text2.replace(/\s+/g,"");
return text1 == text2;
}
let root = document.querySelector("#root");
let t = new Template(root, store, (prop, args) => {
return prop + ":" + args.join("/");
});
t.start();
for (let i = 0; i < changes.length; i++) {
let change = changes[i];
change.exec();
ok(compare(change.reference, root), "Content " + i + " looks good.");
}
SimpleTest.finish();
</script>
</html>

View File

@ -1,283 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const ObservableObject = require("devtools/client/shared/observable-object");
const promise = require("devtools/shared/deprecated-sync-thenables");
const {Connection} = require("devtools/shared/client/connection-manager");
const {Cu} = require("chrome");
const _knownWebappsStores = new WeakMap();
var WebappsStore;
module.exports = WebappsStore = function(connection) {
// If we already know about this connection,
// let's re-use the existing store.
if (_knownWebappsStores.has(connection)) {
return _knownWebappsStores.get(connection);
}
_knownWebappsStores.set(connection, this);
ObservableObject.call(this, {});
this._resetStore();
this.destroy = this.destroy.bind(this);
this._onStatusChanged = this._onStatusChanged.bind(this);
this._connection = connection;
this._connection.once(Connection.Events.DESTROYED, this.destroy);
this._connection.on(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
this._onStatusChanged();
return this;
}
WebappsStore.prototype = {
destroy: function() {
if (this._connection) {
// While this.destroy is bound using .once() above, that event may not
// have occurred when the WebappsStore client calls destroy, so we
// manually remove it here.
this._connection.off(Connection.Events.DESTROYED, this.destroy);
this._connection.off(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
_knownWebappsStores.delete(this._connection);
this._connection = null;
}
},
_resetStore: function() {
this.object.all = []; // list of app objects
this.object.running = []; // list of manifests
},
_getAppFromManifest: function(manifest) {
for (let app of this.object.all) {
if (app.manifestURL == manifest) {
return app;
}
}
return null;
},
_onStatusChanged: function() {
if (this._connection.status == Connection.Status.CONNECTED) {
this._listTabs();
} else {
this._resetStore();
}
},
_listTabs: function() {
this._connection.client.listTabs((resp) => {
this._webAppsActor = resp.webappsActor;
this._feedStore().then(() => {
this.emit("store-ready");
});
});
},
_feedStore: function() {
if (!this._webAppsActor) {
return promise.resolve();
}
this._listenToApps();
return this._getAllApps()
.then(this._getRunningApps.bind(this))
.then(this._getAppsIcons.bind(this));
},
_listenToApps: function() {
let deferred = promise.defer();
let client = this._connection.client;
let request = {
to: this._webAppsActor,
type: "watchApps"
};
client.request(request, (res) => {
if (res.error) {
return deferred.reject(res.error);
}
client.addListener("appOpen", (type, { manifestURL }) => {
this._onAppOpen(manifestURL);
});
client.addListener("appClose", (type, { manifestURL }) => {
this._onAppClose(manifestURL);
});
client.addListener("appInstall", (type, { manifestURL }) => {
this._onAppInstall(manifestURL);
});
client.addListener("appUninstall", (type, { manifestURL }) => {
this._onAppUninstall(manifestURL);
});
return deferred.resolve();
})
return deferred.promise;
},
_getAllApps: function() {
let deferred = promise.defer();
let request = {
to: this._webAppsActor,
type: "getAll"
};
this._connection.client.request(request, (res) => {
if (res.error) {
return deferred.reject(res.error);
}
let apps = res.apps;
for (let a of apps) {
a.running = false;
}
this.object.all = apps;
return deferred.resolve();
});
return deferred.promise;
},
_getRunningApps: function() {
let deferred = promise.defer();
let request = {
to: this._webAppsActor,
type: "listRunningApps"
};
this._connection.client.request(request, (res) => {
if (res.error) {
return deferred.reject(res.error);
}
let manifests = res.apps;
this.object.running = manifests;
for (let m of manifests) {
let a = this._getAppFromManifest(m);
if (a) {
a.running = true;
} else {
return deferred.reject("Unexpected manifest: " + m);
}
}
return deferred.resolve();
});
return deferred.promise;
},
_getAppsIcons: function() {
let deferred = promise.defer();
let allApps = this.object.all;
let request = {
to: this._webAppsActor,
type: "getIconAsDataURL"
};
let client = this._connection.client;
let idx = 0;
(function getIcon() {
if (idx == allApps.length) {
return deferred.resolve();
}
let a = allApps[idx++];
request.manifestURL = a.manifestURL;
return client.request(request, (res) => {
if (res.error) {
Cu.reportError(res.message || res.error);
}
if (res.url) {
a.iconURL = res.url;
}
getIcon();
});
})();
return deferred.promise;
},
_onAppOpen: function(manifest) {
let a = this._getAppFromManifest(manifest);
a.running = true;
let running = this.object.running;
if (running.indexOf(manifest) < 0) {
this.object.running.push(manifest);
}
},
_onAppClose: function(manifest) {
let a = this._getAppFromManifest(manifest);
a.running = false;
let running = this.object.running;
this.object.running = running.filter((m) => {
return m != manifest;
});
},
_onAppInstall: function(manifest) {
let client = this._connection.client;
let request = {
to: this._webAppsActor,
type: "getApp",
manifestURL: manifest
};
client.request(request, (res) => {
if (res.error) {
if (res.error == "forbidden") {
// We got a notification for an app we don't have access to.
// Ignore.
return;
}
Cu.reportError(res.message || res.error);
return;
}
let app = res.app;
app.running = false;
let notFound = true;
let proxifiedApp;
for (let i = 0; i < this.object.all.length; i++) {
let storedApp = this.object.all[i];
if (storedApp.manifestURL == app.manifestURL) {
this.object.all[i] = app;
proxifiedApp = this.object.all[i];
notFound = false;
break;
}
}
if (notFound) {
this.object.all.push(app);
proxifiedApp = this.object.all[this.object.all.length - 1];
}
request.type = "getIconAsDataURL";
client.request(request, (res) => {
if (res.url) {
proxifiedApp.iconURL = res.url;
}
});
// This app may have been running while being installed, so check the list
// of running apps again to get the right answer.
this._getRunningApps();
});
},
_onAppUninstall: function(manifest) {
this.object.all = this.object.all.filter((app) => {
return (app.manifestURL != manifest);
});
},
}

View File

@ -600,10 +600,6 @@ var gDevToolsBrowser = {
gDevToolsBrowser.uninstallWebIDEWidget();
}
// Enable App Manager?
let appMgrEnabled = Services.prefs.getBoolPref("devtools.appmanager.enabled");
toggleCmd("Tools:DevAppMgr", !webIDEEnabled && appMgrEnabled);
// Enable Browser Toolbox?
let chromeEnabled = Services.prefs.getBoolPref("devtools.chrome.enabled");
let devtoolsRemoteEnabled = Services.prefs.getBoolPref("devtools.debugger.remote-enabled");
@ -686,13 +682,6 @@ var gDevToolsBrowser = {
gBrowser.selectedTab = gBrowser.addTab("chrome://devtools/content/framework/connect/connect.xhtml");
},
/**
* Open the App Manager
*/
openAppManager: function(gBrowser) {
gBrowser.selectedTab = gBrowser.addTab("about:app-manager");
},
/**
* Open WebIDE
*/

View File

@ -133,18 +133,6 @@ devtools.jar:
content/framework/connect/connect.xhtml (framework/connect/connect.xhtml)
content/framework/connect/connect.css (framework/connect/connect.css)
content/framework/connect/connect.js (framework/connect/connect.js)
content/app-manager/content/template.js (app-manager/content/template.js)
content/app-manager/content/utils.js (app-manager/content/utils.js)
content/app-manager/content/connection-footer.js (app-manager/content/connection-footer.js)
content/app-manager/content/connection-footer.xhtml (app-manager/content/connection-footer.xhtml)
content/app-manager/content/device.js (app-manager/content/device.js)
content/app-manager/content/device.xhtml (app-manager/content/device.xhtml)
content/app-manager/content/projects.js (app-manager/content/projects.js)
content/app-manager/content/projects.xhtml (app-manager/content/projects.xhtml)
content/app-manager/content/index.xul (app-manager/content/index.xul)
content/app-manager/content/index.js (app-manager/content/index.js)
content/app-manager/content/help.xhtml (app-manager/content/help.xhtml)
content/app-manager/content/manifest-editor.js (app-manager/content/manifest-editor.js)
content/shared/widgets/graphs-frame.xhtml (shared/widgets/graphs-frame.xhtml)
content/shared/widgets/spectrum-frame.xhtml (shared/widgets/spectrum-frame.xhtml)
content/shared/widgets/spectrum.css (shared/widgets/spectrum.css)
@ -332,17 +320,6 @@ devtools.jar:
skin/themes/images/arrow-e.png (themes/images/arrow-e.png)
skin/themes/images/arrow-e@2x.png (themes/images/arrow-e@2x.png)
skin/themes/projecteditor/projecteditor.css (themes/projecteditor/projecteditor.css)
skin/themes/app-manager/connection-footer.css (themes/app-manager/connection-footer.css)
skin/themes/app-manager/index.css (themes/app-manager/index.css)
skin/themes/app-manager/device.css (themes/app-manager/device.css)
skin/themes/app-manager/projects.css (themes/app-manager/projects.css)
skin/themes/app-manager/help.css (themes/app-manager/help.css)
skin/themes/app-manager/images/warning.svg (themes/app-manager/images/warning.svg)
skin/themes/app-manager/images/error.svg (themes/app-manager/images/error.svg)
skin/themes/app-manager/images/plus.svg (themes/app-manager/images/plus.svg)
skin/themes/app-manager/images/remove.svg (themes/app-manager/images/remove.svg)
skin/themes/app-manager/images/add.svg (themes/app-manager/images/add.svg)
skin/themes/app-manager/images/index-icons.svg (themes/app-manager/images/index-icons.svg)
skin/themes/app-manager/images/rocket.svg (themes/app-manager/images/rocket.svg)
skin/themes/app-manager/images/noise.png (themes/app-manager/images/noise.png)
skin/themes/app-manager/images/default-app-icon.png (themes/app-manager/images/default-app-icon.png)

View File

@ -1,224 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/************** LAYOUT **************/
#connection-footer {
display: flex;
flex-direction: column;
height: 50px;
}
#banners-and-logs {
display: flex;
flex-grow: 1;
max-height: 100%;
}
#logs {
display: flex;
width: 40%;
padding: 0;
width: 100%;
}
.banner {
display: none;
width: 60%;
}
#connection-footer[status="connected"] #banner-connected,
#connection-footer[status="connecting"] #banner-connecting,
#connection-footer[status="disconnected"] #banner-disconnected,
#connection-footer[status="disconnecting"] #banner-disconnecting {
display: flex;
}
body.show-simulators .banner,
body.edit-connection .banner {
display: none !important;
}
body.show-simulators #banner-simulators,
body.edit-connection #banner-editing {
display: flex !important;
}
#banner-logs {
width: 40%;
display: flex;
}
#logs > pre {
overflow: auto;
white-space: pre-line;
}
#status.banner-box {
width: 100% !important;
}
.banner-box {
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;
}
#banner-connected > .banner-box {
align-items: flex-start;
}
#start-simulator-box {
display: inline;
}
/************** PIXELS **************/
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 0.9rem;
}
body {
color: #333;
background-color: white;
font-family: Lucida Grande, Helvetica, Helvetica Neue, sans-serif;
}
button {
background: linear-gradient(to bottom, #49535C, #394148);
box-shadow: 0px 1px 1px #3C444D, inset 0 1px 0px rgba(255,255,255,0.1);
color: #9FA6AD;
text-shadow: 0px 1px 1px rgba(0,0,0,0.6);
border: 1px solid #111;
cursor: pointer;
border-radius: 3px;
padding: 3px 10px;
}
button.left {
margin-right: 0px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
button.right {
margin-left: -6px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
button.action-primary {
background: linear-gradient(to bottom, #276DA3, #1E5580);
color: #EEE;
}
button.action-cancel {
background: linear-gradient(to bottom, #B32B02, #942300);
color: #EEE;
}
#banners-and-logs {
border-top: #111 solid;
border-width: 1px 0;
background: linear-gradient(to bottom, #323A42, #29313A);
color: #A8BABF;
box-shadow: inset 0 0 1px #424A51;
}
#status {
background: linear-gradient(to bottom, #454F59, #404952);
box-shadow: inset 0 0 1px #606D78, inset 0 1px 0 #5E6973;
}
#logs > pre {
border: 1px solid #111;
box-shadow: 0px 1px 1px #49525A, inset 0 0 5px rgba(0,0,0,0.3);
font-size: 10px;
background: #22272D;
padding: 5px;
height: 100%;
padding-left: 20px;
position: relative;
}
#logs > pre span{
text-shadow: 0 1px 2px #000;
color: #3195FB;
position: fixed;
right: calc(30% - 15px);
bottom: -1px;
}
#logs > pre b {
font-size: 10px;
color: #70C4FF;
}
.banner-box {
box-shadow: inset 0 0 1px #667480, inset 0 1px 0 #5E6973;
border-right: 1px solid #111;
background-position: center right;
background-size: 1px 100%;
background-repeat: no-repeat;
padding: 10px 20px;
position: relative;
}
.connected-status {
color: #B3BFC9;
text-shadow: 0px 1px 2px rgba(0,0,0,0.9);
padding-bottom: 10px;
}
.connected-status {
font-size: 150%;
top: 10%;
padding-right: 3px;
position: relative;
}
.connected-indicator {
box-shadow: inset 0 1px 0 rgba(255,255,255,0.3), inset 0 0px 1px rgba(255,255,255,0.3);
height: 100%;
flex: 0 0 10px;
}
#banner-connected .connected-indicator,
#banner-connecting .connected-indicator {
background: linear-gradient(to bottom, #69B8FF, #339FFF );
}
#banner-simulators .connected-indicator,
#banner-disconnected .connected-indicator,
#banner-editing .connected-indicator,
#banner-disconnecting .connected-indicator {
background: linear-gradient(to bottom, #375A87, #1C4375 );
}
#banner-simulators .banner-content > * {
display: inline-block;
}
#banner-simulators[simulator-count="0"] .found-simulator,
#banner-simulators:not([simulator-count="0"]) .no-simulator {
display: none;
}
#connection-no-device,
[device-count="0"] > #connection-found-device,
#connection-manual,
#connection-assisted {
display: none;
}
#connection-found-device,
[device-count="0"] > #connection-no-device,
[adb-available="true"] > #connection-assisted,
[adb-available="false"] > #connection-manual {
display: inline;
}

View File

@ -1,410 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/***************** GENERAL *****************/
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
}
body {
font-size: 0.9rem;
color: #333;
background-color: rgb(225, 225, 225);
font-family: Lucida Grande, Helvetica, Helvetica Neue, sans-serif;
display: flex;
flex-direction: column;
}
template {
display: none;
}
h1 {
font-size: 20px;
}
#content {
display: flex;
flex-direction: row;
height: 100%;
overflow: hidden;
}
#detail {
background-image: url('images/noise.png');
display: flex;
flex-grow: 1;
z-index: 1;
overflow: hidden;
}
#meta {
background-size: 100%;
padding-top: 50px;
}
#connection-footer {
border-width: 0;
height: 50px;
min-height: 50px;
}
#root-actor-debug {
background: white;
}
/***************** APP BUTTONS *****************/
.app-buttons {
display: block;
margin-left: 20px;
color: #BBB;
}
button {
margin: 0;
font-size: 11px;
border: 1px solid #CCC;
padding: 5px 15px;
cursor: pointer;
background: rgba(255,255,255,0.4);
text-transform: uppercase;
border-radius: 3px;
border-width: 1px;
}
.app-buttons > button {
display: none;
}
.app-buttons > button[disabled] {
background-color: transparent;
opacity: 0.4;
pointer-events: none;
}
.app[running="false"] > .app-buttons > .button-start,
.app[running="true"] > .app-buttons > .button-stop,
.app[running="true"] > .app-buttons > .button-debug {
display: inline-block;
}
.button-debug {
color: #3498DB;
}
.button-debug:hover {
background-color: #3498DB;
color: #FFF;
}
.button-debug[disabled] {
color: #3498DB;
}
.button-start {
color: #18BC9C
}
.button-start:hover {
background-color: #18BC9C;
color: #FFF;
}
.button-start[disabled] {
color: #18BC9C
}
.button-stop {
color: #E74C3C;
}
.button-stop:hover {
background-color: #E74C3C;
color: #FFF;
}
.button-stop[disabled] {
color: #E74C3C;
}
/***************** PERMISSIONS *****************/
.permission-table {
display: flex;
flex-direction: column;
height: 100%;
}
.permission-table-body {
overflow: auto;
display: flex;
flex-grow: 1;
flex-direction: column;
}
.permission-table-header,
.permission-table-footer {
display: flex;
background: #FFF;
border-top: 1px solid #CCC;
z-index: 2;
flex-shrink: 0;
}
.permission-table-header > div,
.permission-table-footer > div {
z-index: 2;
flex-grow: 1;
background: linear-gradient(to bottom, #49535C, #394148);
box-shadow: 0px 1px 3px rgba(12, 20, 30, 0.5), inset 0 1px 0px rgba(255,255,255,0.1);
color: #9FA6AD;
text-shadow: 0px 1px 1px rgba(0,0,0,0.6);
border: 0;
margin: auto 0;
padding: 5px;
text-align: center;
background: transparent;
box-shadow: none;
text-shadow: none;
}
.permission-table-header > div {
flex-basis: 20%;
}
.permission-table-header > div:first-child {
text-align: start;
padding-left: 10px;
flex-basis: 30%;
}
.permission-table-header {
border: 0;
border-bottom: 1px solid #CCC;
box-shadow: 0 1px 4px rgba(0,0,0,0.3);
}
.permission-table-footer {
box-shadow: 0 -1px 4px rgba(0,0,0,0.3);
}
.permission {
display: flex;
flex-grow: 1;
}
.permission:nth-child(odd) {
background: #E4E4E4;
}
.permission:hover {
background: #EEE;
}
.permission > div {
flex-grow: 1;
flex-basis: 20%;
text-align: center;
padding: 3px;
border-right: 1px solid #CCC;
border-bottom: 1px solid #CCC;
}
.permission > div:first-child {
text-align: start;
padding: 3px 10px;
flex-basis: 30%;
font-weight: bold;
}
.permission > div[permission="1"]:before, .allow-label:after {
color: #98CF39;
content: ' \2713';
}
.permission > div[permission="2"]:before, .deny-label:after {
color: #CC4908;
content: ' \2715';
}
.permission > div[permission="3"]:before, .prompt-label:after {
color: #009EED;
content: ' !';
}
/***************** SIDEBAR *****************/
#sidebar {
background: #EEE;
position: relative;
box-shadow: 0 1px 6px rgba(0,0,0,0.3);
display: flex;
flex-direction: column;
flex: 0 0 350px;
overflow: hidden;
z-index: 100;
}
.sidebar-item {
background-color: #F6F6F6;
box-shadow: inset 0 -1px 0 rgba(0,0,0,0.1);
color: #666;
line-height: 120%;
cursor: pointer;
display: flex;
padding: 15px 10px;
display: block;
text-align: start;
flex-grow: 1;
}
.sidebar-item > * {
flex-shrink: 0;
}
.sidebar-item:hover {
background-color: #EEE;
}
.sidebar-item.selected {
background-color: #46AFE3;
color: #FFF;
}
.help {
float: right;
padding: 0 5px;
}
/***************** HEADER *****************/
header {
padding-top: 140px;
background-image: linear-gradient(to bottom, transparent, rgba(0,0,0,0.7));
color: #FFF;
text-shadow: 0 1px 2px rgba(0,0,0,0.8);
padding: 10px;
}
/***************** APPS & BROWSER TABS *****************/
.apps, .browser-tabs {
display: flex;
flex-direction: column;
overflow: auto;
}
.browser-tabs.hidden {
display: none;
}
.app, .browser-tab {
display: flex;
align-items: center;
order: 1;
}
.app-name, .browser-tab-details {
flex-grow: 1;
font-weight: bold;
}
.app, .browser-tab {
padding: 10px 20px;
border-bottom: 1px solid #CCC;
}
.app:hover, .browser-tab:hover {
background-color: #EFEFEF;
}
.app-icon {
width: 32px;
height: 32px;
margin-right: 10px;
}
.browser-tab-url-subheading {
font-size: 10px;
}
/***************** NOT CONNECTED *****************/
body:not(.notconnected) > #notConnectedMessage,
body.notconnected > #content {
display: none;
}
#notConnectedMessage {
flex-grow: 1;
flex-direction: column;
margin: 50px auto;
}
#notConnectedMessage > span {
padding: 20px;
border: 1px solid #CCC;
border-radius: 5px;
}
#notConnectedMessage > span:before {
content: '';
background: url('images/error.svg') no-repeat;
background-size: 18px;
height: 24px;
width: 24px;
position: relative;
top: 10px;
display: inline-block;
}
/***************** TABS *****************/
#tabs {
flex-grow: 1;
overflow: auto;
}
.tabpanel:not(.selected) {
display: none;
}
#tabs-headers {
flex-shrink: 0;
display: flex;
flex-direction: column;
}

View File

@ -1,40 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
html, body {
margin: 0;
height: 100%;
}
body {
color: #555;
font-family: Lucida Grande, Helvetica, Helvetica Neue, sans-serif;
overflow: hidden;
max-width: 600px;
margin: auto;
padding: 20px 0;
background-color: #FFF;
}
button {
border: 1px solid #CCC;
padding: 5px 15px;
cursor: pointer;
background: rgba(255,255,255,0.4);
text-transform: uppercase;
color: #3498DB;
}
button:hover {
background-color: #3498DB;
color: #FFF;
}
a, a:visited {
color: rgb(39,109,163);
}
#close-button {
float: right;
}

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="64px" height="64px" viewBox="0 0 64 64">
<path fill="#00b2f7" d="M32.336,3.894c-15.74,0-28.5,12.76-28.5,28.5s12.76,28.5,28.5,28.5s28.5-12.76,28.5-28.5 S48.076,3.894,32.336,3.894z M44.86,36.966h-7.823v7.62c0,2.582-2.12,4.702-4.702,4.702c-2.584,0-4.704-2.12-4.704-4.702v-7.62 h-7.817c-2.52,0-4.572-2.056-4.572-4.572s2.053-4.572,4.572-4.572h7.817v-7.62c0-2.582,2.12-4.702,4.704-4.702 c2.582,0,4.702,2.12,4.702,4.702v7.62h7.823c2.514,0,4.57,2.056,4.57,4.572S47.374,36.966,44.86,36.966z"/>
</svg>

Before

Width:  |  Height:  |  Size: 792 B

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="64px" height="64px" viewBox="0 0 64 64">
<path fill="#e25026" d="M32,4.894c-15.74,0-28.5,12.76-28.5,28.5s12.76,28.5,28.5,28.5s28.5-12.76,28.5-28.5S47.74,4.894,32,4.894 z M46.903,48.674c-1.817,1.817-4.691,1.76-6.449,0.002l-8.327-8.327l-8.151,8.151c-1.877,1.877-4.87,1.814-6.685,0 c-1.877-1.877-1.879-4.811-0.002-6.687l8.151-8.151l-8.327-8.327c-1.76-1.76-1.817-4.634,0-6.451c1.76-1.76,4.691-1.76,6.451,0 l8.327,8.327l8.151-8.151c1.877-1.877,4.811-1.874,6.687,0.002c1.814,1.814,1.877,4.808,0,6.685l-8.151,8.151l8.327,8.327 C48.662,43.982,48.662,46.914,46.903,48.674z"/>
</svg>

Before

Width:  |  Height:  |  Size: 874 B

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="160px" height="240px" viewBox="0 0 160 240">
<path fill="#414042" d="M40,21.149c-2.044,0.001-6.042,6.745-7.404,13.436L28,39.181v12l3.204,0l4.467-4.466 c0.457,0.478,0.96,0.88,1.5,1.199h5.652c0.543-0.318,1.05-0.719,1.507-1.199l4.466,4.466l3.204,0v-12l-4.597-4.596 C46.042,27.895,42.044,21.149,40,21.149z M40.005,28.185c0.712,0,1.965,2,2.746,4.392c-0.846-0.157-1.747-0.244-2.686-0.244 c-0.987,0-1.933,0.099-2.815,0.271C38.03,30.199,39.289,28.185,40.005,28.185z"/>
<path fill="#414042" d="M41.436,50.98c0,1.41-1.094,2.553-1.459,2.553c-0.364,0-1.459-1.144-1.459-2.553 c0-0.546,0.099-1.051,0.266-1.466h-1.69c-0.198,0.731-0.31,1.549-0.31,2.412c0,3.108,2.411,5.627,3.215,5.627 s3.216-2.519,3.215-5.626c0-0.864-0.112-1.681-0.31-2.413l-1.734,0C41.337,49.929,41.436,50.434,41.436,50.98z"/>
<path fill="#b2b5b9" d="M40,21.149c-2.044,0.001-6.042,6.745-7.404,13.436L28,39.181v12l3.204,0l4.467-4.466 c0.457,0.478,0.96,0.88,1.5,1.199h5.652c0.543-0.318,1.05-0.719,1.507-1.199l4.466,4.466l3.204,0v-12l-4.597-4.596 C46.042,27.895,42.044,21.149,40,21.149z M40.005,28.185c0.712,0,1.965,2,2.746,4.392c-0.846-0.157-1.747-0.244-2.686-0.244 c-0.987,0-1.933,0.099-2.815,0.271C38.03,30.199,39.289,28.185,40.005,28.185z"/>
<path fill="#b2b5b9" d="M41.436,50.98c0,1.41-1.094,2.553-1.459,2.553c-0.364,0-1.459-1.144-1.459-2.553 c0-0.546,0.099-1.051,0.266-1.466h-1.69c-0.198,0.731-0.31,1.549-0.31,2.412c0,3.108,2.411,5.627,3.215,5.627 s3.216-2.519,3.215-5.626c0-0.864-0.112-1.681-0.31-2.413l-1.734,0C41.337,49.929,41.436,50.434,41.436,50.98z"/>
<path fill="#dce8f3" d="M120,21.149c-2.044,0.001-6.042,6.745-7.404,13.436L108,39.181v12l3.204,0l4.467-4.466 c0.457,0.478,0.96,0.88,1.5,1.199h5.652c0.543-0.318,1.05-0.719,1.507-1.199l4.467,4.466l3.204,0v-12l-4.597-4.596 C126.042,27.895,122.044,21.149,120,21.149z M120.005,28.185c0.712,0,1.965,2,2.746,4.392c-0.846-0.157-1.747-0.244-2.686-0.244 c-0.987,0-1.933,0.099-2.815,0.271C118.03,30.199,119.289,28.185,120.005,28.185z"/>
<path fill="#dce8f3" d="M121.436,50.98c0,1.41-1.094,2.553-1.459,2.553c-0.364,0-1.459-1.144-1.459-2.553 c0-0.546,0.099-1.051,0.266-1.466h-1.69c-0.198,0.731-0.31,1.549-0.31,2.412c0,3.108,2.411,5.627,3.215,5.627 s3.216-2.519,3.215-5.626c0-0.864-0.112-1.681-0.31-2.413l-1.734,0C121.337,49.929,121.436,50.434,121.436,50.98z"/>
<path fill="#b2b5b9" d="M52.5,136.017c0,2.279-1.888,4.167-4.167,4.167H31.667c-2.279,0-4.167-1.888-4.167-4.167v-33.333 c0-2.279,1.888-4.167,4.167-4.167h16.667c2.279,0,4.167,1.888,4.167,4.167V136.017z M49.375,107.892 c0-0.554-0.488-1.042-1.042-1.042H31.667c-0.553,0-1.042,0.488-1.042,1.042v22.917c0,0.554,0.488,1.042,1.042,1.042h16.667 c0.553,0,1.042-0.488,1.042-1.042V107.892z M42.604,102.684h-5.208c-0.293,0-0.521,0.228-0.521,0.521 c0,0.293,0.228,0.521,0.521,0.521h5.208c0.293,0,0.521-0.228,0.521-0.521C43.125,102.912,42.897,102.684,42.604,102.684z M40,133.413c-1.432,0-2.604,1.171-2.604,2.604c0,1.433,1.172,2.604,2.604,2.604s2.604-1.171,2.604-2.604 C42.604,134.585,41.432,133.413,40,133.413z"/>
<path fill="#dce8f3" d="M132.5,136.017c0,2.279-1.888,4.167-4.167,4.167h-16.667c-2.279,0-4.167-1.888-4.167-4.167v-33.333 c0-2.279,1.888-4.167,4.167-4.167h16.667c2.279,0,4.167,1.888,4.167,4.167V136.017z M129.375,107.892 c0-0.554-0.488-1.042-1.042-1.042h-16.667c-0.553,0-1.042,0.488-1.042,1.042v22.917c0,0.554,0.488,1.042,1.042,1.042h16.667 c0.553,0,1.042-0.488,1.042-1.042V107.892z M122.604,102.684h-5.208c-0.293,0-0.521,0.228-0.521,0.521 c0,0.293,0.228,0.521,0.521,0.521h5.208c0.293,0,0.521-0.228,0.521-0.521C123.125,102.912,122.897,102.684,122.604,102.684z M120,133.413c-1.432,0-2.604,1.171-2.604,2.604c0,1.433,1.172,2.604,2.604,2.604s2.604-1.171,2.604-2.604 C122.604,134.585,121.432,133.413,120,133.413z"/>
<path fill="#b2b5b9" d="M40,185.388c8.121,0,14.729,6.607,14.729,14.729S48.121,214.845,40,214.845s-14.729-6.607-14.729-14.729 S31.879,185.388,40,185.388 M40,182.75c-9.591,0-17.367,7.775-17.367,17.367c0,9.591,7.775,17.367,17.367,17.367 s17.367-7.775,17.367-17.367C57.367,190.525,49.591,182.75,40,182.75L40,182.75z"/>
<path fill="#b2b5b9" d="M39.565,204.504c-0.688,0-1.196-0.508-1.286-1.195l-0.299-2.57c-0.12-0.808,0.359-1.405,1.166-1.495 c2.81-0.269,4.364-1.345,4.364-3.229v-0.06c0-1.674-1.285-2.84-3.438-2.84c-1.584,0-2.87,0.568-4.065,1.645 c-0.299,0.239-0.688,0.418-1.106,0.418c-0.926,0-1.674-0.747-1.674-1.644c0-0.448,0.18-0.927,0.598-1.285 c1.584-1.495,3.587-2.481,6.337-2.481c4.185,0,7.024,2.331,7.024,6.068v0.06c0,3.767-2.72,5.47-6.038,6.038l-0.12,1.375 c-0.12,0.657-0.598,1.195-1.285,1.195H39.565z M39.565,206.687c1.226,0,2.122,0.896,2.122,2.062v0.299 c0,1.166-0.896,2.062-2.122,2.062s-2.123-0.896-2.123-2.062v-0.299C37.442,207.583,38.339,206.687,39.565,206.687z"/>
<path fill="#dce8f3" d="M120,185.388c8.121,0,14.729,6.607,14.729,14.729s-6.607,14.729-14.729,14.729s-14.729-6.607-14.729-14.729 S111.879,185.388,120,185.388 M120,182.75c-9.591,0-17.367,7.775-17.367,17.367c0,9.591,7.775,17.367,17.367,17.367 s17.367-7.775,17.367-17.367C137.367,190.525,129.591,182.75,120,182.75L120,182.75z"/>
<path fill="#dce8f3" d="M119.564,204.504c-0.688,0-1.195-0.508-1.285-1.195l-0.299-2.57c-0.12-0.808,0.358-1.405,1.166-1.495 c2.81-0.269,4.363-1.345,4.363-3.229v-0.06c0-1.674-1.285-2.84-3.438-2.84c-1.584,0-2.869,0.568-4.064,1.645 c-0.3,0.239-0.688,0.418-1.106,0.418c-0.927,0-1.674-0.747-1.674-1.644c0-0.448,0.18-0.927,0.598-1.285 c1.584-1.495,3.587-2.481,6.337-2.481c4.186,0,7.024,2.331,7.024,6.068v0.06c0,3.767-2.72,5.47-6.038,6.038l-0.119,1.375 c-0.12,0.657-0.598,1.195-1.285,1.195H119.564z M119.564,206.687c1.226,0,2.122,0.896,2.122,2.062v0.299 c0,1.166-0.896,2.062-2.122,2.062s-2.122-0.896-2.122-2.062v-0.299C117.442,207.583,118.339,206.687,119.564,206.687z"/>
</svg>

Before

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="64px" height="64px" viewBox="0 0 64 64">
<path fill="#ababab" d="M32.336,3.894c-15.74,0-28.5,12.76-28.5,28.5s12.76,28.5,28.5,28.5s28.5-12.76,28.5-28.5 S48.076,3.894,32.336,3.894z M44.86,36.966h-7.823v7.62c0,2.582-2.12,4.702-4.702,4.702c-2.584,0-4.704-2.12-4.704-4.702v-7.62 h-7.817c-2.52,0-4.572-2.056-4.572-4.572s2.053-4.572,4.572-4.572h7.817v-7.62c0-2.582,2.12-4.702,4.704-4.702 c2.582,0,4.702,2.12,4.702,4.702v7.62h7.823c2.514,0,4.57,2.056,4.57,4.572S47.374,36.966,44.86,36.966z"/>
</svg>

Before

Width:  |  Height:  |  Size: 792 B

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="64px" height="64px" viewBox="0 0 64 64">
<path fill="#ff6b00" d="m 12.183457,12.241457 c -11.129861,11.12986 -11.129861,29.175226 0,40.305086 11.12986,11.129861 29.175226,11.129861 40.305086,0 11.129861,-11.12986 11.129861,-29.175226 0,-40.305086 -11.12986,-11.129861 -29.175226,-11.129861 -40.305086,0 z m 32.241241,14.52963 -5.531697,5.531696 5.388154,5.388154 c 1.82575,1.82575 1.82575,4.823882 0,6.649632 -1.827164,1.827164 -4.825297,1.827164 -6.651047,0.0014 l -5.388153,-5.388153 -5.527454,5.527453 c -1.781909,1.781909 -4.686704,1.779081 -6.465784,0 -1.779081,-1.77908 -1.781202,-4.684582 0,-6.465784 l 5.527453,-5.527454 -5.388153,-5.388153 c -1.82575,-1.82575 -1.82575,-4.823883 0.0014,-6.651047 1.82575,-1.82575 4.823882,-1.82575 6.649632,0 l 5.388154,5.388154 5.531696,-5.531697 c 1.777667,-1.777666 4.68529,-1.777666 6.46437,0.0014 1.779081,1.77908 1.779081,4.686703 0.0014,6.46437 z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="64px" height="64px" viewBox="0 0 64 64">
<path fill="#ecb51f" d="M61.689,51.121L36.437,7.384c-2.441-4.227-6.434-4.227-8.875,0L2.311,51.121 c-2.441,4.227-0.444,7.686,4.437,7.686h50.504C62.133,58.807,64.13,55.349,61.689,51.121z M35.968,47.68 c0,2.191-1.688,3.877-3.968,3.877s-3.968-1.686-3.968-3.877v-0.093c0-2.187,1.688-3.873,3.968-3.873s3.968,1.686,3.968,3.873V47.68z M36.059,21.548l-1.961,17.146c-0.137,1.233-0.958,2.009-2.098,2.009s-1.961-0.776-2.098-2.009l-1.961-17.146 c-0.137-1.322,0.592-2.325,1.825-2.325h4.469C35.466,19.223,36.196,20.226,36.059,21.548z"/>
</svg>

Before

Width:  |  Height:  |  Size: 870 B

View File

@ -1,103 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: Lucida Grande, Helvetica, Helvetica Neue, sans-serif;
}
#tabs {
box-shadow: inset -4px 0 0 rgba(0,0,0,0.3);
background: #252C33;
}
#toolbox-tabs {
overflow-y: auto;
}
.button {
width: 80px;
height: 85px;
padding-bottom: 5px;
-moz-appearance: none;
border: none;
border-bottom: 1px solid #121214;
background-color: transparent;
color: #B5B8BB;
cursor: pointer;
text-align: center;
-moz-box-align: end;
font-size: 10px;
text-shadow: 0 1px 0 #333;
color: #9FA6AD;
}
.button:first-child {
border-top: none;
}
.button[selected] {
box-shadow: inset -4px 0 0 rgba(0,0,0,0.3), inset 2px 0 0 #DEFFFF, inset 3px 0 0 #8DC7E8, inset 4px 0 1px #1D6496;
color: #DCE8F3;
background-color: #1A4766;
border-color: #191B1E;
}
.button::-moz-focus-inner {
border-width: 0;
}
.panel {
border-width: 0;
}
.panel:not([selected="true"]) {
display: none;
}
.button.toolbox {
background-repeat: no-repeat;
background-position: center 15px;
background-size: 40px 40px;
}
.projects-button {
background: url('chrome://devtools/skin/themes/app-manager/images/index-icons.svg') no-repeat;
background-position: left -5px;
}
.projects-button[selected] {
background-position: right -5px;
}
.device-button {
background-image: url('chrome://devtools/skin/themes/app-manager/images/index-icons.svg');
background-position: left -85px, top left;
background-repeat: no-repeat, no-repeat;
background-size: 160px 240px, 2px 80px;
}
.device-button[selected] {
background-position: right -85px, top left;
}
.help-button {
border-bottom: 0;
background-image: url('chrome://devtools/skin/themes/app-manager/images/index-icons.svg');
background-position: left -165px, top left;
background-repeat: no-repeat, no-repeat;
background-size: 160px 240px, 2px 80px;
}
.help-button[selected] {
background-position: right -165px, top left;
}
#connection-footer {
border-width: 0;
height: 50px;
min-height: 50px;
}

View File

@ -1,82 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Manifest Editor overrides */
.variables-view-container.manifest-editor {
background-color: #F5F5F5;
padding: 20px 2px;
}
.manifest-editor .variable-or-property:focus > .title {
background-color: #EDEDED;
color: #000;
border-radius: 4px;
}
.manifest-editor .variables-view-property > .title > .name {
color: #27406A;
}
.manifest-editor .variable-or-property > .title > label,
.manifest-editor textbox {
font-family: monospace;
}
.manifest-editor .variable-or-property > .title > .token-string {
color: #54BC6A;
font-weight: bold;
}
.manifest-editor .variable-or-property > .title > .token-boolean,
.manifest-editor .variable-or-property > .title > .token-number {
color: #009BD4;
font-weight: bold;
}
.manifest-editor .variable-or-property > .title > .token-undefined {
color: #bbb;
}
.manifest-editor .variable-or-property > .title > .token-null {
color: #999;
}
.manifest-editor .variable-or-property > .title > .token-other {
color: #333;
}
.manifest-editor .variables-view-variable {
border-bottom: none;
}
.manifest-editor .variables-view-delete,
.manifest-editor .variables-view-delete:hover,
.manifest-editor .variables-view-delete:active,
.manifest-editor .variable-or-property:focus .variables-view-delete,
.manifest-editor .variables-view-add-property,
.manifest-editor .variables-view-add-property:hover,
.manifest-editor .variables-view-add-property:active,
.manifest-editor .variable-or-property:focus .variables-view-add-property {
list-style-image: none;
-moz-image-region: initial;
}
.manifest-editor .variables-view-delete::before,
.manifest-editor .variables-view-add-property::before {
width: 11px;
height: 11px;
content: "";
display: inline-block;
background-size: 11px auto;
}
.manifest-editor .variables-view-delete::before {
background-image: url("images/app-manager/remove.svg");
}
.manifest-editor .variables-view-add-property::before {
background-image: url("images/app-manager/add.svg");
-moz-margin-end: 2px;
}

View File

@ -1,556 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 0.9rem;
}
html, body {
height: 100%;
}
template {
display: none;
}
body {
display: flex;
color: #333;
background-color: white;
font-family: Lucida Grande, Helvetica, Helvetica Neue, sans-serif;
overflow: hidden;
}
body:not(.connected) button.device-action {
display: none;
}
strong {
color: #111;
}
/********* SIDEBAR ***********/
#sidebar {
display: flex;
flex-direction: column;
flex: 0 0 350px;
overflow: hidden;
z-index: 100;
background-color: #E9EAEB;
position: relative;
box-shadow: 3px 0 1.5px rgba(0,0,0,0.08);
}
#project-list {
height: 100%;
overflow: auto;
}
#project-list:not([projects-count="0"]) > #no-project {
display: none;
}
#no-project {
padding: 100px 20px 0;
font-weight: bold;
color: #BBB;
font-size: 22px;
}
/********* PROJECT MENU ***********/
.project-item {
padding: 10px 0;
background-color: #F0F1F2;
box-shadow: inset 0 -1px 0 rgba(0,0,0,0.1);
color: #666;
line-height: 120%;
cursor: pointer;
display: flex;
position: relative;
}
.project-item:hover {
background-color: #EEE;
}
.project-item > * {
flex-shrink: 0;
}
.project-item.selected {
background-color: #46AFE3;
}
.project-item.selected strong {
color: #FFF;
}
.project-item.selected p,
.project-item.selected span {
color: #C1DCF0;
}
.button-remove {
background-image: url('images/remove.svg');
background-size: 20px;
width: 20px;
height: 20px;
position: absolute;
right: 5px;
bottom: 5px;
visibility: hidden;
opacity: 0.5;
}
.project-item:hover .button-remove {
visibility: visible;
}
.project-item-status {
width: 6px;
margin: -10px 0;
border-right: 1px solid rgba(0,0,0,0.1);
box-shadow: inset 0 0 1px 1px rgba(255,255,255,0.2), inset 0 -1px 0 0 rgba(0,0,0,0.2);
}
.project-item-status[status="valid"] {
background-color: #70BF53;
}
.project-item-status[status~="warning"] {
background-color: #F2B33F;
}
.project-item-status[status~="error"] {
background-color: #ED4C62;
}
.project-item-icon {
width: 32px;
height: 32px;
margin: 0 10px;
}
.project-item-meta {
flex-grow: 1;
flex-shrink: 1 !important;
}
.project-item-type {
font-size: 10px;
line-height: 20px;
float: right;
padding-right: 10px;
color: #7597B9;
text-transform: uppercase;
}
.project-item-description {
color: #888;
font-size: 90%;
}
/********* ADD PROJECT ***********/
#new-packaged-project {
box-shadow: 0 -1px 5px rgba(0,0,0,0.1);
background-position: calc(100% - 10px) 10px;
}
#new-packaged-project,
#new-hosted-project {
background-color: #EEE;
border: none;
border-top: 1px solid #DDD;
padding: 10px;
font-weight: bold;
}
#new-packaged-project:hover,
#new-hosted-project:hover {
background-color: #DDD;
}
#new-hosted-project-wrapper {
display: flex;
align-items: center;
}
#new-packaged-project,
#new-hosted-project-click {
background-image: url('images/plus.svg');
background-size: 20px;
background-repeat: no-repeat;
cursor: pointer;
}
#new-hosted-project-click {
background-position: top right;
width: 20px;
height: 20px;
margin-left: 5px;
}
#url-input {
flex-grow: 1;
width: 90%;
box-shadow: none;
border-radius: 3px;
border: 1px solid #DDD;
padding: 4px;
margin-top: 4px;
}
/********* LENSE ***********/
#lense {
height: 100%;
flex-grow: 1;
display: flex;
z-index: 1;
overflow: hidden;
background-color: rgb(225, 225, 225);
background-image: url('images/rocket.svg'), url('images/noise.png');
background-repeat: no-repeat, repeat;
background-size: 35%, auto;
background-position: center center, top left;
}
#lense > div {
display: flex;
flex-grow: 1;
flex-direction: column;
}
/********* PROJECT ***********/
.project-details {
background-color: rgb(225, 225, 225);
padding: 10px;
line-height: 160%;
display: flex;
flex-direction: column;
}
.project-metadata {
flex-grow: 1;
}
.project-status {
display: flex;
}
.project-title {
flex-direction: row;
display: flex;
align-items: flex-start;
padding-bottom: 10px;
border-bottom: 1px solid #CCC;
margin-bottom: 10px;
}
.project-title > h1 {
flex-grow: 1;
font-size: 24px;
}
.project-location {
color: gray;
font-size: 10px;
cursor: pointer;
font-family: monospace;
}
.project-location:hover {
text-decoration: underline;
}
.project-header {
display: flex;
border-bottom: 1px solid #CCC;
margin: 10px 20px 10px 20px;
padding-bottom: 10px;
}
.project-icon {
flex-shrink: 0;
width: 64px;
height: 64px;
margin-right: 10px;
}
.project-location {
font-size: 11px;
color: #999;
}
.project-description {
font-style: italic;
color: #333;
}
.project-status > p {
text-transform: uppercase;
font-size: 10px;
padding: 2px 10px;
border-radius: 2px;
margin-top: 6px;
line-height: 10px;
}
.project-validation {
color: #FFF;
display: none;
margin-left: 10px;
}
.project-validation.valid {
background-color: #70BF53;
}
.project-validation.warning {
background-color: #F2B33F;
}
.project-validation.error {
background-color: #ED4C62;
}
[status="valid"] > .project-validation.valid,
[status~="warning"] > .project-validation.warning,
[status~="error"] > .project-validation.error {
display: inline;
}
.project-type {
display: none;
margin-left: 10px;
}
[type="hosted"] > .project-type.hosted,
[type="packaged"] > .project-type.packaged {
display: inline;
}
/********* PROJECT BUTTONS ***********/
.project-buttons {
display: flex;
margin-left: 20px;
color: #BBB;
}
.project-buttons > button {
margin: 0;
font-size: 11px;
border: 1px solid #CCC;
border-left-width: 0;
padding: 5px 15px;
cursor: pointer;
background: rgba(255,255,255,0.4);
text-transform: uppercase;
}
.project-buttons > button[disabled] {
background-color: transparent;
opacity: 0.4;
pointer-events: none;
}
.project-buttons > button:first-child {
border-left-width: 1px;
}
.project-button-debug {
color: #3498DB;
}
.project-button-debug:hover {
background-color: #3498DB;
color: #FFF;
}
.project-button-debug[disabled] {
color: #3498DB;
}
.project-button-update {
color: #777;
}
.project-button-update:hover {
background-color: #777;
color: #FFF;
}
.project-button-update[disabled] {
color: #777;
}
/********* ERRORS AND WARNINGS ***********/
.project-warnings,
.project-errors,
.project-item-warnings,
.project-item-errors {
display: none;
}
[status~="warning"] .project-item-warnings,
[status~="error"] .project-item-errors {
display: inline-block;
}
[status~="warning"] > .project-warnings,
[status~="error"] > .project-errors {
display: block;
}
.project-warnings,
.project-errors {
margin: 20px 20px 0;
padding: 10px 10px;
font-family: monospace;
}
.project-warnings {
border-left: 3px solid #ECB51E;
background-color: rgba(236, 181, 20, 0.1);
}
.project-errors {
border-left: 3px solid #ED4C62;
background-color: rgba(237,76,98,0.1);
}
.project-item-warnings {
background-image: url('images/warning.svg');
}
.project-item-errors {
background-image: url('images/error.svg');
color: rgb(227, 79, 34);
}
.project-item-warnings,
.project-item-errors {
background-repeat: no-repeat;
background-size: 12px;
background-position: left center;
margin-top: 6px;
}
.project-item-warnings > span,
.project-item-errors > span {
font-size: 11px;
padding-left: 16px;
font-weight: bold;
}
/********* MANIFEST EDITOR ***********/
.manifest-editor {
display: flex;
flex-direction: column;
flex-grow: 1;
background-color: #E1E1E1;
}
.manifest-header {
display: flex;
flex-direction: row;
}
.manifest-header > h2 {
font-size: 18px;
margin: 1em 15px 1em 30px;
display: none;
}
.manifest-header > button {
margin: 18px 0;
font-size: 11px;
border: 1px solid #CCC;
border-right-width: 0;
padding: 2px;
cursor: pointer;
background: rgba(255,255,255,0.4);
text-transform: uppercase;
display: none;
}
.manifest-header > button[disabled] {
background-color: transparent;
opacity: 0.4;
pointer-events: none;
}
.manifest-header > button:last-child {
border-right-width: 1px;
}
[type="packaged"] > .editable {
display: block;
}
[type="hosted"] > .viewable {
display: block;
}
.manifest-button-save {
color: #777;
}
.manifest-button-save:hover {
background-color: #777;
color: #FFF;
}
.manifest-button-save[disabled] {
color: #777;
}
.variables-view {
flex-grow: 1;
border: 0;
border-top: 5px solid #C9C9C9;
}
/* Bug 925921: Remove when the manifest editor is always on */
.manifest-editor {
display: none;
}
.project-details {
flex-grow: 1;
}
#lense[manifest-editable] .manifest-editor {
display: flex;
}
#lense[manifest-editable] .project-details {
flex-grow: 0;
}
/* End blocks to remove */

View File

@ -1517,5 +1517,3 @@
background-size: auto 18px;
width: 18px;
}
%include app-manager/manifest-editor.inc.css