mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 12:20:56 +00:00
Bug 1007061 - Remove app-manager. r=jryans
This commit is contained in:
parent
97e65e8041
commit
48802de620
@ -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;"/>
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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 },
|
||||
{
|
||||
|
@ -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 },
|
||||
|
@ -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">
|
||||
|
@ -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">
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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;
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
@ -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>
|
@ -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);
|
@ -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>
|
@ -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>
|
@ -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();
|
@ -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>
|
@ -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();
|
||||
}
|
||||
}
|
||||
};
|
@ -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);
|
@ -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>
|
@ -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));
|
||||
}
|
||||
|
||||
};
|
@ -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
|
||||
}
|
||||
})();
|
@ -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;
|
||||
});
|
||||
}
|
||||
};
|
@ -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',
|
||||
)
|
||||
|
@ -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;
|
@ -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
|
@ -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");
|
||||
});
|
||||
}
|
@ -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]
|
||||
|
@ -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;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"name": "My hosted app"
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"name": "My packaged app",
|
||||
"developer": {
|
||||
"name": "Foo Bar"
|
||||
},
|
||||
"tester" : {
|
||||
"who": "qa"
|
||||
}
|
||||
}
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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);
|
||||
});
|
||||
},
|
||||
}
|
@ -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
|
||||
*/
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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 */
|
@ -1517,5 +1517,3 @@
|
||||
background-size: auto 18px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
%include app-manager/manifest-editor.inc.css
|
||||
|
Loading…
x
Reference in New Issue
Block a user