Bug 1135191 - Add runtime panel with toggle. r=jryans

This commit is contained in:
Jennifer Fong 2015-04-27 14:19:00 -04:00
parent 2e4b6ee914
commit 51abd56739
38 changed files with 1936 additions and 306 deletions

View File

@ -31,5 +31,8 @@ webide.jar:
content/project-listing.xhtml (project-listing.xhtml)
content/project-listing.js (project-listing.js)
content/project-panel.js (project-panel.js)
content/runtime-panel.js (runtime-panel.js)
content/runtime-listing.xhtml (runtime-listing.xhtml)
content/runtime-listing.js (runtime-listing.js)
content/simulator.js (simulator.js)
content/simulator.xhtml (simulator.xhtml)

View File

@ -4,38 +4,24 @@
const Cu = Components.utils;
const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
const {AppManager} = require("devtools/webide/app-manager");
const ProjectList = require("devtools/webide/project-list");
let projectList = new ProjectList(window, window.parent);
window.addEventListener("load", function onLoad() {
window.removeEventListener("load", onLoad);
AppManager.on("app-manager-update", onAppManagerUpdate);
window.removeEventListener("load", onLoad, true);
document.getElementById("new-app").onclick = CreateNewApp;
document.getElementById("hosted-app").onclick = ImportHostedApp;
document.getElementById("packaged-app").onclick = ImportPackagedApp;
projectList.update();
projectList.updateCommands();
}, true);
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
projectList = null;
AppManager.off("app-manager-update", onAppManagerUpdate);
projectList.destroy();
});
function onAppManagerUpdate(event, what, details) {
switch (what) {
case "runtime-global-actors":
case "runtime-targets":
case "project-validated":
case "project-removed":
case "project":
projectList.update(details);
break;
}
}
function CreateNewApp() {
projectList.newApp();
}

View File

@ -12,7 +12,7 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf8"/>
<link rel="stylesheet" href="chrome://webide/skin/project-listing.css" type="text/css"/>
<link rel="stylesheet" href="chrome://webide/skin/panel-listing.css" type="text/css"/>
<script type="application/javascript;version=1.8" src="chrome://webide/content/project-listing.js"></script>
</head>
<body>

View File

@ -4,35 +4,31 @@
let ProjectPanel = {
// TODO: Expand function to save toggle state.
toggle: function(sidebarsEnabled, triggerPopup) {
toggleSidebar: function() {
document.querySelector("#project-listing-panel").setAttribute("sidebar-displayed", true);
document.querySelector("#project-listing-splitter").setAttribute("sidebar-displayed", true);
},
showPopup: function() {
let deferred = promise.defer();
let doc = document;
if (sidebarsEnabled) {
doc.querySelector("#project-listing-panel").setAttribute("sidebar-displayed", true);
doc.querySelector("#project-listing-splitter").setAttribute("sidebar-displayed", true);
deferred.resolve();
} else if (triggerPopup) {
let panelNode = doc.querySelector("#project-panel");
let panelVboxNode = doc.querySelector("#project-panel > #project-panel-box");
let anchorNode = doc.querySelector("#project-panel-button > .panel-button-anchor");
let panelNode = document.querySelector("#project-panel");
let panelVboxNode = document.querySelector("#project-panel > #project-panel-box");
let anchorNode = document.querySelector("#project-panel-button > .panel-button-anchor");
window.setTimeout(() => {
// Open the popup only when the projects are added.
// Not doing it in the next tick can cause mis-calculations
// of the size of the panel.
function onPopupShown() {
panelNode.removeEventListener("popupshown", onPopupShown);
deferred.resolve();
}
window.setTimeout(() => {
// Open the popup only when the projects are added.
// Not doing it in the next tick can cause mis-calculations
// of the size of the panel.
function onPopupShown() {
panelNode.removeEventListener("popupshown", onPopupShown);
deferred.resolve();
}
panelNode.addEventListener("popupshown", onPopupShown);
panelNode.openPopup(anchorNode);
panelVboxNode.scrollTop = 0;
}, 0);
} else {
deferred.resolve();
}
panelNode.addEventListener("popupshown", onPopupShown);
panelNode.openPopup(anchorNode);
panelVboxNode.scrollTop = 0;
}, 0);
return deferred.promise;
}

View File

@ -0,0 +1,61 @@
/* 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 = Components.utils;
const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
const RuntimeList = require("devtools/webide/runtime-list");
let runtimeList = new RuntimeList(window, window.parent);
window.addEventListener("load", function onLoad() {
window.removeEventListener("load", onLoad, true);
document.getElementById("runtime-screenshot").onclick = TakeScreenshot;
document.getElementById("runtime-permissions").onclick = ShowPermissionsTable;
document.getElementById("runtime-details").onclick = ShowRuntimeDetails;
document.getElementById("runtime-disconnect").onclick = DisconnectRuntime;
document.getElementById("runtime-preferences").onclick = ShowDevicePreferences;
document.getElementById("runtime-settings").onclick = ShowSettings;
document.getElementById("runtime-panel-installsimulator").onclick = ShowAddons;
document.getElementById("runtime-panel-noadbhelper").onclick = ShowAddons;
document.getElementById("runtime-panel-nousbdevice").onclick = ShowTroubleShooting;
runtimeList.update();
runtimeList.updateCommands();
}, true);
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
runtimeList.destroy();
});
function TakeScreenshot() {
runtimeList.takeScreenshot();
}
function ShowRuntimeDetails() {
runtimeList.showRuntimeDetails();
}
function ShowPermissionsTable() {
runtimeList.showPermissionsTable();
}
function ShowDevicePreferences() {
runtimeList.showDevicePreferences();
}
function ShowSettings() {
runtimeList.showSettings();
}
function DisconnectRuntime() {
window.parent.Cmds.disconnectRuntime();
}
function ShowAddons() {
runtimeList.showAddons();
}
function ShowTroubleShooting() {
runtimeList.showTroubleShooting();
}

View File

@ -0,0 +1,43 @@
<?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 % webideDTD SYSTEM "chrome://browser/locale/devtools/webide.dtd" >
%webideDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf8"/>
<link rel="stylesheet" href="chrome://webide/skin/panel-listing.css" type="text/css"/>
<script type="application/javascript;version=1.8" src="chrome://webide/content/runtime-listing.js"></script>
</head>
<body>
<div id="runtime-panel">
<div id="runtime-panel-box">
<label class="panel-header">&runtimePanel_usb;</label>
<button class="panel-item" id="runtime-panel-nousbdevice">&runtimePanel_nousbdevice;</button>
<button class="panel-item" id="runtime-panel-noadbhelper">&runtimePanel_noadbhelper;</button>
<div id="runtime-panel-usb"></div>
<label class="panel-header" id="runtime-header-wifi">&runtimePanel_wifi;</label>
<div id="runtime-panel-wifi"></div>
<label class="panel-header">&runtimePanel_simulator;</label>
<div id="runtime-panel-simulator"></div>
<button class="panel-item" id="runtime-panel-installsimulator">&runtimePanel_installsimulator;</button>
<label class="panel-header">&runtimePanel_other;</label>
<div id="runtime-panel-other"></div>
<div id="runtime-actions">
<button class="panel-item" id="runtime-details">&runtimeMenu_showDetails_label;</button>
<button class="panel-item" id="runtime-permissions">&runtimeMenu_showPermissionTable_label;</button>
<button class="panel-item" id="runtime-preferences">&runtimeMenu_showDevicePrefs_label;</button>
<button class="panel-item" id="runtime-settings">&runtimeMenu_showSettings_label;</button>
<button class="panel-item" id="runtime-screenshot">&runtimeMenu_takeScreenshot_label;</button>
<button class="panel-item" id="runtime-disconnect">&runtimeMenu_disconnect_label;</button>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,26 @@
/* 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/. */
let RuntimePanel = {
// TODO: Expand function to save toggle state.
toggleSidebar: function() {
document.querySelector("#runtime-listing-panel").setAttribute("sidebar-displayed", true);
document.querySelector("#runtime-listing-splitter").setAttribute("sidebar-displayed", true);
},
showPopup: function() {
let deferred = promise.defer();
let panel = document.querySelector("#runtime-panel");
let anchor = document.querySelector("#runtime-panel-button > .panel-button-anchor");
function onPopupShown() {
panel.removeEventListener("popupshown", onPopupShown);
deferred.resolve();
}
panel.addEventListener("popupshown", onPopupShown);
panel.openPopup(anchor);
return deferred.promise;
}
};

View File

@ -15,17 +15,18 @@ const {Services} = Cu.import("resource://gre/modules/Services.jsm");
const {AppProjects} = require("devtools/app-manager/app-projects");
const {Connection} = require("devtools/client/connection-manager");
const {AppManager} = require("devtools/webide/app-manager");
const EventEmitter = require("devtools/toolkit/event-emitter");
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
const ProjectEditor = require("projecteditor/projecteditor");
const {Devices} = Cu.import("resource://gre/modules/devtools/Devices.jsm");
const {GetAvailableAddons} = require("devtools/webide/addons");
const {getJSON} = require("devtools/shared/getjson");
const utils = require("devtools/webide/utils");
const Telemetry = require("devtools/shared/telemetry");
const {RuntimeScanners, WiFiScanner} = require("devtools/webide/runtimes");
const {RuntimeScanners} = require("devtools/webide/runtimes");
const {showDoorhanger} = require("devtools/shared/doorhanger");
const ProjectList = require("devtools/webide/project-list");
const {Simulators} = require("devtools/webide/simulators");
const RuntimeList = require("devtools/webide/runtime-list");
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
@ -56,6 +57,7 @@ window.addEventListener("unload", function onUnload() {
});
let projectList;
let runtimeList;
let UI = {
init: function() {
@ -71,17 +73,26 @@ let UI = {
AppManager.on("app-manager-update", this.appManagerUpdate);
projectList = new ProjectList(window, window);
ProjectPanel.toggle(projectList.sidebarsEnabled);
if (projectList.sidebarsEnabled) {
ProjectPanel.toggleSidebar();
}
runtimeList = new RuntimeList(window, window);
if (runtimeList.sidebarsEnabled) {
Cmds.showRuntimePanel();
} else {
runtimeList.update();
}
this.updateCommands();
this.updateRuntimeList();
this.onfocus = this.onfocus.bind(this);
window.addEventListener("focus", this.onfocus, true);
AppProjects.load().then(() => {
this.autoSelectProject();
projectList.update();
if (!projectList.sidebarsEnabled) {
projectList.update();
}
}, e => {
console.error(e);
this.reportError("error_appProjectsLoadFailed");
@ -129,7 +140,8 @@ let UI = {
AppManager.off("app-manager-update", this.appManagerUpdate);
AppManager.destroy();
Simulators.off("configure", this.configureSimulator);
projectList = null;
projectList.destroy();
runtimeList.destroy();
window.removeEventListener("message", this.onMessage);
this.updateConnectionTelemetry();
this._telemetry.toolClosed("webide");
@ -165,7 +177,6 @@ let UI = {
// See AppManager.update() for descriptions of what these events mean.
switch (what) {
case "runtime-list":
this.updateRuntimeList();
this.autoConnectRuntime();
break;
case "connection":
@ -188,22 +199,19 @@ let UI = {
yield UI.autoStartProject();
UI.autoOpenToolbox();
UI.saveLastSelectedProject();
projectList.update();
UI.updateRemoveProjectButton();
});
return;
case "project-started":
this.updateCommands();
projectList.update();
UI.autoOpenToolbox();
break;
case "project-stopped":
UI.destroyToolbox();
this.updateCommands();
projectList.update();
break;
case "runtime-global-actors":
this.updateCommands();
projectList.update();
break;
case "runtime-details":
this.updateRuntimeButton();
@ -217,17 +225,12 @@ let UI = {
this.updateCommands();
this.updateProjectButton();
this.updateProjectEditorHeader();
projectList.update();
break;
case "project-removed":
projectList.update();
break;
case "install-progress":
this.updateProgress(Math.round(100 * details.bytesSent / details.totalBytes));
break;
case "runtime-targets":
this.autoSelectProject();
projectList.update(details);
break;
case "pre-package":
this.prePackageLog(details);
@ -286,17 +289,19 @@ let UI = {
busy: function() {
this.hidePanels();
let win = document.querySelector("window");
win.classList.add("busy")
win.classList.add("busy");
win.classList.add("busy-undetermined");
this.updateCommands();
this.update("busy");
},
unbusy: function() {
let win = document.querySelector("window");
win.classList.remove("busy")
win.classList.remove("busy");
win.classList.remove("busy-determined");
win.classList.remove("busy-undetermined");
this.updateCommands();
this.update("unbusy");
this._busyPromise = null;
},
@ -384,75 +389,95 @@ let UI = {
nbox.removeAllNotifications(true);
},
/********** RUNTIME **********/
/********** COMMANDS **********/
updateRuntimeList: function() {
let wifiHeaderNode = document.querySelector("#runtime-header-wifi");
if (WiFiScanner.allowed) {
wifiHeaderNode.removeAttribute("hidden");
} else {
wifiHeaderNode.setAttribute("hidden", "true");
/**
* This module emits various events when state changes occur.
*
* The events this module may emit include:
* busy:
* The window is currently busy and certain UI functions may be disabled.
* unbusy:
* The window is not busy and certain UI functions may be re-enabled.
*/
update: function(what, details) {
this.emit("webide-update", what, details);
},
updateCommands: function() {
// Action commands
let playCmd = document.querySelector("#cmd_play");
let stopCmd = document.querySelector("#cmd_stop");
let debugCmd = document.querySelector("#cmd_toggleToolbox");
let playButton = document.querySelector('#action-button-play');
let projectPanelCmd = document.querySelector("#cmd_showProjectPanel");
if (document.querySelector("window").classList.contains("busy")) {
playCmd.setAttribute("disabled", "true");
stopCmd.setAttribute("disabled", "true");
debugCmd.setAttribute("disabled", "true");
projectPanelCmd.setAttribute("disabled", "true");
return;
}
let usbListNode = document.querySelector("#runtime-panel-usb");
let wifiListNode = document.querySelector("#runtime-panel-wifi");
let simulatorListNode = document.querySelector("#runtime-panel-simulator");
let otherListNode = document.querySelector("#runtime-panel-other");
let noHelperNode = document.querySelector("#runtime-panel-noadbhelper");
let noUSBNode = document.querySelector("#runtime-panel-nousbdevice");
if (Devices.helperAddonInstalled) {
noHelperNode.setAttribute("hidden", "true");
if (!AppManager.selectedProject || !AppManager.connected) {
playCmd.setAttribute("disabled", "true");
stopCmd.setAttribute("disabled", "true");
debugCmd.setAttribute("disabled", "true");
} else {
noHelperNode.removeAttribute("hidden");
}
let runtimeList = AppManager.runtimeList;
if (runtimeList.usb.length === 0 && Devices.helperAddonInstalled) {
noUSBNode.removeAttribute("hidden");
} else {
noUSBNode.setAttribute("hidden", "true");
}
for (let [type, parent] of [
["usb", usbListNode],
["wifi", wifiListNode],
["simulator", simulatorListNode],
["other", otherListNode],
]) {
while (parent.hasChildNodes()) {
parent.firstChild.remove();
let isProjectRunning = AppManager.isProjectRunning();
if (isProjectRunning) {
playButton.classList.add("reload");
stopCmd.removeAttribute("disabled");
debugCmd.removeAttribute("disabled");
} else {
playButton.classList.remove("reload");
stopCmd.setAttribute("disabled", "true");
debugCmd.setAttribute("disabled", "true");
}
for (let runtime of runtimeList[type]) {
let r = runtime;
let panelItemNode = document.createElement("hbox");
panelItemNode.className = "panel-item-complex";
let connectButton = document.createElement("toolbarbutton");
connectButton.className = "panel-item runtime-panel-item-" + type;
connectButton.setAttribute("label", r.name);
connectButton.setAttribute("flex", "1");
connectButton.addEventListener("click", () => {
this.hidePanels();
this.dismissErrorNotification();
this.connectToRuntime(r);
}, true);
panelItemNode.appendChild(connectButton);
if (r.configure && UI.isRuntimeConfigurationEnabled()) {
let configButton = document.createElement("toolbarbutton");
configButton.className = "configure-button";
configButton.addEventListener("click", r.configure.bind(r), true);
panelItemNode.appendChild(configButton);
// If connected and a project is selected
if (AppManager.selectedProject.type == "runtimeApp") {
playCmd.removeAttribute("disabled");
} else if (AppManager.selectedProject.type == "tab") {
playCmd.removeAttribute("disabled");
stopCmd.setAttribute("disabled", "true");
} else if (AppManager.selectedProject.type == "mainProcess") {
playCmd.setAttribute("disabled", "true");
stopCmd.setAttribute("disabled", "true");
} else {
if (AppManager.selectedProject.errorsCount == 0 &&
AppManager.runtimeCanHandleApps()) {
playCmd.removeAttribute("disabled");
} else {
playCmd.setAttribute("disabled", "true");
}
parent.appendChild(panelItemNode);
}
}
let runtimePanelButton = document.querySelector("#runtime-panel-button");
if (AppManager.connected) {
runtimePanelButton.setAttribute("active", "true");
} else {
runtimePanelButton.removeAttribute("active");
}
projectPanelCmd.removeAttribute("disabled");
},
updateRemoveProjectButton: function() {
// Remove command
let removeCmdNode = document.querySelector("#cmd_removeProject");
if (AppManager.selectedProject) {
removeCmdNode.removeAttribute("disabled");
} else {
removeCmdNode.setAttribute("disabled", "true");
}
},
/********** RUNTIME **********/
get lastConnectedRuntime() {
return Services.prefs.getCharPref("devtools.webide.lastConnectedRuntime");
},
@ -531,6 +556,8 @@ let UI = {
}
},
/********** ACTIONS **********/
_actionsToLog: new Set(),
/**
@ -869,121 +896,6 @@ let UI = {
this.updateProjectEditorMenusVisibility();
},
/********** COMMANDS **********/
updateCommands: function() {
if (document.querySelector("window").classList.contains("busy")) {
document.querySelector("#cmd_newApp").setAttribute("disabled", "true");
document.querySelector("#cmd_importPackagedApp").setAttribute("disabled", "true");
document.querySelector("#cmd_importHostedApp").setAttribute("disabled", "true");
document.querySelector("#cmd_showProjectPanel").setAttribute("disabled", "true");
document.querySelector("#cmd_showRuntimePanel").setAttribute("disabled", "true");
document.querySelector("#cmd_removeProject").setAttribute("disabled", "true");
document.querySelector("#cmd_disconnectRuntime").setAttribute("disabled", "true");
document.querySelector("#cmd_showPermissionsTable").setAttribute("disabled", "true");
document.querySelector("#cmd_takeScreenshot").setAttribute("disabled", "true");
document.querySelector("#cmd_showRuntimeDetails").setAttribute("disabled", "true");
document.querySelector("#cmd_play").setAttribute("disabled", "true");
document.querySelector("#cmd_stop").setAttribute("disabled", "true");
document.querySelector("#cmd_toggleToolbox").setAttribute("disabled", "true");
document.querySelector("#cmd_showDevicePrefs").setAttribute("disabled", "true");
document.querySelector("#cmd_showSettings").setAttribute("disabled", "true");
return;
}
document.querySelector("#cmd_newApp").removeAttribute("disabled");
document.querySelector("#cmd_importPackagedApp").removeAttribute("disabled");
document.querySelector("#cmd_importHostedApp").removeAttribute("disabled");
document.querySelector("#cmd_showProjectPanel").removeAttribute("disabled");
document.querySelector("#cmd_showRuntimePanel").removeAttribute("disabled");
// Action commands
let playCmd = document.querySelector("#cmd_play");
let stopCmd = document.querySelector("#cmd_stop");
let debugCmd = document.querySelector("#cmd_toggleToolbox");
let playButton = document.querySelector('#action-button-play');
if (!AppManager.selectedProject || !AppManager.connected) {
playCmd.setAttribute("disabled", "true");
stopCmd.setAttribute("disabled", "true");
debugCmd.setAttribute("disabled", "true");
} else {
let isProjectRunning = AppManager.isProjectRunning();
if (isProjectRunning) {
playButton.classList.add("reload");
stopCmd.removeAttribute("disabled");
debugCmd.removeAttribute("disabled");
} else {
playButton.classList.remove("reload");
stopCmd.setAttribute("disabled", "true");
debugCmd.setAttribute("disabled", "true");
}
// If connected and a project is selected
if (AppManager.selectedProject.type == "runtimeApp") {
playCmd.removeAttribute("disabled");
} else if (AppManager.selectedProject.type == "tab") {
playCmd.removeAttribute("disabled");
stopCmd.setAttribute("disabled", "true");
} else if (AppManager.selectedProject.type == "mainProcess") {
playCmd.setAttribute("disabled", "true");
stopCmd.setAttribute("disabled", "true");
} else {
if (AppManager.selectedProject.errorsCount == 0 &&
AppManager.runtimeCanHandleApps()) {
playCmd.removeAttribute("disabled");
} else {
playCmd.setAttribute("disabled", "true");
}
}
}
// Remove command
let removeCmdNode = document.querySelector("#cmd_removeProject");
if (AppManager.selectedProject) {
removeCmdNode.removeAttribute("disabled");
} else {
removeCmdNode.setAttribute("disabled", "true");
}
// Runtime commands
let screenshotCmd = document.querySelector("#cmd_takeScreenshot");
let permissionsCmd = document.querySelector("#cmd_showPermissionsTable");
let detailsCmd = document.querySelector("#cmd_showRuntimeDetails");
let disconnectCmd = document.querySelector("#cmd_disconnectRuntime");
let devicePrefsCmd = document.querySelector("#cmd_showDevicePrefs");
let settingsCmd = document.querySelector("#cmd_showSettings");
let box = document.querySelector("#runtime-actions");
let runtimePanelButton = document.querySelector("#runtime-panel-button");
if (AppManager.connected) {
if (AppManager.deviceFront) {
detailsCmd.removeAttribute("disabled");
permissionsCmd.removeAttribute("disabled");
screenshotCmd.removeAttribute("disabled");
}
if (AppManager.preferenceFront) {
devicePrefsCmd.removeAttribute("disabled");
}
if (AppManager.settingsFront) {
settingsCmd.removeAttribute("disabled");
}
disconnectCmd.removeAttribute("disabled");
runtimePanelButton.setAttribute("active", "true");
} else {
detailsCmd.setAttribute("disabled", "true");
permissionsCmd.setAttribute("disabled", "true");
screenshotCmd.setAttribute("disabled", "true");
disconnectCmd.setAttribute("disabled", "true");
devicePrefsCmd.setAttribute("disabled", "true");
settingsCmd.setAttribute("disabled", "true");
runtimePanelButton.removeAttribute("active");
}
},
/********** TOOLBOX **********/
onMessage: function(event) {
@ -1099,6 +1011,8 @@ let UI = {
}
};
EventEmitter.decorate(UI);
let Cmds = {
quit: function() {
if (UI.canCloseProject()) {
@ -1126,7 +1040,11 @@ let Cmds = {
},
showProjectPanel: function() {
ProjectPanel.toggle(projectList.sidebarsEnabled, true);
if (projectList.sidebarsEnabled) {
ProjectPanel.toggleSidebar();
} else {
ProjectPanel.showPopup();
}
// There are currently no available events to listen for when an unselected
// tab navigates. Since we show every tab's location in the project menu,
@ -1144,18 +1062,11 @@ let Cmds = {
showRuntimePanel: function() {
RuntimeScanners.scan();
let panel = document.querySelector("#runtime-panel");
let anchor = document.querySelector("#runtime-panel-button > .panel-button-anchor");
let deferred = promise.defer();
function onPopupShown() {
panel.removeEventListener("popupshown", onPopupShown);
deferred.resolve();
if (runtimeList.sidebarsEnabled) {
RuntimePanel.toggleSidebar();
} else {
RuntimePanel.showPopup();
}
panel.addEventListener("popupshown", onPopupShown);
panel.openPopup(anchor);
return deferred.promise;
},
disconnectRuntime: function() {
@ -1167,12 +1078,7 @@ let Cmds = {
},
takeScreenshot: function() {
return UI.busyUntil(AppManager.deviceFront.screenshotToDataURL().then(longstr => {
return longstr.string().then(dataURL => {
longstr.release().then(null, console.error);
UI.openInBrowser(dataURL);
});
}), "taking screenshot");
runtimeList.takeScreenshot();
},
showPermissionsTable: function() {

View File

@ -28,6 +28,7 @@
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"></script>
<script type="application/javascript" src="project-panel.js"></script>
<script type="application/javascript" src="runtime-panel.js"></script>
<script type="application/javascript" src="webide.js"></script>
<commandset id="mainCommandSet">
@ -167,7 +168,7 @@
<!-- Runtime panel -->
<panel id="runtime-panel" type="arrow" position="bottomcenter topright" consumeoutsideclicks="true" animate="false">
<vbox flex="1">
<vbox flex="1" id="runtime-panel-box">
<label class="panel-header">&runtimePanel_usb;</label>
<toolbarbutton class="panel-item" label="&runtimePanel_nousbdevice;" id="runtime-panel-nousbdevice" command="cmd_showTroubleShooting"/>
<toolbarbutton class="panel-item" label="&runtimePanel_noadbhelper;" id="runtime-panel-noadbhelper" command="cmd_showAddons"/>
@ -193,9 +194,9 @@
</popupset>
<notificationbox flex="1" id="notificationbox">
<hbox flex="1" id="deck-panels">
<vbox id="project-listing-panel" class="project-listing" flex="1">
<div id="project-listing-wrapper">
<div flex="1" id="deck-panels">
<vbox id="project-listing-panel" class="project-listing panel-list" flex="1">
<div id="project-listing-wrapper" class="panel-list-wrapper">
<iframe id="project-listing-panel-details" flex="1" src="project-listing.xhtml"/>
</div>
</vbox>
@ -213,7 +214,13 @@
<iframe id="deck-panel-logs" flex="1" src="logs.xhtml"/>
<iframe id="deck-panel-simulator" flex="1" lazysrc="simulator.xhtml"/>
</deck>
</hbox>
<splitter class="devtools-side-splitter" id="runtime-listing-splitter"/>
<vbox id="runtime-listing-panel" class="runtime-listing panel-list" flex="1">
<div id="runtime-listing-wrapper" class="panel-list-wrapper">
<iframe id="runtime-listing-panel-details" flex="1" src="runtime-listing.xhtml"/>
</div>
</vbox>
</div>
<splitter hidden="true" class="devtools-horizontal-splitter" orient="vertical"/>
<!-- toolbox iframe will be inserted here -->
</notificationbox>

View File

@ -117,6 +117,8 @@ let AppManager = exports.AppManager = {
* name, manifest details, etc.
* runtime:
* The selected runtime has changed.
* runtime-apps-icons:
* The list of URLs for the runtime app icons are available.
* runtime-global-actors:
* The list of global actors for the entire runtime (but not actors for a
* specific tab or app) are now available, so we can test for features
@ -131,7 +133,7 @@ let AppManager = exports.AppManager = {
* The list of remote runtime targets available from the currently
* connected runtime (such as tabs or apps) has changed, or any of the
* user-visible details (like names) for the non-selected runtime targets
* has changed. This event includes |type| in the details, to distguish
* has changed. This event includes |type| in the details, to distinguish
* "apps" and "tabs".
*/
update: function(what, details) {
@ -186,7 +188,7 @@ let AppManager = exports.AppManager = {
.then(() => {
this.checkIfProjectIsRunning();
this.update("runtime-targets", { type: "apps" });
front.fetchIcons();
front.fetchIcons().then(() => this.update("runtime-apps-icons"));
});
} else {
this._listTabsResponse = response;

View File

@ -16,9 +16,9 @@ const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/
let ProjectList;
module.exports = ProjectList = function(window, parentWindow) {
module.exports = ProjectList = function(win, parentWindow) {
EventEmitter.decorate(this);
this._doc = window.document;
this._doc = win.document;
this._UI = parentWindow.UI;
this._parentWindow = parentWindow;
this._panelNodeEl = "toolbarbutton";
@ -28,9 +28,12 @@ module.exports = ProjectList = function(window, parentWindow) {
this._panelNodeEl = "div";
}
AppManager.init();
this.onWebIDEUpdate = this.onWebIDEUpdate.bind(this);
this._UI.on("webide-update", this.onWebIDEUpdate);
return this;
AppManager.init();
this.appManagerUpdate = this.appManagerUpdate.bind(this);
AppManager.on("app-manager-update", this.appManagerUpdate);
};
ProjectList.prototype = {
@ -42,6 +45,29 @@ ProjectList.prototype = {
return this._sidebarsEnabled;
},
appManagerUpdate: function(event, what, details) {
// Got a message from app-manager.js
// See AppManager.update() for descriptions of what these events mean.
switch (what) {
case "project-removed":
case "runtime-apps-icons":
case "runtime-targets":
case "connection":
this.update(details);
break;
case "project":
this.updateCommands();
this.update(details);
break;
};
},
onWebIDEUpdate: function(event, what, details) {
if (what == "busy" || what == "unbusy") {
this.updateCommands();
}
},
/**
* testOptions: { chrome mochitest support
* folder: nsIFile, where to store the app
@ -103,7 +129,7 @@ ProjectList.prototype = {
* }
*/
_renderProjectItem: function(opts) {
if (this._sidebarsEnabled) {
if (this._sidebarsEnabled && this._doc !== this._parentWindow.document) {
let span = this._doc.createElement("span");
span.textContent = opts.name;
let icon = this._doc.createElement("img");
@ -232,7 +258,7 @@ ProjectList.prototype = {
this._renderProjectItem({
panel: panelItemNode,
name: app.manifest.name,
icon: app.iconURL
icon: app.iconURL || AppManager.DEFAULT_PROJECT_ICON
});
runtimeAppsNode.appendChild(panelItemNode);
panelItemNode.addEventListener("click", () => {
@ -242,7 +268,7 @@ ProjectList.prototype = {
AppManager.selectedProject = {
type: "runtimeApp",
app: app.manifest,
icon: app.iconURL,
icon: app.iconURL || AppManager.DEFAULT_PROJECT_ICON,
name: app.manifest.name
};
}, true);
@ -251,6 +277,38 @@ ProjectList.prototype = {
return promise.resolve();
},
updateCommands: function() {
let doc = this._doc;
let newAppCmd;
let packagedAppCmd;
let hostedAppCmd;
if (this._sidebarsEnabled) {
newAppCmd = doc.querySelector("#new-app");
packagedAppCmd = doc.querySelector("#packaged-app");
hostedAppCmd = doc.querySelector("#hosted-app");
} else {
newAppCmd = doc.querySelector("#cmd_newApp")
packagedAppCmd = doc.querySelector("#cmd_importPackagedApp");
hostedAppCmd = doc.querySelector("#cmd_importHostedApp");
}
if (!newAppCmd || !packagedAppCmd || !hostedAppCmd) {
return;
}
if (this._parentWindow.document.querySelector("window").classList.contains("busy")) {
newAppCmd.setAttribute("disabled", "true");
packagedAppCmd.setAttribute("disabled", "true");
hostedAppCmd.setAttribute("disabled", "true");
return;
}
newAppCmd.removeAttribute("disabled");
packagedAppCmd.removeAttribute("disabled");
hostedAppCmd.removeAttribute("disabled");
},
/**
* Trigger an update of the project and remote runtime list.
* @param options object (optional)
@ -323,5 +381,17 @@ ProjectList.prototype = {
}
return deferred.promise;
},
destroy: function() {
this._doc = null;
AppManager.off("app-manager-update", this.appManagerUpdate);
if (this._sidebarsEnabled) {
this._UI.off("webide-update", this.onWebIDEUpdate);
}
this._UI = null;
this._parentWindow = null;
this._panelNodeEl = null;
this._sidebarsEnabled = null;
}
};

View File

@ -0,0 +1,232 @@
/* 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 {Services} = Cu.import("resource://gre/modules/Services.jsm");
const {AppProjects} = require("devtools/app-manager/app-projects");
const {AppManager} = require("devtools/webide/app-manager");
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
const EventEmitter = require("devtools/toolkit/event-emitter");
const {RuntimeScanners, WiFiScanner} = require("devtools/webide/runtimes");
const {Devices} = Cu.import("resource://gre/modules/devtools/Devices.jsm");
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
const utils = require("devtools/webide/utils");
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
let RuntimeList;
module.exports = RuntimeList = function(window, parentWindow) {
EventEmitter.decorate(this);
this._doc = window.document;
this._UI = parentWindow.UI;
this._Cmds = parentWindow.Cmds;
this._parentWindow = parentWindow;
this._panelNodeEl = "toolbarbutton";
this._panelBoxEl = "hbox";
this._sidebarsEnabled = Services.prefs.getBoolPref("devtools.webide.sidebars");
if (this._sidebarsEnabled) {
this._panelNodeEl = "button";
this._panelBoxEl = "div";
}
this.onWebIDEUpdate = this.onWebIDEUpdate.bind(this);
this._UI.on("webide-update", this.onWebIDEUpdate);
AppManager.init();
this.appManagerUpdate = this.appManagerUpdate.bind(this);
AppManager.on("app-manager-update", this.appManagerUpdate);
};
RuntimeList.prototype = {
get doc() {
return this._doc;
},
get sidebarsEnabled() {
return this._sidebarsEnabled;
},
appManagerUpdate: function(event, what, details) {
// Got a message from app-manager.js
// See AppManager.update() for descriptions of what these events mean.
switch (what) {
case "runtime-list":
this.update();
break;
case "connection":
case "runtime-global-actors":
this.updateCommands();
break;
};
},
onWebIDEUpdate: function(event, what, details) {
if (what == "busy" || what == "unbusy") {
this.updateCommands();
}
},
takeScreenshot: function() {
return this._UI.busyUntil(AppManager.deviceFront.screenshotToDataURL().then(longstr => {
return longstr.string().then(dataURL => {
longstr.release().then(null, console.error);
this._UI.openInBrowser(dataURL);
});
}), "taking screenshot");
},
showRuntimeDetails: function() {
this._Cmds.showRuntimeDetails();
},
showPermissionsTable: function() {
this._Cmds.showPermissionsTable();
},
showDevicePreferences: function() {
this._Cmds.showDevicePrefs();
},
showSettings: function() {
this._Cmds.showSettings();
},
showTroubleShooting: function() {
this._Cmds.showTroubleShooting();
},
showAddons: function() {
this._Cmds.showAddons();
},
updateCommands: function() {
let doc = this._doc;
// Runtime commands
let screenshotCmd = doc.querySelector("#runtime-screenshot");
let permissionsCmd = doc.querySelector("#runtime-permissions");
let detailsCmd = doc.querySelector("#runtime-details");
let disconnectCmd = doc.querySelector("#runtime-disconnect");
let devicePrefsCmd = doc.querySelector("#runtime-preferences");
let settingsCmd = doc.querySelector("#runtime-settings");
if (AppManager.connected) {
if (AppManager.deviceFront) {
detailsCmd.removeAttribute("disabled");
permissionsCmd.removeAttribute("disabled");
screenshotCmd.removeAttribute("disabled");
}
if (AppManager.preferenceFront) {
devicePrefsCmd.removeAttribute("disabled");
}
if (AppManager.settingsFront) {
settingsCmd.removeAttribute("disabled");
}
disconnectCmd.removeAttribute("disabled");
} else {
detailsCmd.setAttribute("disabled", "true");
permissionsCmd.setAttribute("disabled", "true");
screenshotCmd.setAttribute("disabled", "true");
disconnectCmd.setAttribute("disabled", "true");
devicePrefsCmd.setAttribute("disabled", "true");
settingsCmd.setAttribute("disabled", "true");
}
},
update: function() {
let doc = this._doc;
let wifiHeaderNode = doc.querySelector("#runtime-header-wifi");
if (WiFiScanner.allowed) {
wifiHeaderNode.removeAttribute("hidden");
} else {
wifiHeaderNode.setAttribute("hidden", "true");
}
let usbListNode = doc.querySelector("#runtime-panel-usb");
let wifiListNode = doc.querySelector("#runtime-panel-wifi");
let simulatorListNode = doc.querySelector("#runtime-panel-simulator");
let otherListNode = doc.querySelector("#runtime-panel-other");
let noHelperNode = doc.querySelector("#runtime-panel-noadbhelper");
let noUSBNode = doc.querySelector("#runtime-panel-nousbdevice");
if (Devices.helperAddonInstalled) {
noHelperNode.setAttribute("hidden", "true");
} else {
noHelperNode.removeAttribute("hidden");
}
let runtimeList = AppManager.runtimeList;
if (!runtimeList) {
return;
}
if (runtimeList.usb.length === 0 && Devices.helperAddonInstalled) {
noUSBNode.removeAttribute("hidden");
} else {
noUSBNode.setAttribute("hidden", "true");
}
for (let [type, parent] of [
["usb", usbListNode],
["wifi", wifiListNode],
["simulator", simulatorListNode],
["other", otherListNode],
]) {
while (parent.hasChildNodes()) {
parent.firstChild.remove();
}
for (let runtime of runtimeList[type]) {
let r = runtime;
let panelItemNode = doc.createElement(this._panelBoxEl);
panelItemNode.className = "panel-item-complex";
let connectButton = doc.createElement(this._panelNodeEl);
connectButton.className = "panel-item runtime-panel-item-" + type;
if (this._sidebarsEnabled) {
connectButton.textContent = r.name;
} else {
connectButton.setAttribute("label", r.name);
connectButton.setAttribute("flex", "1");
}
connectButton.addEventListener("click", () => {
if (!this._sidebarsEnabled) {
this._UI.hidePanels();
}
this._UI.dismissErrorNotification();
this._UI.connectToRuntime(r);
}, true);
panelItemNode.appendChild(connectButton);
if (r.configure && this._UI.isRuntimeConfigurationEnabled()) {
let configButton = doc.createElement(this._panelNodeEl);
configButton.className = "configure-button";
configButton.addEventListener("click", r.configure.bind(r), true);
panelItemNode.appendChild(configButton);
}
parent.appendChild(panelItemNode);
}
}
},
destroy: function() {
this._doc = null;
AppManager.off("app-manager-update", this.appManagerUpdate);
if (this.sidebarsEnabled) {
this._UI.off("webide-update", this.onWebIDEUpdate);
}
this._UI = null;
this._Cmds = null;
this._parentWindow = null;
this._panelNodeEl = null;
this._sidebarsEnabled = null;
}
};

View File

@ -25,6 +25,7 @@ EXTRA_JS_MODULES.devtools.webide += [
'modules/build.js',
'modules/config-view.js',
'modules/project-list.js',
'modules/runtime-list.js',
'modules/runtimes.js',
'modules/simulator-process.js',
'modules/simulators.js',

View File

@ -6,7 +6,7 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webide/test/doc_ta
function test() {
waitForExplicitFinish();
SimpleTest.requestCompleteLog();
requestCompleteLog();
Task.spawn(function() {
const { DebuggerServer } =
@ -39,6 +39,7 @@ function test() {
let tabsNode = win.document.querySelector("#project-panel-tabs");
is(tabsNode.querySelectorAll(".panel-item").length, 2, "2 tabs available");
yield removeTab(tab);
yield waitForUpdate(win, "project");
yield waitForUpdate(win, "runtime-targets");
is(tabsNode.querySelectorAll(".panel-item").length, 1, "1 tab available");

View File

@ -34,7 +34,9 @@ Services.prefs.setCharPref("devtools.webide.adaptersAddonURL", TEST_BASE + "addo
Services.prefs.setCharPref("devtools.webide.templatesURL", TEST_BASE + "templates.json");
Services.prefs.setCharPref("devtools.devices.url", TEST_BASE + "browser_devices.json");
SimpleTest.registerCleanupFunction(() => {
let registerCleanupFunction = registerCleanupFunction ||
SimpleTest.registerCleanupFunction;
registerCleanupFunction(() => {
gDevTools.testing = false;
Services.prefs.clearUserPref("devtools.webide.enabled");
Services.prefs.clearUserPref("devtools.webide.enableLocalRuntime");
@ -194,10 +196,29 @@ function removeTab(aTab, aWindow) {
return deferred.promise;
}
function getRuntimeDocument(win) {
return win.document.querySelector("#runtime-listing-panel-details").contentDocument;
}
function getProjectDocument(win) {
return win.document.querySelector("#project-listing-panel-details").contentDocument;
}
function connectToLocalRuntime(aWindow) {
info("Loading local runtime.");
let panelNode = aWindow.document.querySelector("#runtime-panel");
let panelNode;
let runtimePanel;
// If we are currently toggled to the sidebar panel display in WebIDE then
// the runtime panel is in an iframe.
if (aWindow.runtimeList.sidebarsEnabled) {
runtimePanel = getRuntimeDocument(aWindow);
} else {
runtimePanel = aWindow.document;
}
panelNode = runtimePanel.querySelector("#runtime-panel");
let items = panelNode.querySelectorAll(".runtime-panel-item-other");
is(items.length, 2, "Found 2 custom runtime buttons");

View File

@ -2,4 +2,8 @@
tags = devtools
subsuite = devtools
support-files =
../doc_tabs.html
../head.js
[browser_tabs.js]
skip-if = e10s # Bug 1072167 - browser_tabs.js test fails under e10s

View File

@ -0,0 +1,75 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const TEST_URI = "http://example.com/browser/browser/devtools/webide/test/doc_tabs.html";
function test() {
waitForExplicitFinish();
requestCompleteLog();
Task.spawn(function() {
const { DebuggerServer } =
Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
// Since we test the connections set below, destroy the server in case it
// was left open.
DebuggerServer.destroy();
DebuggerServer.init();
DebuggerServer.addBrowserActors();
let tab = yield addTab(TEST_URI);
let win = yield openWebIDE();
let docProject = getProjectDocument(win);
let docRuntime = getRuntimeDocument(win);
yield connectToLocal(win, docRuntime);
is(Object.keys(DebuggerServer._connections).length, 1, "Locally connected");
yield selectTabProject(win, docProject);
ok(win.UI.toolboxPromise, "Toolbox promise exists");
yield win.UI.toolboxPromise;
let project = win.AppManager.selectedProject;
is(project.location, TEST_URI, "Location is correct");
is(project.name, "example.com: Test Tab", "Name is correct");
// Ensure tab list changes are noticed
let tabsNode = docProject.querySelector("#project-panel-tabs");
is(tabsNode.querySelectorAll(".panel-item").length, 2, "2 tabs available");
yield removeTab(tab);
yield waitForUpdate(win, "project");
yield waitForUpdate(win, "runtime-targets");
is(tabsNode.querySelectorAll(".panel-item").length, 1, "1 tab available");
yield win.Cmds.disconnectRuntime();
yield closeWebIDE(win);
DebuggerServer.destroy();
}).then(finish, handleError);
}
function connectToLocal(win, docRuntime) {
let deferred = promise.defer();
win.AppManager.connection.once(
win.Connection.Events.CONNECTED,
() => deferred.resolve());
docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
return deferred.promise;
}
function selectTabProject(win, docProject) {
return Task.spawn(function() {
yield waitForUpdate(win, "runtime-targets");
let tabsNode = docProject.querySelector("#project-panel-tabs");
let tabNode = tabsNode.querySelectorAll(".panel-item")[1];
let project = waitForUpdate(win, "project");
tabNode.click();
yield project;
});
}

View File

@ -1,9 +1,22 @@
[DEFAULT]
tags = devtools
skip-if = buildapp == 'b2g'
support-files =
../app/index.html
../app/manifest.webapp
../head.js
../device_front_shared.js
[test_duplicate_import.html]
[test_newapp.html]
[test_import.html]
[test_duplicate_import.html]
[test_runtime.html]
[test_manifestUpdate.html]
[test_addons.html]
[test_autoconnect_runtime.html]
[test_autoselect_project.html]
[test_fullscreenToolbox.html]
[test_device_preferences.html]
[test_device_permissions.html]
[test_device_settings.html]
[test_telemetry.html]

View File

@ -0,0 +1,178 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript;version=1.8" src="../head.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">
window.onload = function() {
SimpleTest.waitForExplicitFinish();
const {GetAvailableAddons} = require("devtools/webide/addons");
const {Devices} = Cu.import("resource://gre/modules/devtools/Devices.jsm");
const {Simulators} = require("devtools/webide/simulators");
let adbAddonsInstalled = promise.defer();
Devices.on("addon-status-updated", function onUpdate1() {
Devices.off("addon-status-updated", onUpdate1);
adbAddonsInstalled.resolve();
});
function getVersion(name) {
return name.match(/(\d+\.\d+)/)[0];
}
function onSimulatorInstalled(name) {
let deferred = promise.defer();
Simulators.on("updated", function onUpdate() {
Simulators.findSimulatorAddons().then(addons => {
for (let addon of addons) {
if (name == addon.name.replace(" Simulator", "")) {
Simulators.off("updated", onUpdate);
nextTick().then(deferred.resolve);
return;
}
}
});
});
return deferred.promise;
}
function installSimulatorFromUI(doc, name) {
let li = doc.querySelector('[addon="simulator-' + getVersion(name) + '"]');
li.querySelector(".install-button").click();
return onSimulatorInstalled(name);
}
function uninstallSimulatorFromUI(doc, name) {
let deferred = promise.defer();
Simulators.on("updated", function onUpdate() {
nextTick().then(() => {
let li = doc.querySelector('[status="uninstalled"][addon="simulator-' + getVersion(name) + '"]');
if (li) {
Simulators.off("updated", onUpdate);
deferred.resolve();
} else {
deferred.reject("Can't find item");
}
});
});
let li = doc.querySelector('[status="installed"][addon="simulator-' + getVersion(name) + '"]');
li.querySelector(".uninstall-button").click();
return deferred.promise;
}
function uninstallADBFromUI(doc) {
let deferred = promise.defer();
Devices.on("addon-status-updated", function onUpdate() {
nextTick().then(() => {
let li = doc.querySelector('[status="uninstalled"][addon="adb"]');
if (li) {
Devices.off("addon-status-updated", onUpdate);
deferred.resolve();
} else {
deferred.reject("Can't find item");
}
})
});
let li = doc.querySelector('[status="installed"][addon="adb"]');
li.querySelector(".uninstall-button").click();
return deferred.promise;
}
Task.spawn(function*() {
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
ok(!Devices.helperAddonInstalled, "Helper not installed");
let win = yield openWebIDE(true);
let docRuntime = getRuntimeDocument(win);
yield adbAddonsInstalled.promise;
ok(Devices.helperAddonInstalled, "Helper has been auto-installed");
yield nextTick();
let addons = yield GetAvailableAddons();
is(addons.simulators.length, 3, "3 simulator addons to install");
let sim10 = addons.simulators.filter(a => a.version == "1.0")[0];
sim10.install();
yield onSimulatorInstalled("Firefox OS 1.0");
win.Cmds.showAddons();
let frame = win.document.querySelector("#deck-panel-addons");
let addonDoc = frame.contentWindow.document;
let lis;
lis = addonDoc.querySelectorAll("li");
is(lis.length, 5, "5 addons listed");
lis = addonDoc.querySelectorAll('li[status="installed"]');
is(lis.length, 3, "3 addons installed");
lis = addonDoc.querySelectorAll('li[status="uninstalled"]');
is(lis.length, 2, "2 addons uninstalled");
info("Uninstalling Simulator 2.0");
yield installSimulatorFromUI(addonDoc, "Firefox OS 2.0");
info("Uninstalling Simulator 3.0");
yield installSimulatorFromUI(addonDoc, "Firefox OS 3.0");
yield nextTick();
let panelNode = docRuntime.querySelector("#runtime-panel");
let items;
items = panelNode.querySelectorAll(".runtime-panel-item-usb");
is(items.length, 1, "Found one runtime button");
items = panelNode.querySelectorAll(".runtime-panel-item-simulator");
is(items.length, 3, "Found 3 simulators button");
yield uninstallSimulatorFromUI(addonDoc, "Firefox OS 1.0");
yield uninstallSimulatorFromUI(addonDoc, "Firefox OS 2.0");
yield uninstallSimulatorFromUI(addonDoc, "Firefox OS 3.0");
items = panelNode.querySelectorAll(".runtime-panel-item-simulator");
is(items.length, 0, "No simulator listed");
let w = addonDoc.querySelector(".warning");
let display = addonDoc.defaultView.getComputedStyle(w).display
is(display, "none", "Warning about missing ADB hidden");
yield uninstallADBFromUI(addonDoc, "adb");
items = panelNode.querySelectorAll(".runtime-panel-item-usb");
is(items.length, 0, "No usb runtime listed");
display = addonDoc.defaultView.getComputedStyle(w).display
is(display, "block", "Warning about missing ADB present");
yield closeWebIDE(win);
SimpleTest.finish();
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,93 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript;version=1.8" src="../head.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">
window.onload = function() {
SimpleTest.waitForExplicitFinish();
Task.spawn(function*() {
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let win = yield openWebIDE();
let docRuntime = getRuntimeDocument(win);
let fakeRuntime = {
type: "USB",
connect: function(connection) {
is(connection, win.AppManager.connection, "connection is valid");
connection.host = null; // force connectPipe
connection.connect();
return promise.resolve();
},
get id() {
return "fakeRuntime";
},
get name() {
return "fakeRuntime";
}
};
win.AppManager.runtimeList.usb.push(fakeRuntime);
win.AppManager.update("runtime-list");
let panelNode = docRuntime.querySelector("#runtime-panel");
let items = panelNode.querySelectorAll(".runtime-panel-item-usb");
is(items.length, 1, "Found one runtime button");
let deferred = promise.defer();
win.AppManager.connection.once(
win.Connection.Events.CONNECTED,
() => deferred.resolve());
items[0].click();
ok(win.document.querySelector("window").className, "busy", "UI is busy");
yield win.UI._busyPromise;
is(Object.keys(DebuggerServer._connections).length, 1, "Connected");
yield nextTick();
yield closeWebIDE(win);
is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected");
win = yield openWebIDE();
win.AppManager.runtimeList.usb.push(fakeRuntime);
win.AppManager.update("runtime-list");
yield waitForUpdate(win, "runtime-targets");
is(Object.keys(DebuggerServer._connections).length, 1, "Automatically reconnected");
yield win.Cmds.disconnectRuntime();
yield closeWebIDE(win);
DebuggerServer.destroy();
SimpleTest.finish();
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,93 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript;version=1.8" src="../head.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">
window.onload = function() {
SimpleTest.waitForExplicitFinish();
Task.spawn(function* () {
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let win = yield openWebIDE();
let docRuntime = getRuntimeDocument(win);
let docProject = getProjectDocument(win);
let panelNode = docRuntime.querySelector("#runtime-panel");
let items = panelNode.querySelectorAll(".runtime-panel-item-other");
is(items.length, 2, "Found 2 runtime buttons");
// Connect to local runtime
items[1].click();
yield waitForUpdate(win, "runtime-targets");
is(Object.keys(DebuggerServer._connections).length, 1, "Locally connected");
ok(win.AppManager.isMainProcessDebuggable(), "Main process available");
// Select main process
yield win.Cmds.showProjectPanel();
yield waitForUpdate(win, "runtime-targets");
SimpleTest.executeSoon(() => {
docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
});
yield waitForUpdate(win, "project");
let lastProject = Services.prefs.getCharPref("devtools.webide.lastSelectedProject");
is(lastProject, "mainProcess:", "Last project is main process");
yield nextTick();
yield closeWebIDE(win);
is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected");
// Re-open, should reselect main process after connection
win = yield openWebIDE();
docRuntime = getRuntimeDocument(win);
panelNode = docRuntime.querySelector("#runtime-panel");
items = panelNode.querySelectorAll(".runtime-panel-item-other");
is(items.length, 2, "Found 2 runtime buttons");
// Connect to local runtime
items[1].click();
yield waitForUpdate(win, "runtime-targets");
is(Object.keys(DebuggerServer._connections).length, 1, "Locally connected");
ok(win.AppManager.isMainProcessDebuggable(), "Main process available");
is(win.AppManager.selectedProject.type, "mainProcess", "Main process reselected");
yield win.Cmds.disconnectRuntime();
yield closeWebIDE(win);
DebuggerServer.destroy();
SimpleTest.finish();
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript;version=1.8" src="../head.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">
window.onload = function() {
SimpleTest.waitForExplicitFinish();
Task.spawn(function* () {
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let win = yield openWebIDE();
let permIframe = win.document.querySelector("#deck-panel-permissionstable");
let docRuntime = getRuntimeDocument(win);
yield connectToLocalRuntime(win);
let perm = docRuntime.querySelector("#runtime-permissions");
ok(!perm.hasAttribute("disabled"), "perm cmd enabled");
let deck = win.document.querySelector("#deck");
win.Cmds.showPermissionsTable();
is(deck.selectedPanel, permIframe, "permission iframe selected");
yield nextTick();
yield lazyIframeIsLoaded(permIframe);
yield permIframe.contentWindow.getRawPermissionsTablePromise;
doc = permIframe.contentWindow.document;
trs = doc.querySelectorAll(".line");
found = false;
for (let tr of trs) {
let [name,v1,v2,v3] = tr.querySelectorAll("td");
if (name.textContent == "geolocation") {
found = true;
is(v1.className, "permprompt", "geolocation perm is valid");
is(v2.className, "permprompt", "geolocation perm is valid");
is(v3.className, "permprompt", "geolocation perm is valid");
break;
}
}
ok(found, "Found geolocation line");
doc.querySelector("#close").click();
ok(!deck.selectedPanel, "No panel selected");
DebuggerServer.destroy();
yield closeWebIDE(win);
SimpleTest.finish();
}).then(null, e => {
ok(false, "Exception: " + e);
SimpleTest.finish();
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,90 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript;version=1.8" src="../head.js"></script>
<script type="application/javascript;version=1.8" src="../device_front_shared.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">
window.onload = function() {
SimpleTest.waitForExplicitFinish();
Task.spawn(function* () {
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let win = yield openWebIDE();
let prefIframe = win.document.querySelector("#deck-panel-devicepreferences");
let docRuntime = getRuntimeDocument(win);
win.AppManager.update("runtime-list");
yield connectToLocalRuntime(win);
let prefs = docRuntime.querySelector("#runtime-preferences");
ok(!prefs.hasAttribute("disabled"), "device prefs cmd enabled");
let deck = win.document.querySelector("#deck");
win.Cmds.showDevicePrefs();
is(deck.selectedPanel, prefIframe, "device preferences iframe selected");
yield nextTick();
yield lazyIframeIsLoaded(prefIframe);
yield prefIframe.contentWindow.getAllPrefs;
setDocument(prefIframe);
let fields = doc.querySelectorAll(".editable");
addNewField();
let preference = "accessibility.accesskeycausesactivation";
fieldChange(fields, preference);
addNewFieldWithEnter();
editExistingField();
addNewFieldInteger();
yield editFieldInteger();
yield resetExistingField("accessibility.accesskeycausesactivation");
addNewFieldBoolean();
searchFields(deck, "debugger");
DebuggerServer.destroy();
yield closeWebIDE(win);
SimpleTest.finish();
}).then(null, e => {
ok(false, "Exception: " + e);
SimpleTest.finish();
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript;version=1.8" src="head.js"></script>
<script type="application/javascript;version=1.8" src="device_front_shared.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">
window.onload = function() {
SimpleTest.waitForExplicitFinish();
Task.spawn(function*() {
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
if (SpecialPowers.isMainProcess()) {
Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
}
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let win = yield openWebIDE();
let settingIframe = win.document.querySelector("#deck-panel-devicesettings");
let docRuntime = getRuntimeDocument(win);
win.AppManager.update("runtime-list");
yield connectToLocalRuntime(win);
let settings = docRuntime.querySelector("#runtime-settings");
ok(!settings.hasAttribute("disabled"), "device settings cmd enabled");
let deck = win.document.querySelector("#deck");
win.Cmds.showSettings();
is(deck.selectedPanel, settingIframe, "device settings iframe selected");
yield nextTick();
yield lazyIframeIsLoaded(settingIframe);
yield settingIframe.contentWindow.getAllSettings;
setDocument(settingIframe);
let fields = doc.querySelectorAll(".editable");
addNewField();
addNewFieldWithEnter();
editExistingField();
addNewFieldInteger();
yield editFieldInteger();
yield resetNewField("new-string-field");
addNewFieldBoolean();
searchFields(deck, "new-boolean-field2");
DebuggerServer.destroy();
yield closeWebIDE(win);
SimpleTest.finish();
}).then(null, e => {
ok(false, "Exception: " + e);
SimpleTest.finish();
});
}
</script>
</body>
</html>

View File

@ -20,7 +20,7 @@
Task.spawn(function*() {
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
let win = yield openWebIDE();
let winIframe = win.document.querySelector("#project-listing-panel-details").contentWindow;
let docProject = getProjectDocument(win);
let packagedAppLocation = getTestFilePath("../app");
let hostedAppManifest = TEST_BASE + "hosted_app.manifest";
@ -52,7 +52,7 @@
is(project.location, hostedAppManifest, "Correctly reselected existing hosted app.");
yield nextTick();
let panelNode = winIframe.document.querySelector("#project-panel");
let panelNode = docProject.querySelector("#project-panel");
let items = panelNode.querySelectorAll(".panel-item");
// 3 controls, + 2 projects
is(items.length, 5, "5 projects in panel");

View File

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript;version=1.8" src="../head.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">
function connectToLocal(win, docRuntime) {
let deferred = promise.defer();
win.AppManager.connection.once(
win.Connection.Events.CONNECTED,
() => deferred.resolve());
docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
return deferred.promise;
}
window.onload = function() {
SimpleTest.waitForExplicitFinish();
Task.spawn(function* () {
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
let win = yield openWebIDE();
let docProject = getProjectDocument(win);
let docRuntime = getRuntimeDocument(win);
win.AppManager.update("runtime-list");
yield connectToLocal(win, docRuntime);
// Select main process
yield waitForUpdate(win, "runtime-targets");
SimpleTest.executeSoon(() => {
docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
});
yield waitForUpdate(win, "project");
ok(win.UI.toolboxPromise, "Toolbox promise exists");
yield win.UI.toolboxPromise;
ok(win.UI.toolboxIframe, "Toolbox iframe exists");
let nbox = win.document.querySelector("#notificationbox");
ok(nbox.hasAttribute("toolboxfullscreen"), "Toolbox is fullsreen");
win.Cmds.showRuntimeDetails();
ok(!nbox.hasAttribute("toolboxfullscreen"), "Toolbox is not fullscreen");
yield win.Cmds.disconnectRuntime();
yield closeWebIDE(win);
const { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
DebuggerServer.destroy();
SimpleTest.finish();
});
}
</script>
</body>
</html>

View File

@ -20,7 +20,7 @@
Task.spawn(function*() {
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
let win = yield openWebIDE();
let winIframe = win.document.querySelector("#project-listing-panel-details").contentWindow;
let docProject = getProjectDocument(win);
let packagedAppLocation = getTestFilePath("../app");
yield win.AppProjects.load();
@ -57,7 +57,7 @@
project = win.AppManager.selectedProject;
ok(project.location.endsWith('manifest.webapp'), "The manifest was found and the project was updated");
let panelNode = winIframe.document.querySelector("#project-panel");
let panelNode = docProject.querySelector("#project-panel");
let items = panelNode.querySelectorAll(".panel-item");
// 3 controls, + 2 projects
is(items.length, 6, "6 projects in panel");

View File

@ -0,0 +1,95 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript;version=1.8" src="../head.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">
window.onload = function() {
SimpleTest.waitForExplicitFinish();
let {TextDecoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
Task.spawn(function* () {
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
let win = yield openWebIDE();
let AppManager = win.AppManager;
function isProjectMarkedAsValid() {
let details = win.frames[1];
return !details.document.body.classList.contains("error");
}
let packagedAppLocation = getTestFilePath("../app");
yield win.projectList.importPackagedApp(packagedAppLocation);
yield waitForUpdate(win, "details");
let project = win.AppManager.selectedProject;
ok("name" in project.manifest, "manifest includes name");
is(project.name, project.manifest.name, "Display name uses manifest name");
ok(isProjectMarkedAsValid(), "project is marked as valid");
// Change the name
let originalName = project.manifest.name;
project.manifest.name = "xxx";
// Write to disk
yield AppManager.writeManifest(project);
// Read file
let manifestPath = OS.Path.join(packagedAppLocation, "manifest.webapp");
let Decoder = new TextDecoder();
let data = yield OS.File.read(manifestPath);
data = new TextDecoder().decode(data);
let json = JSON.parse(data);
is(json.name, "xxx", "manifest written on disc");
// Make the manifest invalid on disk
delete json.name;
let Encoder = new TextEncoder();
data = Encoder.encode(JSON.stringify(json));
yield OS.File.writeAtomic(manifestPath, data , {tmpPath: manifestPath + ".tmp"});
// Trigger validation
yield AppManager.validateAndUpdateProject(AppManager.selectedProject);
yield nextTick();
ok(!("name" in project.manifest), "manifest has been updated");
is(project.name, "--", "Placeholder is used for display name");
ok(!isProjectMarkedAsValid(), "project is marked as invalid");
// Make the manifest valid on disk
project.manifest.name = originalName;
yield AppManager.writeManifest(project);
// Trigger validation
yield AppManager.validateAndUpdateProject(AppManager.selectedProject);
yield nextTick();
ok("name" in project.manifest, "manifest includes name");
is(project.name, originalName, "Display name uses original manifest name");
ok(isProjectMarkedAsValid(), "project is marked as valid");
yield closeWebIDE(win);
yield removeAllProjects();
SimpleTest.finish();
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript;version=1.8" src="../head.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">
window.onload = function() {
SimpleTest.waitForExplicitFinish();
Task.spawn(function* () {
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
let win = yield openWebIDE();
let tmpDir = FileUtils.getDir("TmpD", []);
yield win.projectList.newApp({
index: 0,
name: "webideTmpApp",
folder: tmpDir
});
let project = win.AppManager.selectedProject;
tmpDir = FileUtils.getDir("TmpD", ["webidetmpapp"]);
ok(tmpDir.isDirectory(), "Directory created");
is(project.location, tmpDir.path, "Location is valid (and lowercase)");
is(project.name, "webideTmpApp", "name field has been updated");
// Clean up
tmpDir.remove(true);
yield closeWebIDE(win);
yield removeAllProjects();
SimpleTest.finish();
});
}
</script>
</body>
</html>

View File

@ -49,7 +49,8 @@
}
win = yield openWebIDE();
let winIframe = win.document.querySelector("#project-listing-panel-details").contentWindow;
let docRuntime = getRuntimeDocument(win);
let docProject = getProjectDocument(win);
win.AppManager.runtimeList.usb.push({
connect: function(connection) {
@ -64,15 +65,40 @@
}
});
win.AppManager.runtimeList.usb.push({
connect: function(connection) {
let deferred = promise.defer();
return deferred.promise;
},
get name() {
return "infiniteRuntime";
}
});
win.AppManager.runtimeList.usb.push({
connect: function(connection) {
let deferred = promise.defer();
return deferred.promise;
},
prolongedConnection: true,
get name() {
return "prolongedRuntime";
}
});
win.AppManager.update("runtime-list");
let packagedAppLocation = getTestFilePath("app");
let packagedAppLocation = getTestFilePath("../app");
yield win.Cmds.importPackagedApp(packagedAppLocation);
yield win.projectList.importPackagedApp(packagedAppLocation);
yield waitForUpdate(win, "project-validated");
let panelNode = winIframe.document.querySelector("#runtime-panel");
let panelNode = docRuntime.querySelector("#runtime-panel");
let items = panelNode.querySelectorAll(".runtime-panel-item-usb");
is(items.length, 1, "Found one runtime button");
is(items.length, 3, "Found 3 runtime buttons");
let deferred = promise.defer();
win.AppManager.connection.once(
@ -86,7 +112,7 @@
is(Object.keys(DebuggerServer._connections).length, 1, "Connected");
yield waitForUpdate(win, "runtime-targets");
yield waitForUpdate(win, "runtime-global-actors");
ok(isPlayActive(), "play button is enabled 1");
ok(!isStopActive(), "stop button is disabled 1");
@ -113,7 +139,7 @@
ok(!isPlayActive(), "play button is disabled 4");
ok(!isStopActive(), "stop button is disabled 4");
winIframe.document.querySelectorAll(".runtime-panel-item-other")[1].click();
docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
yield waitForUpdate(win, "runtime-targets");
@ -122,9 +148,8 @@
ok(win.AppManager.isMainProcessDebuggable(), "Main process available");
// Select main process
yield win.Cmds.showProjectPanel();
SimpleTest.executeSoon(() => {
winIframe.document.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
});
yield waitForUpdate(win, "project");
@ -137,6 +162,39 @@
yield win.Cmds.disconnectRuntime();
Services.prefs.setIntPref("devtools.webide.busyTimeout", 100);
// Wait for error message since connection never completes
let errorDeferred = promise.defer();
win.UI.reportError = errorName => {
if (errorName === "error_operationTimeout") {
errorDeferred.resolve();
}
};
// Click the infinite runtime
items[1].click();
ok(win.document.querySelector("window").className, "busy", "UI is busy");
yield errorDeferred.promise;
// Check for unexpected error message since this is prolonged
let noErrorDeferred = promise.defer();
win.UI.reportError = errorName => {
if (errorName === "error_operationTimeout") {
noErrorDeferred.reject();
}
};
// Click the prolonged runtime
items[2].click();
ok(win.document.querySelector("window").className, "busy", "UI is busy");
setTimeout(() => {
noErrorDeferred.resolve();
}, 1000);
yield noErrorDeferred.promise;
SimpleTest.finish();
});
}

View File

@ -0,0 +1,268 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript;version=1.8" src="../head.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 Telemetry = require("devtools/shared/telemetry");
const { _DeprecatedUSBRuntime, _WiFiRuntime, _SimulatorRuntime,
_gRemoteRuntime, _gLocalRuntime, RuntimeTypes }
= require("devtools/webide/runtimes");
// Because we need to gather stats for the period of time that a tool has
// been opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
function patchTelemetry() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];
}
this.telemetryInfo[histogramId].push(value);
}
}
}
function resetTelemetry() {
Telemetry.prototype.log = Telemetry.prototype._oldlog;
delete Telemetry.prototype._oldlog;
delete Telemetry.prototype.telemetryInfo;
}
function cycleWebIDE() {
return Task.spawn(function*() {
let win = yield openWebIDE();
// Wait a bit, so we're open for a non-zero time
yield waitForTime(TOOL_DELAY);
yield closeWebIDE(win);
});
}
function addFakeRuntimes(win) {
// We use the real runtimes here (and switch out some functionality)
// so we can ensure that logging happens as it would in real use.
let usb = new _DeprecatedUSBRuntime("fakeUSB");
// Use local pipe instead
usb.connect = function(connection) {
ok(connection, win.AppManager.connection, "connection is valid");
connection.host = null; // force connectPipe
connection.connect();
return promise.resolve();
};
win.AppManager.runtimeList.usb.push(usb);
let wifi = new _WiFiRuntime("fakeWiFi");
// Use local pipe instead
wifi.connect = function(connection) {
ok(connection, win.AppManager.connection, "connection is valid");
connection.host = null; // force connectPipe
connection.connect();
return promise.resolve();
};
win.AppManager.runtimeList.wifi.push(wifi);
let sim = new _SimulatorRuntime("fakeSimulator");
// Use local pipe instead
sim.connect = function(connection) {
ok(connection, win.AppManager.connection, "connection is valid");
connection.host = null; // force connectPipe
connection.connect();
return promise.resolve();
};
Object.defineProperty(sim, "name", {
get() {
return this.version;
}
});
win.AppManager.runtimeList.simulator.push(sim);
let remote = _gRemoteRuntime;
// Use local pipe instead
remote.connect = function(connection) {
ok(connection, win.AppManager.connection, "connection is valid");
connection.host = null; // force connectPipe
connection.connect();
return promise.resolve();
};
let local = _gLocalRuntime;
let other = Object.create(_gLocalRuntime);
other.type = RuntimeTypes.OTHER;
win.AppManager.runtimeList.other = [remote, local, other];
win.AppManager.update("runtime-list");
}
function addTestApp(win) {
return Task.spawn(function*() {
let packagedAppLocation = getTestFilePath("../app");
yield win.projectList.importPackagedApp(packagedAppLocation);
yield waitForUpdate(win, "project-validated");
});
}
function startConnection(win, docRuntime, type, index) {
let panelNode = docRuntime.querySelector("#runtime-panel");
let items = panelNode.querySelectorAll(".runtime-panel-item-" + type);
if (index === undefined) {
is(items.length, 1, "Found one runtime button");
}
let deferred = promise.defer();
win.AppManager.connection.once(
win.Connection.Events.CONNECTED,
() => deferred.resolve());
items[index || 0].click();
return deferred.promise;
}
function waitUntilConnected(win) {
return Task.spawn(function*() {
ok(win.document.querySelector("window").className, "busy", "UI is busy");
yield win.UI._busyPromise;
is(Object.keys(DebuggerServer._connections).length, 1, "Connected");
});
}
function connectToRuntime(win, docRuntime, type, index) {
return Task.spawn(function*() {
startConnection(win, docRuntime, type, index);
yield waitUntilConnected(win);
});
}
function checkResults() {
let result = Telemetry.prototype.telemetryInfo;
for (let [histId, value] of Iterator(result)) {
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
ok(value.length === 1 && !!value[0],
"Per user value " + histId + " has a single value of true");
} else if (histId.endsWith("OPENED_BOOLEAN")) {
ok(value.length > 1, histId + " has more than one entry");
let okay = value.every(function(element) {
return !!element;
});
ok(okay, "All " + histId + " entries are true");
} else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
ok(value.length > 1, histId + " has more than one entry");
let okay = value.every(function(element) {
return element > 0;
});
ok(okay, "All " + histId + " entries have time > 0");
} else if (histId === "DEVTOOLS_WEBIDE_CONNECTION_RESULT") {
ok(value.length === 6, histId + " has 6 connection results");
let okay = value.every(function(element) {
return !!element;
});
ok(okay, "All " + histId + " connections succeeded");
} else if (histId.endsWith("CONNECTION_RESULT")) {
ok(value.length === 1 && !!value[0],
histId + " has 1 successful connection");
} else if (histId === "DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS") {
ok(value.length === 6, histId + " has 6 connection results");
let okay = value.every(function(element) {
return element > 0;
});
ok(okay, "All " + histId + " connections have time > 0");
} else if (histId.endsWith("USED")) {
ok(value.length === 6, histId + " has 6 connection actions");
let okay = value.every(function(element) {
return !element;
});
ok(okay, "All " + histId + " actions were skipped");
} else {
ok(false, "Unexpected " + histId + " was logged");
}
}
}
window.onload = function() {
SimpleTest.waitForExplicitFinish();
let win;
SimpleTest.registerCleanupFunction(() => {
Task.spawn(function*() {
if (win) {
yield closeWebIDE(win);
}
DebuggerServer.destroy();
yield removeAllProjects();
resetTelemetry();
});
});
Task.spawn(function*() {
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
patchTelemetry();
// Cycle once, so we can test for multiple opens
yield cycleWebIDE();
win = yield openWebIDE();
let docRuntime = getRuntimeDocument(win);
// Wait a bit, so we're open for a non-zero time
yield waitForTime(TOOL_DELAY);
addFakeRuntimes(win);
yield addTestApp(win);
// Each one should log a connection result and non-zero connection
// time
yield connectToRuntime(win, docRuntime, "usb");
yield waitForTime(TOOL_DELAY);
yield connectToRuntime(win, docRuntime, "wifi");
yield waitForTime(TOOL_DELAY);
yield connectToRuntime(win, docRuntime, "simulator");
yield waitForTime(TOOL_DELAY);
yield connectToRuntime(win, docRuntime, "other", 0 /* remote */);
yield waitForTime(TOOL_DELAY);
yield connectToRuntime(win, docRuntime, "other", 1 /* local */);
yield waitForTime(TOOL_DELAY);
yield connectToRuntime(win, docRuntime, "other", 2 /* other */);
yield waitForTime(TOOL_DELAY);
yield closeWebIDE(win);
checkResults();
SimpleTest.finish();
});
}
</script>
</body>
</html>

View File

@ -21,8 +21,11 @@
Task.spawn(function* () {
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
DebuggerServer.init();
DebuggerServer.addBrowserActors();
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let win = yield openWebIDE();

View File

@ -21,8 +21,11 @@
Task.spawn(function* () {
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
DebuggerServer.init();
DebuggerServer.addBrowserActors();
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let win = yield openWebIDE();

View File

@ -90,7 +90,7 @@
let packagedAppLocation = getTestFilePath("app");
yield win.Cmds.importPackagedApp(packagedAppLocation);
yield win.projectList.importPackagedApp(packagedAppLocation);
yield waitForUpdate(win, "project-validated");
let panelNode = win.document.querySelector("#runtime-panel");

View File

@ -17,5 +17,5 @@ webide.jar:
skin/config-view.css (config-view.css)
skin/wifi-auth.css (wifi-auth.css)
skin/logs.css (logs.css)
skin/project-listing.css (project-listing.css)
skin/panel-listing.css (panel-listing.css)
skin/simulator.css (simulator.css)

View File

@ -8,10 +8,10 @@ html {
font-weight: normal;
}
.panel-item, label, #project-panel-projects {
.panel-item, label, #project-panel-projects, #runtime-panel-projects {
display: block;
float: left;
width: 100%;
width: auto;
}
.project-image, .panel-item span {
@ -25,13 +25,14 @@ html {
max-height: 20px;
}
label {
color: #888;
display: block;
font-size: 12px;
padding: 15px 0 5px;
text-shadow: 1px 1px #fff;
.panel-header {
color: #ACACAC;
text-transform: uppercase;
line-height: 200%;
margin: 5px 0;
font-size: 100%;
font-weight: bold;
width: 100%;
}
.panel-item {
@ -39,3 +40,7 @@ label {
padding: 5px 0;
min-width: 130px;
}
.panel-header[hidden] {
display: none;
}

View File

@ -151,14 +151,14 @@ panel > .panel-arrowcontainer > .panel-arrowcontent {
max-width: 400px;
}
#project-listing-panel {
.panel-list {
display: none;
position: relative;
max-width: 250px;
overflow: hidden;
}
#project-listing-wrapper {
.panel-list-wrapper {
height: 100%;
width: 100%;
min-width: 100px;
@ -169,7 +169,7 @@ panel > .panel-arrowcontainer > .panel-arrowcontent {
left: 0;
}
#project-listing-panel-details {
.panel-list-wrapper > iframe {
height: inherit;
width: 100%;
position: absolute;
@ -180,12 +180,14 @@ panel > .panel-arrowcontainer > .panel-arrowcontent {
}
/* TODO: remove once Bug 1079347 is complete */
.project-listing, #project-listing-splitter {
.project-listing, #project-listing-splitter, #runtime-listing-splitter {
display: none;
}
#project-listing-splitter[sidebar-displayed], #project-listing-panel[sidebar-displayed],
#project-listing-panel[sidebar-displayed] .project-listing {
#project-listing-panel[sidebar-displayed] .project-listing,
#runtime-listing-splitter[sidebar-displayed], #runtime-listing-panel[sidebar-displayed],
#runtime-listing-panel[sidebar-displayed] .runtime-listing {
display: block;
}
@ -272,8 +274,9 @@ panel > .panel-arrowcontainer > .panel-arrowcontent {
#runtime-details { -moz-image-region: rect(156px,438px,182px,412px) }
#runtime-screenshot { -moz-image-region: rect(130px,438px,156px,412px) }
#runtime-permissions { -moz-image-region: rect(104px,438px,130px,412px) }
#runtime-preferences { -moz-image-region: rect(104px,462px,129px,438px) }
#runtime-settings { -moz-image-region: rect(104px,462px,129px,438px) }
#runtime-preferences, #runtime-settings {
-moz-image-region: rect(104px,462px,129px,438px);
}
#runtime-disconnect { -moz-image-region: rect(52px,438px,78px,412px) }
#runtime-panel-nousbdevice { -moz-image-region: rect(156px,438px,182px,412px) }
#runtime-panel-noadbhelper { -moz-image-region: rect(234px,438px,260px,412px) }

View File

@ -5,6 +5,7 @@ const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm");
const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils.js");
const EventEmitter = require("devtools/toolkit/event-emitter");
// XXX: bug 912476 make this module a real protocol.js front
@ -620,8 +621,9 @@ AppActorFront.prototype = {
for (let [manifestURL, app] of this._apps) {
promises.push(app.getIcon());
}
return promise.all(promises)
.then(null, () => {}); // Ignore any failure
return DevToolsUtils.settleAll(promises)
.then(null, () => {});
},
_listenAppEvents: function (listener) {